2.5 - NLA SoC Branch Merged to 2.5!

(19863 to 21513)

Highlights of the new NLA System (and related Animation System changes):
* NLA Data is stored in AnimData alongside Action and Drivers. The NLA stack is evaluated before the Action, with the Action always overriding the results of the stack.
* NLA Data is arranged in 'Tracks', which act like PhotoShop layers. These can be muted, protected, and/or made to be played back by themselves
* Within each track, there can be multiple 'Strips'. There are 3 types of strip -> Action Clip (references some action), Transition (blends between the endpoints of two strips), and Meta (container for several strips that occur sequentially)
* FModifiers can be applied to strips, and strips can have animated influence/time controls. Playback for strips can also be backwards now!
* Playback can now go in forward and backwards directions.
* Animation Editors have been polished (unfinished features added, existing features cleaned up and made more consistent)

Notes for BuildSystem Maintainers:
* Only scons has been actively tested. Makefiles should work fine.
* MSVC ProjectFiles are broken due to the very way they work.
* CMake status unknown...

Other notes:
* Hopefully I haven't made any mistakes while doing the merge. More files than expected were showing some weird conflicts, so you may have some broken code...
* Not all old files (with NLA) data load exactly the same anymore. However, the bulk of the files out there should be ok (I hope)
This commit is contained in:
Joshua Leung 2009-07-11 05:41:21 +00:00
commit 4a0df3ad7b
96 changed files with 13975 additions and 5756 deletions

@ -68,6 +68,9 @@ void make_local_action(struct bAction *act);
/* Some kind of bounding box operation on the action */
void calc_action_range(const struct bAction *act, float *start, float *end, int incl_hidden);
/* Does action have any motion data at all? */
short action_has_motion(const struct bAction *act);
/* Action Groups API ----------------- */
/* Make the given Action Group the active one */
@ -145,12 +148,6 @@ void copy_pose_result(struct bPose *to, struct bPose *from);
/* clear all transforms */
void rest_pose(struct bPose *pose);
/* map global time (frame nr) to strip converted time, doesn't clip */
float get_action_frame(struct Object *ob, float cframe);
/* map strip time to global time (frame nr) */
float get_action_frame_inv(struct Object *ob, float cframe);
/* functions used by the game engine */
void game_copy_pose(struct bPose **dst, struct bPose *src);
void game_free_pose(struct bPose *pose);

@ -1,12 +1,33 @@
/* Testing code for new animation system in 2.5
* Copyright 2009, Joshua Leung
/**
* $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) 2009 Blender Foundation, Joshua Leung
* All rights reserved.
*
* Contributor(s): Joshua Leung (full recode)
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef BKE_FCURVE_H
#define BKE_FCURVE_H
//struct ListBase;
struct FCurve;
struct FModifier;
struct ChannelDriver;
@ -54,8 +75,8 @@ typedef struct FModifierTypeInfo {
short size; /* size in bytes of the struct */
short acttype; /* eFMI_Action_Types */
short requires; /* eFMI_Requirement_Flags */
char name[32]; /* name of modifier in interface */
char structName[32]; /* name of struct for SDNA */
char name[64]; /* name of modifier in interface */
char structName[64]; /* name of struct for SDNA */
/* data management function pointers - special handling */
/* free any data that is allocated separately (optional) */
@ -104,14 +125,20 @@ FModifierTypeInfo *get_fmodifier_typeinfo(int type);
/* ---------------------- */
struct FModifier *fcurve_add_modifier(struct FCurve *fcu, int type);
void fcurve_copy_modifiers(ListBase *dst, ListBase *src);
void fcurve_remove_modifier(struct FCurve *fcu, struct FModifier *fcm);
void fcurve_free_modifiers(struct FCurve *fcu);
void fcurve_bake_modifiers(struct FCurve *fcu, int start, int end);
struct FModifier *add_fmodifier(ListBase *modifiers, int type);
void copy_fmodifiers(ListBase *dst, ListBase *src);
void remove_fmodifier(ListBase *modifiers, struct FModifier *fcm);
void free_fmodifiers(ListBase *modifiers);
struct FModifier *fcurve_find_active_modifier(struct FCurve *fcu);
void fcurve_set_active_modifier(struct FCurve *fcu, struct FModifier *fcm);
struct FModifier *find_active_fmodifier(ListBase *modifiers);
void set_active_fmodifier(ListBase *modifiers, struct FModifier *fcm);
short list_has_suitable_fmodifier(ListBase *modifiers, int mtype, short acttype);
float evaluate_time_fmodifiers(ListBase *modifiers, struct FCurve *fcu, float cvalue, float evaltime);
void evaluate_value_fmodifiers(ListBase *modifiers, struct FCurve *fcu, float *cvalue, float evaltime);
void fcurve_bake_modifiers(struct FCurve *fcu, int start, int end);
/* ************** F-Curves API ******************** */
@ -126,9 +153,6 @@ void copy_fcurves(ListBase *dst, ListBase *src);
/* find matching F-Curve in the given list of F-Curves */
struct FCurve *list_find_fcurve(ListBase *list, const char rna_path[], const int array_index);
/* test if there is a keyframe at cfra */
short on_keyframe_fcurve(struct FCurve *fcu, float cfra);
/* get the time extents for F-Curve */
void calc_fcurve_range(struct FCurve *fcu, float *min, float *max);

@ -17,12 +17,12 @@
* 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.
* The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
* Contributor(s): Joshua Leung (full recode)
*
* ***** END GPL LICENSE BLOCK *****
*/
@ -30,15 +30,90 @@
#ifndef BKE_NLA_H
#define BKE_NLA_H
struct bActionStrip;
struct ListBase;
struct Object;
struct AnimData;
struct NlaStrip;
struct NlaTrack;
struct bAction;
/* ----------------------------- */
/* Data Management */
void free_nlastrip(ListBase *strips, struct NlaStrip *strip);
void free_nlatrack(ListBase *tracks, struct NlaTrack *nlt);
void free_nladata(ListBase *tracks);
struct NlaStrip *copy_nlastrip(struct NlaStrip *strip);
struct NlaTrack *copy_nlatrack(struct NlaTrack *nlt);
void copy_nladata(ListBase *dst, ListBase *src);
struct NlaTrack *add_nlatrack(struct AnimData *adt, struct NlaTrack *prev);
struct NlaStrip *add_nlastrip(struct bAction *act);
struct NlaStrip *add_nlastrip_to_stack(struct AnimData *adt, struct bAction *act);
/* ----------------------------- */
/* API */
short BKE_nlastrips_has_space(ListBase *strips, float start, float end);
void BKE_nlastrips_sort_strips(ListBase *strips);
short BKE_nlastrips_add_strip(ListBase *strips, struct NlaStrip *strip);
void BKE_nlastrips_make_metas(ListBase *strips, short temp);
void BKE_nlastrips_clear_metas(ListBase *strips, short onlySel, short onlyTemp);
void BKE_nlastrips_clear_metastrip(ListBase *strips, struct NlaStrip *strip);
short BKE_nlameta_add_strip(struct NlaStrip *mstrip, struct NlaStrip *strip);
void BKE_nlameta_flush_transforms(struct NlaStrip *mstrip);
/* ............ */
struct NlaTrack *BKE_nlatrack_find_active(ListBase *tracks);
void BKE_nlatrack_set_active(ListBase *tracks, struct NlaTrack *nlt);
void BKE_nlatrack_solo_toggle(struct AnimData *adt, struct NlaTrack *nlt);
short BKE_nlatrack_has_space(struct NlaTrack *nlt, float start, float end);
void BKE_nlatrack_sort_strips(struct NlaTrack *nlt);
short BKE_nlatrack_add_strip(struct NlaTrack *nlt, struct NlaStrip *strip);
/* ............ */
struct NlaStrip *BKE_nlastrip_find_active(struct NlaTrack *nlt);
short BKE_nlastrip_within_bounds(struct NlaStrip *strip, float min, float max);
void BKE_nlastrip_validate_name(struct AnimData *adt, struct NlaStrip *strip);
/* ............ */
short BKE_nlatrack_has_animated_strips(struct NlaTrack *nlt);
short BKE_nlatracks_have_animated_strips(ListBase *tracks);
void BKE_nlastrip_validate_fcurves(struct NlaStrip *strip);
/* ............ */
void BKE_nla_action_pushdown(struct AnimData *adt);
short BKE_nla_tweakmode_enter(struct AnimData *adt);
void BKE_nla_tweakmode_exit(struct AnimData *adt);
/* ----------------------------- */
/* Time Mapping */
/* time mapping conversion modes */
enum {
/* convert from global time to strip time - for evaluation */
NLATIME_CONVERT_EVAL = 0,
/* convert from global time to strip time - for editing corrections */
// XXX old 0 invert
NLATIME_CONVERT_UNMAP,
/* convert from strip time to global time */
// xxx old 1 invert
NLATIME_CONVERT_MAP,
} eNlaTime_ConvertModes;
float BKE_nla_tweakedit_remap(struct AnimData *adt, float cframe, short mode);
void free_actionstrip (struct bActionStrip* strip);
void free_nlastrips (struct ListBase *nlalist);
void copy_nlastrips (struct ListBase *dst, struct ListBase *src);
void copy_actionstrip (struct bActionStrip **dst, struct bActionStrip **src);
void find_stridechannel(struct Object *ob, struct bActionStrip *strip);
struct bActionStrip *convert_action_to_strip (struct Object *ob);
#endif

@ -128,6 +128,7 @@
#define IS_EQT(a, b, c) ((a > b)? (((a-b) <= c)? 1:0) : ((((b-a) <= c)? 1:0)))
#define IN_RANGE(a, b, c) ((b < c)? ((b<a && a<c)? 1:0) : ((c<a && a<b)? 1:0))
#define IN_RANGE_INCL(a, b, c) ((b < c)? ((b<=a && a<=c)? 1:0) : ((c<=a && a<=b)? 1:0))
/* this weirdo pops up in two places ... */
#if !defined(WIN32)

@ -769,70 +769,23 @@ void framechange_poses_clear_unkeyed(void)
/* ************** time ****************** */
static bActionStrip *get_active_strip(Object *ob)
/* Check if the given action has any keyframes */
short action_has_motion(const bAction *act)
{
#if 0 // XXX old animation system
bActionStrip *strip;
FCurve *fcu;
if(ob->action==NULL)
return NULL;
/* return on the first F-Curve that has some keyframes/samples defined */
if (act) {
for (fcu= act->curves.first; fcu; fcu= fcu->next) {
if (fcu->totvert)
return 1;
}
}
for (strip=ob->nlastrips.first; strip; strip=strip->next)
if(strip->flag & ACTSTRIP_ACTIVE)
break;
if(strip && strip->act==ob->action)
return strip;
#endif // XXX old animation system
return NULL;
/* nothing found */
return 0;
}
/* non clipped mapping of strip */
static float get_actionstrip_frame(bActionStrip *strip, float cframe, int invert)
{
float length, actlength, repeat, scale;
if (strip->repeat == 0.0f) strip->repeat = 1.0f;
repeat = (strip->flag & ACTSTRIP_USESTRIDE) ? (1.0f) : (strip->repeat);
if (strip->scale == 0.0f) strip->scale= 1.0f;
scale = (float)fabs(strip->scale); /* scale must be positive (for now) */
actlength = strip->actend-strip->actstart;
if (actlength == 0.0f) actlength = 1.0f;
length = repeat * scale * actlength;
/* invert = convert action-strip time to global time */
if (invert)
return length*(cframe - strip->actstart)/(repeat*actlength) + strip->start;
else
return repeat*actlength*(cframe - strip->start)/length + strip->actstart;
}
/* if the conditions match, it converts current time to strip time */
float get_action_frame(Object *ob, float cframe)
{
bActionStrip *strip= get_active_strip(ob);
if(strip)
return get_actionstrip_frame(strip, cframe, 0);
return cframe;
}
/* inverted, strip time to current time */
float get_action_frame_inv(Object *ob, float cframe)
{
bActionStrip *strip= get_active_strip(ob);
if(strip)
return get_actionstrip_frame(strip, cframe, 1);
return cframe;
}
/* Calculate the extents of given action */
void calc_action_range(const bAction *act, float *start, float *end, int incl_hidden)
{

@ -1,10 +1,37 @@
/* Testing code for new animation system in 2.5
* Copyright 2009, Joshua Leung
/**
* $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) 2009 Blender Foundation, Joshua Leung
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Joshua Leung (full recode)
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <float.h>
#include <math.h>
#include "MEM_guardedalloc.h"
@ -12,9 +39,12 @@
#include "BLI_arithb.h"
#include "BLI_dynstr.h"
#include "DNA_anim_types.h"
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_fcurve.h"
#include "BKE_nla.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_utildefines.h"
@ -22,7 +52,7 @@
#include "RNA_access.h"
#include "RNA_types.h"
#include "DNA_anim_types.h"
#include "nla_private.h"
/* ***************************************** */
/* AnimData API */
@ -116,6 +146,12 @@ void BKE_free_animdata (ID *id)
/* unlink action (don't free, as it's in its own list) */
if (adt->action)
adt->action->id.us--;
/* same goes for the temporarily displaced action */
if (adt->tmpact)
adt->tmpact->id.us--;
/* free nla data */
free_nladata(&adt->nla_tracks);
/* free drivers - stored as a list of F-Curves */
free_fcurves(&adt->drivers);
@ -146,9 +182,10 @@ AnimData *BKE_copy_animdata (AnimData *adt)
// XXX review this... it might not be optimal behaviour yet...
//id_us_plus((ID *)dadt->action);
dadt->action= copy_action(adt->action);
dadt->tmpact= copy_action(adt->tmpact);
/* duplicate NLA data */
// XXX todo...
copy_nladata(&dadt->nla_tracks, &adt->nla_tracks);
/* duplicate drivers (F-Curves) */
copy_fcurves(&dadt->drivers, &adt->drivers);
@ -355,10 +392,10 @@ void BKE_keyingsets_free (ListBase *list)
short animsys_remap_path (AnimMapper *remap, char *path, char **dst)
{
/* is there a valid remapping table to use? */
if (remap) {
//if (remap) {
/* find a matching entry... to use to remap */
// ...TODO...
}
//}
/* nothing suitable found, so just set dst to look at path (i.e. no alloc/free needed) */
*dst= path;
@ -455,11 +492,14 @@ static void animsys_evaluate_fcurves (PointerRNA *ptr, ListBase *list, AnimMappe
/* calculate then execute each curve */
for (fcu= list->first; fcu; fcu= fcu->next)
{
/* check if this curve should be skipped */
if ((fcu->flag & (FCURVE_MUTED|FCURVE_DISABLED)) == 0)
{
calculate_fcurve(fcu, ctime);
animsys_execute_fcurve(ptr, remap, fcu);
/* check if this F-Curve doesn't belong to a muted group */
if ((fcu->grp == NULL) || (fcu->grp->flag & AGRP_MUTED)==0) {
/* check if this curve should be skipped */
if ((fcu->flag & (FCURVE_MUTED|FCURVE_DISABLED)) == 0)
{
calculate_fcurve(fcu, ctime);
animsys_execute_fcurve(ptr, remap, fcu);
}
}
}
}
@ -481,7 +521,6 @@ static void animsys_evaluate_drivers (PointerRNA *ptr, AnimData *adt, float ctim
short ok= 0;
/* check if this driver's curve should be skipped */
// FIXME: maybe we shouldn't check for muted, though that would make things more confusing, as there's already too many ways to disable?
if ((fcu->flag & (FCURVE_MUTED|FCURVE_DISABLED)) == 0)
{
/* check if driver itself is tagged for recalculation */
@ -514,6 +553,10 @@ void animsys_evaluate_action_group (PointerRNA *ptr, bAction *act, bActionGroup
if ELEM(NULL, act, agrp) return;
if ((remap) && (remap->target != act)) remap= NULL;
/* if group is muted, don't evaluated any of the F-Curve */
if (agrp->flag & AGRP_MUTED)
return;
/* calculate then execute each curve */
for (fcu= agrp->channels.first; (fcu) && (fcu->grp == agrp); fcu= fcu->next)
{
@ -540,152 +583,590 @@ void animsys_evaluate_action (PointerRNA *ptr, bAction *act, AnimMapper *remap,
/* ***************************************** */
/* NLA System - Evaluation */
/* used for list of strips to accumulate at current time */
typedef struct NlaEvalStrip {
struct NlaEvalStrip *next, *prev;
NlaTrack *track; /* track that this strip belongs to */
NlaStrip *strip; /* strip that's being used */
NlaStrip *sblend; /* strip that's being blended towards (if applicable) */
short track_index; /* the index of the track within the list */
short strip_mode; /* which end of the strip are we looking at */
} NlaEvalStrip;
/* bNlaEvalStrip->strip_mode */
enum {
NES_TIME_BEFORE = -1,
NES_TIME_WITHIN,
NES_TIME_AFTER,
NES_TIME_AFTER_BLEND
} eNlaEvalStrip_StripMode;
/* temp channel for accumulating data from NLA (avoids needing to clear all values first) */
// TODO: maybe this will be used as the 'cache' stuff needed for editable values too?
typedef struct NlaEvalChannel {
struct NlaEvalChannel *next, *prev;
char *path; /* ready-to-use path (i.e. remapped already) */
int array_index; /* if applicable... */
float value; /* value of this channel */
} NlaEvalChannel;
/* ---------------------- */
/* evaluate the F-Curves controlling settings for the NLA-strips (currently, not relinkable) */
static void nlastrip_evaluate_fcurves (NlaStrip *strip, float ctime)
/* calculate influence of strip based for given frame based on blendin/out values */
static float nlastrip_get_influence (NlaStrip *strip, float cframe)
{
//PointerRNA actstrip_ptr;
//FCurve *fcu;
/* sanity checks - normalise the blendin/out values? */
strip->blendin= (float)fabs(strip->blendin);
strip->blendout= (float)fabs(strip->blendout);
/* create RNA-pointer needed to set values */
//RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &actstrip_ptr);
/* execute these settings as per normal */
//animsys_evaluate_fcurves(&actstrip_ptr, &strip->fcurves, NULL, ctime);
/* result depends on where frame is in respect to blendin/out values */
if (IS_EQ(strip->blendin, 0)==0 && (cframe <= (strip->start + strip->blendin))) {
/* there is some blend-in */
return (float)fabs(cframe - strip->start) / (strip->blendin);
}
else if (IS_EQ(strip->blendout, 0)==0 && (cframe >= (strip->end - strip->blendout))) {
/* there is some blend-out */
return (float)fabs(strip->end - cframe) / (strip->blendout);
}
else {
/* in the middle of the strip, we should be full strength */
return 1.0f;
}
}
/* gets the strip active at the current time for a track */
static void nlatrack_ctime_get_strip (ListBase *list, NlaTrack *nlt, short index, float ctime)
/* evaluate the evaluation time and influence for the strip, storing the results in the strip */
static void nlastrip_evaluate_controls (NlaStrip *strip, float ctime)
{
NlaStrip *strip, *astrip=NULL, *bstrip=NULL;
/* firstly, analytically generate values for influence and time (if applicable) */
if ((strip->flag & NLASTRIP_FLAG_USR_TIME) == 0)
strip->strip_time= nlastrip_get_frame(strip, ctime, NLATIME_CONVERT_EVAL);
if ((strip->flag & NLASTRIP_FLAG_USR_INFLUENCE) == 0)
strip->influence= nlastrip_get_influence(strip, ctime);
/* now strip's evaluate F-Curves for these settings (if applicable) */
if (strip->fcurves.first) {
PointerRNA strip_ptr;
/* create RNA-pointer needed to set values */
RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
/* execute these settings as per normal */
animsys_evaluate_fcurves(&strip_ptr, &strip->fcurves, NULL, ctime);
}
}
/* gets the strip active at the current time for a list of strips for evaluation purposes */
NlaEvalStrip *nlastrips_ctime_get_strip (ListBase *list, ListBase *strips, short index, float ctime)
{
NlaStrip *strip, *estrip=NULL;
NlaEvalStrip *nes;
short side= 0;
/* skip if track is muted */
if (nlt->flag & NLATRACK_MUTED)
return;
/* loop over strips, checking if they fall within the range */
for (strip= nlt->strips.first; strip; strip= strip->next) {
/* only consider if:
* - current time occurs within strip's extents
* - current time occurs before strip (if it is the first)
* - current time occurs after strip (if hold is on)
* - current time occurs between strips (1st of those isn't holding) - blend!
*/
if (IN_RANGE(ctime, strip->start, strip->end)) {
astrip= strip;
for (strip= strips->first; strip; strip= strip->next) {
/* check if current time occurs within this strip */
if (IN_RANGE_INCL(ctime, strip->start, strip->end)) {
/* this strip is active, so try to use it */
estrip= strip;
side= NES_TIME_WITHIN;
break;
}
else if (ctime < strip->start) {
if (strip == nlt->strips.first) {
astrip= strip;
/* if time occurred before current strip... */
if (ctime < strip->start) {
if (strip == strips->first) {
/* before first strip - only try to use it if it extends backwards in time too */
if (strip->extendmode == NLASTRIP_EXTEND_HOLD)
estrip= strip;
/* side is 'before' regardless of whether there's a useful strip */
side= NES_TIME_BEFORE;
break;
}
else {
astrip= strip->prev;
/* before next strip - previous strip has ended, but next hasn't begun,
* so blending mode depends on whether strip is being held or not...
* - only occurs when no transition strip added, otherwise the transition would have
* been picked up above...
*/
strip= strip->prev;
if (astrip->flag & NLASTRIP_HOLDLASTFRAME) {
side= NES_TIME_AFTER;
break;
}
else {
bstrip= strip;
side= NES_TIME_AFTER_BLEND;
break;
}
if (strip->extendmode != NLASTRIP_EXTEND_NOTHING)
estrip= strip;
side= NES_TIME_AFTER;
}
break;
}
/* if time occurred after current strip... */
if (ctime > strip->end) {
/* only if this is the last strip should we do anything, and only if that is being held */
if (strip == strips->last) {
if (strip->extendmode != NLASTRIP_EXTEND_NOTHING)
estrip= strip;
side= NES_TIME_AFTER;
break;
}
/* otherwise, skip... as the 'before' case will catch it more elegantly! */
}
}
/* check if strip has been found (and whether it has data worth considering) */
if (ELEM(NULL, astrip, astrip->act))
return;
if (astrip->flag & NLASTRIP_MUTE)
return;
/* check if a valid strip was found
* - must not be muted (i.e. will have contribution
*/
if ((estrip == NULL) || (estrip->flag & NLASTRIP_FLAG_MUTED))
return NULL;
/* check if blending between strips */
if (side == NES_TIME_AFTER_BLEND) {
/* blending between strips... so calculate influence+act_time of both */
nlastrip_evaluate_fcurves(astrip, ctime);
nlastrip_evaluate_fcurves(bstrip, ctime);
if ((astrip->influence <= 0.0f) && (bstrip->influence <= 0.0f))
return;
}
else {
/* calculate/set the influence+act_time of this strip - don't consider if 0 influence */
nlastrip_evaluate_fcurves(astrip, ctime);
if (astrip->influence <= 0.0f)
return;
/* if ctime was not within the boundaries of the strip, clamp! */
switch (side) {
case NES_TIME_BEFORE: /* extend first frame only */
ctime= estrip->start;
break;
case NES_TIME_AFTER: /* extend last frame only */
ctime= estrip->end;
break;
}
/* evaluate strip's evaluation controls
* - skip if no influence (i.e. same effect as muting the strip)
* - negative influence is not supported yet... how would that be defined?
*/
// TODO: this sounds a bit hacky having a few isolated F-Curves stuck on some data it operates on...
nlastrip_evaluate_controls(estrip, ctime);
if (estrip->influence <= 0.0f)
return NULL;
/* allocate new eval-strip for this strip + add to stack */
/* check if strip has valid data to evaluate,
* and/or perform any additional type-specific actions
*/
switch (estrip->type) {
case NLASTRIP_TYPE_CLIP:
/* clip must have some action to evaluate */
if (estrip->act == NULL)
return NULL;
break;
case NLASTRIP_TYPE_TRANSITION:
/* there must be strips to transition from and to (i.e. prev and next required) */
if (ELEM(NULL, estrip->prev, estrip->next))
return NULL;
/* evaluate controls for the relevant extents of the bordering strips... */
nlastrip_evaluate_controls(estrip->prev, estrip->start);
nlastrip_evaluate_controls(estrip->next, estrip->end);
break;
}
/* add to list of strips we need to evaluate */
nes= MEM_callocN(sizeof(NlaEvalStrip), "NlaEvalStrip");
nes->track= nlt;
nes->strip= astrip;
nes->sblend= bstrip;
nes->track_index= index;
nes->strip= estrip;
nes->strip_mode= side;
nes->track_index= index;
nes->strip_time= estrip->strip_time;
BLI_addtail(list, nes);
if (list)
BLI_addtail(list, nes);
return nes;
}
/* ---------------------- */
/* evaluates the given evaluation strip */
// FIXME: will we need the evaluation cache table set up to blend stuff in?
// TODO: only evaluate here, but flush in one go using the accumulated channels at end...
static void nlastrip_ctime_evaluate (ListBase *channels, NlaEvalStrip *nes, float ctime)
/* find an NlaEvalChannel that matches the given criteria
* - ptr and prop are the RNA data to find a match for
*/
static NlaEvalChannel *nlaevalchan_find_match (ListBase *channels, PointerRNA *ptr, PropertyRNA *prop, int array_index)
{
// 1. (in old code) was to extract 'IPO-channels' from actions
// 2. blend between the 'accumulated' data, and the new data
NlaEvalChannel *nec;
/* sanity check */
if (channels == NULL)
return NULL;
/* loop through existing channels, checking for a channel which affects the same property */
for (nec= channels->first; nec; nec= nec->next) {
/* - comparing the PointerRNA's is done by comparing the pointers
* to the actual struct the property resides in, since that all the
* other data stored in PointerRNA cannot allow us to definitively
* identify the data
*/
if ((nec->ptr.data == ptr->data) && (nec->prop == prop) && (nec->index == array_index))
return nec;
}
/* not found */
return NULL;
}
/* verify that an appropriate NlaEvalChannel for this F-Curve exists */
static NlaEvalChannel *nlaevalchan_verify (PointerRNA *ptr, ListBase *channels, NlaEvalStrip *nes, FCurve *fcu, short *newChan)
{
NlaEvalChannel *nec;
NlaStrip *strip= nes->strip;
PropertyRNA *prop;
PointerRNA new_ptr;
char *path = NULL;
short free_path=0;
/* sanity checks */
if (channels == NULL)
return NULL;
/* get RNA pointer+property info from F-Curve for more convenient handling */
/* get path, remapped as appropriate to work in its new environment */
free_path= animsys_remap_path(strip->remap, fcu->rna_path, &path);
/* a valid property must be available, and it must be animateable */
if (RNA_path_resolve(ptr, path, &new_ptr, &prop) == 0) {
if (G.f & G_DEBUG) printf("NLA Strip Eval: Cannot resolve path \n");
return NULL;
}
/* only ok if animateable */
else if (RNA_property_animateable(&new_ptr, prop) == 0) {
if (G.f & G_DEBUG) printf("NLA Strip Eval: Property not animateable \n");
return NULL;
}
/* try to find a match */
nec= nlaevalchan_find_match(channels, &new_ptr, prop, fcu->array_index);
/* allocate a new struct for this if none found */
if (nec == NULL) {
nec= MEM_callocN(sizeof(NlaEvalChannel), "NlaEvalChannel");
*newChan= 1;
BLI_addtail(channels, nec);
nec->ptr= new_ptr;
nec->prop= prop;
nec->index= fcu->array_index;
}
else
*newChan= 0;
/* we can now return */
return nec;
}
/* accumulate (i.e. blend) the given value on to the channel it affects */
static void nlaevalchan_accumulate (NlaEvalChannel *nec, NlaEvalStrip *nes, short newChan, float value)
{
NlaStrip *strip= nes->strip;
short blendmode= strip->blendmode;
float inf= strip->influence;
/* if channel is new, just store value regardless of blending factors, etc. */
if (newChan) {
nec->value= value;
return;
}
/* if this is being performed as part of transition evaluation, incorporate
* an additional weighting factor for the influence
*/
if (nes->strip_mode == NES_TIME_TRANSITION_END)
inf *= nes->strip_time;
/* premultiply the value by the weighting factor */
if (IS_EQ(inf, 0)) return;
value *= inf;
/* perform blending */
switch (blendmode) {
case NLASTRIP_MODE_ADD:
/* simply add the scaled value on to the stack */
nec->value += value;
break;
case NLASTRIP_MODE_SUBTRACT:
/* simply subtract the scaled value from the stack */
nec->value -= value;
break;
case NLASTRIP_MODE_MULTIPLY:
/* multiply the scaled value with the stack */
nec->value *= value;
break;
case NLASTRIP_MODE_REPLACE:
default: // TODO: do we really want to blend by default? it seems more uses might prefer add...
/* do linear interpolation
* - the influence of the accumulated data (elsewhere, that is called dstweight)
* is 1 - influence, since the strip's influence is srcweight
*/
nec->value= nec->value * (1.0f - inf) + value;
break;
}
}
/* accumulate the results of a temporary buffer with the results of the full-buffer */
static void nlaevalchan_buffers_accumulate (ListBase *channels, ListBase *tmp_buffer, NlaEvalStrip *nes)
{
NlaEvalChannel *nec, *necn, *necd;
/* optimise - abort if no channels */
if (tmp_buffer->first == NULL)
return;
/* accumulate results in tmp_channels buffer to the accumulation buffer */
for (nec= tmp_buffer->first; nec; nec= necn) {
/* get pointer to next channel in case we remove the current channel from the temp-buffer */
necn= nec->next;
/* try to find an existing matching channel for this setting in the accumulation buffer */
necd= nlaevalchan_find_match(channels, &nec->ptr, nec->prop, nec->index);
/* if there was a matching channel already in the buffer, accumulate to it,
* otherwise, add the current channel to the buffer for efficiency
*/
if (necd)
nlaevalchan_accumulate(necd, nes, 0, nec->value);
else {
BLI_remlink(tmp_buffer, nec);
BLI_addtail(channels, nec);
}
}
/* free temp-channels that haven't been assimilated into the buffer */
BLI_freelistN(tmp_buffer);
}
/* ---------------------- */
/* F-Modifier stack joining/separation utilities - should we generalise these for BLI_listbase.h interface? */
/* Temporarily join two lists of modifiers together, storing the result in a third list */
static void nlaeval_fmodifiers_join_stacks (ListBase *result, ListBase *list1, ListBase *list2)
{
FModifier *fcm1, *fcm2;
/* if list1 is invalid... */
if ELEM(NULL, list1, list1->first) {
if (list2 && list2->first) {
result->first= list2->first;
result->last= list2->last;
}
}
/* if list 2 is invalid... */
else if ELEM(NULL, list2, list2->first) {
result->first= list1->first;
result->last= list1->last;
}
else {
/* list1 should be added first, and list2 second, with the endpoints of these being the endpoints for result
* - the original lists must be left unchanged though, as we need that fact for restoring
*/
result->first= list1->first;
result->last= list2->last;
fcm1= list1->last;
fcm2= list2->first;
fcm1->next= fcm2;
fcm2->prev= fcm1;
}
}
/* Split two temporary lists of modifiers */
static void nlaeval_fmodifiers_split_stacks (ListBase *list1, ListBase *list2)
{
FModifier *fcm1, *fcm2;
/* if list1/2 is invalid... just skip */
if ELEM(NULL, list1, list2)
return;
if ELEM(NULL, list1->first, list2->first)
return;
/* get endpoints */
fcm1= list1->last;
fcm2= list2->first;
/* clear their links */
fcm1->next= NULL;
fcm2->prev= NULL;
}
/* ---------------------- */
/* evaluate action-clip strip */
static void nlastrip_evaluate_actionclip (PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
{
ListBase tmp_modifiers = {NULL, NULL};
NlaStrip *strip= nes->strip;
FCurve *fcu;
float evaltime;
/* join this strip's modifiers to the parent's modifiers (own modifiers first) */
nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers);
/* evaluate strip's modifiers which modify time to evaluate the base curves at */
evaltime= evaluate_time_fmodifiers(&tmp_modifiers, NULL, 0.0f, strip->strip_time);
/* evaluate all the F-Curves in the action, saving the relevant pointers to data that will need to be used */
for (fcu= strip->act->curves.first; fcu; fcu= fcu->next) {
NlaEvalChannel *nec;
float value = 0.0f;
short newChan = -1;
/* check if this curve should be skipped */
if (fcu->flag & (FCURVE_MUTED|FCURVE_DISABLED))
continue;
if ((fcu->grp) && (fcu->grp->flag & AGRP_MUTED))
continue;
/* evaluate the F-Curve's value for the time given in the strip
* NOTE: we use the modified time here, since strip's F-Curve Modifiers are applied on top of this
*/
value= evaluate_fcurve(fcu, evaltime);
/* apply strip's F-Curve Modifiers on this value
* NOTE: we apply the strip's original evaluation time not the modified one (as per standard F-Curve eval)
*/
evaluate_value_fmodifiers(&tmp_modifiers, fcu, &value, strip->strip_time);
/* get an NLA evaluation channel to work with, and accumulate the evaluated value with the value(s)
* stored in this channel if it has been used already
*/
nec= nlaevalchan_verify(ptr, channels, nes, fcu, &newChan);
if (nec)
nlaevalchan_accumulate(nec, nes, newChan, value);
}
/* unlink this strip's modifiers from the parent's modifiers again */
nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers);
}
/* evaluate transition strip */
static void nlastrip_evaluate_transition (PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
{
ListBase tmp_channels = {NULL, NULL};
ListBase tmp_modifiers = {NULL, NULL};
NlaEvalStrip tmp_nes;
NlaStrip *s1, *s2;
/* join this strip's modifiers to the parent's modifiers (own modifiers first) */
nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &nes->strip->modifiers, modifiers);
/* get the two strips to operate on
* - we use the endpoints of the strips directly flanking our strip
* using these as the endpoints of the transition (destination and source)
* - these should have already been determined to be valid...
* - if this strip is being played in reverse, we need to swap these endpoints
* otherwise they will be interpolated wrong
*/
if (nes->strip->flag & NLASTRIP_FLAG_REVERSE) {
s1= nes->strip->next;
s2= nes->strip->prev;
}
else {
s1= nes->strip->prev;
s2= nes->strip->next;
}
/* prepare template for 'evaluation strip'
* - based on the transition strip's evaluation strip data
* - strip_mode is NES_TIME_TRANSITION_* based on which endpoint
* - strip_time is the 'normalised' (i.e. in-strip) time for evaluation,
* which doubles up as an additional weighting factor for the strip influences
* which allows us to appear to be 'interpolating' between the two extremes
*/
tmp_nes= *nes;
/* evaluate these strips into a temp-buffer (tmp_channels) */
// FIXME: modifier evalation here needs some work...
/* first strip */
tmp_nes.strip_mode= NES_TIME_TRANSITION_START;
tmp_nes.strip= s1;
nlastrip_evaluate_actionclip(ptr, &tmp_channels, &tmp_modifiers, &tmp_nes);
/* second strip */
tmp_nes.strip_mode= NES_TIME_TRANSITION_END;
tmp_nes.strip= s2;
nlastrip_evaluate_actionclip(ptr, &tmp_channels, &tmp_modifiers, &tmp_nes);
/* assumulate temp-buffer and full-buffer, using the 'real' strip */
nlaevalchan_buffers_accumulate(channels, &tmp_channels, nes);
/* unlink this strip's modifiers from the parent's modifiers again */
nlaeval_fmodifiers_split_stacks(&nes->strip->modifiers, modifiers);
}
/* evaluate meta-strip */
static void nlastrip_evaluate_meta (PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
{
ListBase tmp_channels = {NULL, NULL};
ListBase tmp_modifiers = {NULL, NULL};
NlaStrip *strip= nes->strip;
NlaEvalStrip *tmp_nes;
float evaltime;
/* meta-strip was calculated normally to have some time to be evaluated at
* and here we 'look inside' the meta strip, treating it as a decorated window to
* it's child strips, which get evaluated as if they were some tracks on a strip
* (but with some extra modifiers to apply).
*
* NOTE: keep this in sync with animsys_evaluate_nla()
*/
/* join this strip's modifiers to the parent's modifiers (own modifiers first) */
nlaeval_fmodifiers_join_stacks(&tmp_modifiers, &strip->modifiers, modifiers);
/* find the child-strip to evaluate */
evaltime= (nes->strip_time * (strip->end - strip->start)) + strip->start;
tmp_nes= nlastrips_ctime_get_strip(NULL, &strip->strips, -1, evaltime);
if (tmp_nes == NULL)
return;
/* evaluate child-strip into tmp_channels buffer before accumulating
* in the accumulation buffer
*/
nlastrip_evaluate(ptr, &tmp_channels, &tmp_modifiers, tmp_nes);
/* assumulate temp-buffer and full-buffer, using the 'real' strip */
nlaevalchan_buffers_accumulate(channels, &tmp_channels, nes);
/* free temp eval-strip */
MEM_freeN(tmp_nes);
/* unlink this strip's modifiers from the parent's modifiers again */
nlaeval_fmodifiers_split_stacks(&strip->modifiers, modifiers);
}
/* evaluates the given evaluation strip */
void nlastrip_evaluate (PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes)
{
/* actions to take depend on the type of strip */
switch (nes->strip->type) {
case NLASTRIP_TYPE_CLIP: /* action-clip */
nlastrip_evaluate_actionclip(ptr, channels, modifiers, nes);
break;
case NLASTRIP_TYPE_TRANSITION: /* transition */
nlastrip_evaluate_transition(ptr, channels, modifiers, nes);
break;
case NLASTRIP_TYPE_META: /* meta */
nlastrip_evaluate_meta(ptr, channels, modifiers, nes);
break;
}
}
/* write the accumulated settings to */
static void nladata_flush_channels (PointerRNA *ptr, ListBase *channels)
void nladata_flush_channels (ListBase *channels)
{
NlaEvalChannel *nec;
/* sanity checks */
if (channels == NULL)
return;
/* for each channel with accumulated values, write its value on the property it affects */
for (nec= channels->first; nec; nec= nec->next) {
PointerRNA *ptr= &nec->ptr;
PropertyRNA *prop= nec->prop;
int array_index= nec->index;
float value= nec->value;
/* write values - see animsys_write_rna_setting() to sync the code */
switch (RNA_property_type(prop))
{
case PROP_BOOLEAN:
if (RNA_property_array_length(prop))
RNA_property_boolean_set_index(ptr, prop, array_index, (int)value);
else
RNA_property_boolean_set(ptr, prop, (int)value);
break;
case PROP_INT:
if (RNA_property_array_length(prop))
RNA_property_int_set_index(ptr, prop, array_index, (int)value);
else
RNA_property_int_set(ptr, prop, (int)value);
break;
case PROP_FLOAT:
if (RNA_property_array_length(prop))
RNA_property_float_set_index(ptr, prop, array_index, value);
else
RNA_property_float_set(ptr, prop, value);
break;
case PROP_ENUM:
RNA_property_enum_set(ptr, prop, (int)value);
break;
default:
// can't do anything with other types of property....
break;
}
}
}
/* ---------------------- */
@ -703,9 +1184,26 @@ static void animsys_evaluate_nla (PointerRNA *ptr, AnimData *adt, float ctime)
ListBase echannels= {NULL, NULL};
NlaEvalStrip *nes;
// TODO: need to zero out all channels used, otherwise we have problems with threadsafety
// and also when the user jumps between different times instead of moving sequentially...
/* 1. get the stack of strips to evaluate at current time (influence calculated here) */
for (nlt=adt->nla_tracks.first; nlt; nlt=nlt->next, track_index++)
nlatrack_ctime_get_strip(&estrips, nlt, track_index, ctime);
for (nlt=adt->nla_tracks.first; nlt; nlt=nlt->next, track_index++) {
/* if tweaking is on and this strip is the tweaking track, stop on this one */
if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED))
break;
/* skip if we're only considering a track tagged 'solo' */
if ((adt->flag & ADT_NLA_SOLO_TRACK) && (nlt->flag & NLATRACK_SOLO)==0)
continue;
/* skip if track is muted */
if (nlt->flag & NLATRACK_MUTED)
continue;
/* otherwise, get strip to evaluate for this channel */
nes= nlastrips_ctime_get_strip(&estrips, &nlt->strips, track_index, ctime);
if (nes) nes->track= nlt;
}
/* only continue if there are strips to evaluate */
if (estrips.first == NULL)
@ -714,10 +1212,10 @@ static void animsys_evaluate_nla (PointerRNA *ptr, AnimData *adt, float ctime)
/* 2. for each strip, evaluate then accumulate on top of existing channels, but don't set values yet */
for (nes= estrips.first; nes; nes= nes->next)
nlastrip_ctime_evaluate(&echannels, nes, ctime);
nlastrip_evaluate(ptr, &echannels, NULL, nes);
/* 3. flush effects of accumulating channels in NLA to the actual data they affect */
nladata_flush_channels(ptr, &echannels);
nladata_flush_channels(&echannels);
/* 4. free temporary evaluation data */
BLI_freelistN(&estrips);
@ -799,17 +1297,23 @@ void BKE_animsys_evaluate_animdata (ID *id, AnimData *adt, float ctime, short re
* - NLA before Active Action, as Active Action behaves as 'tweaking track'
* that overrides 'rough' work in NLA
*/
// TODO: need to double check that this all works correctly
if ((recalc & ADT_RECALC_ANIM) || (adt->recalc & ADT_RECALC_ANIM))
{
/* evaluate NLA data */
if ((adt->nla_tracks.first) && !(adt->flag & ADT_NLA_EVAL_OFF))
{
/* evaluate NLA-stack */
animsys_evaluate_nla(&id_ptr, adt, ctime);
}
/* evaluate Action data */
// FIXME: what if the solo track was not tweaking one, then nla-solo should be checked too?
if (adt->action)
/* evaluate 'active' Action (may be tweaking track) on top of results of NLA-evaluation
* - only do this if we're not exclusively evaluating the 'solo' NLA-track
*/
if ((adt->action) && !(adt->flag & ADT_NLA_SOLO_TRACK))
animsys_evaluate_action(&id_ptr, adt->action, adt->remap, ctime);
}
/* evaluate Active Action only */
else if (adt->action)
animsys_evaluate_action(&id_ptr, adt->action, adt->remap, ctime);
/* reset tag */
@ -876,10 +1380,22 @@ void BKE_animsys_evaluate_all_animation (Main *main, float ctime)
EVAL_ANIM_IDS(main->camera.first, ADT_RECALC_ANIM);
/* shapekeys */
// TODO: we probably need the same hack as for curves (ctime-hack)
EVAL_ANIM_IDS(main->key.first, ADT_RECALC_ANIM);
/* curves */
// TODO...
/* we need to perform a special hack here to ensure that the ctime
* value of the curve gets set in case there's no animation for that
* - it needs to be set before animation is evaluated just so that
* animation can successfully override...
*/
for (id= main->curve.first; id; id= id->next) {
AnimData *adt= BKE_animdata_from_id(id);
Curve *cu= (Curve *)id;
cu->ctime= ctime;
BKE_animsys_evaluate_animdata(id, adt, ctime, ADT_RECALC_ANIM);
}
/* meshes */
// TODO...

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -58,6 +58,7 @@
#include "DNA_key_types.h"
#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_nla_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force.h"
#include "DNA_particle_types.h"
@ -85,6 +86,7 @@
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
#include "BKE_nla.h"
#include "BKE_object.h"
@ -825,6 +827,10 @@ char *get_rna_access (int blocktype, int adrcode, char actname[], char constname
char buf[512];
int dummy_index= 0;
/* hack: if constname is set, we can only be dealing with an Constraint curve */
if (constname)
blocktype= ID_CO;
/* get property name based on blocktype */
switch (blocktype) {
case ID_OB: /* object */
@ -870,7 +876,10 @@ char *get_rna_access (int blocktype, int adrcode, char actname[], char constname
/* XXX problematic blocktypes */
case ID_CU: /* curve */
propname= "speed"; // XXX this was a 'dummy curve' that didn't really correspond to any real var...
/* this used to be a 'dummy' curve which got evaluated on the fly...
* now we've got real var for this!
*/
propname= "eval_time";
break;
case ID_SEQ: /* sequencer strip */
@ -1144,7 +1153,7 @@ static void icu_to_fcurves (ListBase *groups, ListBase *list, IpoCurve *icu, cha
/* Add a new FModifier (Cyclic) instead of setting extend value
* as that's the new equivilant of that option.
*/
FModifier *fcm= fcurve_add_modifier(fcu, FMODIFIER_TYPE_CYCLES);
FModifier *fcm= add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES);
FMod_Cycles *data= (FMod_Cycles *)fcm->data;
/* if 'offset' one is in use, set appropriate settings */
@ -1463,6 +1472,87 @@ static void action_to_animdata (ID *id, bAction *act)
action_to_animato(act, &adt->action->groups, &adt->action->curves, &adt->drivers);
}
/* ------------------------- */
// TODO:
// - NLA group duplicators info
// - NLA curve/stride modifiers...
/* Convert NLA-Strip to new system */
static void nlastrips_to_animdata (ID *id, ListBase *strips)
{
AnimData *adt= BKE_animdata_from_id(id);
NlaTrack *nlt = NULL;
NlaStrip *strip;
bActionStrip *as, *asn;
/* for each one of the original strips, convert to a new strip and free the old... */
for (as= strips->first; as; as= asn) {
asn= as->next;
/* this old strip is only worth something if it had an action... */
if (as->act) {
/* convert Action data (if not yet converted), storing the results in the same Action */
action_to_animato(as->act, &as->act->groups, &as->act->curves, &adt->drivers);
/* create a new-style NLA-strip which references this Action, then copy over relevant settings */
{
/* init a new strip, and assign the action to it
* - no need to muck around with the user-counts, since this is just
* passing over the ref to the new owner, not creating an additional ref
*/
strip= MEM_callocN(sizeof(NlaStrip), "NlaStrip");
strip->act= as->act;
/* endpoints */
strip->start= as->start;
strip->end= as->end;
strip->actstart= as->actstart;
strip->actend= as->actend;
/* action reuse */
strip->repeat= as->repeat;
strip->scale= as->scale;
if (as->flag & ACTSTRIP_LOCK_ACTION) strip->flag |= NLASTRIP_FLAG_SYNC_LENGTH;
/* blending */
strip->blendin= as->blendin;
strip->blendout= as->blendout;
strip->blendmode= (as->mode==ACTSTRIPMODE_ADD) ? NLASTRIP_MODE_ADD : NLASTRIP_MODE_REPLACE;
if (as->flag & ACTSTRIP_AUTO_BLENDS) strip->flag |= NLASTRIP_FLAG_AUTO_BLENDS;
/* assorted setting flags */
if (as->flag & ACTSTRIP_SELECT) strip->flag |= NLASTRIP_FLAG_SELECT;
if (as->flag & ACTSTRIP_ACTIVE) strip->flag |= NLASTRIP_FLAG_ACTIVE;
if (as->flag & ACTSTRIP_MUTE) strip->flag |= NLASTRIP_FLAG_MUTED;
if (as->flag & ACTSTRIP_REVERSE) strip->flag |= NLASTRIP_FLAG_REVERSE;
/* by default, we now always extrapolate, while in the past this was optional */
if ((as->flag & ACTSTRIP_HOLDLASTFRAME)==0)
strip->extendmode= NLASTRIP_EXTEND_NOTHING;
}
/* try to add this strip to the current NLA-Track (i.e. the 'last' one on the stack atm) */
if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
/* trying to add to the current failed (no space),
* so add a new track to the stack, and add to that...
*/
nlt= add_nlatrack(adt, NULL);
BKE_nlatrack_add_strip(nlt, strip);
}
}
/* modifiers */
// FIXME: for now, we just free them...
if (as->modifiers.first)
BLI_freelistN(&as->modifiers);
/* free the old strip */
BLI_freelinkN(strips, as);
}
}
/* *************************************************** */
/* External API - Only Called from do_versions() */
@ -1509,7 +1599,30 @@ void do_versions_ipos_to_animato(Main *main)
if (G.f & G_DEBUG) printf("\tconverting ob %s \n", id->name+2);
/* check if object has any animation data */
if ((ob->ipo) || (ob->action) || (ob->nlastrips.first)) {
if (ob->nlastrips.first) {
/* Add AnimData block */
adt= BKE_id_add_animdata(id);
/* IPO first to take into any non-NLA'd Object Animation */
if (ob->ipo) {
ipo_to_animdata(id, ob->ipo, NULL, NULL);
ob->ipo->id.us--;
ob->ipo= NULL;
}
/* Action is skipped since it'll be used by some strip in the NLA anyway,
* causing errors with evaluation in the new evaluation pipeline
*/
if (ob->action) {
ob->action->id.us--;
ob->action= NULL;
}
/* finally NLA */
nlastrips_to_animdata(id, &ob->nlastrips);
}
else if ((ob->ipo) || (ob->action)) {
/* Add AnimData block */
adt= BKE_id_add_animdata(id);
@ -1530,9 +1643,6 @@ void do_versions_ipos_to_animato(Main *main)
ob->ipo->id.us--;
ob->ipo= NULL;
}
/* finally NLA */
// XXX todo... for now, new NLA code not hooked up yet, so keep old stuff (but not for too long!)
}
/* check PoseChannels for constraints with local data */

File diff suppressed because it is too large Load Diff

@ -1198,18 +1198,12 @@ Object *copy_object(Object *ob)
armature_rebuild_pose(obn, obn->data);
}
copy_defgroups(&obn->defbase, &ob->defbase);
#if 0 // XXX old animation system
copy_nlastrips(&obn->nlastrips, &ob->nlastrips);
#endif // XXX old animation system
copy_constraints(&obn->constraints, &ob->constraints);
/* increase user numbers */
id_us_plus((ID *)obn->data);
#if 0 // XXX old animation system
id_us_plus((ID *)obn->ipo);
id_us_plus((ID *)obn->action);
#endif // XXX old animation system
id_us_plus((ID *)obn->dup_group);
// FIXME: add this for animdata too...
for(a=0; a<obn->totcol; a++) id_us_plus((ID *)obn->mat[a]);
@ -1575,14 +1569,14 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[][4])
}
/* catch exceptions: curve paths used as a duplicator */
else if(enable_cu_speed) {
ctime= bsystem_time(scene, ob, (float)scene->r.cfra, 0.0);
#if 0 // XXX old animation system
if(calc_ipo_spec(cu->ipo, CU_SPEED, &ctime)==0) {
ctime /= cu->pathlen;
CLAMP(ctime, 0.0, 1.0);
}
#endif // XXX old animation system
/* ctime is now a proper var setting of Curve which gets set by Animato like any other var that's animated,
* but this will only work if it actually is animated...
*
* we firstly calculate the modulus of cu->ctime/cu->pathlen to clamp ctime within the 0.0 to 1.0 times pathlen
* range, then divide this (the modulus) by pathlen to get a value between 0.0 and 1.0
*/
ctime= fmod(cu->ctime, cu->pathlen) / cu->pathlen;
CLAMP(ctime, 0.0, 1.0);
}
else {
ctime= scene->r.cfra - give_timeoffset(ob);

@ -0,0 +1,85 @@
/**
* $Id: BKE_nla.h 20999 2009-06-19 04:45: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) 2009 Blender Foundation, Joshua Leung
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Joshua Leung (full recode)
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef NLA_PRIVATE
#define NLA_PRIVATE
/* --------------- NLA Evaluation DataTypes ----------------------- */
/* used for list of strips to accumulate at current time */
typedef struct NlaEvalStrip {
struct NlaEvalStrip *next, *prev;
NlaTrack *track; /* track that this strip belongs to */
NlaStrip *strip; /* strip that's being used */
short track_index; /* the index of the track within the list */
short strip_mode; /* which end of the strip are we looking at */
float strip_time; /* time at which which strip is being evaluated */
} NlaEvalStrip;
/* NlaEvalStrip->strip_mode */
enum {
/* standard evaluation */
NES_TIME_BEFORE = -1,
NES_TIME_WITHIN,
NES_TIME_AFTER,
/* transition-strip evaluations */
NES_TIME_TRANSITION_START,
NES_TIME_TRANSITION_END,
} eNlaEvalStrip_StripMode;
/* temp channel for accumulating data from NLA (avoids needing to clear all values first) */
// TODO: maybe this will be used as the 'cache' stuff needed for editable values too?
typedef struct NlaEvalChannel {
struct NlaEvalChannel *next, *prev;
PointerRNA ptr; /* pointer to struct containing property to use */
PropertyRNA *prop; /* RNA-property type to use (should be in the struct given) */
int index; /* array index (where applicable) */
float value; /* value of this channel */
} NlaEvalChannel;
/* --------------- NLA Functions (not to be used as a proper API) ----------------------- */
/* convert from strip time <-> global time */
float nlastrip_get_frame(NlaStrip *strip, float cframe, short mode);
/* --------------- NLA Evaluation (very-private stuff) ----------------------- */
/* these functions are only defined here to avoid problems with the order in which they get defined... */
NlaEvalStrip *nlastrips_ctime_get_strip(ListBase *list, ListBase *strips, short index, float ctime);
void nlastrip_evaluate(PointerRNA *ptr, ListBase *channels, ListBase *modifiers, NlaEvalStrip *nes);
void nladata_flush_channels(ListBase *channels);
#endif // NLA_PRIVATE

@ -1667,10 +1667,26 @@ static void lib_link_constraint_channels(FileData *fd, ID *id, ListBase *chanbas
/* Data Linking ----------------------------- */
static void lib_link_fmodifiers(FileData *fd, ID *id, ListBase *list)
{
FModifier *fcm;
for (fcm= list->first; fcm; fcm= fcm->next) {
/* data for specific modifiers */
switch (fcm->type) {
case FMODIFIER_TYPE_PYTHON:
{
FMod_Python *data= (FMod_Python *)fcm->data;
data->script = newlibadr(fd, id->lib, data->script);
}
break;
}
}
}
static void lib_link_fcurves(FileData *fd, ID *id, ListBase *list)
{
FCurve *fcu;
FModifier *fcm;
/* relink ID-block references... */
for (fcu= list->first; fcu; fcu= fcu->next) {
@ -1684,16 +1700,45 @@ static void lib_link_fcurves(FileData *fd, ID *id, ListBase *list)
}
/* modifiers */
for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) {
/* data for specific modifiers */
switch (fcm->type) {
case FMODIFIER_TYPE_PYTHON:
{
FMod_Python *data= (FMod_Python *)fcm->data;
data->script = newlibadr(fd, id->lib, data->script);
}
break;
lib_link_fmodifiers(fd, id, &fcu->modifiers);
}
}
/* NOTE: this assumes that link_list has already been called on the list */
static void direct_link_fmodifiers(FileData *fd, ListBase *list)
{
FModifier *fcm;
for (fcm= list->first; fcm; fcm= fcm->next) {
/* relink general data */
fcm->data = newdataadr(fd, fcm->data);
fcm->edata= NULL;
/* do relinking of data for specific types */
switch (fcm->type) {
case FMODIFIER_TYPE_GENERATOR:
{
FMod_Generator *data= (FMod_Generator *)fcm->data;
data->coefficients= newdataadr(fd, data->coefficients);
}
break;
case FMODIFIER_TYPE_ENVELOPE:
{
FMod_Envelope *data= (FMod_Envelope *)fcm->data;
data->data= newdataadr(fd, data->data);
}
break;
case FMODIFIER_TYPE_PYTHON:
{
FMod_Python *data= (FMod_Python *)fcm->data;
data->prop = newdataadr(fd, data->prop);
IDP_DirectLinkProperty(data->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
break;
}
}
}
@ -1702,7 +1747,6 @@ static void lib_link_fcurves(FileData *fd, ID *id, ListBase *list)
static void direct_link_fcurves(FileData *fd, ListBase *list)
{
FCurve *fcu;
FModifier *fcm;
/* link F-Curve data to F-Curve again (non ID-libs) */
for (fcu= list->first; fcu; fcu= fcu->next) {
@ -1730,37 +1774,7 @@ static void direct_link_fcurves(FileData *fd, ListBase *list)
/* modifiers */
link_list(fd, &fcu->modifiers);
for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) {
/* relink general data */
fcm->data = newdataadr(fd, fcm->data);
fcm->edata= NULL;
/* do relinking of data for specific types */
switch (fcm->type) {
case FMODIFIER_TYPE_GENERATOR:
{
FMod_Generator *data= (FMod_Generator *)fcm->data;
data->coefficients= newdataadr(fd, data->coefficients);
}
break;
case FMODIFIER_TYPE_ENVELOPE:
{
FMod_Envelope *data= (FMod_Envelope *)fcm->data;
data->data= newdataadr(fd, data->data);
}
break;
case FMODIFIER_TYPE_PYTHON:
{
FMod_Python *data= (FMod_Python *)fcm->data;
data->prop = newdataadr(fd, data->prop);
IDP_DirectLinkProperty(data->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd);
}
break;
}
}
direct_link_fmodifiers(fd, &fcu->modifiers);
}
}
@ -1812,6 +1826,65 @@ static void direct_link_action(FileData *fd, bAction *act)
}
}
static void lib_link_nladata_strips(FileData *fd, ID *id, ListBase *list)
{
NlaStrip *strip;
for (strip= list->first; strip; strip= strip->next) {
/* check strip's children */
lib_link_nladata_strips(fd, id, &strip->strips);
/* reassign the counted-reference to action */
strip->act = newlibadr_us(fd, id->lib, strip->act);
}
}
static void lib_link_nladata(FileData *fd, ID *id, ListBase *list)
{
NlaTrack *nlt;
/* we only care about the NLA strips inside the tracks */
for (nlt= list->first; nlt; nlt= nlt->next) {
lib_link_nladata_strips(fd, id, &nlt->strips);
}
}
/* This handles Animato NLA-Strips linking
* NOTE: this assumes that link_list has already been called on the list
*/
static void direct_link_nladata_strips(FileData *fd, ListBase *list)
{
NlaStrip *strip;
for (strip= list->first; strip; strip= strip->next) {
/* strip's child strips */
link_list(fd, &strip->strips);
direct_link_nladata_strips(fd, &strip->strips);
/* strip's F-Curves */
link_list(fd, &strip->fcurves);
direct_link_fcurves(fd, &strip->fcurves);
/* strip's F-Modifiers */
link_list(fd, &strip->modifiers);
direct_link_fcurves(fd, &strip->modifiers);
}
}
/* NOTE: this assumes that link_list has already been called on the list */
static void direct_link_nladata(FileData *fd, ListBase *list)
{
NlaTrack *nlt;
for (nlt= list->first; nlt; nlt= nlt->next) {
/* relink list of strips */
link_list(fd, &nlt->strips);
/* relink strip data */
direct_link_nladata_strips(fd, &nlt->strips);
}
}
/* ------- */
static void lib_link_keyingsets(FileData *fd, ID *id, ListBase *list)
@ -1854,6 +1927,7 @@ static void lib_link_animdata(FileData *fd, ID *id, AnimData *adt)
/* link action data */
adt->action= newlibadr_us(fd, id->lib, adt->action);
adt->tmpact= newlibadr_us(fd, id->lib, adt->tmpact);
/* link drivers */
lib_link_fcurves(fd, id, &adt->drivers);
@ -1861,7 +1935,7 @@ static void lib_link_animdata(FileData *fd, ID *id, AnimData *adt)
/* overrides don't have lib-link for now, so no need to do anything */
/* link NLA-data */
// TODO...
lib_link_nladata(fd, id, &adt->nla_tracks);
}
static void direct_link_animdata(FileData *fd, AnimData *adt)
@ -1878,7 +1952,12 @@ static void direct_link_animdata(FileData *fd, AnimData *adt)
// TODO...
/* link NLA-data */
// TODO...
link_list(fd, &adt->nla_tracks);
direct_link_nladata(fd, &adt->nla_tracks);
/* clear temp pointers that may have been set... */
// TODO: it's probably only a small cost to reload this anyway...
adt->actstrip= NULL;
}
/* ************ READ NODE TREE *************** */
@ -4708,6 +4787,11 @@ static void direct_link_screen(FileData *fd, bScreen *sc)
sipo->ads= newdataadr(fd, sipo->ads);
sipo->ghostCurves.first= sipo->ghostCurves.last= NULL;
}
else if (sl->spacetype==SPACE_NLA) {
SpaceNla *snla= (SpaceNla*)sl;
snla->ads= newdataadr(fd, snla->ads);
}
else if (sl->spacetype==SPACE_OUTLINER) {
SpaceOops *soops= (SpaceOops*) sl;
@ -9150,7 +9234,14 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
if(ts->normalsize == 0.0 || !ts->uv_selectmode || ts->vgroup_weight == 0.0) {
ts->normalsize= 0.1f;
ts->selectmode= SCE_SELECT_VERTEX;
/* autokeying - setting should be taken from the user-prefs
* but the userprefs version may not have correct flags set
* (i.e. will result in blank box when enabled)
*/
ts->autokey_mode= U.autokey_mode;
if (ts->autokey_mode == 0)
ts->autokey_mode= 2; /* 'add/replace' but not on */
ts->uv_selectmode= UV_SELECT_VERTEX;
ts->vgroup_weight= 1.0f;
}
@ -9485,12 +9576,27 @@ static void expand_keyingsets(FileData *fd, Main *mainvar, ListBase *list)
}
}
static void expand_animdata_nlastrips(FileData *fd, Main *mainvar, ListBase *list)
{
NlaStrip *strip;
for (strip= list->first; strip; strip= strip->next) {
/* check child strips */
expand_animdata_nlastrips(fd, mainvar, &strip->strips);
/* relink referenced action */
expand_doit(fd, mainvar, strip->act);
}
}
static void expand_animdata(FileData *fd, Main *mainvar, AnimData *adt)
{
FCurve *fcd;
NlaTrack *nlt;
/* own action */
expand_doit(fd, mainvar, adt->action);
expand_doit(fd, mainvar, adt->tmpact);
/* drivers - assume that these F-Curves have driver data to be in this list... */
for (fcd= adt->drivers.first; fcd; fcd= fcd->next) {
@ -9500,6 +9606,10 @@ static void expand_animdata(FileData *fd, Main *mainvar, AnimData *adt)
for (dtar= driver->targets.first; dtar; dtar= dtar->next)
expand_doit(fd, mainvar, dtar->id);
}
/* nla-data - referenced actions */
for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next)
expand_animdata_nlastrips(fd, mainvar, &nlt->strips);
}
static void expand_particlesettings(FileData *fd, Main *mainvar, ParticleSettings *part)

@ -781,10 +781,59 @@ static void write_actuators(WriteData *wd, ListBase *lb)
}
}
static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers)
{
FModifier *fcm;
/* Modifiers */
for (fcm= fmodifiers->first; fcm; fcm= fcm->next) {
FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
/* Write the specific data */
if (fmi && fcm->data) {
/* firstly, just write the plain fmi->data struct */
writestruct(wd, DATA, fmi->structName, 1, fcm->data);
/* do any modifier specific stuff */
switch (fcm->type) {
case FMODIFIER_TYPE_GENERATOR:
{
FMod_Generator *data= (FMod_Generator *)fcm->data;
/* write coefficients array */
if (data->coefficients)
writedata(wd, DATA, sizeof(float)*(data->arraysize), data->coefficients);
}
break;
case FMODIFIER_TYPE_ENVELOPE:
{
FMod_Envelope *data= (FMod_Envelope *)fcm->data;
/* write envelope data */
if (data->data)
writedata(wd, DATA, sizeof(FCM_EnvelopeData)*(data->totvert), data->data);
}
break;
case FMODIFIER_TYPE_PYTHON:
{
FMod_Python *data = (FMod_Python *)fcm->data;
/* Write ID Properties -- and copy this comment EXACTLY for easy finding
of library blocks that implement this.*/
IDP_WriteProperty(data->prop, wd);
}
break;
}
}
/* Write the modifier */
writestruct(wd, DATA, "FModifier", 1, fcm);
}
}
static void write_fcurves(WriteData *wd, ListBase *fcurves)
{
FCurve *fcu;
FModifier *fcm;
for (fcu=fcurves->first; fcu; fcu=fcu->next) {
/* F-Curve */
@ -815,50 +864,8 @@ static void write_fcurves(WriteData *wd, ListBase *fcurves)
}
}
/* Modifiers */
for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) {
FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
/* Write the specific data */
if (fmi && fcm->data) {
/* firstly, just write the plain fmi->data struct */
writestruct(wd, DATA, fmi->structName, 1, fcm->data);
/* do any modifier specific stuff */
switch (fcm->type) {
case FMODIFIER_TYPE_GENERATOR:
{
FMod_Generator *data= (FMod_Generator *)fcm->data;
/* write coefficients array */
if (data->coefficients)
writedata(wd, DATA, sizeof(float)*(data->arraysize), data->coefficients);
}
break;
case FMODIFIER_TYPE_ENVELOPE:
{
FMod_Envelope *data= (FMod_Envelope *)fcm->data;
/* write envelope data */
if (data->data)
writedata(wd, DATA, sizeof(FCM_EnvelopeData)*(data->totvert), data->data);
}
break;
case FMODIFIER_TYPE_PYTHON:
{
FMod_Python *data = (FMod_Python *)fcm->data;
/* Write ID Properties -- and copy this comment EXACTLY for easy finding
of library blocks that implement this.*/
IDP_WriteProperty(data->prop, wd);
}
break;
}
}
/* Write the modifier */
writestruct(wd, DATA, "FModifier", 1, fcm);
}
/* write F-Modifiers */
write_fmodifiers(wd, &fcu->modifiers);
}
}
@ -909,6 +916,37 @@ static void write_keyingsets(WriteData *wd, ListBase *list)
}
}
static void write_nlastrips(WriteData *wd, ListBase *strips)
{
NlaStrip *strip;
for (strip= strips->first; strip; strip= strip->next) {
/* write the strip first */
writestruct(wd, DATA, "NlaStrip", 1, strip);
/* write the strip's F-Curves and modifiers */
write_fcurves(wd, &strip->fcurves);
write_fmodifiers(wd, &strip->modifiers);
/* write the strip's children */
write_nlastrips(wd, &strip->strips);
}
}
static void write_nladata(WriteData *wd, ListBase *nlabase)
{
NlaTrack *nlt;
/* write all the tracks */
for (nlt= nlabase->first; nlt; nlt= nlt->next) {
/* write the track first */
writestruct(wd, DATA, "NlaTrack", 1, nlt);
/* write the track's strips */
write_nlastrips(wd, &nlt->strips);
}
}
static void write_animdata(WriteData *wd, AnimData *adt)
{
AnimOverride *aor;
@ -920,14 +958,17 @@ static void write_animdata(WriteData *wd, AnimData *adt)
write_fcurves(wd, &adt->drivers);
/* write overrides */
// FIXME: are these needed?
for (aor= adt->overrides.first; aor; aor= aor->next) {
/* overrides consist of base data + rna_path */
writestruct(wd, DATA, "AnimOverride", 1, aor);
writedata(wd, DATA, strlen(aor->rna_path)+1, aor->rna_path);
}
// TODO write the remaps (if they are needed)
/* write NLA data */
// XXX todo...
write_nladata(wd, &adt->nla_tracks);
}
static void write_constraints(WriteData *wd, ListBase *conlist)
@ -1899,7 +1940,10 @@ static void write_screens(WriteData *wd, ListBase *scrbase)
writestruct(wd, DATA, "SpaceSound", 1, sl);
}
else if(sl->spacetype==SPACE_NLA){
writestruct(wd, DATA, "SpaceNla", 1, sl);
SpaceNla *snla= (SpaceNla *)sl;
writestruct(wd, DATA, "SpaceNla", 1, snla);
if(snla->ads) writestruct(wd, DATA, "bDopeSheet", 1, snla->ads);
}
else if(sl->spacetype==SPACE_TIME){
writestruct(wd, DATA, "SpaceTime", 1, sl);

@ -63,9 +63,10 @@
#include "RNA_access.h"
#include "RNA_define.h"
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_depsgraph.h"
#include "BKE_ipo.h"
#include "BKE_fcurve.h"
#include "BKE_key.h"
#include "BKE_material.h"
#include "BKE_object.h"
@ -87,43 +88,16 @@
/* ************************************************************************** */
/* CHANNELS API */
/* -------------------------- Internal Macros ------------------------------- */
/* set/clear/toggle macro
* - channel - channel with a 'flag' member that we're setting
* - smode - 0=clear, 1=set, 2=toggle
* - sflag - bitflag to set
*/
#define ACHANNEL_SET_FLAG(channel, smode, sflag) \
{ \
if (smode == ACHANNEL_SETFLAG_TOGGLE) (channel)->flag ^= (sflag); \
else if (smode == ACHANNEL_SETFLAG_ADD) (channel)->flag |= (sflag); \
else (channel)->flag &= ~(sflag); \
}
/* set/clear/toggle macro, where the flag is negative
* - channel - channel with a 'flag' member that we're setting
* - smode - 0=clear, 1=set, 2=toggle
* - sflag - bitflag to set
*/
#define ACHANNEL_SET_FLAG_NEG(channel, smode, sflag) \
{ \
if (smode == ACHANNEL_SETFLAG_TOGGLE) (channel)->flag ^= (sflag); \
else if (smode == ACHANNEL_SETFLAG_ADD) (channel)->flag &= ~(sflag); \
else (channel)->flag |= (sflag); \
}
/* -------------------------- Exposed API ----------------------------------- */
/* Set the given animation-channel as the active one for the active context */
void ANIM_set_active_channel (void *data, short datatype, int filter, void *channel_data, short channel_type)
void ANIM_set_active_channel (bAnimContext *ac, void *data, short datatype, int filter, void *channel_data, short channel_type)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
/* try to build list of filtered items */
// XXX we don't need/supply animcontext for now, since in this case, there's nothing really essential there that isn't already covered
ANIM_animdata_filter(NULL, &anim_data, filter, data, datatype);
ANIM_animdata_filter(ac, &anim_data, filter, data, datatype);
if (anim_data.first == NULL)
return;
@ -149,11 +123,18 @@ void ANIM_set_active_channel (void *data, short datatype, int filter, void *chan
ACHANNEL_SET_FLAG(fcu, ACHANNEL_SETFLAG_CLEAR, FCURVE_ACTIVE);
}
break;
case ANIMTYPE_NLATRACK:
{
NlaTrack *nlt= (NlaTrack *)ale->data;
ACHANNEL_SET_FLAG(nlt, ACHANNEL_SETFLAG_CLEAR, NLATRACK_ACTIVE);
}
break;
}
}
/* set active flag */
if (channel_data) {
if (channel_data != NULL) {
switch (channel_type) {
case ANIMTYPE_GROUP:
{
@ -167,6 +148,12 @@ void ANIM_set_active_channel (void *data, short datatype, int filter, void *chan
fcu->flag |= FCURVE_ACTIVE;
}
break;
case ANIMTYPE_NLATRACK:
{
NlaTrack *nlt= (NlaTrack *)channel_data;
nlt->flag |= NLATRACK_ACTIVE;
}
break;
}
}
@ -217,6 +204,10 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short
if (ale->flag & FCURVE_SELECTED)
sel= ACHANNEL_SETFLAG_CLEAR;
break;
case ANIMTYPE_NLATRACK:
if (ale->flag & NLATRACK_SELECTED)
sel= ACHANNEL_SETFLAG_CLEAR;
break;
}
}
}
@ -263,6 +254,14 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short
fcu->flag &= ~FCURVE_ACTIVE;
}
break;
case ANIMTYPE_NLATRACK:
{
NlaTrack *nlt= (NlaTrack *)ale->data;
ACHANNEL_SET_FLAG(nlt, sel, NLATRACK_SELECTED);
nlt->flag &= ~NLATRACK_ACTIVE;
}
break;
}
}
@ -273,6 +272,47 @@ void ANIM_deselect_anim_channels (void *data, short datatype, short test, short
/* ************************************************************************** */
/* OPERATORS */
/* ****************** Operator Utilities ********************************** */
/* poll callback for being in an Animation Editor channels list region */
int animedit_poll_channels_active (bContext *C)
{
ScrArea *sa= CTX_wm_area(C);
/* channels region test */
// TODO: could enhance with actually testing if channels region?
if (ELEM(NULL, sa, CTX_wm_region(C)))
return 0;
/* animation editor test */
if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
return 0;
return 1;
}
/* poll callback for Animation Editor channels list region + not in NLA-tweakmode for NLA */
int animedit_poll_channels_nla_tweakmode_off (bContext *C)
{
ScrArea *sa= CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
/* channels region test */
// TODO: could enhance with actually testing if channels region?
if (ELEM(NULL, sa, CTX_wm_region(C)))
return 0;
/* animation editor test */
if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
return 0;
/* NLA TweakMode test */
if (sa->spacetype == SPACE_NLA) {
if ((scene == NULL) || (scene->flag & SCE_NLA_EDIT_ON))
return 0;
}
return 1;
}
/* ****************** Rearrange Channels Operator ******************* */
/* This operator only works for Action Editor mode for now, as having it elsewhere makes things difficult */
@ -575,8 +615,8 @@ static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
mode= RNA_enum_get(op->ptr, "direction");
rearrange_action_channels(&ac, mode);
/* set notifier tha things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN_EDIT, NULL);
return OPERATOR_FINISHED;
}
@ -652,6 +692,121 @@ void ANIM_OT_channels_move_bottom (wmOperatorType *ot)
#endif // XXX old animation system - needs to be updated for new system...
/* ******************** Delete Channel Operator *********************** */
static int animchannels_delete_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
/* cannot delete in shapekey */
if (ac.datatype == ANIMCONT_SHAPEKEY)
return OPERATOR_CANCELLED;
/* do groups only first (unless in Drivers mode, where there are none) */
if (ac.datatype != ANIMCONT_DRIVERS) {
/* filter data */
filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CHANNELS | ANIMFILTER_FOREDIT);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* delete selected groups and their associated channels */
for (ale= anim_data.first; ale; ale= ale->next) {
/* only groups - don't check other types yet, since they may no-longer exist */
if (ale->type == ANIMTYPE_GROUP) {
bActionGroup *agrp= (bActionGroup *)ale->data;
AnimData *adt= BKE_animdata_from_id(ale->id);
FCurve *fcu, *fcn;
/* skip this group if no AnimData available, as we can't safely remove the F-Curves */
if (adt == NULL)
continue;
/* delete all of the Group's F-Curves, but no others */
for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcn) {
fcn= fcu->next;
/* remove from group and action, then free */
action_groups_remove_channel(adt->action, fcu);
free_fcurve(fcu);
}
/* free the group itself */
if (adt->action)
BLI_freelinkN(&adt->action->groups, agrp);
else
MEM_freeN(agrp);
}
}
/* cleanup */
BLI_freelistN(&anim_data);
}
/* now do F-Curves */
if (ac.datatype != ANIMCONT_GPENCIL) {
/* filter data */
filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* delete selected F-Curves */
for (ale= anim_data.first; ale; ale= ale->next) {
/* only F-Curves, and only if we can identify its parent */
if (ale->type == ANIMTYPE_FCURVE) {
AnimData *adt= BKE_animdata_from_id(ale->id);
FCurve *fcu= (FCurve *)ale->data;
/* if no AnimData, we've got nowhere to remove the F-Curve from */
if (adt == NULL)
continue;
/* remove from whatever list it came from
* - Action Group
* - Action
* - Drivers
* - TODO... some others?
*/
if (fcu->grp)
action_groups_remove_channel(adt->action, fcu);
else if (adt->action)
BLI_remlink(&adt->action->curves, fcu);
else if (ac.datatype == ANIMCONT_DRIVERS)
BLI_remlink(&adt->drivers, fcu);
/* free the F-Curve itself */
free_fcurve(fcu);
}
}
/* cleanup */
BLI_freelistN(&anim_data);
}
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN_EDIT, NULL);
return OPERATOR_FINISHED;
}
void ANIM_OT_channels_delete (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Delete Channels";
ot->idname= "ANIM_OT_channels_delete";
/* api callbacks */
ot->exec= animchannels_delete_exec;
ot->poll= animedit_poll_channels_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
/* ******************** Toggle Channel Visibility Operator *********************** */
@ -668,7 +823,7 @@ static int animchannels_visibility_toggle_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
/* filter data */
filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVESONLY);
filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* See if we should be making showing all selected or hiding */
@ -676,21 +831,35 @@ static int animchannels_visibility_toggle_exec(bContext *C, wmOperator *op)
if (vis == ACHANNEL_SETFLAG_CLEAR)
break;
if (ale->flag & FCURVE_VISIBLE)
if ((ale->type == ANIMTYPE_FCURVE) && (ale->flag & FCURVE_VISIBLE))
vis= ACHANNEL_SETFLAG_CLEAR;
else if ((ale->type == ANIMTYPE_GROUP) && !(ale->flag & AGRP_NOTVISIBLE))
vis= ACHANNEL_SETFLAG_CLEAR;
}
/* Now set the flags */
for (ale= anim_data.first; ale; ale= ale->next) {
FCurve *fcu= (FCurve *)ale->data;
ACHANNEL_SET_FLAG(fcu, vis, FCURVE_VISIBLE);
switch (ale->type) {
case ANIMTYPE_FCURVE: /* F-Curve */
{
FCurve *fcu= (FCurve *)ale->data;
ACHANNEL_SET_FLAG(fcu, vis, FCURVE_VISIBLE);
}
break;
case ANIMTYPE_GROUP: /* Group */
{
bActionGroup *agrp= (bActionGroup *)ale->data;
ACHANNEL_SET_FLAG_NEG(agrp, vis, AGRP_NOTVISIBLE);
}
break;
}
}
/* cleanup */
BLI_freelistN(&anim_data);
/* set notifier tha things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN_EDIT, NULL);
return OPERATOR_FINISHED;
}
@ -889,6 +1058,12 @@ static void setflag_anim_channels (bAnimContext *ac, short setting, short mode,
case ACHANNEL_SETTING_EXPAND:
ACHANNEL_SET_FLAG(agrp, mode, AGRP_EXPANDED);
break;
case ACHANNEL_SETTING_MUTE:
ACHANNEL_SET_FLAG(agrp, mode, AGRP_MUTED);
break;
case ACHANNEL_SETTING_VISIBLE:
ACHANNEL_SET_FLAG_NEG(agrp, mode, AGRP_NOTVISIBLE);
break;
}
}
break;
@ -947,8 +1122,8 @@ static int animchannels_setflag_exec(bContext *C, wmOperator *op)
/* modify setting */
setflag_anim_channels(&ac, setting, mode, 1);
/* set notifier tha things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN_EDIT, NULL);
return OPERATOR_FINISHED;
}
@ -963,7 +1138,7 @@ void ANIM_OT_channels_setting_enable (wmOperatorType *ot)
/* api callbacks */
ot->invoke= WM_menu_invoke;
ot->exec= animchannels_setflag_exec;
ot->poll= ED_operator_areaactive;
ot->poll= animedit_poll_channels_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -984,7 +1159,7 @@ void ANIM_OT_channels_setting_disable (wmOperatorType *ot)
/* api callbacks */
ot->invoke= WM_menu_invoke;
ot->exec= animchannels_setflag_exec;
ot->poll= ED_operator_areaactive;
ot->poll= animedit_poll_channels_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1005,7 +1180,7 @@ void ANIM_OT_channels_setting_toggle (wmOperatorType *ot)
/* api callbacks */
ot->invoke= WM_menu_invoke;
ot->exec= animchannels_setflag_exec;
ot->poll= ED_operator_areaactive;
ot->poll= animedit_poll_channels_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1026,7 +1201,7 @@ void ANIM_OT_channels_editable_toggle (wmOperatorType *ot)
/* api callbacks */
ot->exec= animchannels_setflag_exec;
ot->poll= ED_operator_areaactive;
ot->poll= animedit_poll_channels_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1056,8 +1231,8 @@ static int animchannels_expand_exec (bContext *C, wmOperator *op)
/* modify setting */
setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_ADD, onlysel);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN_EDIT, NULL);
return OPERATOR_FINISHED;
}
@ -1070,7 +1245,7 @@ void ANIM_OT_channels_expand (wmOperatorType *ot)
/* api callbacks */
ot->exec= animchannels_expand_exec;
ot->poll= ED_operator_areaactive;
ot->poll= animedit_poll_channels_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1097,8 +1272,8 @@ static int animchannels_collapse_exec (bContext *C, wmOperator *op)
/* modify setting */
setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_CLEAR, onlysel);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN_EDIT, NULL);
return OPERATOR_FINISHED;
}
@ -1111,7 +1286,7 @@ void ANIM_OT_channels_collapse (wmOperatorType *ot)
/* api callbacks */
ot->exec= animchannels_collapse_exec;
ot->poll= ED_operator_areaactive;
ot->poll= animedit_poll_channels_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1136,8 +1311,8 @@ static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
else
ANIM_deselect_anim_channels(ac.data, ac.datatype, 1, ACHANNEL_SETFLAG_ADD);
/* set notifier tha things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN_SELECT, NULL);
return OPERATOR_FINISHED;
}
@ -1150,7 +1325,7 @@ void ANIM_OT_channels_select_all_toggle (wmOperatorType *ot)
/* api callbacks */
ot->exec= animchannels_deselectall_exec;
ot->poll= ED_operator_areaactive;
ot->poll= animedit_poll_channels_nla_tweakmode_off;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1218,6 +1393,14 @@ static void borderselect_anim_channels (bAnimContext *ac, rcti *rect, short sele
ACHANNEL_SET_FLAG(gpl, selectmode, GP_LAYER_SELECT);
}
break;
case ANIMTYPE_NLATRACK: /* nla-track */
{
NlaTrack *nlt= (NlaTrack *)ale->data;
ACHANNEL_SET_FLAG(nlt, selectmode, NLATRACK_SELECTED);
}
break;
}
}
@ -1257,6 +1440,9 @@ static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
/* apply borderselect animation channels */
borderselect_anim_channels(&ac, &rect, selectmode);
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN_SELECT, NULL);
return OPERATOR_FINISHED;
}
@ -1271,7 +1457,7 @@ void ANIM_OT_channels_select_border(wmOperatorType *ot)
ot->exec= animchannels_borderselect_exec;
ot->modal= WM_border_select_modal;
ot->poll= ED_operator_areaactive;
ot->poll= animedit_poll_channels_nla_tweakmode_off;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1291,11 +1477,12 @@ void ANIM_OT_channels_select_border(wmOperatorType *ot)
* NOTE: eventually, this should probably be phased out when many of these things are replaced with buttons
*/
static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, short selectmode)
static int mouse_anim_channels (bAnimContext *ac, float x, int channel_index, short selectmode)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
int notifierFlags = 0;
/* get the channel that was clicked on */
/* filter channels */
@ -1309,7 +1496,7 @@ static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, s
printf("Error: animation channel (index = %d) not found in mouse_anim_channels() \n", channel_index);
BLI_freelistN(&anim_data);
return;
return 0;
}
/* selectmode -1 is a special case for ActionGroups only, which selects all of the channels underneath it only... */
@ -1317,7 +1504,7 @@ static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, s
if ((selectmode == -1) && (ale->type != ANIMTYPE_GROUP)) {
/* normal channels should not behave normally in this case */
BLI_freelistN(&anim_data);
return;
return 0;
}
/* action to take depends on what channel we've got */
@ -1329,6 +1516,8 @@ static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, s
if (x < 16) {
/* toggle expand */
sce->flag ^= SCE_DS_COLLAPSED;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
else {
/* set selection status */
@ -1339,6 +1528,8 @@ static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, s
else {
sce->flag |= SCE_DS_SELECTED;
}
notifierFlags |= ND_ANIMCHAN_SELECT;
}
}
break;
@ -1352,6 +1543,8 @@ static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, s
if (x < 16) {
/* toggle expand */
ob->nlaflag ^= OB_ADS_COLLAPSED; // XXX
notifierFlags |= ND_ANIMCHAN_EDIT;
}
else {
/* set selection status */
@ -1376,6 +1569,8 @@ static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, s
/* xxx should be ED_base_object_activate(), but we need context pointer for that... */
//set_active_base(base);
notifierFlags |= ND_ANIMCHAN_SELECT;
}
}
break;
@ -1383,18 +1578,21 @@ static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, s
{
bAction *act= (bAction *)ale->data;
act->flag ^= ACT_COLLAPSED;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
break;
case ANIMTYPE_FILLDRIVERS:
{
AnimData *adt= (AnimData* )ale->data;
adt->flag ^= ADT_DRIVERS_COLLAPSED;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
break;
case ANIMTYPE_FILLMATD:
{
Object *ob= (Object *)ale->data;
ob->nlaflag ^= OB_ADS_SHOWMATS; // XXX
notifierFlags |= ND_ANIMCHAN_EDIT;
}
break;
@ -1402,36 +1600,42 @@ static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, s
{
Material *ma= (Material *)ale->data;
ma->flag ^= MA_DS_EXPAND;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
break;
case ANIMTYPE_DSLAM:
{
Lamp *la= (Lamp *)ale->data;
la->flag ^= LA_DS_EXPAND;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
break;
case ANIMTYPE_DSCAM:
{
Camera *ca= (Camera *)ale->data;
ca->flag ^= CAM_DS_EXPAND;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
break;
case ANIMTYPE_DSCUR:
{
Curve *cu= (Curve *)ale->data;
cu->flag ^= CU_DS_EXPAND;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
break;
case ANIMTYPE_DSSKEY:
{
Key *key= (Key *)ale->data;
key->flag ^= KEYBLOCK_DS_EXPAND;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
break;
case ANIMTYPE_DSWOR:
{
World *wo= (World *)ale->data;
wo->flag ^= WO_DS_EXPAND;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
break;
@ -1443,10 +1647,22 @@ static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, s
if ((x < (offset+17)) && (agrp->channels.first)) {
/* toggle expand */
agrp->flag ^= AGRP_EXPANDED;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
else if ((x < (offset+32)) && (ac->spacetype==SPACE_IPO)) {
/* toggle visibility (of grouped F-Curves in Graph editor) */
agrp->flag ^= AGRP_NOTVISIBLE;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
else if (x >= (ACHANNEL_NAMEWIDTH-ACHANNEL_BUTTON_WIDTH)) {
/* toggle protection/locking */
agrp->flag ^= AGRP_PROTECTED;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
else if (x >= (ACHANNEL_NAMEWIDTH-2*ACHANNEL_BUTTON_WIDTH)) {
/* toggle mute */
agrp->flag ^= AGRP_MUTED;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
else {
/* select/deselect group */
@ -1474,7 +1690,9 @@ static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, s
/* if group is selected now, make group the 'active' one in the visible list */
if (agrp->flag & AGRP_SELECTED)
ANIM_set_active_channel(ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
notifierFlags |= ND_ANIMCHAN_SELECT;
}
}
break;
@ -1495,16 +1713,20 @@ static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, s
if (x >= (ACHANNEL_NAMEWIDTH-ACHANNEL_BUTTON_WIDTH)) {
/* toggle protection (only if there's a toggle there) */
if (fcu->bezt)
if (fcu->bezt) {
fcu->flag ^= FCURVE_PROTECTED;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
}
else if (x >= (ACHANNEL_NAMEWIDTH-2*ACHANNEL_BUTTON_WIDTH)) {
/* toggle mute */
fcu->flag ^= FCURVE_MUTED;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
else if ((x < (offset+17)) && (ac->spacetype==SPACE_IPO)) {
/* toggle visibility */
fcu->flag ^= FCURVE_VISIBLE;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
else {
/* select/deselect */
@ -1520,7 +1742,9 @@ static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, s
/* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */
if (fcu->flag & FCURVE_SELECTED)
ANIM_set_active_channel(ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
notifierFlags |= ND_ANIMCHAN_SELECT;
}
}
break;
@ -1530,6 +1754,8 @@ static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, s
/* toggle expand */
gpd->flag ^= GP_DATA_EXPAND;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
break;
case ANIMTYPE_GPLAYER:
@ -1568,6 +1794,9 @@ static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, s
/* free channels */
BLI_freelistN(&anim_data);
/* return notifier flags */
return notifierFlags;
}
/* ------------------- */
@ -1580,6 +1809,7 @@ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *
ARegion *ar;
View2D *v2d;
int mval[2], channel_index;
int notifierFlags = 0;
short selectmode;
float x, y;
@ -1614,10 +1844,10 @@ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *
UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
/* handle mouse-click in the relevant channel then */
mouse_anim_channels(&ac, x, channel_index, selectmode);
notifierFlags= mouse_anim_channels(&ac, x, channel_index, selectmode);
/* set notifier tha things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION|notifierFlags, NULL);
return OPERATOR_FINISHED;
}
@ -1630,7 +1860,7 @@ void ANIM_OT_channels_click (wmOperatorType *ot)
/* api callbacks */
ot->invoke= animchannels_mouseclick_invoke;
ot->poll= ED_operator_areaactive;
ot->poll= animedit_poll_channels_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1653,6 +1883,8 @@ void ED_operatortypes_animchannels(void)
WM_operatortype_append(ANIM_OT_channels_setting_disable);
WM_operatortype_append(ANIM_OT_channels_setting_toggle);
WM_operatortype_append(ANIM_OT_channels_delete);
// XXX does this need to be a separate operator?
WM_operatortype_append(ANIM_OT_channels_editable_toggle);
@ -1686,6 +1918,10 @@ void ED_keymap_animchannels(wmWindowManager *wm)
/* borderselect */
WM_keymap_add_item(keymap, "ANIM_OT_channels_select_border", BKEY, KM_PRESS, 0, 0);
/* delete */
WM_keymap_add_item(keymap, "ANIM_OT_channels_delete", XKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ANIM_OT_channels_delete", DELKEY, KM_PRESS, 0, 0);
/* settings */
WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_toggle", WKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_enable", WKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);

@ -77,72 +77,6 @@ void ED_anim_object_flush_update(const bContext *C, Object *ob)
}
/* **************************** animation tool notifiers ******************************** */
/* Send notifiers on behalf of animation editing tools, based on various context info
* - data_changed: eAnimData_Changed
*/
void ANIM_animdata_send_notifiers (bContext *C, bAnimContext *ac, short data_changed)
{
/* types of notifiers to send, depends on the editor context */
switch (ac->datatype) {
case ANIMCONT_DOPESHEET: /* dopesheet */
case ANIMCONT_FCURVES: /* fcurve editor */
case ANIMCONT_DRIVERS: /* drivers editor */ // XXX probably this will need separate handling, since these are part of dependency system
{
/* what action was taken */
switch (data_changed) {
case ANIM_CHANGED_KEYFRAMES_VALUES:
/* keyframe values changed, so transform may have changed */
// XXX what about other cases? maybe we need general ND_KEYFRAMES or ND_ANIMATION?
WM_event_add_notifier(C, NC_OBJECT|ND_KEYS|ND_TRANSFORM, NULL);
break;
case ANIM_CHANGED_KEYFRAMES_SELECT:
WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, NULL);
break;
case ANIM_CHANGED_CHANNELS:
// XXX err... check available datatypes in dopesheet first?
// FIXME: this currently doesn't work (to update own view)
WM_event_add_notifier(C, NC_SCENE|ND_OB_ACTIVE|ND_OB_SELECT, ac->scene);
WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE|ND_BONE_SELECT, NULL);
break;
}
// XXX for now, at least update own editor!
ED_area_tag_redraw(CTX_wm_area(C));
}
break;
case ANIMCONT_ACTION: /* action editor */
{
Object *obact= CTX_data_active_object(C);
switch (data_changed) {
case ANIM_CHANGED_KEYFRAMES_VALUES:
/* keyframe values changed, so transform may have changed */
// XXX what about other cases? maybe we need general ND_KEYFRAMES or ND_ANIMATION?
WM_event_add_notifier(C, NC_OBJECT|ND_KEYS|ND_TRANSFORM, obact);
break;
case ANIM_CHANGED_KEYFRAMES_SELECT:
WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, obact);
break;
case ANIM_CHANGED_CHANNELS:
// XXX err... check available datatypes in dopesheet first?
// FIXME: this currently doesn't work (to update own view)
WM_event_add_notifier(C, NC_OBJECT|ND_BONE_ACTIVE|ND_BONE_SELECT, obact);
break;
}
// XXX for now, at least update own editor!
ED_area_tag_redraw(CTX_wm_area(C));
}
break;
default: /* some other data... just update area for now */
ED_area_tag_redraw(CTX_wm_area(C));
}
}
/* **************************** pose <-> action syncing ******************************** */
/* Summary of what needs to be synced between poses and actions:
* 1) Flags
@ -152,6 +86,10 @@ void ANIM_animdata_send_notifiers (bContext *C, bAnimContext *ac, short data_cha
* 3) Grouping (only for pose to action for now)
*/
/* XXX OBSOLETE CODE WARNING:
* With the Animato system, the code below is somewhat obsolete now...
*/
/* Notifier from Action/Dopesheet (this may be extended to include other things such as Python...)
* Channels in action changed, so update pose channels/groups to reflect changes.
*

@ -43,10 +43,12 @@
#include "BLI_blenlib.h"
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_fcurve.h"
#include "BKE_nla.h"
#include "BKE_object.h"
#include "BKE_screen.h"
#include "BKE_utildefines.h"
@ -232,37 +234,16 @@ void ANIM_draw_previewrange (const bContext *C, View2D *v2d)
/* *************************************************** */
/* NLA-MAPPING UTILITIES (required for drawing and also editing keyframes) */
/* Obtain the Object providing NLA-scaling for the given channel (if applicable) */
Object *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
/* Obtain the AnimData block providing NLA-mapping for the given channel (if applicable) */
AnimData *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 (ac->datatype == ANIMCONT_ACTION) {
/* Action Editor (action mode) or Graph Editor (ipo mode):
* Only use if editor is not pinned, and active object has action
*/
if (ac->obact && ac->obact->action) {
SpaceAction *saction= (SpaceAction *)ac->sa->spacedata.first;
if (saction->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;
}
}
// XXX todo: add F-Curves mode (Graph Editor) ...
if (ale && ale->id)
return BKE_animdata_from_id(ale->id);
/* no appropriate object found */
return NULL;
@ -273,7 +254,8 @@ Object *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale)
* (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)
// TODO: should this be depreceated?
void ANIM_nla_mapping_draw(gla2DDrawInfo *di, AnimData *adt, short restore)
{
static rctf stored;
@ -288,8 +270,8 @@ void ANIM_nla_mapping_draw(gla2DDrawInfo *di, Object *ob, short restore)
gla2DGetMap(di, &stored);
map= stored;
map.xmin= get_action_frame(ob, map.xmin);
map.xmax= get_action_frame(ob, map.xmax);
map.xmin= BKE_nla_tweakedit_remap(adt, map.xmin, NLATIME_CONVERT_MAP);
map.xmax= BKE_nla_tweakedit_remap(adt, map.xmax, NLATIME_CONVERT_MAP);
if (map.xmin == map.xmax) map.xmax += 1.0f;
gla2DSetMap(di, &map);
@ -298,36 +280,38 @@ void ANIM_nla_mapping_draw(gla2DDrawInfo *di, Object *ob, short restore)
/* ------------------- */
/* helper function for ANIM_nla_mapping_apply_ipocurve() -> "restore", i.e. mapping points back to IPO-time */
/* helper function for ANIM_nla_mapping_apply_fcurve() -> "restore", i.e. mapping points back to action-time */
static short bezt_nlamapping_restore(BeztEditData *bed, BezTriple *bezt)
{
/* object providing scaling is stored in 'data', only_keys option is stored in i1 */
Object *ob= (Object *)bed->data;
/* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */
AnimData *adt= (AnimData *)bed->data;
short only_keys= (short)bed->i1;
/* adjust BezTriple handles only if allowed to */
if (only_keys == 0) {
bezt->vec[0][0]= get_action_frame(ob, bezt->vec[0][0]);
bezt->vec[2][0]= get_action_frame(ob, bezt->vec[2][0]);
bezt->vec[0][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_UNMAP);
bezt->vec[2][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_UNMAP);
}
bezt->vec[1][0]= get_action_frame(ob, bezt->vec[1][0]);
bezt->vec[1][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_UNMAP);
return 0;
}
/* helper function for ANIM_nla_mapping_apply_ipocurve() -> "apply", i.e. mapping points to NLA-mapped global time */
/* helper function for ANIM_nla_mapping_apply_fcurve() -> "apply", i.e. mapping points to NLA-mapped global time */
static short bezt_nlamapping_apply(BeztEditData *bed, BezTriple *bezt)
{
/* object providing scaling is stored in 'data', only_keys option is stored in i1 */
Object *ob= (Object *)bed->data;
/* AnimData block providing scaling is stored in 'data', only_keys option is stored in i1 */
AnimData *adt= (AnimData *)bed->data;
short only_keys= (short)bed->i1;
/* adjust BezTriple handles only if allowed to */
if (only_keys == 0) {
bezt->vec[0][0]= get_action_frame_inv(ob, bezt->vec[0][0]);
bezt->vec[2][0]= get_action_frame_inv(ob, bezt->vec[2][0]);
bezt->vec[0][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[0][0], NLATIME_CONVERT_MAP);
bezt->vec[2][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[2][0], NLATIME_CONVERT_MAP);
}
bezt->vec[1][0]= get_action_frame_inv(ob, bezt->vec[1][0]);
bezt->vec[1][0]= BKE_nla_tweakedit_remap(adt, bezt->vec[1][0], NLATIME_CONVERT_MAP);
return 0;
}
@ -338,17 +322,17 @@ static short bezt_nlamapping_apply(BeztEditData *bed, BezTriple *bezt)
* - restore = whether to map points back to non-mapped time
* - only_keys = whether to only adjust the location of the center point of beztriples
*/
void ANIM_nla_mapping_apply_fcurve(Object *ob, FCurve *fcu, short restore, short only_keys)
void ANIM_nla_mapping_apply_fcurve (AnimData *adt, FCurve *fcu, short restore, short only_keys)
{
BeztEditData bed;
BeztEditFunc map_cb;
/* init edit data
* - ob is stored in 'data'
* - AnimData is stored in 'data'
* - only_keys is stored in 'i1'
*/
memset(&bed, 0, sizeof(BeztEditData));
bed.data= (void *)ob;
bed.data= (void *)adt;
bed.i1= (int)only_keys;
/* get editing callback */

@ -195,7 +195,7 @@ static short actedit_get_context (bAnimContext *ac, SpaceAction *saction)
}
}
/* ----------- Private Stuff - IPO Editor ------------- */
/* ----------- Private Stuff - Graph Editor ------------- */
/* Get data being edited in Graph Editor (depending on current 'mode') */
static short graphedit_get_context (bAnimContext *ac, SpaceIpo *sipo)
@ -237,6 +237,26 @@ static short graphedit_get_context (bAnimContext *ac, SpaceIpo *sipo)
}
}
/* ----------- Private Stuff - NLA Editor ------------- */
/* Get data being edited in Graph Editor (depending on current 'mode') */
static short nlaedit_get_context (bAnimContext *ac, SpaceNla *snla)
{
/* init dopesheet data if non-existant (i.e. for old files) */
if (snla->ads == NULL)
snla->ads= MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet");
/* sync settings with current view status, then return appropriate data */
/* update scene-pointer (no need to check for pinning yet, as not implemented) */
snla->ads->source= (ID *)ac->scene;
snla->ads->filterflag |= ADS_FILTER_ONLYNLA;
ac->datatype= ANIMCONT_NLA;
ac->data= snla->ads;
return 1;
}
/* ----------- Public API --------------- */
/* Obtain current anim-data context, given that context info from Blender context has already been set
@ -264,6 +284,13 @@ short ANIM_animdata_context_getdata (bAnimContext *ac)
ok= graphedit_get_context(ac, sipo);
}
break;
case SPACE_NLA:
{
SpaceNla *snla= (SpaceNla *)sa->spacedata.first;
ok= nlaedit_get_context(ac, snla);
}
break;
}
}
@ -313,6 +340,68 @@ short ANIM_animdata_get_context (const bContext *C, bAnimContext *ac)
/* quick macro to test if AnimData is usable for drivers */
#define ANIMDATA_HAS_DRIVERS(id) ((id)->adt && (id)->adt->drivers.first)
/* quick macro to test if AnimData is usable for NLA */
#define ANIMDATA_HAS_NLA(id) ((id)->adt && (id)->adt->nla_tracks.first)
/* Quick macro to test for all three avove usability tests, performing the appropriate provided
* action for each when the AnimData context is appropriate.
*
* Priority order for this goes (most important, to least): AnimData blocks, NLA, Drivers, Keyframes.
*
* For this to work correctly, a standard set of data needs to be available within the scope that this
* gets called in:
* - ListBase anim_data;
* - bDopeSheet *ads;
* - bAnimListElem *ale;
* - int items;
*
* - id: ID block which should have an AnimData pointer following it immediately, to use
* - adtOk: line or block of code to execute for AnimData-blocks case (usually ANIMDATA_ADD_ANIMDATA)
* - nlaOk: line or block of code to execute for NLA case
* - driversOk: line or block of code to execute for Drivers case
* - keysOk: line or block of code for Keyframes case
*/
#define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, keysOk) \
{\
if (filter_mode & ANIMFILTER_ANIMDATA) {\
if ((id)->adt) {\
adtOk\
}\
}\
else if (ads->filterflag & ADS_FILTER_ONLYNLA) {\
if (ANIMDATA_HAS_NLA(id)) {\
nlaOk\
}\
else if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) && ANIMDATA_HAS_KEYS(id)) {\
nlaOk\
}\
}\
else if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) {\
if (ANIMDATA_HAS_DRIVERS(id)) {\
driversOk\
}\
}\
else {\
if (ANIMDATA_HAS_KEYS(id)) {\
keysOk\
}\
}\
}
/* quick macro to add a pointer to an AnimData block as a channel */
#define ANIMDATA_ADD_ANIMDATA(id) \
{\
ale= make_new_animlistelem((id)->adt, ANIMTYPE_ANIMDATA, NULL, ANIMTYPE_NONE, (ID *)id);\
if (ale) {\
BLI_addtail(anim_data, ale);\
items++;\
}\
}
/* quick macro to test if a anim-channel (F-Curve, Group, etc.) is selected in an acceptable way */
#define ANIMCHANNEL_SELOK(test_func) \
( !(filter_mode & (ANIMFILTER_SEL|ANIMFILTER_UNSEL)) || \
@ -494,6 +583,25 @@ bAnimListElem *make_new_animlistelem (void *data, short datatype, void *owner, s
ale->datatype= ALE_GPFRAME;
}
break;
case ANIMTYPE_NLATRACK:
{
NlaTrack *nlt= (NlaTrack *)data;
ale->flag= nlt->flag;
// XXX or should this be done some other way?
ale->key_data= &nlt->strips;
ale->datatype= ALE_NLASTRIP;
}
break;
case ANIMTYPE_NLAACTION:
{
/* nothing to include for now... nothing editable from NLA-perspective here */
ale->key_data= NULL;
ale->datatype= ALE_NONE;
}
break;
}
}
@ -522,7 +630,6 @@ static int animdata_filter_fcurves (ListBase *anim_data, FCurve *first, bActionG
if ( ANIMCHANNEL_SELOK(SEL_FCU(fcu)) ) {
/* only include if this curve is active */
if (!(filter_mode & ANIMFILTER_ACTIVE) || (fcu->flag & FCURVE_ACTIVE)) {
/* owner/ownertype will be either object or action-channel, depending if it was dopesheet or part of an action */
ale= make_new_animlistelem(fcu, ANIMTYPE_FCURVE, owner, ownertype, owner_id);
if (ale) {
@ -575,25 +682,30 @@ static int animdata_filter_action (ListBase *anim_data, bAction *act, int filter
* cases when we should include F-Curves inside group:
* - we don't care about visibility
* - group is expanded
* - we're interested in keyframes, but not if they appear in selected channels
* - we just need the F-Curves present
*/
// XXX what was the selection check here for again?
if ( (!(filter_mode & ANIMFILTER_VISIBLE) || EXPANDED_AGRP(agrp)) ||
( /*ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) &&*/ (filter_mode & ANIMFILTER_CURVESONLY) ) )
if ( (!(filter_mode & ANIMFILTER_VISIBLE) || EXPANDED_AGRP(agrp)) || (filter_mode & ANIMFILTER_CURVESONLY) )
{
if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) {
// XXX the 'owner' info here needs review...
items += animdata_filter_fcurves(anim_data, agrp->channels.first, agrp, owner, ownertype, filter_mode, owner_id);
/* for the Graph Editor, curves may be set to not be visible in the view to lessen clutter,
* but to do this, we need to check that the group doesn't have it's not-visible flag set preventing
* all its sub-curves to be shown
*/
if ( !(filter_mode & ANIMFILTER_CURVEVISIBLE) || !(agrp->flag & AGRP_NOTVISIBLE) )
{
if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) {
// XXX the 'owner' info here needs review...
items += animdata_filter_fcurves(anim_data, agrp->channels.first, agrp, owner, ownertype, filter_mode, owner_id);
/* remove group from filtered list if last element is group
* (i.e. only if group had channels, which were all hidden)
*/
// XXX this is really hacky... it should be fixed in a much more elegant way!
if ( (ale) && (anim_data->last == ale) &&
(ale->data == agrp) && (agrp->channels.first) )
{
BLI_freelinkN(anim_data, ale);
items--;
/* remove group from filtered list if last element is group
* (i.e. only if group had channels, which were all hidden)
*/
// XXX this is really hacky... it should be fixed in a much more elegant way!
if ( (ale) && (anim_data->last == ale) &&
(ale->data == agrp) && (agrp->channels.first) )
{
BLI_freelinkN(anim_data, ale);
items--;
}
}
}
}
@ -610,6 +722,83 @@ static int animdata_filter_action (ListBase *anim_data, bAction *act, int filter
return items;
}
/* Include NLA-Data for NLA-Editor:
* - when ANIMFILTER_CHANNELS is used, that means we should be filtering the list for display
* Although the evaluation order is from the first track to the last and then apply the Action on top,
* we present this in the UI as the Active Action followed by the last track to the first so that we
* get the evaluation order presented as per a stack.
* - for normal filtering (i.e. for editing), we only need the NLA-tracks but they can be in 'normal' evaluation
* order, i.e. first to last. Otherwise, some tools may get screwed up.
*/
static int animdata_filter_nla (ListBase *anim_data, AnimData *adt, int filter_mode, void *owner, short ownertype, ID *owner_id)
{
bAnimListElem *ale;
NlaTrack *nlt;
NlaTrack *first=NULL, *next=NULL;
int items = 0;
/* if showing channels, include active action */
if (filter_mode & ANIMFILTER_CHANNELS) {
/* there isn't really anything editable here, so skip if need editable */
// TODO: currently, selection isn't checked since it doesn't matter
if ((filter_mode & ANIMFILTER_FOREDIT) == 0) {
/* just add the action track now (this MUST appear for drawing)
* - as AnimData may not have an action, we pass a dummy pointer just to get the list elem created, then
* overwrite this with the real value - REVIEW THIS...
*/
ale= make_new_animlistelem((void *)(&adt->action), ANIMTYPE_NLAACTION, owner, ownertype, owner_id);
ale->data= (adt->action) ? adt->action : NULL;
if (ale) {
BLI_addtail(anim_data, ale);
items++;
}
}
/* first track to include will be the last one if we're filtering by channels */
first= adt->nla_tracks.last;
}
else {
/* first track to include will the the first one (as per normal) */
first= adt->nla_tracks.first;
}
/* loop over NLA Tracks - assume that the caller of this has already checked that these should be included */
for (nlt= first; nlt; nlt= next) {
/* 'next' NLA-Track to use depends on whether we're filtering for drawing or not */
if (filter_mode & ANIMFILTER_CHANNELS)
next= nlt->prev;
else
next= nlt->next;
/* if we're in NLA-tweakmode, don't show this track if it was disabled (due to tweaking) for now
* - active track should still get shown though (even though it has disabled flag set)
*/
// FIXME: the channels after should still get drawn, just 'differently', and after an active-action channel
if ((adt->flag & ADT_NLA_EDIT_ON) && (nlt->flag & NLATRACK_DISABLED) && !(nlt->flag & NLATRACK_ACTIVE))
continue;
/* only work with this channel and its subchannels if it is editable */
if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_NLT(nlt)) {
/* only include this track if selected in a way consistent with the filtering requirements */
if ( ANIMCHANNEL_SELOK(SEL_NLT(nlt)) ) {
/* only include if this track is active */
if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) {
ale= make_new_animlistelem(nlt, ANIMTYPE_NLATRACK, owner, ownertype, owner_id);
if (ale) {
BLI_addtail(anim_data, ale);
items++;
}
}
}
}
}
/* return the number of items added to the list */
return items;
}
static int animdata_filter_shapekey (ListBase *anim_data, Key *key, int filter_mode, void *owner, short ownertype, ID *owner_id)
{
bAnimListElem *ale;
@ -752,19 +941,19 @@ static int animdata_filter_dopesheet_mats (ListBase *anim_data, bDopeSheet *ads,
/* firstly check that we actuallly have some materials, by gathering all materials in a temp list */
for (a=0; a < ob->totcol; a++) {
Material *ma= give_current_material(ob, a);
short ok = 0;
/* for now, if no material returned, skip (this shouldn't confuse the user I hope) */
if (ELEM(NULL, ma, ma->adt))
continue;
if ((ads->filterflag & ADS_FILTER_ONLYDRIVERS)==0) {
if (ANIMDATA_HAS_KEYS(ma) == 0)
continue;
}
else {
if (ANIMDATA_HAS_DRIVERS(ma) == 0)
continue;
}
/* check if ok */
ANIMDATA_FILTER_CASES(ma,
{ /* AnimData blocks - do nothing... */ },
ok=1;,
ok=1;,
ok=1;)
if (ok == 0) continue;
/* make a temp list elem for this */
ld= MEM_callocN(sizeof(LinkData), "DopeSheet-MaterialCache");
@ -801,16 +990,13 @@ static int animdata_filter_dopesheet_mats (ListBase *anim_data, bDopeSheet *ads,
}
}
/* add material's F-Curve or Driver channels? */
/* add material's animation data */
if (FILTER_MAT_OBJD(ma) || (filter_mode & ANIMFILTER_CURVESONLY)) {
if ((ads->filterflag & ADS_FILTER_ONLYDRIVERS)==0) {
// XXX the 'owner' info here is still subject to improvement
items += animdata_filter_action(anim_data, ma->adt->action, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma);
}
else {
// need to make the ownertype normal object here... (maybe type should be a separate one for clarity?)
items += animdata_filter_fcurves(anim_data, ma->adt->drivers.first, NULL, ma, ANIMTYPE_DSMAT, filter_mode, (ID *)ma);
}
ANIMDATA_FILTER_CASES(ma,
{ /* AnimData blocks - do nothing... */ },
items += animdata_filter_nla(anim_data, ma->adt, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma);,
items += animdata_filter_fcurves(anim_data, ma->adt->drivers.first, NULL, ma, ANIMTYPE_DSMAT, filter_mode, (ID *)ma);,
items += animdata_filter_action(anim_data, ma->adt->action, filter_mode, ma, ANIMTYPE_DSMAT, (ID *)ma);)
}
}
}
@ -871,15 +1057,12 @@ static int animdata_filter_dopesheet_obdata (ListBase *anim_data, bDopeSheet *ad
/* add object-data animation channels? */
if ((expanded) || (filter_mode & ANIMFILTER_CURVESONLY)) {
/* Action or Drivers? */
if ((ads->filterflag & ADS_FILTER_ONLYDRIVERS) == 0) {
// XXX the 'owner' info here is still subject to improvement
items += animdata_filter_action(anim_data, iat->adt->action, filter_mode, iat, type, (ID *)iat);
}
else {
// need to make the ownertype normal object here... (maybe type should be a separate one for clarity?)
items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, iat, type, filter_mode, (ID *)iat);
}
/* filtering for channels - nla, drivers, keyframes */
ANIMDATA_FILTER_CASES(iat,
{ /* AnimData blocks - do nothing... */ },
items+= animdata_filter_nla(anim_data, iat->adt, filter_mode, iat, type, (ID *)iat);,
items+= animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, iat, type, filter_mode, (ID *)iat);,
items += animdata_filter_action(anim_data, iat->adt->action, filter_mode, iat, type, (ID *)iat);)
}
/* return the number of items added to the list */
@ -889,12 +1072,14 @@ static int animdata_filter_dopesheet_obdata (ListBase *anim_data, bDopeSheet *ad
static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
{
bAnimListElem *ale=NULL;
AnimData *adt = NULL;
Object *ob= base->object;
Key *key= ob_get_key(ob);
short obdata_ok = 0;
int items = 0;
/* add this object as a channel first */
if ((filter_mode & ANIMFILTER_CURVESONLY) == 0) {
if ((filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) == 0) {
/* check if filtering by selection */
if ANIMCHANNEL_SELOK((base->flag & SELECT)) {
ale= make_new_animlistelem(base, ANIMTYPE_OBJECT, NULL, ANIMTYPE_NONE, NULL);
@ -906,76 +1091,64 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B
}
/* if collapsed, don't go any further (unless adding keyframes only) */
if ( (EXPANDED_OBJC(ob) == 0) && !(filter_mode & ANIMFILTER_CURVESONLY) )
if ( (EXPANDED_OBJC(ob) == 0) && !(filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) )
return items;
/* Action or Drivers */
if ((ads->filterflag & ADS_FILTER_ONLYDRIVERS) == 0) {
/* Action? */
if (ANIMDATA_HAS_KEYS(ob) /*&& !(ads->filterflag & ADS_FILTER_NOACTS)*/) {
AnimData *adt= ob->adt;
/* Action, Drivers, or NLA */
if (ob->adt) {
adt= ob->adt;
ANIMDATA_FILTER_CASES(ob,
{ /* AnimData blocks - do nothing... */ },
{ /* nla */
/* add NLA tracks */
items += animdata_filter_nla(anim_data, adt, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob);
},
{ /* drivers */
/* include drivers-expand widget? */
if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLDRIVERS, base, ANIMTYPE_OBJECT, (ID *)ob);
if (ale) {
BLI_addtail(anim_data, ale);
items++;
}
}
/* include action-expand widget? */
if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLACTD, base, ANIMTYPE_OBJECT, (ID *)ob);
if (ale) {
BLI_addtail(anim_data, ale);
items++;
/* add F-Curve channels (drivers are F-Curves) */
if (EXPANDED_DRVD(adt) || !(filter_mode & ANIMFILTER_CHANNELS)) {
// need to make the ownertype normal object here... (maybe type should be a separate one for clarity?)
items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, ob, ANIMTYPE_OBJECT, filter_mode, (ID *)ob);
}
},
{ /* action (keyframes) */
/* include action-expand widget? */
if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLACTD, base, ANIMTYPE_OBJECT, (ID *)ob);
if (ale) {
BLI_addtail(anim_data, ale);
items++;
}
}
/* add F-Curve channels? */
if (EXPANDED_ACTC(adt->action) || !(filter_mode & ANIMFILTER_CHANNELS)) {
// need to make the ownertype normal object here... (maybe type should be a separate one for clarity?)
items += animdata_filter_action(anim_data, adt->action, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob);
}
}
/* add F-Curve channels? */
if (EXPANDED_ACTC(adt->action) || !(filter_mode & ANIMFILTER_CHANNELS)) {
// need to make the ownertype normal object here... (maybe type should be a separate one for clarity?)
items += animdata_filter_action(anim_data, adt->action, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob);
}
}
);
}
else {
/* Drivers */
if (ANIMDATA_HAS_DRIVERS(ob)) {
AnimData *adt= ob->adt;
/* include drivers-expand widget? */
if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLDRIVERS, base, ANIMTYPE_OBJECT, (ID *)ob);
if (ale) {
BLI_addtail(anim_data, ale);
items++;
}
}
/* add F-Curve channels (drivers are F-Curves) */
if (EXPANDED_DRVD(adt) || !(filter_mode & ANIMFILTER_CHANNELS)) {
// need to make the ownertype normal object here... (maybe type should be a separate one for clarity?)
items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, ob, ANIMTYPE_OBJECT, filter_mode, (ID *)ob);
}
}
}
/* ShapeKeys? */
if ((key) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)) {
/* Animation or Drivers */
if ((ads->filterflag & ADS_FILTER_ONLYDRIVERS) == 0) {
/* include shapekey-expand widget? */
if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob);
if (ale) {
BLI_addtail(anim_data, ale);
items++;
}
}
/* add channels */
if (FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY)) {
items += animdata_filter_shapekey(anim_data, key, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob);
}
}
else {
/* Drivers */
if (ANIMDATA_HAS_DRIVERS(key)) {
AnimData *adt= key->adt;
adt= key->adt;
ANIMDATA_FILTER_CASES(key,
{ /* AnimData blocks - do nothing... */ },
{ /* nla */
/* add NLA tracks */
items += animdata_filter_nla(anim_data, adt, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob);
},
{ /* drivers */
/* include shapekey-expand widget? */
if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob);
@ -985,16 +1158,29 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B
}
}
/* add F-Curve channels (drivers are F-Curves) */
if (FILTER_SKE_OBJD(key)/*EXPANDED_DRVD(adt)*/ || !(filter_mode & ANIMFILTER_CHANNELS)) {
// XXX owner info is messed up now...
items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, ob, ANIMTYPE_OBJECT, filter_mode, (ID *)key);
/* add channels */
if (FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY)) {
items += animdata_filter_shapekey(anim_data, key, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob);
}
},
{ /* action (keyframes) */
/* include shapekey-expand widget? */
if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT, (ID *)ob);
if (ale) {
BLI_addtail(anim_data, ale);
items++;
}
}
/* add channels */
if (FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_CURVESONLY)) {
items += animdata_filter_shapekey(anim_data, key, filter_mode, ob, ANIMTYPE_OBJECT, (ID *)ob);
}
}
}
);
}
/* Materials? */
if ((ob->totcol) && !(ads->filterflag & ADS_FILTER_NOMAT))
items += animdata_filter_dopesheet_mats(anim_data, ads, base, filter_mode);
@ -1006,14 +1192,11 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B
Camera *ca= (Camera *)ob->data;
if ((ads->filterflag & ADS_FILTER_NOCAM) == 0) {
if ((ads->filterflag & ADS_FILTER_ONLYDRIVERS)==0) {
if (ANIMDATA_HAS_KEYS(ca))
items += animdata_filter_dopesheet_obdata(anim_data, ads, base, filter_mode);
}
else {
if (ANIMDATA_HAS_DRIVERS(ca))
items += animdata_filter_dopesheet_obdata(anim_data, ads, base, filter_mode);
}
ANIMDATA_FILTER_CASES(ca,
{ /* AnimData blocks - do nothing... */ },
obdata_ok= 1;,
obdata_ok= 1;,
obdata_ok= 1;)
}
}
break;
@ -1022,14 +1205,11 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B
Lamp *la= (Lamp *)ob->data;
if ((ads->filterflag & ADS_FILTER_NOLAM) == 0) {
if ((ads->filterflag & ADS_FILTER_ONLYDRIVERS)==0) {
if (ANIMDATA_HAS_KEYS(la))
items += animdata_filter_dopesheet_obdata(anim_data, ads, base, filter_mode);
}
else {
if (ANIMDATA_HAS_DRIVERS(la))
items += animdata_filter_dopesheet_obdata(anim_data, ads, base, filter_mode);
}
ANIMDATA_FILTER_CASES(la,
{ /* AnimData blocks - do nothing... */ },
obdata_ok= 1;,
obdata_ok= 1;,
obdata_ok= 1;)
}
}
break;
@ -1038,18 +1218,17 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B
Curve *cu= (Curve *)ob->data;
if ((ads->filterflag & ADS_FILTER_NOCUR) == 0) {
if ((ads->filterflag & ADS_FILTER_ONLYDRIVERS)==0) {
if (ANIMDATA_HAS_KEYS(cu))
items += animdata_filter_dopesheet_obdata(anim_data, ads, base, filter_mode);
}
else {
if (ANIMDATA_HAS_DRIVERS(cu))
items += animdata_filter_dopesheet_obdata(anim_data, ads, base, filter_mode);
}
ANIMDATA_FILTER_CASES(cu,
{ /* AnimData blocks - do nothing... */ },
obdata_ok= 1;,
obdata_ok= 1;,
obdata_ok= 1;)
}
}
break;
}
if (obdata_ok)
items += animdata_filter_dopesheet_obdata(anim_data, ads, base, filter_mode);
/* return the number of items added to the list */
return items;
@ -1058,11 +1237,12 @@ static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, B
static int animdata_filter_dopesheet_scene (ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode)
{
World *wo= sce->world;
AnimData *adt= NULL;
bAnimListElem *ale;
int items = 0;
/* add scene as a channel first (even if we aren't showing scenes we still need to show the scene's sub-data */
if ((filter_mode & ANIMFILTER_CURVESONLY) == 0) {
if ((filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) == 0) {
/* check if filtering by selection */
if (ANIMCHANNEL_SELOK( (sce->flag & SCE_DS_SELECTED) )) {
ale= make_new_animlistelem(sce, ANIMTYPE_SCENE, NULL, ANIMTYPE_NONE, NULL);
@ -1074,77 +1254,63 @@ static int animdata_filter_dopesheet_scene (ListBase *anim_data, bDopeSheet *ads
}
/* if collapsed, don't go any further (unless adding keyframes only) */
if ( (EXPANDED_SCEC(sce) == 0) && !(filter_mode & ANIMFILTER_CURVESONLY) )
if ( (EXPANDED_SCEC(sce) == 0) && !(filter_mode & (ANIMFILTER_CURVESONLY|ANIMFILTER_NLATRACKS)) )
return items;
/* Action or Drivers */
if ((ads->filterflag & ADS_FILTER_ONLYDRIVERS) == 0) {
/* Action? */
if (ANIMDATA_HAS_KEYS(sce) && !(ads->filterflag & ADS_FILTER_NOSCE)) {
AnimData *adt= sce->adt;
/* Action, Drivers, or NLA for Scene */
if ((ads->filterflag & ADS_FILTER_NOSCE) == 0) {
adt= sce->adt;
ANIMDATA_FILTER_CASES(sce,
{ /* AnimData blocks - do nothing... */ },
{ /* nla */
/* add NLA tracks */
items += animdata_filter_nla(anim_data, adt, filter_mode, sce, ANIMTYPE_SCENE, (ID *)sce);
},
{ /* drivers */
/* include drivers-expand widget? */
if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLDRIVERS, sce, ANIMTYPE_SCENE, (ID *)sce);
if (ale) {
BLI_addtail(anim_data, ale);
items++;
}
}
/* include action-expand widget? */
if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLACTD, sce, ANIMTYPE_SCENE, (ID *)sce);
if (ale) {
BLI_addtail(anim_data, ale);
items++;
/* add F-Curve channels (drivers are F-Curves) */
if (EXPANDED_DRVD(adt) || !(filter_mode & ANIMFILTER_CHANNELS)) {
items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, sce, ANIMTYPE_SCENE, filter_mode, (ID *)sce);
}
},
{ /* action */
/* include action-expand widget? */
if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLACTD, sce, ANIMTYPE_SCENE, (ID *)sce);
if (ale) {
BLI_addtail(anim_data, ale);
items++;
}
}
/* add F-Curve channels? */
if (EXPANDED_ACTC(adt->action) || !(filter_mode & ANIMFILTER_CHANNELS)) {
items += animdata_filter_action(anim_data, adt->action, filter_mode, sce, ANIMTYPE_SCENE, (ID *)sce);
}
}
/* add F-Curve channels? */
if (EXPANDED_ACTC(adt->action) || !(filter_mode & ANIMFILTER_CHANNELS)) {
items += animdata_filter_action(anim_data, adt->action, filter_mode, sce, ANIMTYPE_SCENE, (ID *)sce);
}
}
}
else {
/* Drivers */
if (ANIMDATA_HAS_DRIVERS(sce) && !(ads->filterflag & ADS_FILTER_NOSCE)) {
AnimData *adt= sce->adt;
/* include drivers-expand widget? */
if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
ale= make_new_animlistelem(adt->action, ANIMTYPE_FILLDRIVERS, sce, ANIMTYPE_SCENE, (ID *)sce);
if (ale) {
BLI_addtail(anim_data, ale);
items++;
}
}
/* add F-Curve channels (drivers are F-Curves) */
if (EXPANDED_DRVD(adt) || !(filter_mode & ANIMFILTER_CHANNELS)) {
items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, sce, ANIMTYPE_SCENE, filter_mode, (ID *)sce);
}
}
)
}
/* world */
if ((wo && wo->adt) && !(ads->filterflag & ADS_FILTER_NOWOR)) {
/* Animation or Drivers */
if ((ads->filterflag & ADS_FILTER_ONLYDRIVERS) == 0) {
AnimData *adt= wo->adt;
/* include world-expand widget? */
if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
ale= make_new_animlistelem(wo, ANIMTYPE_DSWOR, sce, ANIMTYPE_SCENE, (ID *)sce);
if (ale) {
BLI_addtail(anim_data, ale);
items++;
}
}
/* add channels */
if (FILTER_WOR_SCED(wo) || (filter_mode & ANIMFILTER_CURVESONLY)) {
items += animdata_filter_action(anim_data, adt->action, filter_mode, wo, ANIMTYPE_DSWOR, (ID *)wo);
}
}
else {
/* Drivers */
if (ANIMDATA_HAS_DRIVERS(wo)) {
AnimData *adt= wo->adt;
/* include shapekey-expand widget? */
/* Action, Drivers, or NLA for World */
adt= wo->adt;
ANIMDATA_FILTER_CASES(wo,
{ /* AnimData blocks - do nothing... */ },
{ /* nla */
/* add NLA tracks */
items += animdata_filter_nla(anim_data, adt, filter_mode, wo, ANIMTYPE_DSWOR, (ID *)wo);
},
{ /* drivers */
/* include world-expand widget? */
if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
ale= make_new_animlistelem(wo, ANIMTYPE_DSWOR, sce, ANIMTYPE_SCENE, (ID *)wo);
if (ale) {
@ -1158,8 +1324,23 @@ static int animdata_filter_dopesheet_scene (ListBase *anim_data, bDopeSheet *ads
// XXX owner info is messed up now...
items += animdata_filter_fcurves(anim_data, adt->drivers.first, NULL, wo, ANIMTYPE_DSWOR, filter_mode, (ID *)wo);
}
},
{ /* action */
/* include world-expand widget? */
if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & ANIMFILTER_CURVESONLY)) {
ale= make_new_animlistelem(wo, ANIMTYPE_DSWOR, sce, ANIMTYPE_SCENE, (ID *)sce);
if (ale) {
BLI_addtail(anim_data, ale);
items++;
}
}
/* add channels */
if (FILTER_WOR_SCED(wo) || (filter_mode & ANIMFILTER_CURVESONLY)) {
items += animdata_filter_action(anim_data, adt->action, filter_mode, wo, ANIMTYPE_DSWOR, (ID *)wo);
}
}
}
)
}
/* return the number of items added to the list */
@ -1171,6 +1352,7 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int
{
Scene *sce= (Scene *)ads->source;
Base *base;
bAnimListElem *ale;
int items = 0;
/* check that we do indeed have a scene */
@ -1182,22 +1364,32 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int
/* scene-linked animation */
// TODO: sequencer, composite nodes - are we to include those here too?
{
short sceOk, worOk;
short sceOk= 0, worOk= 0;
/* check filtering-flags if ok */
if (ads->filterflag) {
if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) {
sceOk= (ANIMDATA_HAS_DRIVERS(sce) && !(ads->filterflag & ADS_FILTER_NOSCE));
worOk= ((sce->world) && ANIMDATA_HAS_DRIVERS(sce->world) && !(ads->filterflag & ADS_FILTER_NOWOR));
}
else {
sceOk= (ANIMDATA_HAS_KEYS(sce) && !(ads->filterflag & ADS_FILTER_NOSCE));
worOk= ((sce->world) && ANIMDATA_HAS_KEYS(sce->world) && !(ads->filterflag & ADS_FILTER_NOWOR));
}
}
else {
sceOk= (ANIMDATA_HAS_KEYS(sce));
worOk= ((sce->world) && ANIMDATA_HAS_KEYS(sce->world));
ANIMDATA_FILTER_CASES(sce,
{
/* for the special AnimData blocks only case, we only need to add
* the block if it is valid... then other cases just get skipped (hence ok=0)
*/
ANIMDATA_ADD_ANIMDATA(sce);
sceOk=0;
},
sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);,
sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);,
sceOk= !(ads->filterflag & ADS_FILTER_NOSCE);)
if (sce->world) {
ANIMDATA_FILTER_CASES(sce->world,
{
/* for the special AnimData blocks only case, we only need to add
* the block if it is valid... then other cases just get skipped (hence ok=0)
*/
ANIMDATA_ADD_ANIMDATA(sce->world);
worOk=0;
},
worOk= !(ads->filterflag & ADS_FILTER_NOWOR);,
worOk= !(ads->filterflag & ADS_FILTER_NOWOR);,
worOk= !(ads->filterflag & ADS_FILTER_NOWOR);)
}
/* check if not all bad (i.e. so there is something to show) */
@ -1239,13 +1431,33 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int
}
/* check filters for datatypes */
if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) {
actOk= (ANIMDATA_HAS_DRIVERS(ob));
keyOk= ((key) && ANIMDATA_HAS_DRIVERS(key) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS));
}
else {
actOk= ANIMDATA_HAS_KEYS(ob);
keyOk= ((key) && ANIMDATA_HAS_KEYS(key) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS));
/* object */
actOk= 0;
keyOk= 0;
ANIMDATA_FILTER_CASES(ob,
{
/* for the special AnimData blocks only case, we only need to add
* the block if it is valid... then other cases just get skipped (hence ok=0)
*/
ANIMDATA_ADD_ANIMDATA(ob);
actOk=0;
},
actOk= 1;,
actOk= 1;,
actOk= 1;)
if (key) {
/* shapekeys */
ANIMDATA_FILTER_CASES(key,
{
/* for the special AnimData blocks only case, we only need to add
* the block if it is valid... then other cases just get skipped (hence ok=0)
*/
ANIMDATA_ADD_ANIMDATA(key);
keyOk=0;
},
keyOk= 1;,
keyOk= 1;,
keyOk= 1;)
}
/* materials - only for geometric types */
@ -1260,18 +1472,20 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int
Material *ma= give_current_material(ob, a);
/* if material has relevant animation data, break */
if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) {
if (ANIMDATA_HAS_DRIVERS(ma)) {
matOk= 1;
break;
}
}
else {
if (ANIMDATA_HAS_KEYS(ma)) {
matOk= 1;
break;
}
}
ANIMDATA_FILTER_CASES(ma,
{
/* for the special AnimData blocks only case, we only need to add
* the block if it is valid... then other cases just get skipped (hence ok=0)
*/
ANIMDATA_ADD_ANIMDATA(ma);
matOk=0;
},
matOk= 1;,
matOk= 1;,
matOk= 1;)
if (matOk)
break;
}
}
@ -1280,19 +1494,52 @@ static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int
case OB_CAMERA: /* ------- Camera ------------ */
{
Camera *ca= (Camera *)ob->data;
if (ads->filterflag & ADS_FILTER_ONLYDRIVERS)
dataOk= (ANIMDATA_HAS_DRIVERS(ca) && !(ads->filterflag & ADS_FILTER_NOCAM));
else
dataOk= (ANIMDATA_HAS_KEYS(ca) && !(ads->filterflag & ADS_FILTER_NOCAM));
dataOk= 0;
ANIMDATA_FILTER_CASES(ca,
if ((ads->filterflag & ADS_FILTER_NOCAM)==0) {
/* for the special AnimData blocks only case, we only need to add
* the block if it is valid... then other cases just get skipped (hence ok=0)
*/
ANIMDATA_ADD_ANIMDATA(ca);
dataOk=0;
},
dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);,
dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);,
dataOk= !(ads->filterflag & ADS_FILTER_NOCAM);)
}
break;
case OB_LAMP: /* ---------- Lamp ----------- */
{
Lamp *la= (Lamp *)ob->data;
if (ads->filterflag & ADS_FILTER_ONLYDRIVERS)
dataOk= (ANIMDATA_HAS_DRIVERS(la) && !(ads->filterflag & ADS_FILTER_NOLAM));
else
dataOk= (ANIMDATA_HAS_KEYS(la) && !(ads->filterflag & ADS_FILTER_NOLAM));
dataOk= 0;
ANIMDATA_FILTER_CASES(la,
if ((ads->filterflag & ADS_FILTER_NOLAM)==0) {
/* for the special AnimData blocks only case, we only need to add
* the block if it is valid... then other cases just get skipped (hence ok=0)
*/
ANIMDATA_ADD_ANIMDATA(la);
dataOk=0;
},
dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);,
dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);,
dataOk= !(ads->filterflag & ADS_FILTER_NOLAM);)
}
break;
case OB_CURVE: /* ------- Curve ---------- */
{
Curve *cu= (Curve *)ob->data;
dataOk= 0;
ANIMDATA_FILTER_CASES(cu,
if ((ads->filterflag & ADS_FILTER_NOCUR)==0) {
/* for the special AnimData blocks only case, we only need to add
* the block if it is valid... then other cases just get skipped (hence ok=0)
*/
ANIMDATA_ADD_ANIMDATA(cu);
dataOk=0;
},
dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);,
dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);,
dataOk= !(ads->filterflag & ADS_FILTER_NOCUR);)
}
break;
default: /* --- other --- */
@ -1400,6 +1647,7 @@ int ANIM_animdata_filter (bAnimContext *ac, ListBase *anim_data, int filter_mode
case ANIMCONT_DOPESHEET:
case ANIMCONT_FCURVES:
case ANIMCONT_DRIVERS:
case ANIMCONT_NLA:
items= animdata_filter_dopesheet(anim_data, data, filter_mode);
break;
}

@ -83,10 +83,12 @@ static void change_frame_apply(bContext *C, wmOperator *op)
Scene *scene= CTX_data_scene(C);
int cfra;
/* get frame, and clamp to MINFRAME */
/* get frame, and clamp to MINAFRAME
* - not MINFRAME, since it's useful to be able to key a few-frames back
*/
cfra= RNA_int_get(op->ptr, "frame");
if (cfra < MINFRAME) cfra= MINFRAME;
if (cfra < MINAFRAME) cfra= MINAFRAME;
CFRA= cfra;
WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
@ -209,7 +211,7 @@ void ANIM_OT_change_frame(wmOperatorType *ot)
ot->modal= change_frame_modal;
/* rna */
RNA_def_int(ot->srna, "frame", 0, 1, MAXFRAME, "Frame", "", 1, MAXFRAME);
RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
}
/* ****************** set preview range operator ****************************/

@ -1,5 +1,30 @@
/* Testing code for 2.5 animation system
* Copyright 2009, Joshua Leung
/**
* $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) 2009 Blender Foundation, Joshua Leung
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Joshua Leung (full recode)
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <stdio.h>
@ -94,7 +119,7 @@ FCurve *verify_driver_fcurve (ID *id, const char rna_path[], const int array_ind
fcu->driver= MEM_callocN(sizeof(ChannelDriver), "ChannelDriver");
/* add simple generator modifier for driver so that there is some visible representation */
fcurve_add_modifier(fcu, FMODIFIER_TYPE_GENERATOR);
add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR);
/* just add F-Curve to end of driver list */
BLI_addtail(&adt->drivers, fcu);

@ -0,0 +1,679 @@
/**
* $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) 2009 Blender Foundation.
* All rights reserved.
*
*
* Contributor(s): Blender Foundation, Joshua Leung
*
* ***** END GPL LICENSE BLOCK *****
*/
/* User-Interface Stuff for F-Modifiers:
* This file defines the (C-Coded) templates + editing callbacks needed
* by the interface stuff or F-Modifiers, as used by F-Curves in the Graph Editor,
* and NLA-Strips in the NLA Editor.
*/
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <float.h>
#include "DNA_anim_types.h"
#include "DNA_action_types.h"
#include "DNA_object_types.h"
#include "DNA_space_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
#include "MEM_guardedalloc.h"
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
#include "BLI_editVert.h"
#include "BLI_rand.h"
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_customdata.h"
#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_object.h"
#include "BKE_global.h"
#include "BKE_nla.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_utildefines.h"
#include "BIF_gl.h"
#include "WM_api.h"
#include "WM_types.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "ED_anim_api.h"
#include "ED_keyframing.h"
#include "ED_screen.h"
#include "ED_types.h"
#include "ED_util.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "UI_view2d.h"
// XXX! --------------------------------
/* temporary definition for limits of float number buttons (FLT_MAX tends to infinity with old system) */
#define UI_FLT_MAX 10000.0f
/* ********************************************** */
#define B_REDR 1
#define B_FMODIFIER_REDRAW 20
/* macro for use here to draw background box and set height */
// XXX for now, roundbox has it's callback func set to NULL to not intercept events
#define DRAW_BACKDROP(height) \
{ \
uiDefBut(block, ROUNDBOX, B_REDR, "", -3, yco-height, width+3, height-1, NULL, 5.0, 0.0, 12.0, (float)rb_col, ""); \
}
/* callback to verify modifier data */
static void validate_fmodifier_cb (bContext *C, void *fcm_v, void *dummy)
{
FModifier *fcm= (FModifier *)fcm_v;
FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
/* call the verify callback on the modifier if applicable */
if (fmi && fmi->verify_data)
fmi->verify_data(fcm);
}
/* callback to set the active modifier */
static void activate_fmodifier_cb (bContext *C, void *fmods_v, void *fcm_v)
{
ListBase *modifiers = (ListBase *)fmods_v;
FModifier *fcm= (FModifier *)fcm_v;
/* call API function to set the active modifier for active modifier-stack */
set_active_fmodifier(modifiers, fcm);
}
/* callback to remove the given modifier */
static void delete_fmodifier_cb (bContext *C, void *fmods_v, void *fcm_v)
{
ListBase *modifiers = (ListBase *)fmods_v;
FModifier *fcm= (FModifier *)fcm_v;
/* remove the given F-Modifier from the active modifier-stack */
remove_fmodifier(modifiers, fcm);
}
/* --------------- */
/* draw settings for generator modifier */
static void draw_modifier__generator(uiLayout *layout, ID *id, FModifier *fcm, short width)
{
FMod_Generator *data= (FMod_Generator *)fcm->data;
uiLayout *col, *row;
uiBlock *block;
uiBut *but;
PointerRNA ptr;
/* init the RNA-pointer */
RNA_pointer_create(id, &RNA_FModifierFunctionGenerator, fcm, &ptr);
/* basic settings (backdrop + mode selector + some padding) */
col= uiLayoutColumn(layout, 1);
block= uiLayoutGetBlock(layout);
uiBlockBeginAlign(block);
but= uiDefButR(block, MENU, B_FMODIFIER_REDRAW, NULL, 0, 0, width-30, UI_UNIT_Y, &ptr, "mode", -1, 0, 0, -1, -1, NULL);
uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
uiDefButR(block, TOG, B_FMODIFIER_REDRAW, NULL, 0, 0, width-30, UI_UNIT_Y, &ptr, "additive", -1, 0, 0, -1, -1, NULL);
uiBlockEndAlign(block);
/* now add settings for individual modes */
switch (data->mode) {
case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */
{
float *cp = NULL;
char xval[32];
unsigned int i;
/* draw polynomial order selector */
row= uiLayoutRow(layout, 0);
block= uiLayoutGetBlock(row);
but= uiDefButI(block, NUM, B_FMODIFIER_REDRAW, "Poly Order: ", 10,0,width-30,19, &data->poly_order, 1, 100, 0, 0, "'Order' of the Polynomial - for a polynomial with n terms, 'order' is n-1");
uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
/* draw controls for each coefficient and a + sign at end of row */
row= uiLayoutRow(layout, 1);
block= uiLayoutGetBlock(row);
uiDefBut(block, LABEL, 1, "y = ", 0, 0, 50, 20, NULL, 0.0, 0.0, 0, 0, "");
cp= data->coefficients;
for (i=0; (i < data->arraysize) && (cp); i++, cp++) {
/* coefficient */
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 0, 0, 150, 20, cp, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Coefficient for polynomial");
/* 'x' param (and '+' if necessary) */
if (i) {
if (i == 1)
strcpy(xval, "x");
else
sprintf(xval, "x^%d", i);
uiDefBut(block, LABEL, 1, xval, 0, 0, 50, 20, NULL, 0.0, 0.0, 0, 0, "Power of x");
}
if ( (i != (data->arraysize - 1)) || ((i==0) && data->arraysize==2) ) {
uiDefBut(block, LABEL, 1, "+", 0,0 , 30, 20, NULL, 0.0, 0.0, 0, 0, "");
/* next coefficient on a new row */
row= uiLayoutRow(layout, 1);
block= uiLayoutGetBlock(row);
}
}
}
break;
case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial expression */
{
float *cp = NULL;
unsigned int i;
/* draw polynomial order selector */
row= uiLayoutRow(layout, 0);
block= uiLayoutGetBlock(row);
but= uiDefButI(block, NUM, B_FMODIFIER_REDRAW, "Poly Order: ", 0,0,width-30,19, &data->poly_order, 1, 100, 0, 0, "'Order' of the Polynomial - for a polynomial with n terms, 'order' is n-1");
uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
/* draw controls for each pair of coefficients */
row= uiLayoutRow(layout, 1);
block= uiLayoutGetBlock(row);
uiDefBut(block, LABEL, 1, "y=", 0, 0, 50, 20, NULL, 0.0, 0.0, 0, 0, "");
cp= data->coefficients;
for (i=0; (i < data->poly_order) && (cp); i++, cp+=2) {
/* opening bracket */
uiDefBut(block, LABEL, 1, "(", 0, 0, 20, 20, NULL, 0.0, 0.0, 0, 0, "");
/* coefficients */
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 0, 0, 100, 20, cp, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Coefficient of x");
uiDefBut(block, LABEL, 1, "x+", 0, 0, 40, 20, NULL, 0.0, 0.0, 0, 0, "");
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 0, 0, 100, 20, cp+1, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Second coefficient");
/* closing bracket and '+' sign */
if ( (i != (data->poly_order - 1)) || ((i==0) && data->poly_order==2) ) {
uiDefBut(block, LABEL, 1, ") +", 0, 0, 30, 20, NULL, 0.0, 0.0, 0, 0, "");
/* set up new row for the next pair of coefficients*/
row= uiLayoutRow(layout, 1);
block= uiLayoutGetBlock(row);
}
else
uiDefBut(block, LABEL, 1, ")", 0, 0, 20, 20, NULL, 0.0, 0.0, 0, 0, "");
}
}
break;
}
}
/* --------------- */
/* draw settings for noise modifier */
static void draw_modifier__fn_generator(uiLayout *layout, ID *id, FModifier *fcm, short width)
{
uiLayout *col;
PointerRNA ptr;
/* init the RNA-pointer */
RNA_pointer_create(id, &RNA_FModifierFunctionGenerator, fcm, &ptr);
/* add the settings */
col= uiLayoutColumn(layout, 1);
uiItemR(col, "", 0, &ptr, "type", 0, 0, 0);
uiItemR(col, NULL, 0, &ptr, "additive", 0, 0, 1);
col= uiLayoutColumn(layout, 0); // no grouping for now
uiItemR(col, NULL, 0, &ptr, "amplitude", 0, 0, 0);
uiItemR(col, NULL, 0, &ptr, "phase_multiplier", 0, 0, 0);
uiItemR(col, NULL, 0, &ptr, "phase_offset", 0, 0, 0);
uiItemR(col, NULL, 0, &ptr, "value_offset", 0, 0, 0);
}
/* --------------- */
/* draw settings for cycles modifier */
static void draw_modifier__cycles(uiLayout *layout, ID *id, FModifier *fcm, short width)
{
uiLayout *split, *col;
PointerRNA ptr;
/* init the RNA-pointer */
RNA_pointer_create(id, &RNA_FModifierCycles, fcm, &ptr);
/* split into 2 columns
* NOTE: the mode comboboxes shouldn't get labels, otherwise there isn't enough room
*/
split= uiLayoutSplit(layout, 0.5f);
/* before range */
col= uiLayoutColumn(split, 1);
uiItemL(col, "Before:", 0);
uiItemR(col, "", 0, &ptr, "before_mode", 0, 0, 0);
uiItemR(col, NULL, 0, &ptr, "before_cycles", 0, 0, 0);
/* after range */
col= uiLayoutColumn(split, 1);
uiItemL(col, "After:", 0);
uiItemR(col, "", 0, &ptr, "after_mode", 0, 0, 0);
uiItemR(col, NULL, 0, &ptr, "after_cycles", 0, 0, 0);
}
/* --------------- */
/* draw settings for noise modifier */
static void draw_modifier__noise(uiLayout *layout, ID *id, FModifier *fcm, short width)
{
uiLayout *split, *col;
PointerRNA ptr;
/* init the RNA-pointer */
RNA_pointer_create(id, &RNA_FModifierNoise, fcm, &ptr);
/* blending mode */
uiItemR(layout, NULL, 0, &ptr, "modification", 0, 0, 0);
/* split into 2 columns */
split= uiLayoutSplit(layout, 0.5f);
/* col 1 */
col= uiLayoutColumn(split, 0);
uiItemR(col, NULL, 0, &ptr, "size", 0, 0, 0);
uiItemR(col, NULL, 0, &ptr, "strength", 0, 0, 0);
/* col 2 */
col= uiLayoutColumn(split, 0);
uiItemR(col, NULL, 0, &ptr, "phase", 0, 0, 0);
uiItemR(col, NULL, 0, &ptr, "depth", 0, 0, 0);
}
/* --------------- */
#define BINARYSEARCH_FRAMEEQ_THRESH 0.0001
/* Binary search algorithm for finding where to insert Envelope Data Point.
* Returns the index to insert at (data already at that index will be offset if replace is 0)
*/
static int binarysearch_fcm_envelopedata_index (FCM_EnvelopeData array[], float frame, int arraylen, short *exists)
{
int start=0, end=arraylen;
int loopbreaker= 0, maxloop= arraylen * 2;
/* initialise exists-flag first */
*exists= 0;
/* sneaky optimisations (don't go through searching process if...):
* - keyframe to be added is to be added out of current bounds
* - keyframe to be added would replace one of the existing ones on bounds
*/
if ((arraylen <= 0) || (array == NULL)) {
printf("Warning: binarysearch_fcm_envelopedata_index() encountered invalid array \n");
return 0;
}
else {
/* check whether to add before/after/on */
float framenum;
/* 'First' Point (when only one point, this case is used) */
framenum= array[0].time;
if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) {
*exists = 1;
return 0;
}
else if (frame < framenum)
return 0;
/* 'Last' Point */
framenum= array[(arraylen-1)].time;
if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) {
*exists= 1;
return (arraylen - 1);
}
else if (frame > framenum)
return arraylen;
}
/* most of the time, this loop is just to find where to put it
* - 'loopbreaker' is just here to prevent infinite loops
*/
for (loopbreaker=0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
/* compute and get midpoint */
int mid = start + ((end - start) / 2); /* we calculate the midpoint this way to avoid int overflows... */
float midfra= array[mid].time;
/* check if exactly equal to midpoint */
if (IS_EQT(frame, midfra, BINARYSEARCH_FRAMEEQ_THRESH)) {
*exists = 1;
return mid;
}
/* repeat in upper/lower half */
if (frame > midfra)
start= mid + 1;
else if (frame < midfra)
end= mid - 1;
}
/* print error if loop-limit exceeded */
if (loopbreaker == (maxloop-1)) {
printf("Error: binarysearch_fcm_envelopedata_index() was taking too long \n");
// include debug info
printf("\tround = %d: start = %d, end = %d, arraylen = %d \n", loopbreaker, start, end, arraylen);
}
/* not found, so return where to place it */
return start;
}
/* callback to add new envelope data point */
// TODO: should we have a separate file for things like this?
static void fmod_envelope_addpoint_cb (bContext *C, void *fcm_dv, void *dummy)
{
Scene *scene= CTX_data_scene(C);
FMod_Envelope *env= (FMod_Envelope *)fcm_dv;
FCM_EnvelopeData *fedn;
FCM_EnvelopeData fed;
/* init template data */
fed.min= -1.0f;
fed.max= 1.0f;
fed.time= (float)scene->r.cfra; // XXX make this int for ease of use?
fed.f1= fed.f2= 0;
/* check that no data exists for the current frame... */
if (env->data) {
short exists = -1;
int i= binarysearch_fcm_envelopedata_index(env->data, (float)(scene->r.cfra), env->totvert, &exists);
/* binarysearch_...() will set exists by default to 0, so if it is non-zero, that means that the point exists already */
if (exists)
return;
/* add new */
fedn= MEM_callocN((env->totvert+1)*sizeof(FCM_EnvelopeData), "FCM_EnvelopeData");
/* add the points that should occur before the point to be pasted */
if (i > 0)
memcpy(fedn, env->data, i*sizeof(FCM_EnvelopeData));
/* add point to paste at index i */
*(fedn + i)= fed;
/* add the points that occur after the point to be pasted */
if (i < env->totvert)
memcpy(fedn+i+1, env->data+i, (env->totvert-i)*sizeof(FCM_EnvelopeData));
/* replace (+ free) old with new */
MEM_freeN(env->data);
env->data= fedn;
env->totvert++;
}
else {
env->data= MEM_callocN(sizeof(FCM_EnvelopeData), "FCM_EnvelopeData");
*(env->data)= fed;
env->totvert= 1;
}
}
/* callback to remove envelope data point */
// TODO: should we have a separate file for things like this?
static void fmod_envelope_deletepoint_cb (bContext *C, void *fcm_dv, void *ind_v)
{
FMod_Envelope *env= (FMod_Envelope *)fcm_dv;
FCM_EnvelopeData *fedn;
int index= GET_INT_FROM_POINTER(ind_v);
/* check that no data exists for the current frame... */
if (env->totvert > 1) {
/* allocate a new smaller array */
fedn= MEM_callocN(sizeof(FCM_EnvelopeData)*(env->totvert-1), "FCM_EnvelopeData");
memcpy(fedn, &env->data, sizeof(FCM_EnvelopeData)*(index));
memcpy(&fedn[index], &env->data[index+1], sizeof(FCM_EnvelopeData)*(env->totvert-index-1));
/* free old array, and set the new */
MEM_freeN(env->data);
env->data= fedn;
env->totvert--;
}
else {
/* just free array, since the only vert was deleted */
if (env->data)
MEM_freeN(env->data);
env->totvert= 0;
}
}
/* draw settings for envelope modifier */
static void draw_modifier__envelope(uiLayout *layout, ID *id, FModifier *fcm, short width)
{
FMod_Envelope *env= (FMod_Envelope *)fcm->data;
FCM_EnvelopeData *fed;
uiLayout *col, *row;
uiBlock *block;
uiBut *but;
PointerRNA ptr;
int i;
/* init the RNA-pointer */
RNA_pointer_create(id, &RNA_FModifierEnvelope, fcm, &ptr);
/* general settings */
col= uiLayoutColumn(layout, 1);
uiItemL(col, "Envelope:", 0);
uiItemR(col, NULL, 0, &ptr, "reference_value", 0, 0, 0);
row= uiLayoutRow(col, 1);
uiItemR(row, "Min", 0, &ptr, "default_minimum", 0, 0, 0);
uiItemR(row, "Max", 0, &ptr, "default_maximum", 0, 0, 0);
/* control points header */
// TODO: move this control-point control stuff to using the new special widgets for lists
// the current way is far too cramped
row= uiLayoutRow(layout, 0);
block= uiLayoutGetBlock(row);
uiDefBut(block, LABEL, 1, "Control Points:", 0, 0, 150, 20, NULL, 0.0, 0.0, 0, 0, "");
but= uiDefBut(block, BUT, B_FMODIFIER_REDRAW, "Add Point", 0,0,150,19, NULL, 0, 0, 0, 0, "Adds a new control-point to the envelope on the current frame");
uiButSetFunc(but, fmod_envelope_addpoint_cb, env, NULL);
/* control points list */
for (i=0, fed=env->data; i < env->totvert; i++, fed++) {
/* get a new row to operate on */
row= uiLayoutRow(layout, 1);
block= uiLayoutGetBlock(row);
uiBlockBeginAlign(block);
but=uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Fra:", 0, 0, 90, 20, &fed->time, -UI_FLT_MAX, UI_FLT_MAX, 10, 1, "Frame that envelope point occurs");
uiButSetFunc(but, validate_fmodifier_cb, fcm, NULL);
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Min:", 0, 0, 100, 20, &fed->min, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, "Minimum bound of envelope at this point");
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Max:", 0, 0, 100, 20, &fed->max, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, "Maximum bound of envelope at this point");
but= uiDefIconBut(block, BUT, B_FMODIFIER_REDRAW, ICON_X, 0, 0, 18, 20, NULL, 0.0, 0.0, 0.0, 0.0, "Delete envelope control point");
uiButSetFunc(but, fmod_envelope_deletepoint_cb, env, SET_INT_IN_POINTER(i));
uiBlockBeginAlign(block);
}
}
/* --------------- */
/* draw settings for limits modifier */
static void draw_modifier__limits(uiLayout *layout, ID *id, FModifier *fcm, short width)
{
uiLayout *split, *col, *row;
PointerRNA ptr;
/* init the RNA-pointer */
RNA_pointer_create(id, &RNA_FModifierLimits, fcm, &ptr);
/* row 1: minimum */
{
row= uiLayoutRow(layout, 0);
/* split into 2 columns */
split= uiLayoutSplit(layout, 0.5f);
/* x-minimum */
col= uiLayoutColumn(split, 1);
uiItemR(col, NULL, 0, &ptr, "use_minimum_x", 0, 0, 0);
uiItemR(col, NULL, 0, &ptr, "minimum_x", 0, 0, 0);
/* y-minimum*/
col= uiLayoutColumn(split, 1);
uiItemR(col, NULL, 0, &ptr, "use_minimum_y", 0, 0, 0);
uiItemR(col, NULL, 0, &ptr, "minimum_y", 0, 0, 0);
}
/* row 2: minimum */
{
row= uiLayoutRow(layout, 0);
/* split into 2 columns */
split= uiLayoutSplit(layout, 0.5f);
/* x-minimum */
col= uiLayoutColumn(split, 1);
uiItemR(col, NULL, 0, &ptr, "use_maximum_x", 0, 0, 0);
uiItemR(col, NULL, 0, &ptr, "maximum_x", 0, 0, 0);
/* y-minimum*/
col= uiLayoutColumn(split, 1);
uiItemR(col, NULL, 0, &ptr, "use_maximum_y", 0, 0, 0);
uiItemR(col, NULL, 0, &ptr, "maximum_y", 0, 0, 0);
}
}
/* --------------- */
void ANIM_uiTemplate_fmodifier_draw (uiLayout *layout, ID *id, ListBase *modifiers, FModifier *fcm)
{
FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
uiLayout *box, *row, *subrow;
uiBlock *block;
uiBut *but;
short width= 314;
/* draw header */
{
/* get layout-row + UI-block for this */
box= uiLayoutBox(layout);
row= uiLayoutRow(box, 0);
block= uiLayoutGetBlock(row); // err...
uiBlockSetEmboss(block, UI_EMBOSSN);
/* left-align -------------------------------------------- */
subrow= uiLayoutRow(row, 0);
uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_LEFT);
/* expand */
uiDefIconButBitS(block, ICONTOG, FMODIFIER_FLAG_EXPANDED, B_REDR, ICON_TRIA_RIGHT, 0, -1, UI_UNIT_X, UI_UNIT_Y, &fcm->flag, 0.0, 0.0, 0, 0, "Modifier is expanded.");
/* checkbox for 'active' status (for now) */
but= uiDefIconButBitS(block, ICONTOG, FMODIFIER_FLAG_ACTIVE, B_REDR, ICON_RADIOBUT_OFF, 0, -1, UI_UNIT_X, UI_UNIT_Y, &fcm->flag, 0.0, 0.0, 0, 0, "Modifier is active one.");
uiButSetFunc(but, activate_fmodifier_cb, modifiers, fcm);
/* name */
if (fmi)
uiDefBut(block, LABEL, 1, fmi->name, 0, 0, 150, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "F-Curve Modifier Type. Click to make modifier active one.");
else
uiDefBut(block, LABEL, 1, "<Unknown Modifier>", 0, 0, 150, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "F-Curve Modifier Type. Click to make modifier active one.");
/* right-align ------------------------------------------- */
subrow= uiLayoutRow(row, 0);
uiLayoutSetAlignment(subrow, UI_LAYOUT_ALIGN_RIGHT);
/* 'mute' button */
uiDefIconButBitS(block, ICONTOG, FMODIFIER_FLAG_MUTED, B_REDR, ICON_MUTE_IPO_OFF, 0, 0, UI_UNIT_X, UI_UNIT_Y, &fcm->flag, 0.0, 0.0, 0, 0, "Modifier is temporarily muted (not evaluated).");
/* delete button */
but= uiDefIconBut(block, BUT, B_REDR, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0.0, 0.0, "Delete F-Curve Modifier.");
uiButSetFunc(but, delete_fmodifier_cb, modifiers, fcm);
uiBlockSetEmboss(block, UI_EMBOSS);
}
/* when modifier is expanded, draw settings */
if (fcm->flag & FMODIFIER_FLAG_EXPANDED) {
/* set up the flexible-box layout which acts as the backdrop for the modifier settings */
box= uiLayoutBox(layout);
/* draw settings for individual modifiers */
switch (fcm->type) {
case FMODIFIER_TYPE_GENERATOR: /* Generator */
draw_modifier__generator(box, id, fcm, width);
break;
case FMODIFIER_TYPE_FN_GENERATOR: /* Built-In Function Generator */
draw_modifier__fn_generator(box, id, fcm, width);
break;
case FMODIFIER_TYPE_CYCLES: /* Cycles */
draw_modifier__cycles(box, id, fcm, width);
break;
case FMODIFIER_TYPE_ENVELOPE: /* Envelope */
draw_modifier__envelope(box, id, fcm, width);
break;
case FMODIFIER_TYPE_LIMITS: /* Limits */
draw_modifier__limits(box, id, fcm, width);
break;
case FMODIFIER_TYPE_NOISE: /* Noise */
draw_modifier__noise(box, id, fcm, width);
break;
default: /* unknown type */
break;
}
}
}
/* ********************************************** */

@ -51,7 +51,6 @@
#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"
@ -64,6 +63,7 @@
#include "DNA_gpencil_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_world_types.h"
#include "DNA_view2d_types.h"
#include "BKE_action.h"
#include "BKE_depsgraph.h"
@ -234,45 +234,87 @@ static ActKeyColumn *cfra_find_actkeycolumn (ListBase *keys, float cframe)
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)
/* coordinates for diamond shape */
static const float _unit_diamond_shape[4][2] = {
{0.0f, 1.0f}, /* top vert */
{1.0f, 0.0f}, /* mid-right */
{0.0f, -1.0f}, /* bottom vert */
{-1.0f, 0.0f} /* mid-left */
};
/* draw a simple diamond shape with OpenGL */
void draw_keyframe_shape (float x, float y, float xscale, float hsize, short sel, short mode)
{
int xmin= x, ymin= y;
int xmax= x+w-1, ymax= y+h-1;
int xc= (xmin+xmax)/2, yc= (ymin+ymax)/2;
static GLuint displist1=0;
static GLuint displist2=0;
/* interior - hardcoded colors (for selected and unselected only) */
if (sel) glColor3ub(0xF1, 0xCA, 0x13);
else glColor3ub(0xE9, 0xE9, 0xE9);
/* initialise 2 display lists for diamond shape - one empty, one filled */
if (displist1 == 0) {
displist1= glGenLists(1);
glNewList(displist1, GL_COMPILE);
glBegin(GL_QUADS);
glVertex2i(xc, ymin);
glVertex2i(xmax, yc);
glVertex2i(xc, ymax);
glVertex2i(xmin, yc);
glEnd();
glBegin(GL_LINE_LOOP);
glVertex2fv(_unit_diamond_shape[0]);
glVertex2fv(_unit_diamond_shape[1]);
glVertex2fv(_unit_diamond_shape[2]);
glVertex2fv(_unit_diamond_shape[3]);
glEnd();
glEndList();
}
if (displist2 == 0) {
displist2= glGenLists(1);
glNewList(displist2, GL_COMPILE);
glBegin(GL_QUADS);
glVertex2fv(_unit_diamond_shape[0]);
glVertex2fv(_unit_diamond_shape[1]);
glVertex2fv(_unit_diamond_shape[2]);
glVertex2fv(_unit_diamond_shape[3]);
glEnd();
glEndList();
}
/* outline */
glColor3ub(0, 0, 0);
/* adjust view transform before starting */
glTranslatef(x, y, 0.0f);
glScalef(1.0f/xscale*hsize, hsize, 1.0f);
glBegin(GL_LINE_LOOP);
glVertex2i(xc, ymin);
glVertex2i(xmax, yc);
glVertex2i(xc, ymax);
glVertex2i(xmin, yc);
glEnd();
/* anti-aliased lines for more consistent appearance */
glEnable(GL_LINE_SMOOTH);
/* draw! */
if ELEM(mode, KEYFRAME_SHAPE_INSIDE, KEYFRAME_SHAPE_BOTH) {
/* interior - hardcoded colors (for selected and unselected only) */
if (sel) UI_ThemeColorShade(TH_STRIP_SELECT, 50);
else glColor3ub(0xE9, 0xE9, 0xE9);
glCallList(displist2);
}
if ELEM(mode, KEYFRAME_SHAPE_FRAME, KEYFRAME_SHAPE_BOTH) {
/* exterior - black frame */
glColor3ub(0, 0, 0);
glCallList(displist1);
}
glDisable(GL_LINE_SMOOTH);
/* restore view transform */
glScalef(xscale/hsize, 1.0f/hsize, 1.0);
glTranslatef(-x, -y, 0.0f);
}
#endif
static void draw_keylist(gla2DDrawInfo *di, ListBase *keys, ListBase *blocks, float ypos)
static void draw_keylist(View2D *v2d, ListBase *keys, ListBase *blocks, float ypos)
{
ActKeyColumn *ak;
ActKeyBlock *ab;
float xscale;
glEnable(GL_BLEND);
/* get View2D scaling factor */
UI_view2d_getscale(v2d, &xscale, NULL);
/* draw keyblocks */
if (blocks) {
for (ab= blocks->first; ab; ab= ab->next) {
@ -292,18 +334,13 @@ static void draw_keylist(gla2DDrawInfo *di, ListBase *keys, ListBase *blocks, fl
totCurves = (startCurves>endCurves)? endCurves: startCurves;
if (ab->totcurve >= totCurves) {
int sc_xa, sc_xb, sc_ya, sc_yb;
/* get co-ordinates of block */
gla2DDrawTranslatePt(di, ab->start, ypos, &sc_xa, &sc_ya);
gla2DDrawTranslatePt(di, ab->end, ypos, &sc_xb, &sc_yb);
/* draw block */
if (ab->sel)
UI_ThemeColor4(TH_STRIP_SELECT);
else
UI_ThemeColor4(TH_STRIP);
glRectf((float)sc_xa, (float)sc_ya-3, (float)sc_xb, (float)sc_yb+5);
glRectf(ab->start, ypos-5, ab->end, ypos+5);
}
}
}
@ -311,18 +348,28 @@ static void draw_keylist(gla2DDrawInfo *di, ListBase *keys, ListBase *blocks, fl
/* draw keys */
if (keys) {
for (ak= keys->first; ak; ak= ak->next) {
int sc_x, sc_y;
/* draw using OpenGL - uglier but faster */
// NOTE: a previous version of this didn't work nice for some intel cards
draw_keyframe_shape(ak->cfra, ypos, xscale, 5.0f, (ak->sel & SELECT), KEYFRAME_SHAPE_BOTH);
#if 0 // OLD CODE
//int sc_x, sc_y;
/* get co-ordinate to draw at */
gla2DDrawTranslatePt(di, ak->cfra, ypos, &sc_x, &sc_y);
//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)sc_y-6, ICON_SPACE2, 1.0f);
else UI_icon_draw_aspect((float)sc_x-7, (float)sc_y-6, ICON_SPACE3, 1.0f);
//if (ak->sel & SELECT) UI_icon_draw_aspect((float)sc_x-7, (float)sc_y-6, ICON_SPACE2, 1.0f);
//else UI_icon_draw_aspect((float)sc_x-7, (float)sc_y-6, ICON_SPACE3, 1.0f);
#endif // OLD CODE
#if 0 // NEW NON-WORKING CODE
/* draw icon */
// FIXME: this draws slightly wrong, as we need to apply some offset for icon, but that depends on scaling
// so for now disabled
//int icon = (ak->sel & SELECT) ? ICON_SPACE2 : ICON_SPACE3;
//UI_icon_draw_aspect(ak->cfra, ypos-6, icon, 1.0f);
#endif // NEW NON-WORKING CODE
/* 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));
}
}
@ -331,89 +378,86 @@ static void draw_keylist(gla2DDrawInfo *di, ListBase *keys, ListBase *blocks, fl
/* *************************** Channel Drawing Funcs *************************** */
void draw_scene_channel(gla2DDrawInfo *di, ActKeysInc *aki, Scene *sce, float ypos)
void draw_scene_channel(View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos)
{
ListBase keys = {0, 0};
ListBase blocks = {0, 0};
scene_to_keylist(sce, &keys, &blocks, aki);
draw_keylist(di, &keys, &blocks, ypos);
scene_to_keylist(ads, sce, &keys, &blocks);
draw_keylist(v2d, &keys, &blocks, ypos);
BLI_freelistN(&keys);
BLI_freelistN(&blocks);
}
void draw_object_channel(gla2DDrawInfo *di, ActKeysInc *aki, Object *ob, float ypos)
void draw_object_channel(View2D *v2d, bDopeSheet *ads, 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);
ob_to_keylist(ads, ob, &keys, &blocks);
draw_keylist(v2d, &keys, &blocks, ypos);
BLI_freelistN(&keys);
BLI_freelistN(&blocks);
}
void draw_fcurve_channel(gla2DDrawInfo *di, ActKeysInc *aki, FCurve *fcu, float ypos)
void draw_fcurve_channel(View2D *v2d, AnimData *adt, FCurve *fcu, float ypos)
{
ListBase keys = {0, 0};
ListBase blocks = {0, 0};
fcurve_to_keylist(fcu, &keys, &blocks, aki);
draw_keylist(di, &keys, &blocks, ypos);
fcurve_to_keylist(adt, fcu, &keys, &blocks);
draw_keylist(v2d, &keys, &blocks, ypos);
BLI_freelistN(&keys);
BLI_freelistN(&blocks);
}
void draw_agroup_channel(gla2DDrawInfo *di, ActKeysInc *aki, bActionGroup *agrp, float ypos)
void draw_agroup_channel(View2D *v2d, AnimData *adt, 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);
agroup_to_keylist(adt, agrp, &keys, &blocks);
draw_keylist(v2d, &keys, &blocks, ypos);
BLI_freelistN(&keys);
BLI_freelistN(&blocks);
}
void draw_action_channel(gla2DDrawInfo *di, ActKeysInc *aki, bAction *act, float ypos)
void draw_action_channel(View2D *v2d, AnimData *adt, 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);
action_to_keylist(adt, act, &keys, &blocks);
draw_keylist(v2d, &keys, &blocks, ypos);
BLI_freelistN(&keys);
BLI_freelistN(&blocks);
}
void draw_gpl_channel(gla2DDrawInfo *di, ActKeysInc *aki, bGPDlayer *gpl, float ypos)
void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos)
{
ListBase keys = {0, 0};
gpl_to_keylist(gpl, &keys, NULL, aki);
draw_keylist(di, &keys, NULL, ypos);
gpl_to_keylist(ads, gpl, &keys, NULL);
draw_keylist(v2d, &keys, NULL, ypos);
BLI_freelistN(&keys);
}
/* *************************** Keyframe List Conversions *************************** */
void scene_to_keylist(Scene *sce, ListBase *keys, ListBase *blocks, ActKeysInc *aki)
void scene_to_keylist(bDopeSheet *ads, Scene *sce, ListBase *keys, ListBase *blocks)
{
if (sce) {
bDopeSheet *ads= (aki)? (aki->ads) : NULL;
AnimData *adt;
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;
@ -423,7 +467,7 @@ void scene_to_keylist(Scene *sce, ListBase *keys, ListBase *blocks, ActKeysInc *
// TODO: when we adapt NLA system, this needs to be the NLA-scaled version
if (adt->action)
action_to_keylist(adt->action, keys, blocks, aki);
action_to_keylist(adt, adt->action, keys, blocks);
}
/* world animdata */
@ -432,17 +476,16 @@ void scene_to_keylist(Scene *sce, ListBase *keys, ListBase *blocks, ActKeysInc *
// TODO: when we adapt NLA system, this needs to be the NLA-scaled version
if (adt->action)
action_to_keylist(adt->action, keys, blocks, aki);
action_to_keylist(adt, adt->action, keys, blocks);
}
}
}
void ob_to_keylist(Object *ob, ListBase *keys, ListBase *blocks, ActKeysInc *aki)
void ob_to_keylist(bDopeSheet *ads, Object *ob, ListBase *keys, ListBase *blocks)
{
Key *key= ob_get_key(ob);
if (ob) {
bDopeSheet *ads= (aki)? (aki->ads) : NULL;
int filterflag;
/* get filterflag */
@ -453,79 +496,18 @@ void ob_to_keylist(Object *ob, ListBase *keys, ListBase *blocks, ActKeysInc *aki
/* Add action keyframes */
if (ob->adt && ob->adt->action)
action_nlascaled_to_keylist(ob, ob->adt->action, keys, blocks, aki);
action_to_keylist(ob->adt, ob->adt->action, keys, blocks);
/* Add shapekey keyframes (only if dopesheet allows, if it is available) */
// TODO: when we adapt NLA system, this needs to be the NLA-scaled version
if ((key && key->adt && key->adt->action) && !(filterflag & ADS_FILTER_NOSHAPEKEYS))
action_to_keylist(key->adt->action, keys, blocks, aki);
action_to_keylist(key->adt, key->adt->action, keys, blocks);
#if 0 // XXX old animation system
/* 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) && !(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) && !(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) && !(filterflag & ADS_FILTER_NOCUR))
ipo_to_keylist(cu->ipo, keys, blocks, aki);
}
break;
}
#endif // XXX old animation system
// TODO: restore materials, and object data, etc.
}
}
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 0 // XXX this was from some buggy code... do not port for now
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);
}
#endif // XXX this was from some buggy code... do not port for now
return 1;
}
void fcurve_to_keylist(FCurve *fcu, ListBase *keys, ListBase *blocks, ActKeysInc *aki)
void fcurve_to_keylist(AnimData *adt, FCurve *fcu, ListBase *keys, ListBase *blocks)
{
BezTriple *bezt;
ActKeyColumn *ak, *ak2;
@ -533,15 +515,17 @@ void fcurve_to_keylist(FCurve *fcu, ListBase *keys, ListBase *blocks, ActKeysInc
int v;
if (fcu && fcu->totvert && fcu->bezt) {
/* apply NLA-mapping (if applicable) */
if (adt)
ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 1);
/* loop through beztriples, making ActKeys and ActKeyBlocks */
bezt= fcu->bezt;
for (v=0; v < fcu->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, fcu, v);
}
add_bezt_to_keycolumnslist(keys, bezt);
if (blocks) add_bezt_to_keyblockslist(blocks, fcu, v);
}
/* update the number of curves that elements have appeared in */
@ -577,65 +561,38 @@ void fcurve_to_keylist(FCurve *fcu, ListBase *keys, ListBase *blocks, ActKeysInc
}
}
}
/* unapply NLA-mapping if applicable */
ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 1);
}
}
void agroup_to_keylist(bActionGroup *agrp, ListBase *keys, ListBase *blocks, ActKeysInc *aki)
void agroup_to_keylist(AnimData *adt, bActionGroup *agrp, ListBase *keys, ListBase *blocks)
{
FCurve *fcu;
if (agrp) {
/* loop through F-Curves */
for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcu->next) {
fcurve_to_keylist(fcu, keys, blocks, aki);
fcurve_to_keylist(adt, fcu, keys, blocks);
}
}
}
void action_to_keylist(bAction *act, ListBase *keys, ListBase *blocks, ActKeysInc *aki)
void action_to_keylist(AnimData *adt, bAction *act, ListBase *keys, ListBase *blocks)
{
FCurve *fcu;
if (act) {
/* loop through F-Curves */
for (fcu= act->curves.first; fcu; fcu= fcu->next) {
fcurve_to_keylist(fcu, keys, blocks, aki);
fcurve_to_keylist(adt, fcu, keys, blocks);
}
}
}
void action_nlascaled_to_keylist(Object *ob, bAction *act, ListBase *keys, ListBase *blocks, ActKeysInc *aki)
{
FCurve *fcu;
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 F-Curves
* - scaling correction only does times for center-points, so should be faster
*/
for (fcu= act->curves.first; fcu; fcu= fcu->next) {
ANIM_nla_mapping_apply_fcurve(ob, fcu, 0, 1);
fcurve_to_keylist(fcu, keys, blocks, aki);
ANIM_nla_mapping_apply_fcurve(ob, fcu, 1, 1);
}
/* if 'aki' is provided, restore ob */
if (aki)
aki->ob= oldob;
}
}
void gpl_to_keylist(bGPDlayer *gpl, ListBase *keys, ListBase *blocks, ActKeysInc *aki)
void gpl_to_keylist(bDopeSheet *ads, bGPDlayer *gpl, ListBase *keys, ListBase *blocks)
{
bGPDframe *gpf;
ActKeyColumn *ak;

@ -128,6 +128,10 @@ static short agrp_keys_bezier_loop(BeztEditData *bed, bActionGroup *agrp, BeztEd
{
FCurve *fcu;
/* sanity check */
if (agrp == NULL)
return 0;
/* only iterate over the F-Curves that are in this group */
for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcu->next) {
if (ANIM_fcurve_keys_bezier_loop(bed, fcu, bezt_ok, bezt_cb, fcu_cb))
@ -142,6 +146,10 @@ static short act_keys_bezier_loop(BeztEditData *bed, bAction *act, BeztEditFunc
{
FCurve *fcu;
/* sanity check */
if (act == NULL)
return 0;
/* just loop through all F-Curves */
for (fcu= act->curves.first; fcu; fcu= fcu->next) {
if (ANIM_fcurve_keys_bezier_loop(bed, fcu, bezt_ok, bezt_cb, fcu_cb))
@ -154,6 +162,10 @@ static short act_keys_bezier_loop(BeztEditData *bed, bAction *act, BeztEditFunc
/* This function is used to loop over the keyframe data of an AnimData block */
static short adt_keys_bezier_loop(BeztEditData *bed, AnimData *adt, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag)
{
/* sanity check */
if (adt == NULL)
return 0;
/* drivers or actions? */
if (filterflag & ADS_FILTER_ONLYDRIVERS) {
FCurve *fcu;
@ -178,6 +190,10 @@ static short ob_keys_bezier_loop(BeztEditData *bed, Object *ob, BeztEditFunc bez
{
Key *key= ob_get_key(ob);
/* sanity check */
if (ob == NULL)
return 0;
/* firstly, Object's own AnimData */
if (ob->adt)
adt_keys_bezier_loop(bed, ob->adt, bezt_ok, bezt_cb, fcu_cb, filterflag);
@ -194,7 +210,11 @@ static short ob_keys_bezier_loop(BeztEditData *bed, Object *ob, BeztEditFunc bez
/* This function is used to loop over the keyframe data in a Scene */
static short scene_keys_bezier_loop(BeztEditData *bed, Scene *sce, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, FcuEditFunc fcu_cb, int filterflag)
{
World *wo= sce->world;
World *wo= (sce) ? sce->world : NULL;
/* sanity check */
if (sce == NULL)
return 0;
/* Scene's own animation */
if (sce->adt)
@ -231,7 +251,7 @@ short ANIM_animchannel_keys_bezier_loop(BeztEditData *bed, bAnimListElem *ale, B
return act_keys_bezier_loop(bed, (bAction *)ale->data, bezt_ok, bezt_cb, fcu_cb);
case ALE_OB: /* object */
return ob_keys_bezier_loop(bed, (Object *)ale->data, bezt_ok, bezt_cb, fcu_cb, filterflag);
return ob_keys_bezier_loop(bed, (Object *)ale->key_data, bezt_ok, bezt_cb, fcu_cb, filterflag);
case ALE_SCE: /* scene */
return scene_keys_bezier_loop(bed, (Scene *)ale->data, bezt_ok, bezt_cb, fcu_cb, filterflag);
}

@ -52,6 +52,8 @@
#include "ED_keyframing.h"
#include "ED_keyframes_edit.h"
#include "RNA_access.h"
/* This file contains code for various keyframe-editing tools which are 'destructive'
* (i.e. they will modify the order of the keyframes, and change the size of the array).
* While some of these tools may eventually be moved out into blenkernel, for now, it is

@ -1,5 +1,30 @@
/* Testing code for 2.5 animation system
* Copyright 2009, Joshua Leung
/**
* $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) 2009 Blender Foundation, Joshua Leung
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Joshua Leung (full recode)
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <stdio.h>
@ -29,6 +54,7 @@
#include "BKE_action.h"
#include "BKE_constraint.h"
#include "BKE_fcurve.h"
#include "BKE_nla.h"
#include "BKE_global.h"
#include "BKE_utildefines.h"
#include "BKE_context.h"
@ -697,9 +723,119 @@ static float visualkey_get_value (PointerRNA *ptr, PropertyRNA *prop, int array_
/* ------------------------- Insert Key API ------------------------- */
/* Secondary Keyframing API call:
* Use this when validation of necessary animation data is not necessary, since an RNA-pointer to the necessary
* data being keyframed, and a pointer to the F-Curve to use have both been provided.
*
* The flag argument is used for special settings that alter the behaviour of
* the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
* and extra keyframe filtering.
*/
short insert_keyframe_direct (PointerRNA ptr, PropertyRNA *prop, FCurve *fcu, float cfra, short flag)
{
float curval= 0.0f;
/* no F-Curve to add keyframe to? */
if (fcu == NULL) {
printf("ERROR: no F-Curve to add keyframes to \n");
return 0;
}
/* if no property given yet, try to validate from F-Curve info */
if ((ptr.id.data == NULL) && (ptr.data==NULL)) {
printf("ERROR: no RNA-pointer available to retrieve values for keyframing from\n");
return 0;
}
if (prop == NULL) {
PointerRNA tmp_ptr;
/* try to get property we should be affecting */
if ((RNA_path_resolve(&ptr, fcu->rna_path, &tmp_ptr, &prop) == 0) || (prop == NULL)) {
/* property not found... */
char *idname= (ptr.id.data) ? ((ID *)ptr.id.data)->name : "<No ID-Pointer>";
printf("Insert Key: Could not insert keyframe, as RNA Path is invalid for the given ID (ID = %s, Path = %s)\n", idname, fcu->rna_path);
return 0;
}
else {
/* property found, so overwrite 'ptr' to make later code easier */
ptr= tmp_ptr;
}
}
/* set additional flags for the F-Curve (i.e. only integer values) */
fcu->flag &= ~(FCURVE_INT_VALUES|FCURVE_DISCRETE_VALUES);
switch (RNA_property_type(prop)) {
case PROP_FLOAT:
/* do nothing */
break;
case PROP_INT:
/* do integer (only 'whole' numbers) interpolation between all points */
fcu->flag |= FCURVE_INT_VALUES;
break;
default:
/* do 'discrete' (i.e. enum, boolean values which cannot take any intermediate
* values at all) interpolation between all points
* - however, we must also ensure that evaluated values are only integers still
*/
fcu->flag |= (FCURVE_DISCRETE_VALUES|FCURVE_INT_VALUES);
break;
}
/* obtain value to give keyframe */
if ( (flag & INSERTKEY_MATRIX) &&
(visualkey_can_use(&ptr, prop)) )
{
/* visual-keying is only available for object and pchan datablocks, as
* it works by keyframing using a value extracted from the final matrix
* instead of using the kt system to extract a value.
*/
curval= visualkey_get_value(&ptr, prop, fcu->array_index);
}
else {
/* read value from system */
curval= setting_get_rna_value(&ptr, prop, fcu->array_index);
}
/* only insert keyframes where they are needed */
if (flag & INSERTKEY_NEEDED) {
short insert_mode;
/* check whether this curve really needs a new keyframe */
insert_mode= new_key_needed(fcu, cfra, curval);
/* insert new keyframe at current frame */
if (insert_mode)
insert_vert_fcurve(fcu, cfra, curval, (flag & INSERTKEY_FAST));
/* delete keyframe immediately before/after newly added */
switch (insert_mode) {
case KEYNEEDED_DELPREV:
delete_fcurve_key(fcu, fcu->totvert-2, 1);
break;
case KEYNEEDED_DELNEXT:
delete_fcurve_key(fcu, 1, 1);
break;
}
/* only return success if keyframe added */
if (insert_mode)
return 1;
}
else {
/* just insert keyframe */
insert_vert_fcurve(fcu, cfra, curval, (flag & INSERTKEY_FAST));
/* return success */
return 1;
}
/* failed */
return 0;
}
/* Main Keyframing API call:
* Use this when validation of necessary animation data isn't necessary as it
* already exists. It will insert a keyframe using the current value being keyframed.
* Use this when validation of necessary animation data is necessary, since it may not exist yet.
*
* The flag argument is used for special settings that alter the behaviour of
* the keyframe insertion. These include the 'visual' keyframing modes, quick refresh,
@ -719,102 +855,31 @@ short insert_keyframe (ID *id, bAction *act, const char group[], const char rna_
}
/* get F-Curve - if no action is provided, keyframe to the default one attached to this ID-block */
if (act == NULL)
if (act == NULL) {
AnimData *adt= BKE_animdata_from_id(id);
/* get action to add F-Curve+keyframe to */
act= verify_adt_action(id, 1);
/* apply NLA-mapping to frame to use (if applicable) */
cfra= BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
}
fcu= verify_fcurve(act, group, rna_path, array_index, 1);
/* only continue if we have an F-Curve to add keyframe to */
if (fcu) {
float curval= 0.0f;
/* apply special time tweaking */
// XXX check on this stuff...
if (GS(id->name) == ID_OB) {
//Object *ob= (Object *)id;
/* set additional flags for the F-Curve (i.e. only integer values) */
fcu->flag &= ~(FCURVE_INT_VALUES|FCURVE_DISCRETE_VALUES);
switch (RNA_property_type(prop)) {
case PROP_FLOAT:
/* do nothing */
break;
case PROP_INT:
/* do integer (only 'whole' numbers) interpolation between all points */
fcu->flag |= FCURVE_INT_VALUES;
break;
default:
/* do 'discrete' (i.e. enum, boolean values which cannot take any intermediate
* values at all) interpolation between all points
* - however, we must also ensure that evaluated values are only integers still
*/
fcu->flag |= (FCURVE_DISCRETE_VALUES|FCURVE_INT_VALUES);
break;
}
/* apply special time tweaking */
// XXX check on this stuff...
if (GS(id->name) == ID_OB) {
//Object *ob= (Object *)id;
/* apply NLA-scaling (if applicable) */
//cfra= get_action_frame(ob, cfra);
/* ancient time-offset cruft */
//if ( (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)) ) {
// /* actually frametofloat calc again! */
// cfra-= give_timeoffset(ob)*scene->r.framelen;
//}
}
/* obtain value to give keyframe */
if ( (flag & INSERTKEY_MATRIX) &&
(visualkey_can_use(&ptr, prop)) )
{
/* visual-keying is only available for object and pchan datablocks, as
* it works by keyframing using a value extracted from the final matrix
* instead of using the kt system to extract a value.
*/
curval= visualkey_get_value(&ptr, prop, array_index);
}
else {
/* read value from system */
curval= setting_get_rna_value(&ptr, prop, array_index);
}
/* only insert keyframes where they are needed */
if (flag & INSERTKEY_NEEDED) {
short insert_mode;
/* check whether this curve really needs a new keyframe */
insert_mode= new_key_needed(fcu, cfra, curval);
/* insert new keyframe at current frame */
if (insert_mode)
insert_vert_fcurve(fcu, cfra, curval, (flag & INSERTKEY_FAST));
/* delete keyframe immediately before/after newly added */
switch (insert_mode) {
case KEYNEEDED_DELPREV:
delete_fcurve_key(fcu, fcu->totvert-2, 1);
break;
case KEYNEEDED_DELNEXT:
delete_fcurve_key(fcu, 1, 1);
break;
}
/* only return success if keyframe added */
if (insert_mode)
return 1;
}
else {
/* just insert keyframe */
insert_vert_fcurve(fcu, cfra, curval, (flag & INSERTKEY_FAST));
/* return success */
return 1;
}
/* ancient time-offset cruft */
//if ( (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)) ) {
// /* actually frametofloat calc again! */
// cfra-= give_timeoffset(ob)*scene->r.framelen;
//}
}
/* no F-Curve to add keyframes to */
printf("ERROR: no F-Curve to add keyframes to \n");
/* return failure */
return 0;
/* insert keyframe */
return insert_keyframe_direct(ptr, prop, fcu, cfra, flag);
}
/* ************************************************** */
@ -839,6 +904,9 @@ short delete_keyframe (ID *id, bAction *act, const char group[], const char rna_
/* if no action is provided, use the default one attached to this ID-block */
AnimData *adt= BKE_animdata_from_id(id);
act= adt->action;
/* apply NLA-mapping to frame to use (if applicable) */
cfra= BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
}
/* we don't check the validity of the path here yet, but it should be ok... */
fcu= verify_fcurve(act, group, rna_path, array_index, 0);
@ -852,9 +920,6 @@ short delete_keyframe (ID *id, bAction *act, const char group[], const char rna_
if (GS(id->name) == ID_OB) {
//Object *ob= (Object *)id;
/* apply NLA-scaling (if applicable) */
// cfra= get_action_frame(ob, cfra);
/* ancient time-offset cruft */
//if ( (ob->ipoflag & OB_OFFS_OB) && (give_timeoffset(ob)) ) {
// /* actually frametofloat calc again! */
@ -1241,6 +1306,13 @@ static int insert_key_button_exec (bContext *C, wmOperator *op)
MEM_freeN(path);
}
else if (ptr.type == &RNA_NlaStrip) {
/* handle special vars for NLA-strips */
NlaStrip *strip= (NlaStrip *)ptr.data;
FCurve *fcu= list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), 0);
success+= insert_keyframe_direct(ptr, prop, fcu, cfra, 0);
}
else {
if (G.f & G_DEBUG)
printf("Button Insert-Key: no path to property \n");
@ -1358,6 +1430,31 @@ void ANIM_OT_delete_keyframe_button (wmOperatorType *ot)
/* --------------- API/Per-Datablock Handling ------------------- */
/* Checks if some F-Curve has a keyframe for a given frame */
short fcurve_frame_has_keyframe (FCurve *fcu, float frame, short filter)
{
/* quick sanity check */
if (fcu == NULL)
return 0;
/* we either include all regardless of muting, or only non-muted */
if ((filter & ANIMFILTER_KEYS_MUTED) || (fcu->flag & FCURVE_MUTED)==0) {
short replace = -1;
int i = binarysearch_bezt_index(fcu->bezt, frame, fcu->totvert, &replace);
/* binarysearch_bezt_index will set replace to be 0 or 1
* - obviously, 1 represents a match
*/
if (replace) {
/* sanity check: 'i' may in rare cases exceed arraylen */
if ((i >= 0) && (i < fcu->totvert))
return 1;
}
}
return 0;
}
/* Checks whether an Action has a keyframe for a given frame
* Since we're only concerned whether a keyframe exists, we can simply loop until a match is found...
*/
@ -1379,20 +1476,8 @@ short action_frame_has_keyframe (bAction *act, float frame, short filter)
for (fcu= act->curves.first; fcu; fcu= fcu->next) {
/* only check if there are keyframes (currently only of type BezTriple) */
if (fcu->bezt && fcu->totvert) {
/* we either include all regardless of muting, or only non-muted */
if ((filter & ANIMFILTER_KEYS_MUTED) || (fcu->flag & FCURVE_MUTED)==0) {
short replace = -1;
int i = binarysearch_bezt_index(fcu->bezt, frame, fcu->totvert, &replace);
/* binarysearch_bezt_index will set replace to be 0 or 1
* - obviously, 1 represents a match
*/
if (replace) {
/* sanity check: 'i' may in rare cases exceed arraylen */
if ((i >= 0) && (i < fcu->totvert))
return 1;
}
}
if (fcurve_frame_has_keyframe(fcu, frame, filter))
return 1;
}
}

@ -1,5 +1,30 @@
/* Testing code for 2.5 animation system
* Copyright 2009, Joshua Leung
/**
* $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) 2009 Blender Foundation, Joshua Leung
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Joshua Leung (full recode)
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <stdio.h>
@ -1060,6 +1085,9 @@ int modify_keyframes (bContext *C, ListBase *dsources, bAction *act, KeyingSet *
case ID_MA: /* Material Keyframes */
WM_event_add_notifier(C, NC_MATERIAL|ND_KEYS, ksp->id);
break;
default: /* Any keyframes */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
break;
}
}
}
@ -1166,6 +1194,9 @@ int modify_keyframes (bContext *C, ListBase *dsources, bAction *act, KeyingSet *
case ID_MA: /* Material Keyframes */
WM_event_add_notifier(C, NC_MATERIAL|ND_KEYS, cks->id);
break;
default: /* Any keyframes */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
break;
}
}
}

@ -227,7 +227,7 @@ void poselib_validate_act (bAction *act)
}
/* determine which frames have keys */
action_to_keylist(act, &keys, NULL, NULL);
action_to_keylist(NULL, act, &keys, NULL);
/* for each key, make sure there is a correspnding pose */
for (ak= keys.first; ak; ak= ak->next) {

@ -41,7 +41,7 @@ struct gla2DDrawInfo;
struct Object;
struct bActionGroup;
struct FCurve;
struct IpoCurve; // xxx
struct FModifier;
/* ************************************************ */
/* ANIMATION CHANNEL FILTERING */
@ -75,8 +75,9 @@ typedef enum eAnimCont_Types {
ANIMCONT_SHAPEKEY, /* shapekey (Key) */
ANIMCONT_GPENCIL, /* grease pencil (screen) */
ANIMCONT_DOPESHEET, /* dopesheet (bDopesheet) */
ANIMCONT_FCURVES, /* animation F-Curves (bDopesheet) */ // XXX
ANIMCONT_FCURVES, /* animation F-Curves (bDopesheet) */
ANIMCONT_DRIVERS, /* drivers (bDopesheet) */
ANIMCONT_NLA, /* nla (bDopesheet) */
} eAnimCont_Types;
/* --------------- Channels -------------------- */
@ -92,10 +93,10 @@ typedef struct bAnimListElem {
int flag; /* copy of elem's flags for quick access */
int index; /* copy of adrcode where applicable */
void *key_data; /* motion data - ipo or ipo-curve */
void *key_data; /* motion data - mostly F-Curves, but can be other types too */
short datatype; /* type of motion data to expect */
struct ID *id; /* ID block that channel is attached to (may be used */
struct ID *id; /* ID block that channel is attached to (may be used */
void *owner; /* group or channel which acts as this channel's owner */
short ownertype; /* type of owner */
@ -106,6 +107,7 @@ typedef struct bAnimListElem {
// XXX was ACTTYPE_*
typedef enum eAnim_ChannelType {
ANIMTYPE_NONE= 0,
ANIMTYPE_ANIMDATA,
ANIMTYPE_SPECIALDATA,
ANIMTYPE_SCENE,
@ -128,6 +130,9 @@ typedef enum eAnim_ChannelType {
ANIMTYPE_GPDATABLOCK,
ANIMTYPE_GPLAYER,
ANIMTYPE_NLATRACK,
ANIMTYPE_NLAACTION,
} eAnim_ChannelType;
/* types of keyframe data in bAnimListElem */
@ -135,8 +140,8 @@ typedef enum eAnim_KeyType {
ALE_NONE = 0, /* no keyframe data */
ALE_FCURVE, /* F-Curve */
ALE_GPFRAME, /* Grease Pencil Frames */
ALE_NLASTRIP, /* NLA Strips */
// XXX the following are for summaries... should these be kept?
ALE_SCE, /* Scene summary */
ALE_OB, /* Object summary */
ALE_ACT, /* Action summary */
@ -156,7 +161,9 @@ typedef enum eAnimFilter_Flags {
ANIMFILTER_CHANNELS = (1<<5), /* make list for interface drawing */
ANIMFILTER_ACTGROUPED = (1<<6), /* belongs to the active actiongroup */
ANIMFILTER_CURVEVISIBLE = (1<<7), /* F-Curve is visible for editing/viewing in Graph Editor */
ANIMFILTER_ACTIVE = (1<<8), /* channel should be 'active' */ // FIXME: this is only relevant for F-Curves for now
ANIMFILTER_ACTIVE = (1<<8), /* channel should be 'active' */
ANIMFILTER_ANIMDATA = (1<<9), /* only return the underlying AnimData blocks (not the tracks, etc.) data comes from */
ANIMFILTER_NLATRACKS = (1<<10), /* only include NLA-tracks */
} eAnimFilter_Flags;
@ -202,6 +209,10 @@ 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))
/* NLA only */
#define SEL_NLT(nlt) (nlt->flag & NLATRACK_SELECTED)
#define EDITABLE_NLT(nlt) ((nlt->flag & NLATRACK_PROTECTED)==0)
/* -------------- Channel Defines -------------- */
/* channel heights */
@ -217,6 +228,22 @@ typedef enum eAnimFilter_Flags {
/* channel toggle-buttons */
#define ACHANNEL_BUTTON_WIDTH 16
/* -------------- NLA Channel Defines -------------- */
/* NLA channel heights */
#define NLACHANNEL_FIRST -16
#define NLACHANNEL_HEIGHT 24
#define NLACHANNEL_HEIGHT_HALF 12
#define NLACHANNEL_SKIP 2
#define NLACHANNEL_STEP (NLACHANNEL_HEIGHT + NLACHANNEL_SKIP)
/* channel widths */
#define NLACHANNEL_NAMEWIDTH 200
/* channel toggle-buttons */
#define NLACHANNEL_BUTTON_WIDTH 16
/* ---------------- API -------------------- */
/* Obtain list of filtered Animation channels to operate on.
@ -245,7 +272,7 @@ short ANIM_animdata_context_getdata(bAnimContext *ac);
void ANIM_deselect_anim_channels(void *data, short datatype, short test, short sel);
/* Set the 'active' channel of type channel_type, in the given action */
void ANIM_set_active_channel(void *data, short datatype, int filter, void *channel_data, short channel_type);
void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int filter, void *channel_data, short channel_type);
/* --------------- Settings and/or Defines -------------- */
@ -282,6 +309,14 @@ void ANIM_draw_cfra(const struct bContext *C, struct View2D *v2d, short flag);
/* main call to draw preview range curtains */
void ANIM_draw_previewrange(const struct bContext *C, struct View2D *v2d);
/* ************************************************* */
/* F-MODIFIER TOOLS */
struct uiLayout;
/* draw a given F-Modifier for some layout/UI-Block */
void ANIM_uiTemplate_fmodifier_draw(struct uiLayout *layout, struct ID *id, ListBase *modifiers, struct FModifier *fcm);
/* ************************************************* */
/* ASSORTED TOOLS */
@ -299,19 +334,44 @@ void ipo_rainbow(int cur, int tot, float *out);
/* ------------- NLA-Mapping ----------------------- */
/* anim_draw.c */
/* Obtain the Object providing NLA-scaling for the given channel if applicable */
struct Object *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale);
/* Obtain the AnimData block providing NLA-scaling for the given channel if applicable */
struct AnimData *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);
/* Set/clear temporary mapping of coordinates from 'local-action' time to 'global-nla-mapped' time */
void ANIM_nla_mapping_draw(struct gla2DDrawInfo *di, struct AnimData *adt, short restore);
/* Apply/Unapply NLA mapping to all keyframes in the nominated IPO block */
void ANIM_nla_mapping_apply_fcurve(struct Object *ob, struct FCurve *fcu, short restore, short only_keys);
/* Apply/Unapply NLA mapping to all keyframes in the nominated F-Curve */
void ANIM_nla_mapping_apply_fcurve(struct AnimData *adt, struct FCurve *fcu, short restore, short only_keys);
/* ------------- xxx macros ----------------------- */
/* ------------- Utility macros ----------------------- */
/* checks if the given BezTriple is selected */
#define BEZSELECTED(bezt) ((bezt->f2 & SELECT) || (bezt->f1 & SELECT) || (bezt->f3 & SELECT))
/* set/clear/toggle macro
* - channel - channel with a 'flag' member that we're setting
* - smode - 0=clear, 1=set, 2=toggle
* - sflag - bitflag to set
*/
#define ACHANNEL_SET_FLAG(channel, smode, sflag) \
{ \
if (smode == ACHANNEL_SETFLAG_TOGGLE) (channel)->flag ^= (sflag); \
else if (smode == ACHANNEL_SETFLAG_ADD) (channel)->flag |= (sflag); \
else (channel)->flag &= ~(sflag); \
}
/* set/clear/toggle macro, where the flag is negative
* - channel - channel with a 'flag' member that we're setting
* - smode - 0=clear, 1=set, 2=toggle
* - sflag - bitflag to set
*/
#define ACHANNEL_SET_FLAG_NEG(channel, smode, sflag) \
{ \
if (smode == ACHANNEL_SETFLAG_TOGGLE) (channel)->flag ^= (sflag); \
else if (smode == ACHANNEL_SETFLAG_ADD) (channel)->flag &= ~(sflag); \
else (channel)->flag |= (sflag); \
}
/* --------- anim_deps.c, animation updates -------- */
@ -324,18 +384,6 @@ void ED_anim_object_flush_update(const struct bContext *C, struct Object *ob);
void ANIM_action_to_pose_sync(struct Object *ob);
void ANIM_pose_to_action_sync(struct Object *ob, struct ScrArea *sa);
/* what types of animation data was changed (for sending notifiers from animation tools) */
enum {
ANIM_CHANGED_BOTH= 0,
ANIM_CHANGED_KEYFRAMES_VALUES,
ANIM_CHANGED_KEYFRAMES_SELECT,
ANIM_CHANGED_CHANNELS
} eAnimData_Changed;
/* Send notifiers on behalf of animation editing tools, based on various context info */
void ANIM_animdata_send_notifiers(struct bContext *C, bAnimContext *ac, short data_changed);
/* ************************************************* */
/* OPERATORS */

@ -30,15 +30,17 @@
#ifndef ED_KEYFRAMES_DRAW_H
#define ED_KEYFRAMES_DRAW_H
struct AnimData;
struct BezTriple;
struct FCurve;
struct gla2DDrawInfo;
struct bDopeSheet;
struct bAction;
struct bActionGroup;
struct Object;
struct ListBase;
struct bGPDlayer;
struct Scene;
struct View2D;
/* ****************************** Base Structs ****************************** */
@ -66,33 +68,38 @@ typedef struct ActKeyBlock {
} 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) */
/* *********************** Keyframe Drawing ****************************** */
float start, end; /* frames (global-time) to only consider keys between */ // XXX not used anymore!
} ActKeysInc;
/* options for keyframe shape drawing */
typedef enum eKeyframeShapeDrawOpts {
/* only the border */
KEYFRAME_SHAPE_FRAME = 0,
/* only the inside filling */
KEYFRAME_SHAPE_INSIDE,
/* the whole thing */
KEYFRAME_SHAPE_BOTH
} eKeyframeShapeDrawOpts;
/* draw simple diamond-shape keyframe (with OpenGL) */
void draw_keyframe_shape (float x, float y, float xscale, float hsize, short sel, short mode);
/* ******************************* Methods ****************************** */
/* Channel Drawing */
void draw_fcurve_channel(struct gla2DDrawInfo *di, ActKeysInc *aki, struct FCurve *fcu, 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_scene_channel(struct gla2DDrawInfo *di, ActKeysInc *aki, struct Scene *sce, float ypos);
void draw_gpl_channel(struct gla2DDrawInfo *di, ActKeysInc *aki, struct bGPDlayer *gpl, float ypos);
void draw_fcurve_channel(struct View2D *v2d, struct AnimData *adt, struct FCurve *fcu, float ypos);
void draw_agroup_channel(struct View2D *v2d, struct AnimData *adt, struct bActionGroup *agrp, float ypos);
void draw_action_channel(struct View2D *v2d, struct AnimData *adt, struct bAction *act, float ypos);
void draw_object_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Object *ob, float ypos);
void draw_scene_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Scene *sce, float ypos);
void draw_gpl_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPDlayer *gpl, float ypos);
/* Keydata Generation */
void fcurve_to_keylist(struct FCurve *fcu, 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 scene_to_keylist(struct Scene *sce, ListBase *keys, ListBase *blocks, ActKeysInc *aki);
void gpl_to_keylist(struct bGPDlayer *gpl, ListBase *keys, ListBase *blocks, ActKeysInc *aki);
void fcurve_to_keylist(struct AnimData *adt, struct FCurve *fcu, ListBase *keys, ListBase *blocks);
void agroup_to_keylist(struct AnimData *adt, struct bActionGroup *agrp, ListBase *keys, ListBase *blocks);
void action_to_keylist(struct AnimData *adt, struct bAction *act, ListBase *keys, ListBase *blocks);
void ob_to_keylist(struct bDopeSheet *ads, struct Object *ob, ListBase *keys, ListBase *blocks);
void scene_to_keylist(struct bDopeSheet *ads, struct Scene *sce, ListBase *keys, ListBase *blocks);
void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, ListBase *keys, ListBase *blocks);
#endif /* ED_KEYFRAMES_DRAW_H */

@ -43,6 +43,9 @@ struct bConstraint;
struct bContext;
struct wmOperatorType;
struct PointerRNA;
struct PropertyRNA;
/* ************ Keyframing Management **************** */
/* Get (or add relevant data to be able to do so) the Active Action for the given
@ -69,6 +72,16 @@ int insert_bezt_fcurve(struct FCurve *fcu, struct BezTriple *bezt);
*/
void insert_vert_fcurve(struct FCurve *fcu, float x, float y, short flag);
/* -------- */
/* Secondary Keyframing API calls:
* Use this to insert a keyframe using the current value being keyframed, in the
* nominated F-Curve (no creation of animation data performed). Returns success.
*/
short insert_keyframe_direct(struct PointerRNA ptr, struct PropertyRNA *prop, struct FCurve *fcu, float cfra, short flag);
/* -------- */
/* Main Keyframing API calls:
@ -186,6 +199,11 @@ void ANIM_OT_remove_driver_button(struct wmOperatorType *ot);
/* ************ Keyframe Checking ******************** */
/* Lesser Keyframe Checking API call:
* - Used for the buttons to check for keyframes...
*/
short fcurve_frame_has_keyframe(struct FCurve *fcu, float frame, short filter);
/* Main Keyframe Checking API call:
* Checks whether a keyframe exists for the given ID-block one the given frame.
* - It is recommended to call this method over the other keyframe-checkers directly,

@ -118,6 +118,7 @@ int ED_operator_node_active(struct bContext *C);
int ED_operator_ipo_active(struct bContext *C);
int ED_operator_sequencer_active(struct bContext *C);
int ED_operator_image_active(struct bContext *C);
int ED_operator_nla_active(struct bContext *C);
int ED_operator_logic_active(struct bContext *C);
int ED_operator_object_active(struct bContext *C);

@ -33,6 +33,7 @@
typedef struct ScreenAnimData {
ARegion *ar; /* do not read from this, only for comparing if region exists */
int redraws;
int reverse;
} ScreenAnimData;

@ -1,5 +1,5 @@
/**
* $Id$
* $Id: ED_transform.h 21450 2009-07-09 02:45:48Z theeth $
*
* ***** BEGIN GPL LICENSE BLOCK *****
*

@ -52,6 +52,8 @@ enum {
V2D_COMMONVIEW_STANDARD,
/* listview (i.e. Outliner) */
V2D_COMMONVIEW_LIST,
/* stackview (this is basically a list where new items are added at the top) */
V2D_COMMONVIEW_STACK,
/* headers (this is basically the same as listview, but no y-panning) */
V2D_COMMONVIEW_HEADER,
/* ui region containing panels */

@ -18,6 +18,8 @@
#include "RNA_access.h"
#include "RNA_types.h"
#include "ED_keyframing.h"
#include "UI_interface.h"
#include "WM_api.h"
@ -29,7 +31,10 @@ void ui_but_anim_flag(uiBut *but, float cfra)
{
but->flag &= ~(UI_BUT_ANIMATED|UI_BUT_ANIMATED_KEY|UI_BUT_DRIVEN);
if(but->rnaprop && but->rnapoin.id.data) {
/* there must be some RNA-pointer + property combo for this button */
if (but->rnaprop && but->rnapoin.id.data &&
RNA_property_animateable(&but->rnapoin, but->rnaprop))
{
AnimData *adt= BKE_animdata_from_id(but->rnapoin.id.data);
FCurve *fcu;
char *path;
@ -47,7 +52,7 @@ void ui_but_anim_flag(uiBut *but, float cfra)
if (fcu) {
but->flag |= UI_BUT_ANIMATED;
if (on_keyframe_fcurve(fcu, cfra))
if (fcurve_frame_has_keyframe(fcu, cfra, 0))
but->flag |= UI_BUT_ANIMATED_KEY;
}
}
@ -111,7 +116,6 @@ void ui_but_anim_remove_driver(bContext *C)
WM_operator_name_call(C, "ANIM_OT_remove_driver_button", WM_OP_INVOKE_DEFAULT, NULL);
}
// TODO: refine the logic for adding/removing drivers...
void ui_but_anim_menu(bContext *C, uiBut *but)
{
uiPopupMenu *pup;

@ -506,6 +506,9 @@ void ui_theme_init_userdef(void)
SETCOL(btheme->tact.strip, 12, 10, 10, 128);
SETCOL(btheme->tact.strip_select, 255, 140, 0, 255);
/* space nla */
btheme->tnla= btheme->tact;
/* space file */
/* to have something initialized */
btheme->tfile= btheme->tv3d;
@ -522,20 +525,6 @@ void ui_theme_init_userdef(void)
SETCOL(btheme->tfile.scene, 250, 250, 250, 255);
/* space nla */
btheme->tnla= btheme->tv3d;
SETCOL(btheme->tnla.back, 116, 116, 116, 255);
SETCOL(btheme->tnla.text, 0, 0, 0, 255);
SETCOL(btheme->tnla.text_hi, 255, 255, 255, 255);
SETCOL(btheme->tnla.grid, 94, 94, 94, 255);
SETCOL(btheme->tnla.shade1, 172, 172, 172, 255); // sliders
SETCOL(btheme->tnla.shade2, 84, 44, 31, 100); // bar
SETCOL(btheme->tnla.hilite, 17, 27, 60, 100); // bar
SETCOL(btheme->tnla.strip_select, 0xff, 0xff, 0xaa, 255);
SETCOL(btheme->tnla.strip, 0xe4, 0x9c, 0xc6, 255);
/* space seq */
btheme->tseq= btheme->tv3d;
SETCOL(btheme->tseq.back, 116, 116, 116, 255);
@ -1086,19 +1075,6 @@ void init_userdef_do_versions(void)
SETCOL(btheme->ttime.cframe, 0x60, 0xc0, 0x40, 255);
}
}
if ((G.main->versionfile < 245) || (G.main->versionfile == 245 && G.main->subversionfile < 11)) {
bTheme *btheme;
for (btheme= U.themes.first; btheme; btheme= btheme->next) {
/* these should all use the same color */
SETCOL(btheme->tv3d.cframe, 0x60, 0xc0, 0x40, 255);
SETCOL(btheme->tipo.cframe, 0x60, 0xc0, 0x40, 255);
SETCOL(btheme->tact.cframe, 0x60, 0xc0, 0x40, 255);
SETCOL(btheme->tnla.cframe, 0x60, 0xc0, 0x40, 255);
SETCOL(btheme->tseq.cframe, 0x60, 0xc0, 0x40, 255);
SETCOL(btheme->tsnd.cframe, 0x60, 0xc0, 0x40, 255);
SETCOL(btheme->ttime.cframe, 0x60, 0xc0, 0x40, 255);
}
}
if ((G.main->versionfile < 245) || (G.main->versionfile == 245 && G.main->subversionfile < 13)) {
bTheme *btheme;
for (btheme= U.themes.first; btheme; btheme= btheme->next) {
@ -1221,6 +1197,13 @@ void init_userdef_do_versions(void)
/* Graph Editor - Group Channel color */
SETCOL(btheme->tipo.group, 79, 101, 73, 255);
SETCOL(btheme->tipo.group_active, 135, 177, 125, 255);
/* Nla Editor - (Object) Channel color */
SETCOL(btheme->tnla.ds_channel, 82, 96, 110, 255);
SETCOL(btheme->tnla.ds_subchannel, 124, 137, 150, 255);
/* NLA Editor - New Strip colors */
SETCOL(btheme->tnla.strip, 12, 10, 10, 128);
SETCOL(btheme->tnla.strip_select, 255, 140, 0, 255);
}
/* adjust grease-pencil distances */

@ -209,6 +209,23 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
}
break;
/* 'stack view' - practically the same as list/channel view, except is located in the pos y half instead.
* zoom, aspect ratio, and alignment restrictions are set here */
case V2D_COMMONVIEW_STACK:
{
/* zoom + aspect ratio are locked */
v2d->keepzoom = (V2D_LOCKZOOM_X|V2D_LOCKZOOM_Y|V2D_KEEPZOOM|V2D_KEEPASPECT);
v2d->minzoom= v2d->maxzoom= 1.0f;
/* tot rect has strictly regulated placement, and must only occur in +/+ quadrant */
v2d->align = (V2D_ALIGN_NO_NEG_X|V2D_ALIGN_NO_NEG_Y);
v2d->keeptot = V2D_KEEPTOT_STRICT;
tot_changed= 1;
/* scroller settings are currently not set here... that is left for regions... */
}
break;
/* 'header' regions - zoom, aspect ratio, alignment, and panning restrictions are set here */
case V2D_COMMONVIEW_HEADER:
{
@ -256,6 +273,9 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy)
v2d->cur.ymax= 0.0f;
v2d->cur.ymin= -winy*style->panelzoom;
v2d->cur.ymax= 0.0f;
v2d->cur.ymin= -winy*style->panelzoom;
}
break;

@ -1460,7 +1460,9 @@ void ED_screen_full_prevspace(bContext *C)
ed_screen_fullarea(C, sa);
}
/* redraws: uses defines from stime->redraws */
/* redraws: uses defines from stime->redraws
* enable: 1 - forward on, -1 - backwards on, 0 - off
*/
void ED_screen_animation_timer(bContext *C, int redraws, int enable)
{
bScreen *screen= CTX_wm_screen(C);
@ -1477,6 +1479,7 @@ void ED_screen_animation_timer(bContext *C, int redraws, int enable)
screen->animtimer= WM_event_add_window_timer(win, TIMER0, (1.0/FPS));
sad->ar= CTX_wm_region(C);
sad->redraws= redraws;
sad->reverse= (enable < 0);
screen->animtimer->customdata= sad;
}

@ -166,6 +166,7 @@ int ED_operator_node_active(bContext *C)
return 0;
}
// XXX rename
int ED_operator_ipo_active(bContext *C)
{
return ed_spacetype_test(C, SPACE_IPO);
@ -181,6 +182,11 @@ int ED_operator_image_active(bContext *C)
return ed_spacetype_test(C, SPACE_IMAGE);
}
int ED_operator_nla_active(bContext *C)
{
return ed_spacetype_test(C, SPACE_NLA);
}
int ED_operator_logic_active(bContext *C)
{
return ed_spacetype_test(C, SPACE_LOGIC);
@ -2070,19 +2076,40 @@ static int screen_animation_step(bContext *C, wmOperator *op, wmEvent *event)
if(scene->audio.flag & AUDIO_SYNC) {
int step = floor(wt->duration * FPS);
scene->r.cfra += step;
if (sad->reverse) // XXX does this option work with audio?
scene->r.cfra -= step;
else
scene->r.cfra += step;
wt->duration -= ((float)step)/FPS;
}
else
scene->r.cfra++;
else {
if (sad->reverse)
scene->r.cfra--;
else
scene->r.cfra++;
}
if (scene->r.psfra) {
if(scene->r.cfra > scene->r.pefra)
scene->r.cfra= scene->r.psfra;
if (sad->reverse) {
/* jump back to end */
if (scene->r.psfra) {
if(scene->r.cfra < scene->r.psfra)
scene->r.cfra= scene->r.pefra;
}
else {
if(scene->r.cfra < scene->r.sfra)
scene->r.cfra= scene->r.efra;
}
}
else {
if(scene->r.cfra > scene->r.efra)
scene->r.cfra= scene->r.sfra;
/* jump back to start */
if (scene->r.psfra) {
if(scene->r.cfra > scene->r.pefra)
scene->r.cfra= scene->r.psfra;
}
else {
if(scene->r.cfra > scene->r.efra)
scene->r.cfra= scene->r.sfra;
}
}
/* since we follow drawflags, we can't send notifier but tag regions ourselves */
@ -2130,8 +2157,9 @@ static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
ED_screen_animation_timer(C, 0, 0);
}
else {
/* todo: RNA properties to define play types */
ED_screen_animation_timer(C, TIME_REGION|TIME_ALL_3D_WIN, 1);
int mode= (RNA_boolean_get(op->ptr, "reverse")) ? -1 : 1;
ED_screen_animation_timer(C, TIME_REGION|TIME_ALL_3D_WIN, mode);
if(screen->animtimer) {
wmTimer *wt= screen->animtimer;
@ -2155,7 +2183,7 @@ void SCREEN_OT_animation_play(wmOperatorType *ot)
ot->poll= ED_operator_screenactive;
RNA_def_boolean(ot->srna, "reverse", 0, "Play in Reverse", "Animation is played backwards");
}
/* ************** border select operator (template) ***************************** */

@ -422,6 +422,8 @@ void draw_channel_names(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
*/
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;
@ -645,6 +647,11 @@ void draw_channel_names(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
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
@ -955,27 +962,8 @@ void draw_channel_names(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
/* ************************************************************************* */
/* Keyframes */
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;
}
/* 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)
@ -985,13 +973,11 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
int filter;
View2D *v2d= &ar->v2d;
Object *nob= NULL;
gla2DDrawInfo *di;
rcti scr_rct;
bDopeSheet *ads= &saction->ads;
AnimData *adt= NULL;
int act_start, act_end, dummy;
float act_start, act_end, y;
int height, items;
float y, sta, end;
char col1[3], col2[3];
char col1a[3], col2a[3];
@ -1001,6 +987,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
/* get theme colors */
UI_GetThemeColor3ubv(TH_BACK, col2);
UI_GetThemeColor3ubv(TH_HILITE, col1);
UI_GetThemeColor3ubv(TH_GROUP, col2a);
UI_GetThemeColor3ubv(TH_GROUP_ACTIVE, col1a);
@ -1008,26 +995,14 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
UI_GetThemeColor3ubv(TH_DOPESHEET_CHANNELSUBOB, col2b);
/* 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);
adt= ANIM_nla_mapping_get(ac, NULL);
/* 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);
// TODO: this has not had scaling applied
calc_action_range(ac->data, &act_start, &act_end, 0);
}
/* build list of channels to draw */
@ -1058,7 +1033,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
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;
int sel=0;
/* determine if any need to draw channel */
if (ale->datatype != ALE_NONE) {
@ -1097,8 +1072,6 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
}
if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET)) {
gla2DDrawTranslatePt(di, v2d->cur.xmin, y, &frame1_x, &channel_y);
switch (ale->type) {
case ANIMTYPE_SCENE:
case ANIMTYPE_OBJECT:
@ -1134,36 +1107,32 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
}
/* 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);
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((float)act_start, (float)channel_y-ACHANNEL_HEIGHT_HALF, (float)act_end, (float)channel_y+ACHANNEL_HEIGHT_HALF);
glRectf(act_start, (float)y-ACHANNEL_HEIGHT_HALF, act_end, (float)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);
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((float)frame1_x, (float)channel_y-ACHANNEL_HEIGHT_HALF, (float)v2d->hor.xmax, (float)channel_y+ACHANNEL_HEIGHT_HALF);
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) {
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);
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((float)frame1_x, (float)channel_y-ACHANNEL_HEIGHT_HALF, (float)v2d->hor.xmax, (float)channel_y+ACHANNEL_HEIGHT_HALF);
glRectf(v2d->cur.xmin, (float)y-ACHANNEL_HEIGHT_HALF, v2d->cur.xmax+EXTRA_SCROLL_PAD, (float)y+ACHANNEL_HEIGHT_HALF);
}
}
}
@ -1190,36 +1159,29 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
{
/* 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);
adt= ANIM_nla_mapping_get(ac, ale);
/* draw 'keyframes' for each specific datatype */
switch (ale->datatype) {
case ALE_SCE:
draw_scene_channel(di, aki, ale->key_data, y);
draw_scene_channel(v2d, ads, ale->key_data, y);
break;
case ALE_OB:
draw_object_channel(di, aki, ale->key_data, y);
draw_object_channel(v2d, ads, ale->key_data, y);
break;
case ALE_ACT:
draw_action_channel(di, aki, ale->key_data, y);
draw_action_channel(v2d, adt, ale->key_data, y);
break;
case ALE_GROUP:
draw_agroup_channel(di, aki, ale->data, y);
draw_agroup_channel(v2d, adt, ale->data, y);
break;
case ALE_FCURVE:
draw_fcurve_channel(di, aki, ale->key_data, y);
draw_fcurve_channel(v2d, adt, ale->key_data, y);
break;
case ALE_GPFRAME:
draw_gpl_channel(di, aki, ale->data, y);
draw_gpl_channel(v2d, ads, ale->data, y);
break;
}
if (nob)
ANIM_nla_mapping_draw(di, nob, 1);
}
}
@ -1231,16 +1193,11 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
/* 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);
glColor3f(0.0f, 0.0f, 0.0f);
glBegin(GL_LINES);
glVertex2f((float)frame1_x, (float)v2d->mask.ymin - 100);
glVertex2f((float)frame1_x, (float)v2d->mask.ymax);
glVertex2f(saction->timeslide, v2d->cur.ymin-EXTRA_SCROLL_PAD);
glVertex2f(saction->timeslide, v2d->cur.ymax);
glEnd();
}
glaEnd2DDraw(di);
}

@ -67,6 +67,7 @@
#include "BKE_fcurve.h"
#include "BKE_key.h"
#include "BKE_material.h"
#include "BKE_nla.h"
#include "BKE_object.h"
#include "BKE_context.h"
#include "BKE_report.h"
@ -111,16 +112,16 @@ static void get_keyframe_extents (bAnimContext *ac, float *min, float *max)
if (anim_data.first) {
/* go through channels, finding max extents */
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= ANIM_nla_mapping_get(ac, ale);
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
FCurve *fcu= (FCurve *)ale->key_data;
float tmin, tmax;
/* get range and apply necessary scaling before */
calc_fcurve_range(fcu, &tmin, &tmax);
if (nob) {
tmin= get_action_frame_inv(nob, tmin);
tmax= get_action_frame_inv(nob, tmax);
if (adt) {
tmin= BKE_nla_tweakedit_remap(adt, tmin, NLATIME_CONVERT_MAP);
tmax= BKE_nla_tweakedit_remap(adt, tmax, NLATIME_CONVERT_MAP);
}
/* try to set cur using these values, if they're more extreme than previously set values */
@ -180,7 +181,7 @@ void ACT_OT_previewrange_set (wmOperatorType *ot)
/* api callbacks */
ot->exec= actkeys_previewrange_exec;
ot->poll= ED_operator_areaactive;
ot->poll= ED_operator_action_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -213,7 +214,7 @@ static int actkeys_viewall_exec(bContext *C, wmOperator *op)
/* do View2D syncing */
UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
/* set notifier that things have changed */
/* just redraw this view */
ED_area_tag_redraw(CTX_wm_area(C));
return OPERATOR_FINISHED;
@ -227,7 +228,7 @@ void ACT_OT_view_all (wmOperatorType *ot)
/* api callbacks */
ot->exec= actkeys_viewall_exec;
ot->poll= ED_operator_areaactive;
ot->poll= ED_operator_action_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -300,21 +301,18 @@ static int actkeys_copy_exec(bContext *C, wmOperator *op)
}
}
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
return OPERATOR_FINISHED;
}
void ACT_OT_keyframes_copy (wmOperatorType *ot)
void ACT_OT_copy (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Copy Keyframes";
ot->idname= "ACT_OT_keyframes_copy";
ot->idname= "ACT_OT_copy";
/* api callbacks */
ot->exec= actkeys_copy_exec;
ot->poll= ED_operator_areaactive;
ot->poll= ED_operator_action_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -344,21 +342,21 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
return OPERATOR_FINISHED;
}
void ACT_OT_keyframes_paste (wmOperatorType *ot)
void ACT_OT_paste (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Paste Keyframes";
ot->idname= "ACT_OT_keyframes_paste";
ot->idname= "ACT_OT_paste";
/* api callbacks */
ot->exec= actkeys_paste_exec;
ot->poll= ED_operator_areaactive;
ot->poll= ED_operator_action_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -399,14 +397,14 @@ static void insert_action_keys(bAnimContext *ac, short mode)
/* insert keyframes */
for (ale= anim_data.first; ale; ale= ale->next) {
//Object *nob= ANIM_nla_mapping_get(ac, ale);
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
FCurve *fcu= (FCurve *)ale->key_data;
/* adjust current frame for NLA-scaling */
//if (nob)
// cfra= get_action_frame(nob, CFRA);
//else
// cfra= (float)CFRA;
if (adt)
cfra= BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
else
cfra= (float)CFRA;
/* if there's an id */
if (ale->id)
@ -431,31 +429,31 @@ static int actkeys_insertkey_exec(bContext *C, wmOperator *op)
if (ac.datatype == ANIMCONT_GPENCIL)
return OPERATOR_CANCELLED;
/* get snapping mode */
/* what channels to affect? */
mode= RNA_enum_get(op->ptr, "type");
/* snap keyframes */
/* insert keyframes */
insert_action_keys(&ac, mode);
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
return OPERATOR_FINISHED;
}
void ACT_OT_keyframes_insert (wmOperatorType *ot)
void ACT_OT_insert_keyframe (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Insert Keyframes";
ot->idname= "ACT_OT_keyframes_insert";
ot->idname= "ACT_OT_insert_keyframe";
/* api callbacks */
ot->invoke= WM_menu_invoke;
ot->exec= actkeys_insertkey_exec;
ot->poll= ED_operator_areaactive;
ot->poll= ED_operator_action_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -507,8 +505,8 @@ static int actkeys_duplicate_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
return OPERATOR_FINISHED; // xxx - start transform
}
@ -523,16 +521,16 @@ static int actkeys_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_FINISHED;
}
void ACT_OT_keyframes_duplicate (wmOperatorType *ot)
void ACT_OT_duplicate (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Duplicate Keyframes";
ot->idname= "ACT_OT_keyframes_duplicate";
ot->idname= "ACT_OT_duplicate";
/* api callbacks */
ot->invoke= actkeys_duplicate_invoke;
ot->exec= actkeys_duplicate_exec;
ot->poll= ED_operator_areaactive;
ot->poll= ED_operator_action_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -584,22 +582,22 @@ static int actkeys_delete_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
return OPERATOR_FINISHED;
}
void ACT_OT_keyframes_delete (wmOperatorType *ot)
void ACT_OT_delete (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Delete Keyframes";
ot->idname= "ACT_OT_keyframes_delete";
ot->idname= "ACT_OT_delete";
/* api callbacks */
ot->invoke= WM_operator_confirm;
ot->exec= actkeys_delete_exec;
ot->poll= ED_operator_areaactive;
ot->poll= ED_operator_action_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -647,22 +645,22 @@ static int actkeys_clean_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
return OPERATOR_FINISHED;
}
void ACT_OT_keyframes_clean (wmOperatorType *ot)
void ACT_OT_clean (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Clean Keyframes";
ot->idname= "ACT_OT_keyframes_clean";
ot->idname= "ACT_OT_clean";
/* api callbacks */
//ot->invoke= // XXX we need that number popup for this!
ot->exec= actkeys_clean_exec;
ot->poll= ED_operator_areaactive;
ot->poll= ED_operator_action_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -771,21 +769,21 @@ static int actkeys_sample_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
return OPERATOR_FINISHED;
}
void ACT_OT_keyframes_sample (wmOperatorType *ot)
void ACT_OT_sample (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Sample Keyframes";
ot->idname= "ACT_OT_keyframes_sample";
ot->idname= "ACT_OT_sample";
/* api callbacks */
ot->exec= actkeys_sample_exec;
ot->poll= ED_operator_areaactive;
ot->poll= ED_operator_action_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -846,22 +844,22 @@ static int actkeys_expo_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframe properties have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
return OPERATOR_FINISHED;
}
void ACT_OT_keyframes_extrapolation_type_set (wmOperatorType *ot)
void ACT_OT_extrapolation_type (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Set Keyframe Extrapolation";
ot->idname= "ACT_OT_keyframes_extrapolation_type_set";
ot->idname= "ACT_OT_extrapolation_type";
/* api callbacks */
ot->invoke= WM_menu_invoke;
ot->exec= actkeys_expo_exec;
ot->poll= ED_operator_areaactive;
ot->poll= ED_operator_action_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -916,22 +914,22 @@ static int actkeys_ipo_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframe properties have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
return OPERATOR_FINISHED;
}
void ACT_OT_keyframes_interpolation_type (wmOperatorType *ot)
void ACT_OT_interpolation_type (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Set Keyframe Interpolation";
ot->idname= "ACT_OT_keyframes_interpolation_type";
ot->idname= "ACT_OT_interpolation_type";
/* api callbacks */
ot->invoke= WM_menu_invoke;
ot->exec= actkeys_ipo_exec;
ot->poll= ED_operator_areaactive;
ot->poll= ED_operator_action_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1004,22 +1002,22 @@ static int actkeys_handletype_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframe properties have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
return OPERATOR_FINISHED;
}
void ACT_OT_keyframes_handle_type_set (wmOperatorType *ot)
void ACT_OT_handle_type (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Set Keyframe Handle Type";
ot->idname= "ACT_OT_keyframes_handle_type_set";
ot->idname= "ACT_OT_handle_type";
/* api callbacks */
ot->invoke= WM_menu_invoke;
ot->exec= actkeys_handletype_exec;
ot->poll= ED_operator_areaactive;
ot->poll= ED_operator_action_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1031,10 +1029,10 @@ void ACT_OT_keyframes_handle_type_set (wmOperatorType *ot)
/* ************************************************************************** */
/* TRANSFORM STUFF */
/* ***************** Snap Current Frame Operator *********************** */
/* ***************** Jump to Selected Frames Operator *********************** */
/* snap current-frame indicator to 'average time' of selected keyframe */
static int actkeys_cfrasnap_exec(bContext *C, wmOperator *op)
static int actkeys_framejump_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
ListBase anim_data= {NULL, NULL};
@ -1053,8 +1051,17 @@ static int actkeys_cfrasnap_exec(bContext *C, wmOperator *op)
filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
for (ale= anim_data.first; ale; ale= ale->next)
ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
for (ale= anim_data.first; ale; ale= ale->next) {
AnimData *adt= ANIM_nla_mapping_get(&ac, ale);
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
}
else
ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
}
BLI_freelistN(&anim_data);
@ -1070,15 +1077,15 @@ static int actkeys_cfrasnap_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
void ACT_OT_keyframes_cfrasnap (wmOperatorType *ot)
void ACT_OT_frame_jump (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Snap Current Frame to Keys";
ot->idname= "ACT_OT_keyframes_cfrasnap";
ot->name= "Jump to Frame";
ot->idname= "ACT_OT_frame_jump";
/* api callbacks */
ot->exec= actkeys_cfrasnap_exec;
ot->poll= ED_operator_areaactive;
ot->exec= actkeys_framejump_exec;
ot->poll= ED_operator_action_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1124,12 +1131,12 @@ static void snap_action_keys(bAnimContext *ac, short mode)
/* snap keyframes */
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= ANIM_nla_mapping_get(ac, ale);
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
if (nob) {
ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1);
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
}
//else if (ale->type == ACTTYPE_GPLAYER)
// snap_gplayer_frames(ale->data, mode);
@ -1159,22 +1166,22 @@ static int actkeys_snap_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
return OPERATOR_FINISHED;
}
void ACT_OT_keyframes_snap (wmOperatorType *ot)
void ACT_OT_snap (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Snap Keys";
ot->idname= "ACT_OT_keyframes_snap";
ot->idname= "ACT_OT_snap";
/* api callbacks */
ot->invoke= WM_menu_invoke;
ot->exec= actkeys_snap_exec;
ot->poll= ED_operator_areaactive;
ot->poll= ED_operator_action_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1187,10 +1194,10 @@ void ACT_OT_keyframes_snap (wmOperatorType *ot)
/* defines for mirror keyframes tool */
EnumPropertyItem prop_actkeys_mirror_types[] = {
{ACTKEYS_MIRROR_CFRA, "CFRA", 0, "Current frame", ""},
{ACTKEYS_MIRROR_YAXIS, "YAXIS", 0, "Vertical Axis", ""},
{ACTKEYS_MIRROR_XAXIS, "XAXIS", 0, "Horizontal Axis", ""},
{ACTKEYS_MIRROR_MARKER, "MARKER", 0, "First Selected Marker", ""},
{ACTKEYS_MIRROR_CFRA, "CFRA", 0, "By Times over Current frame", ""},
{ACTKEYS_MIRROR_YAXIS, "YAXIS", 0, "By Times over Time=0", ""},
{ACTKEYS_MIRROR_XAXIS, "XAXIS", 0, "By Values over Value=0", ""},
{ACTKEYS_MIRROR_MARKER, "MARKER", 0, "By Times over First Selected Marker", ""},
{0, NULL, 0, NULL, NULL}
};
@ -1240,12 +1247,12 @@ static void mirror_action_keys(bAnimContext *ac, short mode)
/* mirror keyframes */
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= ANIM_nla_mapping_get(ac, ale);
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
if (nob) {
ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1);
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
}
//else if (ale->type == ACTTYPE_GPLAYER)
// snap_gplayer_frames(ale->data, mode);
@ -1275,22 +1282,22 @@ static int actkeys_mirror_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
return OPERATOR_FINISHED;
}
void ACT_OT_keyframes_mirror (wmOperatorType *ot)
void ACT_OT_mirror (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Mirror Keys";
ot->idname= "ACT_OT_keyframes_mirror";
ot->idname= "ACT_OT_mirror";
/* api callbacks */
ot->invoke= WM_menu_invoke;
ot->exec= actkeys_mirror_exec;
ot->poll= ED_operator_areaactive;
ot->poll= ED_operator_action_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;

File diff suppressed because it is too large Load Diff

@ -53,10 +53,10 @@ void action_header_buttons(const struct bContext *C, struct ARegion *ar);
/* ***************************************** */
/* action_select.c */
void ACT_OT_keyframes_select_all_toggle(struct wmOperatorType *ot);
void ACT_OT_keyframes_select_border(struct wmOperatorType *ot);
void ACT_OT_keyframes_select_column(struct wmOperatorType *ot);
void ACT_OT_keyframes_clickselect(struct wmOperatorType *ot);
void ACT_OT_select_all_toggle(struct wmOperatorType *ot);
void ACT_OT_select_border(struct wmOperatorType *ot);
void ACT_OT_select_column(struct wmOperatorType *ot);
void ACT_OT_clickselect(struct wmOperatorType *ot);
/* defines for left-right select tool */
enum {
@ -80,22 +80,23 @@ enum {
void ACT_OT_previewrange_set(struct wmOperatorType *ot);
void ACT_OT_view_all(struct wmOperatorType *ot);
void ACT_OT_keyframes_copy(struct wmOperatorType *ot);
void ACT_OT_keyframes_paste(struct wmOperatorType *ot);
void ACT_OT_copy(struct wmOperatorType *ot);
void ACT_OT_paste(struct wmOperatorType *ot);
void ACT_OT_keyframes_insert(struct wmOperatorType *ot);
void ACT_OT_keyframes_duplicate(struct wmOperatorType *ot);
void ACT_OT_keyframes_delete(struct wmOperatorType *ot);
void ACT_OT_keyframes_clean(struct wmOperatorType *ot);
void ACT_OT_keyframes_sample(struct wmOperatorType *ot);
void ACT_OT_insert_keyframe(struct wmOperatorType *ot);
void ACT_OT_duplicate(struct wmOperatorType *ot);
void ACT_OT_delete(struct wmOperatorType *ot);
void ACT_OT_clean(struct wmOperatorType *ot);
void ACT_OT_sample(struct wmOperatorType *ot);
void ACT_OT_keyframes_handle_type_set(struct wmOperatorType *ot);
void ACT_OT_keyframes_interpolation_type(struct wmOperatorType *ot);
void ACT_OT_keyframes_extrapolation_type_set(struct wmOperatorType *ot);
void ACT_OT_handle_type(struct wmOperatorType *ot);
void ACT_OT_interpolation_type(struct wmOperatorType *ot);
void ACT_OT_extrapolation_type(struct wmOperatorType *ot);
void ACT_OT_keyframes_cfrasnap(struct wmOperatorType *ot);
void ACT_OT_keyframes_snap(struct wmOperatorType *ot);
void ACT_OT_keyframes_mirror(struct wmOperatorType *ot);
void ACT_OT_frame_jump(struct wmOperatorType *ot);
void ACT_OT_snap(struct wmOperatorType *ot);
void ACT_OT_mirror(struct wmOperatorType *ot);
/* defines for snap keyframes
* NOTE: keep in sync with eEditKeyframes_Snap (in ED_keyframes_edit.h)

@ -63,25 +63,25 @@ void action_operatortypes(void)
{
/* keyframes */
/* selection */
WM_operatortype_append(ACT_OT_keyframes_clickselect);
WM_operatortype_append(ACT_OT_keyframes_select_all_toggle);
WM_operatortype_append(ACT_OT_keyframes_select_border);
WM_operatortype_append(ACT_OT_keyframes_select_column);
WM_operatortype_append(ACT_OT_clickselect);
WM_operatortype_append(ACT_OT_select_all_toggle);
WM_operatortype_append(ACT_OT_select_border);
WM_operatortype_append(ACT_OT_select_column);
/* editing */
WM_operatortype_append(ACT_OT_keyframes_snap);
WM_operatortype_append(ACT_OT_keyframes_mirror);
WM_operatortype_append(ACT_OT_keyframes_cfrasnap);
WM_operatortype_append(ACT_OT_keyframes_handle_type_set);
WM_operatortype_append(ACT_OT_keyframes_interpolation_type);
WM_operatortype_append(ACT_OT_keyframes_extrapolation_type_set);
WM_operatortype_append(ACT_OT_keyframes_sample);
WM_operatortype_append(ACT_OT_keyframes_clean);
WM_operatortype_append(ACT_OT_keyframes_delete);
WM_operatortype_append(ACT_OT_keyframes_duplicate);
WM_operatortype_append(ACT_OT_keyframes_insert);
WM_operatortype_append(ACT_OT_keyframes_copy);
WM_operatortype_append(ACT_OT_keyframes_paste);
WM_operatortype_append(ACT_OT_snap);
WM_operatortype_append(ACT_OT_mirror);
WM_operatortype_append(ACT_OT_frame_jump);
WM_operatortype_append(ACT_OT_handle_type);
WM_operatortype_append(ACT_OT_interpolation_type);
WM_operatortype_append(ACT_OT_extrapolation_type);
WM_operatortype_append(ACT_OT_sample);
WM_operatortype_append(ACT_OT_clean);
WM_operatortype_append(ACT_OT_delete);
WM_operatortype_append(ACT_OT_duplicate);
WM_operatortype_append(ACT_OT_insert_keyframe);
WM_operatortype_append(ACT_OT_copy);
WM_operatortype_append(ACT_OT_paste);
WM_operatortype_append(ACT_OT_previewrange_set);
WM_operatortype_append(ACT_OT_view_all);
@ -95,57 +95,58 @@ static void action_keymap_keyframes (wmWindowManager *wm, ListBase *keymap)
/* action_select.c - selection tools */
/* click-select */
WM_keymap_add_item(keymap, "ACT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, 0, 0);
kmi= WM_keymap_add_item(keymap, "ACT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "ACT_OT_clickselect", SELECTMOUSE, KM_PRESS, 0, 0);
kmi= WM_keymap_add_item(keymap, "ACT_OT_clickselect", SELECTMOUSE, KM_PRESS, KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "column", 1);
kmi= WM_keymap_add_item(keymap, "ACT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
kmi= WM_keymap_add_item(keymap, "ACT_OT_clickselect", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "extend", 1);
kmi= WM_keymap_add_item(keymap, "ACT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_ALT|KM_SHIFT, 0);
kmi= WM_keymap_add_item(keymap, "ACT_OT_clickselect", SELECTMOUSE, KM_PRESS, KM_ALT|KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "extend", 1);
RNA_boolean_set(kmi->ptr, "column", 1);
kmi= WM_keymap_add_item(keymap, "ACT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
kmi= WM_keymap_add_item(keymap, "ACT_OT_clickselect", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
RNA_enum_set(kmi->ptr, "left_right", ACTKEYS_LRSEL_TEST);
/* deselect all */
WM_keymap_add_item(keymap, "ACT_OT_keyframes_select_all_toggle", AKEY, KM_PRESS, 0, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "ACT_OT_keyframes_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1);
WM_keymap_add_item(keymap, "ACT_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "ACT_OT_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1);
/* borderselect */
WM_keymap_add_item(keymap, "ACT_OT_keyframes_select_border", BKEY, KM_PRESS, 0, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "ACT_OT_keyframes_select_border", BKEY, KM_PRESS, KM_ALT, 0)->ptr, "axis_range", 1);
WM_keymap_add_item(keymap, "ACT_OT_select_border", BKEY, KM_PRESS, 0, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "ACT_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0)->ptr, "axis_range", 1);
/* column select */
RNA_enum_set(WM_keymap_add_item(keymap, "ACT_OT_keyframes_select_column", KKEY, KM_PRESS, 0, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_KEYS);
RNA_enum_set(WM_keymap_add_item(keymap, "ACT_OT_keyframes_select_column", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_CFRA);
RNA_enum_set(WM_keymap_add_item(keymap, "ACT_OT_keyframes_select_column", KKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_MARKERS_COLUMN);
RNA_enum_set(WM_keymap_add_item(keymap, "ACT_OT_keyframes_select_column", KKEY, KM_PRESS, KM_ALT, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_MARKERS_BETWEEN);
RNA_enum_set(WM_keymap_add_item(keymap, "ACT_OT_select_column", KKEY, KM_PRESS, 0, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_KEYS);
RNA_enum_set(WM_keymap_add_item(keymap, "ACT_OT_select_column", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_CFRA);
RNA_enum_set(WM_keymap_add_item(keymap, "ACT_OT_select_column", KKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_MARKERS_COLUMN);
RNA_enum_set(WM_keymap_add_item(keymap, "ACT_OT_select_column", KKEY, KM_PRESS, KM_ALT, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_MARKERS_BETWEEN);
/* action_edit.c */
/* snap - current frame to selected keys */
WM_keymap_add_item(keymap, "ACT_OT_keyframes_cfrasnap", SKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
// TODO: maybe since this is called jump, we're better to have it on <something>-J?
WM_keymap_add_item(keymap, "ACT_OT_frame_jump", SKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
/* menu + single-step transform */
WM_keymap_add_item(keymap, "ACT_OT_keyframes_snap", SKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ACT_OT_keyframes_mirror", MKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ACT_OT_snap", SKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ACT_OT_mirror", MKEY, KM_PRESS, KM_SHIFT, 0);
/* menu + set setting */
WM_keymap_add_item(keymap, "ACT_OT_keyframes_handle_type_set", HKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACT_OT_keyframes_interpolation_type", TKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ACT_OT_keyframes_extrapolation_type_set", EKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ACT_OT_handle_type", HKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACT_OT_interpolation_type", TKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ACT_OT_extrapolation_type", EKEY, KM_PRESS, KM_SHIFT, 0);
/* destructive */
WM_keymap_add_item(keymap, "ACT_OT_keyframes_clean", OKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACT_OT_keyframes_sample", OKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ACT_OT_clean", OKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACT_OT_sample", OKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ACT_OT_keyframes_delete", XKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACT_OT_keyframes_delete", DELKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACT_OT_delete", XKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACT_OT_delete", DELKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACT_OT_keyframes_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ACT_OT_keyframes_insert", IKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ACT_OT_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ACT_OT_insert_keyframe", IKEY, KM_PRESS, 0, 0);
/* copy/paste */
WM_keymap_add_item(keymap, "ACT_OT_keyframes_copy", CKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "ACT_OT_keyframes_paste", VKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "ACT_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "ACT_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0);
/* auto-set range */
WM_keymap_add_item(keymap, "ACT_OT_previewrange_set", PKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);

@ -64,6 +64,7 @@
#include "BKE_fcurve.h"
#include "BKE_key.h"
#include "BKE_material.h"
#include "BKE_nla.h"
#include "BKE_object.h"
#include "BKE_context.h"
#include "BKE_utildefines.h"
@ -173,21 +174,21 @@ static int actkeys_deselectall_exec(bContext *C, wmOperator *op)
else
deselect_action_keys(&ac, 1, SELECT_ADD);
/* set notifier that things have changed */
ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
/* set notifier that keyframe selection have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_SELECT, NULL);
return OPERATOR_FINISHED;
}
void ACT_OT_keyframes_select_all_toggle (wmOperatorType *ot)
void ACT_OT_select_all_toggle (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Select All";
ot->idname= "ACT_OT_keyframes_select_all_toggle";
ot->idname= "ACT_OT_select_all_toggle";
/* api callbacks */
ot->exec= actkeys_deselectall_exec;
ot->poll= ED_operator_areaactive;
ot->poll= ED_operator_action_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -222,7 +223,8 @@ static void borderselect_action (bAnimContext *ac, rcti rect, short mode, short
BeztEditFunc ok_cb, select_cb;
View2D *v2d= &ac->ar->v2d;
rctf rectf;
float ymin=0, ymax=(float)(-ACHANNEL_HEIGHT);
//float ymin=0, ymax=(float)(-ACHANNEL_HEIGHT);
float ymin=0, ymax=(float)(-ACHANNEL_HEIGHT_HALF);
/* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */
UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin+2, &rectf.xmin, &rectf.ymin);
@ -245,7 +247,7 @@ static void borderselect_action (bAnimContext *ac, rcti rect, short mode, short
/* loop over data, doing border select */
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= ANIM_nla_mapping_get(ac, ale);
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
/* get new vertical minimum extent of channel */
ymin= ymax - ACHANNEL_STEP;
@ -253,9 +255,9 @@ static void borderselect_action (bAnimContext *ac, rcti rect, short mode, short
/* set horizontal range (if applicable) */
if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) {
/* if channel is mapped in NLA, apply correction */
if (nob) {
bed.f1= get_action_frame(nob, rectf.xmin);
bed.f2= get_action_frame(nob, rectf.xmax);
if (adt) {
bed.f1= BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP);
bed.f2= BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP);
}
else {
bed.f1= rectf.xmin;
@ -335,21 +337,24 @@ static int actkeys_borderselect_exec(bContext *C, wmOperator *op)
/* apply borderselect action */
borderselect_action(&ac, rect, mode, selectmode);
/* set notifier that keyframe selection have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_SELECT, NULL);
return OPERATOR_FINISHED;
}
void ACT_OT_keyframes_select_border(wmOperatorType *ot)
void ACT_OT_select_border(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Border Select";
ot->idname= "ACT_OT_keyframes_select_border";
ot->idname= "ACT_OT_select_border";
/* api callbacks */
ot->invoke= WM_border_select_invoke;
ot->exec= actkeys_borderselect_exec;
ot->modal= WM_border_select_modal;
ot->poll= ED_operator_areaactive;
ot->poll= ED_operator_action_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -413,12 +418,12 @@ static void markers_selectkeys_between (bAnimContext *ac)
/* select keys in-between */
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= ANIM_nla_mapping_get(ac, ale);
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
if (nob) {
ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1);
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
}
else {
ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
@ -495,15 +500,15 @@ static void columnselect_action_keys (bAnimContext *ac, short mode)
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= ANIM_nla_mapping_get(ac, ale);
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
/* loop over cfraelems (stored in the BeztEditData->list)
* - we need to do this here, as we can apply fewer NLA-mapping conversions
*/
for (ce= bed.list.first; ce; ce= ce->next) {
/* set frame for validation callback to refer to */
if (nob)
bed.f1= get_action_frame(nob, ce->cfra);
if (adt)
bed.f1= BKE_nla_tweakedit_remap(adt, ce->cfra, NLATIME_CONVERT_UNMAP);
else
bed.f1= ce->cfra;
@ -549,21 +554,21 @@ static int actkeys_columnselect_exec(bContext *C, wmOperator *op)
else
columnselect_action_keys(&ac, mode);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_SELECT);
/* set notifier that keyframe selection have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_SELECT, NULL);
return OPERATOR_FINISHED;
}
void ACT_OT_keyframes_select_column (wmOperatorType *ot)
void ACT_OT_select_column (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Select All";
ot->idname= "ACT_OT_keyframes_select_column";
ot->idname= "ACT_OT_select_column";
/* api callbacks */
ot->exec= actkeys_columnselect_exec;
ot->poll= ED_operator_areaactive;
ot->poll= ED_operator_action_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -641,7 +646,7 @@ static void actkeys_mselect_leftright (bAnimContext *ac, short leftright, short
memset(&bed, 0, sizeof(BeztEditFunc));
if (leftright == ACTKEYS_LRSEL_LEFT) {
bed.f1 = -MAXFRAMEF;
bed.f1 = MINAFRAMEF;
bed.f2 = (float)(CFRA + FRAME_CLICK_THRESH);
}
else {
@ -658,12 +663,12 @@ static void actkeys_mselect_leftright (bAnimContext *ac, short leftright, short
/* select keys on the side where most data occurs */
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= ANIM_nla_mapping_get(ac, ale);
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
if (nob) {
ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1);
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
}
//else if (ale->type == ANIMTYPE_GPLAYER)
// borderselect_gplayer_frames(ale->data, min, max, SELECT_ADD);
@ -702,11 +707,11 @@ static void actkeys_mselect_column(bAnimContext *ac, short select_mode, float se
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= ANIM_nla_mapping_get(ac, ale);
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
/* set frame for validation callback to refer to */
if (nob)
bed.f1= get_action_frame(nob, selx);
if (adt)
bed.f1= BKE_nla_tweakedit_remap(adt, selx, NLATIME_CONVERT_UNMAP);
else
bed.f1= selx;
@ -742,12 +747,16 @@ static void mouse_action_keys (bAnimContext *ac, int mval[2], short select_mode,
int filter;
View2D *v2d= &ac->ar->v2d;
bDopeSheet *ads = NULL;
int channel_index;
short found = 0;
float selx = 0.0f;
float x, y;
rctf rectf;
/* get dopesheet info */
if (ac->datatype == ANIMCONT_DOPESHEET)
ads= ac->data;
/* use View2D to determine the index of the channel (i.e a row in the list) where keyframe was */
UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
@ -766,51 +775,41 @@ static void mouse_action_keys (bAnimContext *ac, int mval[2], short select_mode,
if (ale == NULL) {
/* channel not found */
printf("Error: animation channel (index = %d) not found in mouse_action_keys() \n", channel_index);
BLI_freelistN(&anim_data);
return;
}
else {
/* found match - must return here... */
Object *nob= ANIM_nla_mapping_get(ac, ale);
ActKeysInc *aki= init_aki_data(ac, ale);
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
ActKeyColumn *ak;
float xmin, xmax;
/* apply NLA-scaling correction? */
if (nob) {
xmin= get_action_frame(nob, rectf.xmin);
xmax= get_action_frame(nob, rectf.xmax);
}
else {
xmin= rectf.xmin;
xmax= rectf.xmax;
}
/* make list of keyframes */
// TODO: it would be great if we didn't have to apply this to all the keyframes to do this...
if (ale->key_data) {
switch (ale->datatype) {
case ALE_OB:
{
Object *ob= (Object *)ale->key_data;
ob_to_keylist(ob, &anim_keys, NULL, aki);
ob_to_keylist(ads, ob, &anim_keys, NULL);
}
break;
case ALE_ACT:
{
bAction *act= (bAction *)ale->key_data;
action_to_keylist(act, &anim_keys, NULL, aki);
action_to_keylist(adt, act, &anim_keys, NULL);
}
break;
case ALE_FCURVE:
{
FCurve *fcu= (FCurve *)ale->key_data;
fcurve_to_keylist(fcu, &anim_keys, NULL, aki);
fcurve_to_keylist(adt, fcu, &anim_keys, NULL);
}
break;
}
}
else if (ale->type == ANIMTYPE_GROUP) {
bActionGroup *agrp= (bActionGroup *)ale->data;
agroup_to_keylist(agrp, &anim_keys, NULL, aki);
agroup_to_keylist(adt, agrp, &anim_keys, NULL);
}
else if (ale->type == ANIMTYPE_GPDATABLOCK) {
/* cleanup */
@ -820,13 +819,17 @@ static void mouse_action_keys (bAnimContext *ac, int mval[2], short select_mode,
}
else if (ale->type == ANIMTYPE_GPLAYER) {
bGPDlayer *gpl= (bGPDlayer *)ale->data;
gpl_to_keylist(gpl, &anim_keys, NULL, aki);
gpl_to_keylist(ads, gpl, &anim_keys, NULL);
}
/* loop through keyframes, finding one that was clicked on */
for (ak= anim_keys.first; ak; ak= ak->next) {
if (IN_RANGE(ak->cfra, xmin, xmax)) {
selx= ak->cfra;
if (IN_RANGE(ak->cfra, rectf.xmin, rectf.xmax)) {
/* set the frame to use, and apply inverse-correction for NLA-mapping
* so that the frame will get selected by the selection functiosn without
* requiring to map each frame once again...
*/
selx= BKE_nla_tweakedit_remap(adt, ak->cfra, NLATIME_CONVERT_UNMAP);
found= 1;
break;
}
@ -857,17 +860,19 @@ static void mouse_action_keys (bAnimContext *ac, int mval[2], short select_mode,
ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
/* Highlight Action-Group or F-Curve? */
if (ale->type == ANIMTYPE_GROUP) {
bActionGroup *agrp= ale->data;
if (ale && ale->data) {
if (ale->type == ANIMTYPE_GROUP) {
bActionGroup *agrp= ale->data;
agrp->flag |= AGRP_SELECTED;
ANIM_set_active_channel(ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
}
else if (ale->type == ANIMTYPE_FCURVE) {
FCurve *fcu= ale->data;
agrp->flag |= AGRP_SELECTED;
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
}
else if (ale->type == ANIMTYPE_FCURVE) {
FCurve *fcu= ale->data;
fcu->flag |= FCURVE_SELECTED;
ANIM_set_active_channel(ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
fcu->flag |= FCURVE_SELECTED;
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
}
}
}
else if (ac->datatype == ANIMCONT_GPENCIL) {
@ -881,18 +886,20 @@ static void mouse_action_keys (bAnimContext *ac, int mval[2], short select_mode,
/* only select keyframes if we clicked on a valid channel and hit something */
if (ale) {
/* apply selection to keyframes */
if (/*gpl*/0) {
/* grease pencil */
//select_gpencil_frame(gpl, (int)selx, selectmode);
}
else if (column) {
/* select all keyframes in the same frame as the one we hit on the active channel */
actkeys_mselect_column(ac, select_mode, selx);
}
else {
/* select the nominated keyframe on the given frame */
actkeys_mselect_single(ac, ale, select_mode, selx);
if (found) {
/* apply selection to keyframes */
if (/*gpl*/0) {
/* grease pencil */
//select_gpencil_frame(gpl, (int)selx, selectmode);
}
else if (column) {
/* select all keyframes in the same frame as the one we hit on the active channel */
actkeys_mselect_column(ac, select_mode, selx);
}
else {
/* select the nominated keyframe on the given frame */
actkeys_mselect_single(ac, ale, select_mode, selx);
}
}
/* free this channel */
@ -950,22 +957,22 @@ static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, wmEvent *even
mouse_action_keys(&ac, mval, selectmode, column);
}
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
/* set notifier that keyframe selection (and channels too) have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_SELECT|ND_ANIMCHAN_SELECT, NULL);
/* for tweak grab to work */
return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
}
void ACT_OT_keyframes_clickselect (wmOperatorType *ot)
void ACT_OT_clickselect (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Mouse Select Keys";
ot->idname= "ACT_OT_keyframes_clickselect";
ot->idname= "ACT_OT_clickselect";
/* api callbacks - absolutely no exec() this yet... */
ot->invoke= actkeys_clickselect_invoke;
ot->poll= ED_operator_areaactive;
ot->poll= ED_operator_action_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;

@ -288,6 +288,9 @@ static void action_channel_area_listener(ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch(wmn->category) {
case NC_ANIMATION:
ED_region_tag_redraw(ar);
break;
case NC_SCENE:
switch(wmn->data) {
case ND_OB_ACTIVE:
@ -314,6 +317,9 @@ static void action_main_area_listener(ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch(wmn->category) {
case NC_ANIMATION:
ED_region_tag_redraw(ar);
break;
case NC_SCENE:
switch(wmn->data) {
case ND_OB_ACTIVE:
@ -344,6 +350,9 @@ static void action_listener(ScrArea *sa, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
case NC_ANIMATION:
ED_area_tag_refresh(sa);
break;
case NC_SCENE:
/*switch (wmn->data) {
case ND_OB_ACTIVE:

@ -193,7 +193,7 @@ void buttons_header_buttons(const bContext *C, ARegion *ar)
uiBlockEndAlign(block);
xco+=XIC;
uiDefButI(block, NUM, B_NEWFRAME, "", (xco+20),yco,60,YIC, &(CTX_data_scene(C)->r.cfra), 1.0, MAXFRAMEF, 0, 0, "Displays Current Frame of animation. Click to change.");
uiDefButI(block, NUM, B_NEWFRAME, "", (xco+20),yco,60,YIC, &(CTX_data_scene(C)->r.cfra), MINAFRAMEF, MAXFRAMEF, 0, 0, "Displays Current Frame of animation. Click to change.");
xco+= 80;
/* always as last */

@ -147,6 +147,9 @@ int ED_fileselect_layout_offset(FileLayout* layout, int x, int y)
int offsetx, offsety;
int active_file;
if (layout == NULL)
return NULL;
offsetx = (x)/(layout->tile_w + 2*layout->tile_border_x);
offsety = (y)/(layout->tile_h + 2*layout->tile_border_y);

@ -347,6 +347,7 @@ static void graph_panel_drivers(const bContext *C, Panel *pa)
}
/* ******************* f-modifiers ******************************** */
/* all the drawing code is in editors/animation/fmodifier_ui.c */
#define B_FMODIFIER_REDRAW 20
@ -360,671 +361,41 @@ static void do_graph_region_modifier_buttons(bContext *C, void *arg, int event)
}
}
/* macro for use here to draw background box and set height */
// XXX for now, roundbox has it's callback func set to NULL to not intercept events
#define DRAW_BACKDROP(height) \
{ \
uiDefBut(block, ROUNDBOX, B_REDR, "", -3, *yco-height, width+3, height-1, NULL, 5.0, 0.0, 12.0, (float)rb_col, ""); \
}
/* callback to verify modifier data */
static void validate_fmodifier_cb (bContext *C, void *fcu_v, void *fcm_v)
{
FModifier *fcm= (FModifier *)fcm_v;
FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
/* call the verify callback on the modifier if applicable */
if (fmi && fmi->verify_data)
fmi->verify_data(fcm);
}
/* callback to set the active modifier */
static void activate_fmodifier_cb (bContext *C, void *fcu_v, void *fcm_v)
{
FCurve *fcu= (FCurve *)fcu_v;
FModifier *fcm= (FModifier *)fcm_v;
/* call API function to set the active modifier for active F-Curve */
fcurve_set_active_modifier(fcu, fcm);
}
/* callback to remove the given modifier */
static void delete_fmodifier_cb (bContext *C, void *fcu_v, void *fcm_v)
{
FCurve *fcu= (FCurve *)fcu_v;
FModifier *fcm= (FModifier *)fcm_v;
/* remove the given F-Modifier from the F-Curve */
fcurve_remove_modifier(fcu, fcm);
}
/* --------------- */
/* draw settings for generator modifier */
static void draw_modifier__generator(uiBlock *block, FCurve *fcu, FModifier *fcm, int *yco, short *height, short width, short active, int rb_col)
{
FMod_Generator *data= (FMod_Generator *)fcm->data;
char gen_mode[]="Generator Type%t|Expanded Polynomial%x0|Factorised Polynomial%x1|Built-In Function%x2|Expression%x3";
char fn_type[]="Built-In Function%t|Sin%x0|Cos%x1|Tan%x2|Square Root%x3|Natural Log%x4";
int cy= *yco - 30;
uiBut *but;
/* set the height */
(*height) = 90;
switch (data->mode) {
case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */
(*height) += 20*(data->poly_order+1) + 20;
break;
case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial */
(*height) += 20 * data->poly_order + 15;
break;
case FCM_GENERATOR_FUNCTION: /* builtin function */
(*height) += 55; // xxx
break;
case FCM_GENERATOR_EXPRESSION: /* py-expression */
// xxx nothing to draw
break;
}
/* basic settings (backdrop + mode selector + some padding) */
DRAW_BACKDROP((*height));
uiBlockBeginAlign(block);
but= uiDefButS(block, MENU, B_FMODIFIER_REDRAW, gen_mode, 10,cy,width-30,19, &data->mode, 0, 0, 0, 0, "Selects type of generator algorithm.");
uiButSetFunc(but, validate_fmodifier_cb, fcu, fcm);
cy -= 20;
uiDefButBitS(block, TOG, FCM_GENERATOR_ADDITIVE, B_FMODIFIER_REDRAW, "Additive", 10,cy,width-30,19, &data->flag, 0, 0, 0, 0, "Values generated by this modifier are applied on top of the existing values instead of overwriting them");
cy -= 35;
uiBlockEndAlign(block);
/* now add settings for individual modes */
switch (data->mode) {
case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */
{
float *cp = NULL;
char xval[32];
unsigned int i;
/* draw polynomial order selector */
but= uiDefButS(block, NUM, B_FMODIFIER_REDRAW, "Poly Order: ", 10,cy,width-30,19, &data->poly_order, 1, 100, 0, 0, "'Order' of the Polynomial - for a polynomial with n terms, 'order' is n-1");
uiButSetFunc(but, validate_fmodifier_cb, fcu, fcm);
cy -= 35;
/* draw controls for each coefficient and a + sign at end of row */
uiDefBut(block, LABEL, 1, "y = ", 0, cy, 50, 20, NULL, 0.0, 0.0, 0, 0, "");
cp= data->coefficients;
for (i=0; (i < data->arraysize) && (cp); i++, cp++) {
/* coefficient */
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 50, cy, 150, 20, cp, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Coefficient for polynomial");
/* 'x' param (and '+' if necessary) */
if (i == 0)
strcpy(xval, "");
else if (i == 1)
strcpy(xval, "x");
else
sprintf(xval, "x^%d", i);
uiDefBut(block, LABEL, 1, xval, 200, cy, 50, 20, NULL, 0.0, 0.0, 0, 0, "Power of x");
if ( (i != (data->arraysize - 1)) || ((i==0) && data->arraysize==2) )
uiDefBut(block, LABEL, 1, "+", 250, cy, 30, 20, NULL, 0.0, 0.0, 0, 0, "");
cy -= 20;
}
}
break;
case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* factorised polynomial expression */
{
float *cp = NULL;
unsigned int i;
/* draw polynomial order selector */
but= uiDefButS(block, NUM, B_FMODIFIER_REDRAW, "Poly Order: ", 10,cy,width-30,19, &data->poly_order, 1, 100, 0, 0, "'Order' of the Polynomial - for a polynomial with n terms, 'order' is n-1");
uiButSetFunc(but, validate_fmodifier_cb, fcu, fcm);
cy -= 35;
/* draw controls for each pair of coefficients */
uiDefBut(block, LABEL, 1, "y = ", 0, cy, 50, 20, NULL, 0.0, 0.0, 0, 0, "");
cp= data->coefficients;
for (i=0; (i < data->poly_order) && (cp); i++, cp+=2) {
/* opening bracket */
uiDefBut(block, LABEL, 1, "(", 40, cy, 50, 20, NULL, 0.0, 0.0, 0, 0, "");
/* coefficients */
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 50, cy, 100, 20, cp, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Coefficient of x");
uiDefBut(block, LABEL, 1, "x + ", 150, cy, 30, 20, NULL, 0.0, 0.0, 0, 0, "");
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 180, cy, 100, 20, cp+1, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Second coefficient");
/* closing bracket and '+' sign */
if ( (i != (data->poly_order - 1)) || ((i==0) && data->poly_order==2) )
uiDefBut(block, LABEL, 1, ") ◊", 280, cy, 30, 20, NULL, 0.0, 0.0, 0, 0, "");
else
uiDefBut(block, LABEL, 1, ")", 280, cy, 30, 20, NULL, 0.0, 0.0, 0, 0, "");
cy -= 20;
}
}
break;
case FCM_GENERATOR_FUNCTION: /* built-in function */
{
float *cp= data->coefficients;
/* draw function selector */
but= uiDefButS(block, MENU, B_FMODIFIER_REDRAW, fn_type, 10,cy,width-30,19, &data->func_type, 0, 0, 0, 0, "Built-In Function to use");
uiButSetFunc(but, validate_fmodifier_cb, fcu, fcm);
cy -= 35;
/* draw controls for equation of coefficients */
/* row 1 */
{
uiDefBut(block, LABEL, 1, "y = ", 0, cy, 50, 20, NULL, 0.0, 0.0, 0, 0, "");
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 50, cy, 150, 20, cp+3, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Coefficient (D) for function");
uiDefBut(block, LABEL, 1, "+", 200, cy, 30, 20, NULL, 0.0, 0.0, 0, 0, "");
cy -= 20;
}
/* row 2 */
{
char func_name[32];
/* coefficient outside bracket */
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 5, cy, 80, 20, cp, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Coefficient (A) for function");
/* opening bracket */
switch (data->func_type)
{
case FCM_GENERATOR_FN_SIN: /* sine wave */
sprintf(func_name, "sin(");
break;
case FCM_GENERATOR_FN_COS: /* cosine wave */
sprintf(func_name, "cos(");
break;
case FCM_GENERATOR_FN_TAN: /* tangent wave */
sprintf(func_name, "tan(");
break;
case FCM_GENERATOR_FN_LN: /* natural log */
sprintf(func_name, "ln(");
break;
case FCM_GENERATOR_FN_SQRT: /* square root */
sprintf(func_name, "sqrt(");
break;
default: /* unknown */
sprintf(func_name, "<fn?>(");
break;
}
uiDefBut(block, LABEL, 1, func_name, 85, cy, 40, 20, NULL, 0.0, 0.0, 0, 0, "");
/* coefficients inside bracket */
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 120, cy, 75, 20, cp+1, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Coefficient (B) of x");
uiDefBut(block, LABEL, 1, "x+", 195, cy, 30, 20, NULL, 0.0, 0.0, 0, 0, "");
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 225, cy, 80, 20, cp+2, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "Coefficient (C) of function");
/* closing bracket */
uiDefBut(block, LABEL, 1, ")", 300, cy, 30, 20, NULL, 0.0, 0.0, 0, 0, "");
cy -= 20;
}
}
break;
case FCM_GENERATOR_EXPRESSION: /* py-expression */
// TODO...
break;
}
}
/* --------------- */
/* draw settings for cycles modifier */
static void draw_modifier__cycles(uiBlock *block, FCurve *fcu, FModifier *fcm, int *yco, short *height, short width, short active, int rb_col)
{
FMod_Cycles *data= (FMod_Cycles *)fcm->data;
char cyc_mode[]="Cycling Mode%t|No Cycles%x0|Repeat Motion%x1|Repeat with Offset%x2|Repeat Mirrored%x3";
int cy= (*yco - 30), cy1= (*yco - 50), cy2= (*yco - 70);
/* set the height */
(*height) = 80;
/* basic settings (backdrop + some padding) */
DRAW_BACKDROP((*height));
/* 'before' range */
uiDefBut(block, LABEL, 1, "Before:", 4, cy, 80, 20, NULL, 0.0, 0.0, 0, 0, "Settings for cycling before first keyframe");
uiBlockBeginAlign(block);
uiDefButS(block, MENU, B_FMODIFIER_REDRAW, cyc_mode, 3,cy1,150,20, &data->before_mode, 0, 0, 0, 0, "Cycling mode to use before first keyframe");
uiDefButS(block, NUM, B_FMODIFIER_REDRAW, "Max Cycles:", 3, cy2, 150, 20, &data->before_cycles, 0, 10000, 10, 3, "Maximum number of cycles to allow (0 = infinite)");
uiBlockEndAlign(block);
/* 'after' range */
uiDefBut(block, LABEL, 1, "After:", 155, cy, 80, 20, NULL, 0.0, 0.0, 0, 0, "Settings for cycling after last keyframe");
uiBlockBeginAlign(block);
uiDefButS(block, MENU, B_FMODIFIER_REDRAW, cyc_mode, 157,cy1,150,20, &data->after_mode, 0, 0, 0, 0, "Cycling mode to use after first keyframe");
uiDefButS(block, NUM, B_FMODIFIER_REDRAW, "Max Cycles:", 157, cy2, 150, 20, &data->after_cycles, 0, 10000, 10, 3, "Maximum number of cycles to allow (0 = infinite)");
uiBlockEndAlign(block);
}
/* --------------- */
/* draw settings for noise modifier */
static void draw_modifier__noise(uiBlock *block, FCurve *fcu, FModifier *fcm, int *yco, short *height, short width, short active, int rb_col)
{
FMod_Noise *data= (FMod_Noise *)fcm->data;
int cy= (*yco - 30), cy1= (*yco - 50), cy2= (*yco - 70);
char cyc_mode[]="Modification %t|Replace %x0|Add %x1|Subtract %x2|Multiply %x3";
/* set the height */
(*height) = 80;
/* basic settings (backdrop + some padding) */
DRAW_BACKDROP((*height));
uiDefButS(block, MENU, B_FMODIFIER_REDRAW, cyc_mode,
3, cy, 150, 20, &data->modification, 0, 0, 0, 0, "Method of modifying the existing F-Curve use before first keyframe");
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Size:",
3, cy1, 150, 20, &data->size, 0.000001, 10000.0, 0.01, 3, "");
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Strength:",
3, cy2, 150, 20, &data->strength, 0.0, 10000.0, 0.01, 3, "");
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Phase:",
155, cy1, 150, 20, &data->phase, 0.0, 100000.0, 0.1, 3, "");
uiDefButS(block, NUM, B_FMODIFIER_REDRAW, "Depth:",
155, cy2, 150, 20, &data->depth, 0, 128, 1, 3, "");
}
/* --------------- */
#define BINARYSEARCH_FRAMEEQ_THRESH 0.0001
/* Binary search algorithm for finding where to insert Envelope Data Point.
* Returns the index to insert at (data already at that index will be offset if replace is 0)
*/
static int binarysearch_fcm_envelopedata_index (FCM_EnvelopeData array[], float frame, int arraylen, short *exists)
{
int start=0, end=arraylen;
int loopbreaker= 0, maxloop= arraylen * 2;
/* initialise exists-flag first */
*exists= 0;
/* sneaky optimisations (don't go through searching process if...):
* - keyframe to be added is to be added out of current bounds
* - keyframe to be added would replace one of the existing ones on bounds
*/
if ((arraylen <= 0) || (array == NULL)) {
printf("Warning: binarysearch_fcm_envelopedata_index() encountered invalid array \n");
return 0;
}
else {
/* check whether to add before/after/on */
float framenum;
/* 'First' Point (when only one point, this case is used) */
framenum= array[0].time;
if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) {
*exists = 1;
return 0;
}
else if (frame < framenum)
return 0;
/* 'Last' Point */
framenum= array[(arraylen-1)].time;
if (IS_EQT(frame, framenum, BINARYSEARCH_FRAMEEQ_THRESH)) {
*exists= 1;
return (arraylen - 1);
}
else if (frame > framenum)
return arraylen;
}
/* most of the time, this loop is just to find where to put it
* - 'loopbreaker' is just here to prevent infinite loops
*/
for (loopbreaker=0; (start <= end) && (loopbreaker < maxloop); loopbreaker++) {
/* compute and get midpoint */
int mid = start + ((end - start) / 2); /* we calculate the midpoint this way to avoid int overflows... */
float midfra= array[mid].time;
/* check if exactly equal to midpoint */
if (IS_EQT(frame, midfra, BINARYSEARCH_FRAMEEQ_THRESH)) {
*exists = 1;
return mid;
}
/* repeat in upper/lower half */
if (frame > midfra)
start= mid + 1;
else if (frame < midfra)
end= mid - 1;
}
/* print error if loop-limit exceeded */
if (loopbreaker == (maxloop-1)) {
printf("Error: binarysearch_fcm_envelopedata_index() was taking too long \n");
// include debug info
printf("\tround = %d: start = %d, end = %d, arraylen = %d \n", loopbreaker, start, end, arraylen);
}
/* not found, so return where to place it */
return start;
}
/* callback to add new envelope data point */
// TODO: should we have a separate file for things like this?
static void fmod_envelope_addpoint_cb (bContext *C, void *fcm_dv, void *dummy)
{
Scene *scene= CTX_data_scene(C);
FMod_Envelope *env= (FMod_Envelope *)fcm_dv;
FCM_EnvelopeData *fedn;
FCM_EnvelopeData fed;
/* init template data */
fed.min= -1.0f;
fed.max= 1.0f;
fed.time= (float)scene->r.cfra; // XXX make this int for ease of use?
fed.f1= fed.f2= 0;
/* check that no data exists for the current frame... */
if (env->data) {
short exists = -1;
int i= binarysearch_fcm_envelopedata_index(env->data, (float)(scene->r.cfra), env->totvert, &exists);
/* binarysearch_...() will set exists by default to 0, so if it is non-zero, that means that the point exists already */
if (exists)
return;
/* add new */
fedn= MEM_callocN((env->totvert+1)*sizeof(FCM_EnvelopeData), "FCM_EnvelopeData");
/* add the points that should occur before the point to be pasted */
if (i > 0)
memcpy(fedn, env->data, i*sizeof(FCM_EnvelopeData));
/* add point to paste at index i */
*(fedn + i)= fed;
/* add the points that occur after the point to be pasted */
if (i < env->totvert)
memcpy(fedn+i+1, env->data+i, (env->totvert-i)*sizeof(FCM_EnvelopeData));
/* replace (+ free) old with new */
MEM_freeN(env->data);
env->data= fedn;
env->totvert++;
}
else {
env->data= MEM_callocN(sizeof(FCM_EnvelopeData), "FCM_EnvelopeData");
*(env->data)= fed;
env->totvert= 1;
}
}
/* callback to remove envelope data point */
// TODO: should we have a separate file for things like this?
static void fmod_envelope_deletepoint_cb (bContext *C, void *fcm_dv, void *ind_v)
{
FMod_Envelope *env= (FMod_Envelope *)fcm_dv;
FCM_EnvelopeData *fedn;
int index= GET_INT_FROM_POINTER(ind_v);
/* check that no data exists for the current frame... */
if (env->totvert > 1) {
/* allocate a new smaller array */
fedn= MEM_callocN(sizeof(FCM_EnvelopeData)*(env->totvert-1), "FCM_EnvelopeData");
memcpy(fedn, &env->data, sizeof(FCM_EnvelopeData)*(index));
memcpy(&fedn[index], &env->data[index+1], sizeof(FCM_EnvelopeData)*(env->totvert-index-1));
/* free old array, and set the new */
MEM_freeN(env->data);
env->data= fedn;
env->totvert--;
}
else {
/* just free array, since the only vert was deleted */
if (env->data)
MEM_freeN(env->data);
env->totvert= 0;
}
}
/* draw settings for envelope modifier */
static void draw_modifier__envelope(uiBlock *block, FCurve *fcu, FModifier *fcm, int *yco, short *height, short width, short active, int rb_col)
{
FMod_Envelope *env= (FMod_Envelope *)fcm->data;
FCM_EnvelopeData *fed;
uiBut *but;
int cy= (*yco - 28);
int i;
/* set the height:
* - basic settings + variable height from envelope controls
*/
(*height) = 115 + (35 * env->totvert);
/* basic settings (backdrop + general settings + some padding) */
DRAW_BACKDROP((*height));
/* General Settings */
uiDefBut(block, LABEL, 1, "Envelope:", 10, cy, 100, 20, NULL, 0.0, 0.0, 0, 0, "Settings for cycling before first keyframe");
cy -= 20;
uiBlockBeginAlign(block);
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Reference Val:", 10, cy, 300, 20, &env->midval, -UI_FLT_MAX, UI_FLT_MAX, 10, 3, "");
cy -= 20;
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Min:", 10, cy, 150, 20, &env->min, -UI_FLT_MAX, env->max, 10, 3, "Minimum value (relative to Reference Value) that is used as the 'normal' minimum value");
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Max:", 160, cy, 150, 20, &env->max, env->min, UI_FLT_MAX, 10, 3, "Maximum value (relative to Reference Value) that is used as the 'normal' maximum value");
cy -= 35;
uiBlockEndAlign(block);
/* Points header */
uiDefBut(block, LABEL, 1, "Control Points:", 10, cy, 150, 20, NULL, 0.0, 0.0, 0, 0, "");
but= uiDefBut(block, BUT, B_FMODIFIER_REDRAW, "Add Point", 160,cy,150,19, NULL, 0, 0, 0, 0, "Adds a new control-point to the envelope on the current frame");
uiButSetFunc(but, fmod_envelope_addpoint_cb, env, NULL);
cy -= 35;
/* Points List */
for (i=0, fed=env->data; i < env->totvert; i++, fed++) {
uiBlockBeginAlign(block);
but=uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Fra:", 2, cy, 90, 20, &fed->time, -UI_FLT_MAX, UI_FLT_MAX, 10, 1, "Frame that envelope point occurs");
uiButSetFunc(but, validate_fmodifier_cb, fcu, fcm);
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Min:", 92, cy, 100, 20, &fed->min, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, "Minimum bound of envelope at this point");
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "Max:", 192, cy, 100, 20, &fed->max, -UI_FLT_MAX, UI_FLT_MAX, 10, 2, "Maximum bound of envelope at this point");
but= uiDefIconBut(block, BUT, B_FMODIFIER_REDRAW, ICON_X, 292, cy, 18, 20, NULL, 0.0, 0.0, 0.0, 0.0, "Delete envelope control point");
uiButSetFunc(but, fmod_envelope_deletepoint_cb, env, SET_INT_IN_POINTER(i));
uiBlockBeginAlign(block);
cy -= 25;
}
}
/* --------------- */
/* draw settings for limits modifier */
static void draw_modifier__limits(uiBlock *block, FCurve *fcu, FModifier *fcm, int *yco, short *height, short width, short active, int rb_col)
{
FMod_Limits *data= (FMod_Limits *)fcm->data;
const int togButWidth = 50;
const int textButWidth = ((width/2)-togButWidth);
/* set the height */
(*height) = 60;
/* basic settings (backdrop + some padding) */
DRAW_BACKDROP((*height));
/* Draw Pairs of LimitToggle+LimitValue */
uiBlockBeginAlign(block);
uiDefButBitI(block, TOGBUT, FCM_LIMIT_XMIN, B_FMODIFIER_REDRAW, "xMin", 5, *yco-30, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum x value");
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 5+togButWidth, *yco-30, (textButWidth-5), 18, &data->rect.xmin, -UI_FLT_MAX, UI_FLT_MAX, 0.1,0.5,"Lowest x value to allow");
uiBlockEndAlign(block);
uiBlockBeginAlign(block);
uiDefButBitI(block, TOGBUT, FCM_LIMIT_XMAX, B_FMODIFIER_REDRAW, "XMax", 5+(width-(textButWidth-5)-togButWidth), *yco-30, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum x value");
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 5+(width-textButWidth-5), *yco-30, (textButWidth-5), 18, &data->rect.xmax, -UI_FLT_MAX, UI_FLT_MAX, 0.1,0.5,"Highest x value to allow");
uiBlockEndAlign(block);
uiBlockBeginAlign(block);
uiDefButBitI(block, TOGBUT, FCM_LIMIT_YMIN, B_FMODIFIER_REDRAW, "yMin", 5, *yco-52, togButWidth, 18, &data->flag, 0, 24, 0, 0, "Use minimum y value");
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 5+togButWidth, *yco-52, (textButWidth-5), 18, &data->rect.ymin, -UI_FLT_MAX, UI_FLT_MAX, 0.1,0.5,"Lowest y value to allow");
uiBlockEndAlign(block);
uiBlockBeginAlign(block);
uiDefButBitI(block, TOGBUT, FCM_LIMIT_YMAX, B_FMODIFIER_REDRAW, "YMax", 5+(width-(textButWidth-5)-togButWidth), *yco-52, 50, 18, &data->flag, 0, 24, 0, 0, "Use maximum y value");
uiDefButF(block, NUM, B_FMODIFIER_REDRAW, "", 5+(width-textButWidth-5), *yco-52, (textButWidth-5), 18, &data->rect.ymax, -UI_FLT_MAX, UI_FLT_MAX, 0.1,0.5,"Highest y value to allow");
uiBlockEndAlign(block);
}
/* --------------- */
static void graph_panel_modifier_draw(uiBlock *block, FCurve *fcu, FModifier *fcm, int *yco)
{
FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm);
uiBut *but;
short active= (fcm->flag & FMODIFIER_FLAG_ACTIVE);
short width= 314;
short height = 0;
int rb_col;
/* draw header */
{
uiBlockSetEmboss(block, UI_EMBOSSN);
/* rounded header */
rb_col= (active)?-20:20;
but= uiDefBut(block, ROUNDBOX, B_REDR, "", 0, *yco-2, width, 24, NULL, 5.0, 0.0, 15.0, (float)(rb_col-20), "");
/* expand */
uiDefIconButBitS(block, ICONTOG, FMODIFIER_FLAG_EXPANDED, B_REDR, ICON_TRIA_RIGHT, 5, *yco-1, 20, 20, &fcm->flag, 0.0, 0.0, 0, 0, "Modifier is expanded.");
/* checkbox for 'active' status (for now) */
but= uiDefIconButBitS(block, ICONTOG, FMODIFIER_FLAG_ACTIVE, B_REDR, ICON_RADIOBUT_OFF, 25, *yco-1, 20, 20, &fcm->flag, 0.0, 0.0, 0, 0, "Modifier is active one.");
uiButSetFunc(but, activate_fmodifier_cb, fcu, fcm);
/* name */
if (fmi)
uiDefBut(block, LABEL, 1, fmi->name, 10+40, *yco, 150, 20, NULL, 0.0, 0.0, 0, 0, "F-Curve Modifier Type. Click to make modifier active one.");
else
uiDefBut(block, LABEL, 1, "<Unknown Modifier>", 10+40, *yco, 150, 20, NULL, 0.0, 0.0, 0, 0, "F-Curve Modifier Type. Click to make modifier active one.");
/* 'mute' button */
uiDefIconButBitS(block, ICONTOG, FMODIFIER_FLAG_MUTED, B_REDR, ICON_MUTE_IPO_OFF, 10+(width-60), *yco-1, 20, 20, &fcm->flag, 0.0, 0.0, 0, 0, "Modifier is temporarily muted (not evaluated).");
/* delete button */
but= uiDefIconBut(block, BUT, B_REDR, ICON_X, 10+(width-30), *yco, 19, 19, NULL, 0.0, 0.0, 0.0, 0.0, "Delete F-Curve Modifier.");
uiButSetFunc(but, delete_fmodifier_cb, fcu, fcm);
uiBlockSetEmboss(block, UI_EMBOSS);
}
/* when modifier is expanded, draw settings */
if (fcm->flag & FMODIFIER_FLAG_EXPANDED) {
/* draw settings for individual modifiers */
switch (fcm->type) {
case FMODIFIER_TYPE_GENERATOR: /* Generator */
draw_modifier__generator(block, fcu, fcm, yco, &height, width, active, rb_col);
break;
case FMODIFIER_TYPE_CYCLES: /* Cycles */
draw_modifier__cycles(block, fcu, fcm, yco, &height, width, active, rb_col);
break;
case FMODIFIER_TYPE_ENVELOPE: /* Envelope */
draw_modifier__envelope(block, fcu, fcm, yco, &height, width, active, rb_col);
break;
case FMODIFIER_TYPE_LIMITS: /* Limits */
draw_modifier__limits(block, fcu, fcm, yco, &height, width, active, rb_col);
break;
case FMODIFIER_TYPE_NOISE: /* Noise */
draw_modifier__noise(block, fcu, fcm, yco, &height, width, active, rb_col);
break;
default: /* unknown type */
height= 96;
//DRAW_BACKDROP(height); // XXX buggy...
break;
}
}
/* adjust height for new to start */
(*yco) -= (height + 27);
}
static void graph_panel_modifiers(const bContext *C, Panel *pa)
{
bAnimListElem *ale;
FCurve *fcu;
FModifier *fcm;
uiLayout *col, *row;
uiBlock *block;
int yco= 190;
if(!graph_panel_context(C, &ale, &fcu))
if (!graph_panel_context(C, &ale, &fcu))
return;
block= uiLayoutFreeBlock(pa->layout);
block= uiLayoutGetBlock(pa->layout);
uiBlockSetHandleFunc(block, do_graph_region_modifier_buttons, NULL);
/* 'add modifier' button at top of panel */
// XXX for now, this will be a operator button which calls a temporary 'add modifier' operator
uiDefButO(block, BUT, "GRAPHEDIT_OT_fmodifier_add", WM_OP_INVOKE_REGION_WIN, "Add Modifier", 10, 225, 150, 20, "Adds a new F-Curve Modifier for the active F-Curve");
{
row= uiLayoutRow(pa->layout, 0);
block= uiLayoutGetBlock(row);
// XXX for now, this will be a operator button which calls a temporary 'add modifier' operator
uiDefButO(block, BUT, "GRAPH_OT_fmodifier_add", WM_OP_INVOKE_REGION_WIN, "Add Modifier", 10, 0, 150, 20, "Adds a new F-Curve Modifier for the active F-Curve");
}
/* draw each modifier */
for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next)
graph_panel_modifier_draw(block, fcu, fcm, &yco);
for (fcm= fcu->modifiers.first; fcm; fcm= fcm->next) {
col= uiLayoutColumn(pa->layout, 1);
ANIM_uiTemplate_fmodifier_draw(col, ale->id, &fcu->modifiers, fcm);
}
MEM_freeN(ale);
}
/* ******************* general ******************************** */
/* Find 'active' F-Curve. It must be editable, since that's the purpose of these buttons (subject to change).
* We return the 'wrapper' since it contains valuable context info (about hierarchy), which will need to be freed
* when the caller is done with it.
*/
// TODO: move this to anim api with another name?
bAnimListElem *get_active_fcurve_channel (bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
int filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_ACTIVE | ANIMFILTER_CURVESONLY);
int items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* We take the first F-Curve only, since some other ones may have had 'active' flag set
* if they were from linked data.
*/
if (items) {
bAnimListElem *ale= (bAnimListElem *)anim_data.first;
/* remove first item from list, then free the rest of the list and return the stored one */
BLI_remlink(&anim_data, ale);
BLI_freelistN(&anim_data);
return ale;
}
/* no active F-Curve */
return NULL;
}
void graph_buttons_register(ARegionType *art)
{
PanelType *pt;
@ -1066,10 +437,10 @@ static int graph_properties(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_properties(wmOperatorType *ot)
void GRAPH_OT_properties(wmOperatorType *ot)
{
ot->name= "Properties";
ot->idname= "GRAPHEDIT_OT_properties";
ot->idname= "GRAPH_OT_properties";
ot->exec= graph_properties;
ot->poll= ED_operator_ipo_active; // xxx

@ -835,12 +835,12 @@ void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGri
*/
for (ale=anim_data.first; ale; ale=ale->next) {
FCurve *fcu= (FCurve *)ale->key_data;
FModifier *fcm= fcurve_find_active_modifier(fcu);
//Object *nob= ANIM_nla_mapping_get(ac, ale);
FModifier *fcm= find_active_fmodifier(&fcu->modifiers);
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
/* map keyframes for drawing if scaled F-Curve */
//if (nob)
// ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 0);
if (adt)
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0);
/* draw curve:
* - curve line may be result of one or more destructive modifiers or just the raw data,
@ -918,8 +918,8 @@ void graph_draw_curves (bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGri
}
/* undo mapping of keyframes for drawing if scaled F-Curve */
//if (nob)
// ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 0);
if (adt)
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0);
}
/* free list of curves */
@ -1206,6 +1206,17 @@ void graph_draw_channel_names(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar)
expand = ICON_TRIA_RIGHT;
}
/* for now, 'special' (i.e. in front of name) is used to show visibility status */
if (agrp->flag & AGRP_NOTVISIBLE)
special= ICON_CHECKBOX_DEHLT;
else
special= ICON_CHECKBOX_HLT;
if (agrp->flag & AGRP_MUTED)
mute = ICON_MUTE_IPO_ON;
else
mute = ICON_MUTE_IPO_OFF;
if (EDITABLE_AGRP(agrp))
protect = ICON_UNLOCKED;
else

@ -67,11 +67,13 @@
#include "BKE_fcurve.h"
#include "BKE_key.h"
#include "BKE_material.h"
#include "BKE_nla.h"
#include "BKE_object.h"
#include "BKE_context.h"
#include "BKE_report.h"
#include "BKE_utildefines.h"
#include "UI_interface.h"
#include "UI_view2d.h"
#include "ED_anim_api.h"
@ -114,16 +116,16 @@ void get_graph_keyframe_extents (bAnimContext *ac, float *xmin, float *xmax, flo
if (anim_data.first) {
/* go through channels, finding max extents */
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= NULL; //ANIM_nla_mapping_get(ac, ale);
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
FCurve *fcu= (FCurve *)ale->key_data;
float txmin, txmax, tymin, tymax;
/* get range and apply necessary scaling before */
calc_fcurve_bounds(fcu, &txmin, &txmax, &tymin, &tymax);
if (nob) {
txmin= get_action_frame_inv(nob, txmin);
txmax= get_action_frame_inv(nob, txmax);
if (adt) {
txmin= BKE_nla_tweakedit_remap(adt, txmin, NLATIME_CONVERT_MAP);
txmax= BKE_nla_tweakedit_remap(adt, txmax, NLATIME_CONVERT_MAP);
}
/* try to set cur using these values, if they're more extreme than previously set values */
@ -180,15 +182,15 @@ static int graphkeys_previewrange_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_previewrange_set (wmOperatorType *ot)
void GRAPH_OT_previewrange_set (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Auto-Set Preview Range";
ot->idname= "GRAPHEDIT_OT_previewrange_set";
ot->idname= "GRAPH_OT_previewrange_set";
/* api callbacks */
ot->exec= graphkeys_previewrange_exec;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_visible_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -227,15 +229,15 @@ static int graphkeys_viewall_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_view_all (wmOperatorType *ot)
void GRAPH_OT_view_all (wmOperatorType *ot)
{
/* identifiers */
ot->name= "View All";
ot->idname= "GRAPHEDIT_OT_view_all";
ot->idname= "GRAPH_OT_view_all";
/* api callbacks */
ot->exec= graphkeys_viewall_exec;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_visible_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -271,6 +273,7 @@ static void create_ghost_curves (bAnimContext *ac, int start, int end)
for (ale= anim_data.first; ale; ale= ale->next) {
FCurve *fcu= (FCurve *)ale->key_data;
FCurve *gcu= MEM_callocN(sizeof(FCurve), "Ghost FCurve");
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
ChannelDriver *driver= fcu->driver;
FPoint *fpt;
int cfra;
@ -286,8 +289,10 @@ static void create_ghost_curves (bAnimContext *ac, int start, int end)
/* use the sampling callback at 1-frame intervals from start to end frames */
for (cfra= start; cfra <= end; cfra++, fpt++) {
fpt->vec[0]= (float)cfra;
fpt->vec[1]= fcurve_samplingcb_evalcurve(fcu, NULL, (float)cfra);
float cfrae= BKE_nla_tweakedit_remap(adt, cfra, NLATIME_CONVERT_UNMAP);
fpt->vec[0]= cfrae;
fpt->vec[1]= fcurve_samplingcb_evalcurve(fcu, NULL, cfrae);
}
/* set color of ghost curve
@ -334,16 +339,16 @@ static int graphkeys_create_ghostcurves_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_ghost_curves_create (wmOperatorType *ot)
void GRAPH_OT_ghost_curves_create (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Create Ghost Curves";
ot->idname= "GRAPHEDIT_OT_ghost_curves_create";
ot->idname= "GRAPH_OT_ghost_curves_create";
ot->description= "Create snapshot (Ghosts) of selected F-Curves as background aid for active Graph Editor.";
/* api callbacks */
ot->exec= graphkeys_create_ghostcurves_exec;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_visible_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -377,16 +382,16 @@ static int graphkeys_clear_ghostcurves_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_ghost_curves_clear (wmOperatorType *ot)
void GRAPH_OT_ghost_curves_clear (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Create Ghost Curves";
ot->idname= "GRAPHEDIT_OT_ghost_curves_clear";
ot->idname= "GRAPH_OT_ghost_curves_clear";
ot->description= "Clear F-Curve snapshots (Ghosts) for active Graph Editor.";
/* api callbacks */
ot->exec= graphkeys_clear_ghostcurves_exec;
ot->poll= ED_operator_areaactive;
ot->poll= ED_operator_ipo_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -395,7 +400,103 @@ void GRAPHEDIT_OT_ghost_curves_clear (wmOperatorType *ot)
/* ************************************************************************** */
/* GENERAL STUFF */
// TODO: insertkey
/* ******************** Insert Keyframes Operator ************************* */
/* defines for insert keyframes tool */
EnumPropertyItem prop_graphkeys_insertkey_types[] = {
{1, "ALL", 0, "All Channels", ""},
{2, "SEL", 0, "Only Selected Channels", ""},
{0, NULL, 0, NULL, NULL}
};
/* this function is responsible for snapping keyframes to frame-times */
static void insert_graph_keys(bAnimContext *ac, short mode)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
Scene *scene= ac->scene;
float cfra= (float)CFRA;
short flag = 0;
/* filter data */
filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
if (mode == 2) filter |= ANIMFILTER_SEL;
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* init keyframing flag */
if (IS_AUTOKEY_FLAG(AUTOMATKEY)) flag |= INSERTKEY_MATRIX;
if (IS_AUTOKEY_FLAG(INSERTNEEDED)) flag |= INSERTKEY_NEEDED;
// if (IS_AUTOKEY_MODE(EDITKEYS)) flag |= INSERTKEY_REPLACE;
/* insert keyframes */
for (ale= anim_data.first; ale; ale= ale->next) {
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
FCurve *fcu= (FCurve *)ale->key_data;
/* adjust current frame for NLA-mapping */
if (adt)
cfra= BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
else
cfra= (float)CFRA;
/* if there's an id */
if (ale->id)
insert_keyframe(ale->id, NULL, ((fcu->grp)?(fcu->grp->name):(NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
else
insert_vert_fcurve(fcu, cfra, fcu->curval, 0);
}
BLI_freelistN(&anim_data);
}
/* ------------------- */
static int graphkeys_insertkey_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
short mode;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
if (ac.datatype == ANIMCONT_GPENCIL)
return OPERATOR_CANCELLED;
/* which channels to affect? */
mode= RNA_enum_get(op->ptr, "type");
/* insert keyframes */
insert_graph_keys(&ac, mode);
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
return OPERATOR_FINISHED;
}
void GRAPH_OT_insert_keyframe (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Insert Keyframes";
ot->idname= "GRAPH_OT_insert_keyframe";
/* api callbacks */
ot->invoke= WM_menu_invoke;
ot->exec= graphkeys_insertkey_exec;
ot->poll= graphop_editable_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* id-props */
RNA_def_enum(ot->srna, "type", prop_graphkeys_insertkey_types, 0, "Type", "");
}
/* ******************** Click-Insert Keyframes Operator ************************* */
@ -403,6 +504,7 @@ static int graphkeys_click_insert_exec (bContext *C, wmOperator *op)
{
bAnimContext ac;
bAnimListElem *ale;
AnimData *adt;
float frame, val;
/* get animation context */
@ -420,14 +522,18 @@ static int graphkeys_click_insert_exec (bContext *C, wmOperator *op)
frame= RNA_float_get(op->ptr, "frame");
val= RNA_float_get(op->ptr, "value");
/* apply inverse NLA-mapping to frame to get correct time in un-scaled action */
adt= ANIM_nla_mapping_get(&ac, ale);
frame= BKE_nla_tweakedit_remap(adt, frame, NLATIME_CONVERT_UNMAP);
/* insert keyframe on the specified frame + value */
insert_vert_fcurve((FCurve *)ale->data, frame, val, 0);
/* free temp data */
MEM_freeN(ale);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
/* done */
return OPERATOR_FINISHED;
@ -461,16 +567,16 @@ static int graphkeys_click_insert_invoke (bContext *C, wmOperator *op, wmEvent *
return graphkeys_click_insert_exec(C, op);
}
void GRAPHEDIT_OT_keyframes_click_insert (wmOperatorType *ot)
void GRAPH_OT_click_insert (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Click-Insert Keyframes";
ot->idname= "GRAPHEDIT_OT_keyframes_click_insert";
ot->idname= "GRAPH_OT_click_insert";
/* api callbacks */
ot->invoke= graphkeys_click_insert_invoke;
ot->exec= graphkeys_click_insert_exec;
ot->poll= ED_operator_areaactive; // XXX active + editable poll
ot->poll= graphop_active_fcurve_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -538,21 +644,19 @@ static int graphkeys_copy_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* just return - no operator needed here (no changes) */
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_keyframes_copy (wmOperatorType *ot)
void GRAPH_OT_copy (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Copy Keyframes";
ot->idname= "GRAPHEDIT_OT_keyframes_copy";
ot->idname= "GRAPH_OT_copy";
/* api callbacks */
ot->exec= graphkeys_copy_exec;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_editable_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -577,21 +681,21 @@ static int graphkeys_paste_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_keyframes_paste (wmOperatorType *ot)
void GRAPH_OT_paste (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Paste Keyframes";
ot->idname= "GRAPHEDIT_OT_keyframes_paste";
ot->idname= "GRAPH_OT_paste";
/* api callbacks */
ot->exec= graphkeys_paste_exec;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_editable_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -634,8 +738,8 @@ static int graphkeys_duplicate_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
return OPERATOR_FINISHED;
}
@ -650,16 +754,16 @@ static int graphkeys_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *even
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_keyframes_duplicate (wmOperatorType *ot)
void GRAPH_OT_duplicate (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Duplicate Keyframes";
ot->idname= "GRAPHEDIT_OT_keyframes_duplicate";
ot->idname= "GRAPH_OT_duplicate";
/* api callbacks */
ot->invoke= graphkeys_duplicate_invoke;
ot->exec= graphkeys_duplicate_exec;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_editable_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -705,22 +809,22 @@ static int graphkeys_delete_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_keyframes_delete (wmOperatorType *ot)
void GRAPH_OT_delete (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Delete Keyframes";
ot->idname= "GRAPHEDIT_OT_keyframes_delete";
ot->idname= "GRAPH_OT_delete";
/* api callbacks */
ot->invoke= WM_operator_confirm;
ot->exec= graphkeys_delete_exec;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_editable_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -766,22 +870,22 @@ static int graphkeys_clean_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_keyframes_clean (wmOperatorType *ot)
void GRAPH_OT_clean (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Clean Keyframes";
ot->idname= "GRAPHEDIT_OT_keyframes_clean";
ot->idname= "GRAPH_OT_clean";
/* api callbacks */
//ot->invoke= // XXX we need that number popup for this!
ot->exec= graphkeys_clean_exec;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_editable_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -847,22 +951,23 @@ static int graphkeys_bake_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframes have changed */
// NOTE: some distinction between order/number of keyframes and type should be made?
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_keyframes_bake (wmOperatorType *ot)
void GRAPH_OT_bake (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Bake Curve";
ot->idname= "GRAPHEDIT_OT_keyframes_bake";
ot->idname= "GRAPH_OT_bake";
/* api callbacks */
ot->invoke= WM_operator_confirm; // FIXME...
ot->exec= graphkeys_bake_exec;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_editable_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -973,21 +1078,21 @@ static int graphkeys_sample_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_keyframes_sample (wmOperatorType *ot)
void GRAPH_OT_sample (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Sample Keyframes";
ot->idname= "GRAPHEDIT_OT_keyframes_sample";
ot->idname= "GRAPH_OT_sample";
/* api callbacks */
ot->exec= graphkeys_sample_exec;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_editable_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1047,22 +1152,22 @@ static int graphkeys_expo_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframe properties have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_keyframes_extrapolation_type (wmOperatorType *ot)
void GRAPH_OT_extrapolation_type (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Set Keyframe Extrapolation";
ot->idname= "GRAPHEDIT_OT_keyframes_extrapolation_type";
ot->idname= "GRAPH_OT_extrapolation_type";
/* api callbacks */
ot->invoke= WM_menu_invoke;
ot->exec= graphkeys_expo_exec;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_editable_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1115,22 +1220,22 @@ static int graphkeys_ipo_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframe properties have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_keyframes_interpolation_type (wmOperatorType *ot)
void GRAPH_OT_interpolation_type (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Set Keyframe Interpolation";
ot->idname= "GRAPHEDIT_OT_keyframes_interpolation_type";
ot->idname= "GRAPH_OT_interpolation_type";
/* api callbacks */
ot->invoke= WM_menu_invoke;
ot->exec= graphkeys_ipo_exec;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_editable_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1203,21 +1308,21 @@ static int graphkeys_handletype_exec(bContext *C, wmOperator *op)
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_PROP, NULL);
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_keyframes_handletype (wmOperatorType *ot)
void GRAPH_OT_handletype (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Set Keyframe Handle Type";
ot->idname= "GRAPHEDIT_OT_keyframes_handletype";
ot->idname= "GRAPH_OT_handletype";
/* api callbacks */
ot->invoke= WM_menu_invoke;
ot->exec= graphkeys_handletype_exec;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_editable_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1298,15 +1403,15 @@ static int graphkeys_euler_filter_exec (bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
void GRAPHEDIT_OT_keyframes_euler_filter (wmOperatorType *ot)
void GRAPH_OT_euler_filter (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Euler Filter";
ot->idname= "GRAPHEDIT_OT_keyframes_euler_filter";
ot->idname= "GRAPH_OT_euler_filter";
/* api callbacks */
ot->exec= graphkeys_euler_filter_exec;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_editable_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1314,10 +1419,10 @@ void GRAPHEDIT_OT_keyframes_euler_filter (wmOperatorType *ot)
#endif // XXX this is not ready for the primetime yet
/* ***************** Snap Current Frame Operator *********************** */
/* ***************** Jump to Selected Frames Operator *********************** */
/* snap current-frame indicator to 'average time' of selected keyframe */
static int graphkeys_cfrasnap_exec(bContext *C, wmOperator *op)
static int graphkeys_framejump_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
ListBase anim_data= {NULL, NULL};
@ -1333,11 +1438,21 @@ static int graphkeys_cfrasnap_exec(bContext *C, wmOperator *op)
memset(&bed, 0, sizeof(BeztEditData));
/* loop over action data, averaging values */
filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE| ANIMFILTER_CURVESONLY);
filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
for (ale= anim_data.first; ale; ale= ale->next)
ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
for (ale= anim_data.first; ale; ale= ale->next) {
AnimData *adt= ANIM_nla_mapping_get(&ac, ale);
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
}
else
ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_calc_average, NULL);
}
BLI_freelistN(&anim_data);
@ -1353,15 +1468,15 @@ static int graphkeys_cfrasnap_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_keyframes_cfrasnap (wmOperatorType *ot)
void GRAPH_OT_frame_jump (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Snap Current Frame to Keys";
ot->idname= "GRAPHEDIT_OT_keyframes_cfrasnap";
ot->name= "Jump to Frame";
ot->idname= "GRAPH_OT_frame_jump";
/* api callbacks */
ot->exec= graphkeys_cfrasnap_exec;
ot->poll= ED_operator_areaactive;
ot->exec= graphkeys_framejump_exec;
ot->poll= graphop_visible_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1405,12 +1520,12 @@ static void snap_graph_keys(bAnimContext *ac, short mode)
/* snap keyframes */
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= ANIM_nla_mapping_get(ac, ale);
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
if (nob) {
ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1);
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
}
else
ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
@ -1438,22 +1553,22 @@ static int graphkeys_snap_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_keyframes_snap (wmOperatorType *ot)
void GRAPH_OT_snap (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Snap Keys";
ot->idname= "GRAPHEDIT_OT_keyframes_snap";
ot->idname= "GRAPH_OT_snap";
/* api callbacks */
ot->invoke= WM_menu_invoke;
ot->exec= graphkeys_snap_exec;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_editable_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1466,10 +1581,10 @@ void GRAPHEDIT_OT_keyframes_snap (wmOperatorType *ot)
/* defines for mirror keyframes tool */
EnumPropertyItem prop_graphkeys_mirror_types[] = {
{GRAPHKEYS_MIRROR_CFRA, "CFRA", 0, "Current frame", ""},
{GRAPHKEYS_MIRROR_YAXIS, "YAXIS", 0, "Vertical Axis", ""},
{GRAPHKEYS_MIRROR_XAXIS, "XAXIS", 0, "Horizontal Axis", ""},
{GRAPHKEYS_MIRROR_MARKER, "MARKER", 0, "First Selected Marker", ""},
{GRAPHKEYS_MIRROR_CFRA, "CFRA", 0, "By Times over Current frame", ""},
{GRAPHKEYS_MIRROR_YAXIS, "YAXIS", 0, "By Times over Time=0", ""},
{GRAPHKEYS_MIRROR_XAXIS, "XAXIS", 0, "By Values over Value=0", ""},
{GRAPHKEYS_MIRROR_MARKER, "MARKER", 0, "By Times over First Selected Marker", ""},
{0, NULL, 0, NULL, NULL}
};
@ -1516,12 +1631,12 @@ static void mirror_graph_keys(bAnimContext *ac, short mode)
/* mirror keyframes */
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= ANIM_nla_mapping_get(ac, ale);
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
if (nob) {
ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1);
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
}
else
ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_fcurve);
@ -1549,22 +1664,22 @@ static int graphkeys_mirror_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_keyframes_mirror (wmOperatorType *ot)
void GRAPH_OT_mirror (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Mirror Keys";
ot->idname= "GRAPHEDIT_OT_keyframes_mirror";
ot->idname= "GRAPH_OT_mirror";
/* api callbacks */
ot->invoke= WM_menu_invoke;
ot->exec= graphkeys_mirror_exec;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_editable_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1603,21 +1718,21 @@ static int graphkeys_smooth_exec(bContext *C, wmOperator *op)
/* validate keyframes after editing */
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_VALUES);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_keyframes_smooth (wmOperatorType *ot)
void GRAPH_OT_smooth (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Smooth Keys";
ot->idname= "GRAPHEDIT_OT_keyframes_smooth";
ot->idname= "GRAPH_OT_smooth";
/* api callbacks */
ot->exec= graphkeys_smooth_exec;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_editable_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@ -1626,7 +1741,35 @@ void GRAPHEDIT_OT_keyframes_smooth (wmOperatorType *ot)
/* ************************************************************************** */
/* F-CURVE MODIFIERS */
/* ******************** Add F-Curve Modifier Operator *********************** */
/* ******************** Add F-Modifier Operator *********************** */
/* present a special customised popup menu for this, with some filtering */
static int graph_fmodifier_add_invoke (bContext *C, wmOperator *op, wmEvent *event)
{
uiPopupMenu *pup;
uiLayout *layout;
int i;
pup= uiPupMenuBegin(C, "Add F-Curve Modifier", 0);
layout= uiPupMenuLayout(pup);
/* start from 1 to skip the 'Invalid' modifier type */
for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
FModifierTypeInfo *fmi= get_fmodifier_typeinfo(i);
/* check if modifier is valid for this context */
if (fmi == NULL)
continue;
/* add entry to add this type of modifier */
uiItemEnumO(layout, fmi->name, 0, "GRAPH_OT_fmodifier_add", "type", i);
}
uiItemS(layout);
uiPupMenuEnd(C, pup);
return OPERATOR_CANCELLED;
}
static int graph_fmodifier_add_exec(bContext *C, wmOperator *op)
{
@ -1654,9 +1797,9 @@ static int graph_fmodifier_add_exec(bContext *C, wmOperator *op)
type= RNA_enum_get(op->ptr, "type");
/* add F-Modifier of specified type to active F-Curve, and make it the active one */
fcm= fcurve_add_modifier(fcu, type);
fcm= add_fmodifier(&fcu->modifiers, type);
if (fcm)
fcurve_set_active_modifier(fcu, fcm);
set_active_fmodifier(&fcu->modifiers, fcm);
else {
BKE_report(op->reports, RPT_ERROR, "Modifier couldn't be added. See console for details.");
return OPERATOR_CANCELLED;
@ -1666,21 +1809,22 @@ static int graph_fmodifier_add_exec(bContext *C, wmOperator *op)
ANIM_editkeyframes_refresh(&ac);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
// FIXME: this really isn't the best description for it...
WM_event_add_notifier(C, NC_ANIMATION, NULL);
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_fmodifier_add (wmOperatorType *ot)
void GRAPH_OT_fmodifier_add (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Add F-Curve Modifier";
ot->idname= "GRAPHEDIT_OT_fmodifier_add";
ot->idname= "GRAPH_OT_fmodifier_add";
/* api callbacks */
ot->invoke= WM_menu_invoke;
ot->invoke= graph_fmodifier_add_invoke;
ot->exec= graph_fmodifier_add_exec;
ot->poll= ED_operator_areaactive; // XXX need active F-Curve
ot->poll= graphop_active_fcurve_poll;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;

@ -43,10 +43,13 @@
#include "BKE_screen.h"
#include "ED_anim_api.h"
#include "ED_transform.h"
#include "ED_screen.h"
#include "ED_types.h"
#include "ED_util.h"
#include "RNA_access.h"
#include "WM_api.h"
#include "WM_types.h"
@ -62,76 +65,173 @@
/* ********************************************************* */
/* Menu Defines... */
/* button events */
static void graph_viewmenu(bContext *C, uiLayout *layout, void *arg_unused)
{
bScreen *sc= CTX_wm_screen(C);
ScrArea *sa= CTX_wm_area(C);
SpaceIpo *sipo= (SpaceIpo*)CTX_wm_space_data(C);
PointerRNA spaceptr;
/* retrieve state */
RNA_pointer_create(&sc->id, &RNA_SpaceGraphEditor, sipo, &spaceptr);
/* create menu */
uiItemO(layout, NULL, ICON_MENU_PANEL, "GRAPH_OT_properties");
uiItemS(layout);
uiItemR(layout, NULL, 0, &spaceptr, "show_cframe_indicator", 0, 0, 0);
if (sipo->flag & SIPO_NOHANDLES)
uiItemO(layout, "Show Handles", ICON_CHECKBOX_DEHLT, "GRAPH_OT_handles_view_toggle");
else
uiItemO(layout, "Show Handles", ICON_CHECKBOX_HLT, "GRAPH_OT_handles_view_toggle");
uiItemR(layout, NULL, 0, &spaceptr, "automerge_keyframes", 0, 0, 0);
if (sipo->flag & SIPO_DRAWTIME)
uiItemO(layout, "Show Frames", 0, "ANIM_OT_time_toggle");
else
uiItemO(layout, "Show Seconds", 0, "ANIM_OT_time_toggle");
uiItemS(layout);
uiItemO(layout, NULL, 0, "ANIM_OT_previewrange_set");
uiItemO(layout, NULL, 0, "ANIM_OT_previewrange_clear");
uiItemO(layout, NULL, 0, "GRAPH_OT_previewrange_set");
uiItemS(layout);
uiItemO(layout, NULL, 0, "GRAPH_OT_frame_jump");
uiItemO(layout, NULL, 0, "GRAPH_OT_view_all");
if (sa->full)
uiItemO(layout, NULL, 0, "SCREEN_OT_screen_full_area"); // "Tile Window", Ctrl UpArrow
else
uiItemO(layout, NULL, 0, "SCREEN_OT_screen_full_area"); // "Maximize Window", Ctrl DownArrow
}
static void graph_selectmenu(bContext *C, uiLayout *layout, void *arg_unused)
{
uiItemO(layout, NULL, 0, "GRAPH_OT_select_all_toggle");
uiItemBooleanO(layout, "Invert All", 0, "GRAPH_OT_select_all_toggle", "invert", 1);
uiItemS(layout);
uiItemO(layout, NULL, 0, "GRAPH_OT_select_border");
uiItemBooleanO(layout, "Border Axis Range", 0, "GRAPH_OT_select_border", "axis_range", 1);
uiItemS(layout);
uiItemEnumO(layout, "Columns on Selected Keys", 0, "GRAPH_OT_select_column", "mode", GRAPHKEYS_COLUMNSEL_KEYS);
uiItemEnumO(layout, "Column on Current Frame", 0, "GRAPH_OT_select_column", "mode", GRAPHKEYS_COLUMNSEL_CFRA);
uiItemEnumO(layout, "Columns on Selected Markers", 0, "GRAPH_OT_select_column", "mode", GRAPHKEYS_COLUMNSEL_MARKERS_COLUMN);
uiItemEnumO(layout, "Between Selected Markers", 0, "GRAPH_OT_select_column", "mode", GRAPHKEYS_COLUMNSEL_MARKERS_BETWEEN);
}
static void graph_channelmenu(bContext *C, uiLayout *layout, void *arg_unused)
{
uiItemO(layout, NULL, 0, "ANIM_OT_channels_setting_toggle");
uiItemO(layout, NULL, 0, "ANIM_OT_channels_setting_enable");
uiItemO(layout, NULL, 0, "ANIM_OT_channels_setting_disable");
uiItemS(layout);
uiItemO(layout, NULL, 0, "ANIM_OT_channels_editable_toggle");
uiItemS(layout);
uiItemO(layout, NULL, 0, "ANIM_OT_channels_expand");
uiItemO(layout, NULL, 0, "ANIM_OT_channels_collapse");
}
static void graph_edit_transformmenu(bContext *C, uiLayout *layout, void *arg_unused)
{
uiItemEnumO(layout, "Grab/Move", 0, "TFM_OT_transform", "mode", TFM_TIME_TRANSLATE);
uiItemEnumO(layout, "Extend", 0, "TFM_OT_transform", "mode", TFM_TIME_EXTEND);
uiItemEnumO(layout, "Scale", 0, "TFM_OT_transform", "mode", TFM_TIME_SCALE);
}
static void graph_edit_snapmenu(bContext *C, uiLayout *layout, void *arg_unused)
{
uiItemEnumO(layout, NULL, 0, "GRAPH_OT_snap", "type", GRAPHKEYS_SNAP_CFRA);
uiItemEnumO(layout, NULL, 0, "GRAPH_OT_snap", "type", GRAPHKEYS_SNAP_NEAREST_FRAME);
uiItemEnumO(layout, NULL, 0, "GRAPH_OT_snap", "type", GRAPHKEYS_SNAP_NEAREST_SECOND);
uiItemEnumO(layout, NULL, 0, "GRAPH_OT_snap", "type", GRAPHKEYS_SNAP_NEAREST_MARKER);
}
static void graph_edit_mirrormenu(bContext *C, uiLayout *layout, void *arg_unused)
{
uiItemEnumO(layout, NULL, 0, "GRAPH_OT_mirror", "type", GRAPHKEYS_MIRROR_CFRA);
uiItemEnumO(layout, NULL, 0, "GRAPH_OT_mirror", "type", GRAPHKEYS_MIRROR_YAXIS);
uiItemEnumO(layout, NULL, 0, "GRAPH_OT_mirror", "type", GRAPHKEYS_MIRROR_XAXIS);
uiItemEnumO(layout, NULL, 0, "GRAPH_OT_mirror", "type", GRAPHKEYS_MIRROR_MARKER);
}
static void graph_edit_handlesmenu(bContext *C, uiLayout *layout, void *arg_unused)
{
uiItemEnumO(layout, NULL, 0, "GRAPH_OT_handle_type", "type", HD_FREE);
uiItemEnumO(layout, NULL, 0, "GRAPH_OT_handle_type", "type", HD_AUTO);
uiItemEnumO(layout, NULL, 0, "GRAPH_OT_handle_type", "type", HD_VECT);
uiItemEnumO(layout, NULL, 0, "GRAPH_OT_handle_type", "type", HD_ALIGN);
uiItemEnumO(layout, NULL, 0, "GRAPH_OT_handle_type", "type", HD_AUTO_ANIM); // xxx?
}
static void graph_edit_ipomenu(bContext *C, uiLayout *layout, void *arg_unused)
{
uiItemEnumO(layout, NULL, 0, "GRAPH_OT_interpolation_type", "type", BEZT_IPO_CONST);
uiItemEnumO(layout, NULL, 0, "GRAPH_OT_interpolation_type", "type", BEZT_IPO_LIN);
uiItemEnumO(layout, NULL, 0, "GRAPH_OT_interpolation_type", "type", BEZT_IPO_BEZ);
}
static void graph_edit_expomenu(bContext *C, uiLayout *layout, void *arg_unused)
{
uiItemEnumO(layout, NULL, 0, "GRAPH_OT_extrapolation_type", "type", FCURVE_EXTRAPOLATE_CONSTANT);
uiItemEnumO(layout, NULL, 0, "GRAPH_OT_extrapolation_type", "type", FCURVE_EXTRAPOLATE_LINEAR);
}
static void graph_editmenu(bContext *C, uiLayout *layout, void *arg_unused)
{
uiItemMenuF(layout, "Transform", 0, graph_edit_transformmenu);
uiItemMenuF(layout, "Snap", 0, graph_edit_snapmenu);
uiItemMenuF(layout, "Mirror", 0, graph_edit_mirrormenu);
uiItemS(layout);
uiItemO(layout, NULL, 0, "GRAPH_OT_insert_keyframe");
uiItemO(layout, NULL, 0, "GRAPH_OT_fmodifier_add");
uiItemS(layout);
uiItemO(layout, NULL, 0, "GRAPH_OT_duplicate");
uiItemO(layout, NULL, 0, "GRAPH_OT_delete");
uiItemS(layout);
uiItemMenuF(layout, "Handle Type", 0, graph_edit_handlesmenu);
uiItemMenuF(layout, "Interpolation Mode", 0, graph_edit_ipomenu);
uiItemMenuF(layout, "Extrapolation Mode", 0, graph_edit_expomenu);
uiItemS(layout);
uiItemO(layout, NULL, 0, "GRAPH_OT_clean");
uiItemO(layout, NULL, 0, "GRAPH_OT_sample");
uiItemS(layout);
uiItemO(layout, NULL, 0, "GRAPH_OT_copy");
uiItemO(layout, NULL, 0, "GRAPH_OT_paste");
}
/* ********************************************************* */
enum {
B_REDR = 0,
B_REDR = 0,
B_MODECHANGE,
} eActHeader_ButEvents;
/* ************************ header area region *********************** */
static void do_viewmenu(bContext *C, void *arg, int event)
{
SpaceIpo *sipo= (SpaceIpo *)CTX_wm_space_data(C);
switch (event) {
case 1: /* Show time/frames */
sipo->flag ^= SIPO_DRAWTIME;
break;
case 2: /* AutoMerge Keyframes */
sipo->flag ^= SIPO_NOTRANSKEYCULL;
break;
case 3: /* Show/Hide handles */
sipo->flag ^= SIPO_NOHANDLES;
break;
case 4: /* Show current frame number beside indicator */
sipo->flag ^= SIPO_NODRAWCFRANUM;
break;
}
}
static uiBlock *graph_viewmenu(bContext *C, ARegion *ar, void *arg_unused)
{
ScrArea *curarea= CTX_wm_area(C);
SpaceIpo *sipo= (SpaceIpo *)CTX_wm_space_data(C);
uiBlock *block;
short yco= 0, menuwidth=120;
block= uiBeginBlock(C, ar, "graph_viewmenu", UI_EMBOSSP);
uiBlockSetButmFunc(block, do_viewmenu, NULL);
// XXX these options should use new menu-options
if (sipo->flag & SIPO_DRAWTIME) {
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
"Show Frames|Ctrl T", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
}
else {
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1,
"Show Seconds|Ctrl T", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
}
uiDefIconTextBut(block, BUTM, 1, (sipo->flag & SIPO_NOTRANSKEYCULL)?ICON_CHECKBOX_DEHLT:ICON_CHECKBOX_HLT,
"AutoMerge Keyframes|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
uiDefIconTextBut(block, BUTM, 1, (sipo->flag & SIPO_NOHANDLES)?ICON_CHECKBOX_DEHLT:ICON_CHECKBOX_HLT,
"Show Handles|Ctrl H", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
uiDefIconTextBut(block, BUTM, 1, (sipo->flag & SIPO_NODRAWCFRANUM)?ICON_CHECKBOX_DEHLT:ICON_CHECKBOX_HLT,
"Show Current Frame Number|", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
if (curarea->headertype==HEADERTOP) {
uiBlockSetDirection(block, UI_DOWN);
}
else {
uiBlockSetDirection(block, UI_TOP);
uiBlockFlipOrder(block);
}
uiTextBoundsBlock(block, 50);
uiEndBlock(C, block);
return block;
}
} eGraphEdit_Events;
static void do_graph_buttons(bContext *C, void *arg, int event)
{
@ -163,8 +263,19 @@ void graph_header_buttons(const bContext *C, ARegion *ar)
int xmax;
xmax= GetButStringLength("View");
uiDefPulldownBut(block, graph_viewmenu, CTX_wm_area(C),
"View", xco, yco-2, xmax-3, 24, "");
uiDefMenuBut(block, graph_viewmenu, NULL, "View", xco, yco, xmax-3, 20, "");
xco+= xmax;
xmax= GetButStringLength("Select");
uiDefMenuBut(block, graph_selectmenu, NULL, "Select", xco, yco, xmax-3, 20, "");
xco+= xmax;
xmax= GetButStringLength("Channel");
uiDefMenuBut(block, graph_channelmenu, NULL, "Channel", xco, yco, xmax-3, 20, "");
xco+= xmax;
xmax= GetButStringLength("Key");
uiDefMenuBut(block, graph_editmenu, NULL, "Key", xco, yco, xmax-3, 20, "");
xco+= xmax;
}
@ -202,8 +313,8 @@ void graph_header_buttons(const bContext *C, ARegion *ar)
/* copy + paste */
uiBlockBeginAlign(block);
uiDefIconButO(block, BUT, "GRAPHEDIT_OT_keyframes_copy", WM_OP_INVOKE_REGION_WIN, ICON_COPYDOWN, xco+=XIC,yco,XIC,YIC, "Copies the selected keyframes from the selected channel(s) to the buffer");
uiDefIconButO(block, BUT, "GRAPHEDIT_OT_keyframes_paste", WM_OP_INVOKE_REGION_WIN, ICON_PASTEDOWN, xco+=XIC,yco,XIC,YIC, "Pastes the keyframes from the buffer");
uiDefIconButO(block, BUT, "GRAPH_OT_copy", WM_OP_INVOKE_REGION_WIN, ICON_COPYDOWN, xco+=XIC,yco,XIC,YIC, "Copies the selected keyframes from the selected channel(s) to the buffer");
uiDefIconButO(block, BUT, "GRAPH_OT_paste", WM_OP_INVOKE_REGION_WIN, ICON_PASTEDOWN, xco+=XIC,yco,XIC,YIC, "Pastes the keyframes from the buffer");
uiBlockEndAlign(block);
xco += (XIC + 8);
@ -225,9 +336,9 @@ void graph_header_buttons(const bContext *C, ARegion *ar)
/* ghost curves */
// XXX these icons need to be changed
if (sipo->ghostCurves.first)
uiDefIconButO(block, BUT, "GRAPHEDIT_OT_ghost_curves_clear", WM_OP_INVOKE_REGION_WIN, ICON_OUTLINER_DATA_CURVE, xco,yco,XIC,YIC, "Clear F-Curve snapshots (Ghosts) for this Graph Editor instance");
uiDefIconButO(block, BUT, "GRAPH_OT_ghost_curves_clear", WM_OP_INVOKE_REGION_WIN, ICON_OUTLINER_DATA_CURVE, xco,yco,XIC,YIC, "Clear F-Curve snapshots (Ghosts) for this Graph Editor instance");
else
uiDefIconButO(block, BUT, "GRAPHEDIT_OT_ghost_curves_create", WM_OP_INVOKE_REGION_WIN, ICON_OUTLINER_OB_CURVE, xco,yco,XIC,YIC, "Create snapshot (Ghosts) of selected F-Curves as background aid for this Graph Editor instance");
uiDefIconButO(block, BUT, "GRAPH_OT_ghost_curves_create", WM_OP_INVOKE_REGION_WIN, ICON_OUTLINER_OB_CURVE, xco,yco,XIC,YIC, "Create snapshot (Ghosts) of selected F-Curves as background aid for this Graph Editor instance");
xco+= XIC;

@ -32,6 +32,8 @@ struct bContext;
struct wmWindowManager;
struct bAnimContext;
struct bAnimListElem;
struct FCurve;
struct FModifier;
struct SpaceIpo;
struct ScrArea;
struct ARegion;
@ -58,10 +60,10 @@ void graph_header_buttons(const bContext *C, struct ARegion *ar);
/* ***************************************** */
/* graph_select.c */
void GRAPHEDIT_OT_keyframes_select_all_toggle(struct wmOperatorType *ot);
void GRAPHEDIT_OT_keyframes_select_border(struct wmOperatorType *ot);
void GRAPHEDIT_OT_keyframes_columnselect(struct wmOperatorType *ot);
void GRAPHEDIT_OT_keyframes_clickselect(struct wmOperatorType *ot);
void GRAPH_OT_select_all_toggle(struct wmOperatorType *ot);
void GRAPH_OT_select_border(struct wmOperatorType *ot);
void GRAPH_OT_select_column(struct wmOperatorType *ot);
void GRAPH_OT_clickselect(struct wmOperatorType *ot);
/* defines for left-right select tool */
enum {
@ -84,28 +86,29 @@ enum {
void get_graph_keyframe_extents (struct bAnimContext *ac, float *xmin, float *xmax, float *ymin, float *ymax);
void GRAPHEDIT_OT_previewrange_set(struct wmOperatorType *ot);
void GRAPHEDIT_OT_view_all(struct wmOperatorType *ot);
void GRAPH_OT_previewrange_set(struct wmOperatorType *ot);
void GRAPH_OT_view_all(struct wmOperatorType *ot);
void GRAPHEDIT_OT_keyframes_click_insert(struct wmOperatorType *ot);
void GRAPH_OT_click_insert(struct wmOperatorType *ot);
void GRAPH_OT_insert_keyframe(struct wmOperatorType *ot);
void GRAPHEDIT_OT_keyframes_copy(struct wmOperatorType *ot);
void GRAPHEDIT_OT_keyframes_paste(struct wmOperatorType *ot);
void GRAPH_OT_copy(struct wmOperatorType *ot);
void GRAPH_OT_paste(struct wmOperatorType *ot);
void GRAPHEDIT_OT_keyframes_duplicate(struct wmOperatorType *ot);
void GRAPHEDIT_OT_keyframes_delete(struct wmOperatorType *ot);
void GRAPHEDIT_OT_keyframes_clean(struct wmOperatorType *ot);
void GRAPHEDIT_OT_keyframes_sample(struct wmOperatorType *ot);
void GRAPHEDIT_OT_keyframes_bake(struct wmOperatorType *ot);
void GRAPHEDIT_OT_keyframes_smooth(struct wmOperatorType *ot);
void GRAPH_OT_duplicate(struct wmOperatorType *ot);
void GRAPH_OT_delete(struct wmOperatorType *ot);
void GRAPH_OT_clean(struct wmOperatorType *ot);
void GRAPH_OT_sample(struct wmOperatorType *ot);
void GRAPH_OT_bake(struct wmOperatorType *ot);
void GRAPH_OT_smooth(struct wmOperatorType *ot);
void GRAPHEDIT_OT_keyframes_handletype(struct wmOperatorType *ot);
void GRAPHEDIT_OT_keyframes_interpolation_type(struct wmOperatorType *ot);
void GRAPHEDIT_OT_keyframes_extrapolation_type(struct wmOperatorType *ot);
void GRAPH_OT_handletype(struct wmOperatorType *ot);
void GRAPH_OT_interpolation_type(struct wmOperatorType *ot);
void GRAPH_OT_extrapolation_type(struct wmOperatorType *ot);
void GRAPHEDIT_OT_keyframes_cfrasnap(struct wmOperatorType *ot);
void GRAPHEDIT_OT_keyframes_snap(struct wmOperatorType *ot);
void GRAPHEDIT_OT_keyframes_mirror(struct wmOperatorType *ot);
void GRAPH_OT_frame_jump(struct wmOperatorType *ot);
void GRAPH_OT_snap(struct wmOperatorType *ot);
void GRAPH_OT_mirror(struct wmOperatorType *ot);
/* defines for snap keyframes
* NOTE: keep in sync with eEditKeyframes_Snap (in ED_keyframes_edit.h)
@ -130,20 +133,29 @@ enum {
/* ----------- */
void GRAPHEDIT_OT_fmodifier_add(struct wmOperatorType *ot);
void GRAPH_OT_fmodifier_add(struct wmOperatorType *ot);
/* ----------- */
void GRAPHEDIT_OT_ghost_curves_create(struct wmOperatorType *ot);
void GRAPHEDIT_OT_ghost_curves_clear(struct wmOperatorType *ot);
void GRAPH_OT_ghost_curves_create(struct wmOperatorType *ot);
void GRAPH_OT_ghost_curves_clear(struct wmOperatorType *ot);
/* ***************************************** */
/* graph_buttons.c */
void GRAPHEDIT_OT_properties(struct wmOperatorType *ot);
void GRAPH_OT_properties(struct wmOperatorType *ot);
void graph_buttons_register(struct ARegionType *art);
/* ***************************************** */
/* graph_utils.c */
struct bAnimListElem *get_active_fcurve_channel(struct bAnimContext *ac);
short fcurve_needs_draw_fmodifier_controls(struct FCurve *fcu, struct FModifier *fcm);
int graphop_visible_keyframes_poll(struct bContext *C);
int graphop_editable_keyframes_poll(struct bContext *C);
int graphop_active_fcurve_poll(struct bContext *C);
/* ***************************************** */
/* graph_ops.c */
void graphedit_keymap(struct wmWindowManager *wm);

@ -57,6 +57,10 @@
#include "WM_api.h"
#include "WM_types.h"
/* ************************** poll callbacks **********************************/
/* ************************** view-based operators **********************************/
// XXX this probably shouldn't be here..
@ -79,15 +83,15 @@ static int view_toggle_handles_exec (bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_view_togglehandles (wmOperatorType *ot)
void GRAPH_OT_view_togglehandles (wmOperatorType *ot)
{
/* identification */
ot->name= "Show/Hide All Handles";
ot->idname= "GRAPHEDIT_OT_handles_view_toggle";
ot->idname= "GRAPH_OT_handles_view_toggle";
/* callbacks */
ot->exec= view_toggle_handles_exec;
ot->poll= ED_operator_areaactive;
ot->poll= ED_operator_ipo_active;
}
/* ************************** registration - operator types **********************************/
@ -95,45 +99,44 @@ void GRAPHEDIT_OT_view_togglehandles (wmOperatorType *ot)
void graphedit_operatortypes(void)
{
/* view */
WM_operatortype_append(GRAPHEDIT_OT_view_togglehandles);
WM_operatortype_append(GRAPHEDIT_OT_previewrange_set);
WM_operatortype_append(GRAPHEDIT_OT_view_all);
WM_operatortype_append(GRAPHEDIT_OT_properties);
WM_operatortype_append(GRAPH_OT_view_togglehandles);
WM_operatortype_append(GRAPH_OT_previewrange_set);
WM_operatortype_append(GRAPH_OT_view_all);
WM_operatortype_append(GRAPH_OT_properties);
WM_operatortype_append(GRAPHEDIT_OT_ghost_curves_create);
WM_operatortype_append(GRAPHEDIT_OT_ghost_curves_clear);
WM_operatortype_append(GRAPH_OT_ghost_curves_create);
WM_operatortype_append(GRAPH_OT_ghost_curves_clear);
/* keyframes */
/* selection */
WM_operatortype_append(GRAPHEDIT_OT_keyframes_clickselect);
WM_operatortype_append(GRAPHEDIT_OT_keyframes_select_all_toggle);
WM_operatortype_append(GRAPHEDIT_OT_keyframes_select_border);
WM_operatortype_append(GRAPHEDIT_OT_keyframes_columnselect);
WM_operatortype_append(GRAPH_OT_clickselect);
WM_operatortype_append(GRAPH_OT_select_all_toggle);
WM_operatortype_append(GRAPH_OT_select_border);
WM_operatortype_append(GRAPH_OT_select_column);
/* editing */
WM_operatortype_append(GRAPHEDIT_OT_keyframes_snap);
WM_operatortype_append(GRAPHEDIT_OT_keyframes_mirror);
WM_operatortype_append(GRAPHEDIT_OT_keyframes_cfrasnap);
WM_operatortype_append(GRAPHEDIT_OT_keyframes_handletype);
WM_operatortype_append(GRAPHEDIT_OT_keyframes_interpolation_type);
WM_operatortype_append(GRAPHEDIT_OT_keyframes_extrapolation_type);
WM_operatortype_append(GRAPHEDIT_OT_keyframes_sample);
WM_operatortype_append(GRAPHEDIT_OT_keyframes_bake);
WM_operatortype_append(GRAPHEDIT_OT_keyframes_smooth);
WM_operatortype_append(GRAPHEDIT_OT_keyframes_clean);
WM_operatortype_append(GRAPHEDIT_OT_keyframes_delete);
WM_operatortype_append(GRAPHEDIT_OT_keyframes_duplicate);
WM_operatortype_append(GRAPH_OT_snap);
WM_operatortype_append(GRAPH_OT_mirror);
WM_operatortype_append(GRAPH_OT_frame_jump);
WM_operatortype_append(GRAPH_OT_handletype);
WM_operatortype_append(GRAPH_OT_interpolation_type);
WM_operatortype_append(GRAPH_OT_extrapolation_type);
WM_operatortype_append(GRAPH_OT_sample);
WM_operatortype_append(GRAPH_OT_bake);
WM_operatortype_append(GRAPH_OT_smooth);
WM_operatortype_append(GRAPH_OT_clean);
WM_operatortype_append(GRAPH_OT_delete);
WM_operatortype_append(GRAPH_OT_duplicate);
WM_operatortype_append(GRAPHEDIT_OT_keyframes_copy);
WM_operatortype_append(GRAPHEDIT_OT_keyframes_paste);
WM_operatortype_append(GRAPH_OT_copy);
WM_operatortype_append(GRAPH_OT_paste);
WM_operatortype_append(GRAPHEDIT_OT_keyframes_click_insert);
//TODO: insertkey...
WM_operatortype_append(GRAPH_OT_insert_keyframe);
WM_operatortype_append(GRAPH_OT_click_insert);
/* F-Curve Modifiers */
// XXX temporary?
WM_operatortype_append(GRAPHEDIT_OT_fmodifier_add);
WM_operatortype_append(GRAPH_OT_fmodifier_add);
}
/* ************************** registration - keymaps **********************************/
@ -143,81 +146,82 @@ static void graphedit_keymap_keyframes (wmWindowManager *wm, ListBase *keymap)
wmKeymapItem *kmi;
/* view */
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_handles_view_toggle", HKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_handles_view_toggle", HKEY, KM_PRESS, KM_CTRL, 0);
/* graph_select.c - selection tools */
/* click-select */
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, 0, 0);
kmi= WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_clickselect", SELECTMOUSE, KM_PRESS, 0, 0);
kmi= WM_keymap_add_item(keymap, "GRAPH_OT_clickselect", SELECTMOUSE, KM_PRESS, KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "column", 1);
kmi= WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
kmi= WM_keymap_add_item(keymap, "GRAPH_OT_clickselect", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "extend", 1);
kmi= WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_ALT|KM_SHIFT, 0);
kmi= WM_keymap_add_item(keymap, "GRAPH_OT_clickselect", SELECTMOUSE, KM_PRESS, KM_ALT|KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "extend", 1);
RNA_boolean_set(kmi->ptr, "column", 1);
kmi= WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
kmi= WM_keymap_add_item(keymap, "GRAPH_OT_clickselect", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
RNA_enum_set(kmi->ptr, "left_right", GRAPHKEYS_LRSEL_TEST);
kmi= WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_CTRL|KM_ALT, 0);
kmi= WM_keymap_add_item(keymap, "GRAPH_OT_clickselect", SELECTMOUSE, KM_PRESS, KM_CTRL|KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "curves", 1);
kmi= WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_CTRL|KM_ALT|KM_SHIFT, 0);
kmi= WM_keymap_add_item(keymap, "GRAPH_OT_clickselect", SELECTMOUSE, KM_PRESS, KM_CTRL|KM_ALT|KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "curves", 1);
RNA_boolean_set(kmi->ptr, "extend", 1);
/* deselect all */
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_select_all_toggle", AKEY, KM_PRESS, 0, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1);
WM_keymap_add_item(keymap, "GRAPH_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "GRAPH_OT_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1);
/* borderselect */
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_select_border", BKEY, KM_PRESS, 0, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_select_border", BKEY, KM_PRESS, KM_ALT, 0)->ptr, "axis_range", 1);
WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, 0, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0)->ptr, "axis_range", 1);
/* column select */
// XXX KKEY would be nice to keep for 'keyframe' lines
RNA_enum_set(WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_columnselect", KKEY, KM_PRESS, 0, 0)->ptr, "mode", GRAPHKEYS_COLUMNSEL_KEYS);
RNA_enum_set(WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_columnselect", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", GRAPHKEYS_COLUMNSEL_CFRA);
RNA_enum_set(WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_columnselect", KKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", GRAPHKEYS_COLUMNSEL_MARKERS_COLUMN);
RNA_enum_set(WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_columnselect", KKEY, KM_PRESS, KM_ALT, 0)->ptr, "mode", GRAPHKEYS_COLUMNSEL_MARKERS_BETWEEN);
RNA_enum_set(WM_keymap_add_item(keymap, "GRAPH_OT_select_column", KKEY, KM_PRESS, 0, 0)->ptr, "mode", GRAPHKEYS_COLUMNSEL_KEYS);
RNA_enum_set(WM_keymap_add_item(keymap, "GRAPH_OT_select_column", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", GRAPHKEYS_COLUMNSEL_CFRA);
RNA_enum_set(WM_keymap_add_item(keymap, "GRAPH_OT_select_column", KKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", GRAPHKEYS_COLUMNSEL_MARKERS_COLUMN);
RNA_enum_set(WM_keymap_add_item(keymap, "GRAPH_OT_select_column", KKEY, KM_PRESS, KM_ALT, 0)->ptr, "mode", GRAPHKEYS_COLUMNSEL_MARKERS_BETWEEN);
/* graph_edit.c */
/* snap - current frame to selected keys */
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_cfrasnap", SKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
// TODO: maybe since this is called jump, we're better to have it on <something>-J?
WM_keymap_add_item(keymap, "GRAPH_OT_frame_jump", SKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
/* menu + single-step transform */
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_snap", SKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_mirror", MKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_snap", SKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_mirror", MKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_handletype", HKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_interpolation_type", TKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_extrapolation_type", EKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_handletype", HKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_interpolation_type", TKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_extrapolation_type", EKEY, KM_PRESS, KM_SHIFT, 0);
/* destructive */
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_clean", OKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_smooth", OKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_sample", OKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_clean", OKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_smooth", OKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_sample", OKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_bake", CKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_bake", CKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_delete", XKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_delete", DELKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_delete", XKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_delete", DELKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
/* insertkey */
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_click_insert", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_insert_keyframe", IKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_click_insert", LEFTMOUSE, KM_PRESS, KM_CTRL, 0);
/* copy/paste */
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_copy", CKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_keyframes_paste", VKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_paste", VKEY, KM_PRESS, KM_CTRL, 0);
/* auto-set range */
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_previewrange_set", PKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_previewrange_set", PKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_view_all", HOMEKEY, KM_PRESS, 0, 0);
/* F-Curve Modifiers */
// XXX these are temporary? operators...
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_fmodifier_add", MKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
/* F-Modifiers */
WM_keymap_add_item(keymap, "GRAPH_OT_fmodifier_add", MKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
/* transform system */
@ -232,7 +236,7 @@ void graphedit_keymap(wmWindowManager *wm)
/* keymap for all regions */
keymap= WM_keymap_listbase(wm, "GraphEdit Generic", SPACE_IPO, 0);
WM_keymap_add_item(keymap, "GRAPHEDIT_OT_properties", NKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_properties", NKEY, KM_PRESS, 0, 0);
/* channels */
/* Channels are not directly handled by the Graph Editor module, but are inherited from the Animation module.

@ -63,6 +63,7 @@
#include "BKE_fcurve.h"
#include "BKE_key.h"
#include "BKE_material.h"
#include "BKE_nla.h"
#include "BKE_object.h"
#include "BKE_context.h"
#include "BKE_utildefines.h"
@ -168,20 +169,20 @@ static int graphkeys_deselectall_exec(bContext *C, wmOperator *op)
deselect_graph_keys(&ac, 1, SELECT_ADD);
/* set notifier that things have changed */
ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_SELECT, NULL);
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_keyframes_select_all_toggle (wmOperatorType *ot)
void GRAPH_OT_select_all_toggle (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Select All";
ot->idname= "GRAPHEDIT_OT_keyframes_select_all_toggle";
ot->idname= "GRAPH_OT_select_all_toggle";
/* api callbacks */
ot->exec= graphkeys_deselectall_exec;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_visible_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
@ -231,14 +232,14 @@ static void borderselect_graphkeys (bAnimContext *ac, rcti rect, short mode, sho
/* loop over data, doing border select */
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= ANIM_nla_mapping_get(ac, ale);
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
/* set horizontal range (if applicable) */
if (mode != BEZT_OK_VALUERANGE) {
/* if channel is mapped in NLA, apply correction */
if (nob) {
bed.f1= get_action_frame(nob, rectf.xmin);
bed.f2= get_action_frame(nob, rectf.xmax);
if (adt) {
bed.f1= BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP);
bed.f2= BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP);
}
else {
bed.f1= rectf.xmin;
@ -301,21 +302,24 @@ static int graphkeys_borderselect_exec(bContext *C, wmOperator *op)
/* apply borderselect action */
borderselect_graphkeys(&ac, rect, mode, selectmode);
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_SELECT, NULL);
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_keyframes_select_border(wmOperatorType *ot)
void GRAPH_OT_select_border(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Border Select";
ot->idname= "GRAPHEDIT_OT_keyframes_select_border";
ot->idname= "GRAPH_OT_select_border";
/* api callbacks */
ot->invoke= WM_border_select_invoke;
ot->exec= graphkeys_borderselect_exec;
ot->modal= WM_border_select_modal;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_visible_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
@ -379,12 +383,12 @@ static void markers_selectkeys_between (bAnimContext *ac)
/* select keys in-between */
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= ANIM_nla_mapping_get(ac, ale);
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
if (nob) {
ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1);
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
}
else {
ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
@ -450,15 +454,15 @@ static void columnselect_graph_keys (bAnimContext *ac, short mode)
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= ANIM_nla_mapping_get(ac, ale);
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
/* loop over cfraelems (stored in the BeztEditData->list)
* - we need to do this here, as we can apply fewer NLA-mapping conversions
*/
for (ce= bed.list.first; ce; ce= ce->next) {
/* set frame for validation callback to refer to */
if (nob)
bed.f1= get_action_frame(nob, ce->cfra);
if (ale)
bed.f1= BKE_nla_tweakedit_remap(adt, ce->cfra, NLATIME_CONVERT_UNMAP);
else
bed.f1= ce->cfra;
@ -491,21 +495,21 @@ static int graphkeys_columnselect_exec(bContext *C, wmOperator *op)
else
columnselect_graph_keys(&ac, mode);
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_SELECT);
/* set notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_SELECT, NULL);
return OPERATOR_FINISHED;
}
void GRAPHEDIT_OT_keyframes_columnselect (wmOperatorType *ot)
void GRAPH_OT_select_column (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Select All";
ot->idname= "GRAPHEDIT_OT_keyframes_columnselect";
ot->idname= "GRAPH_OT_select_column";
/* api callbacks */
ot->exec= graphkeys_columnselect_exec;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_visible_keyframes_poll;
/* flags */
ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
@ -566,11 +570,16 @@ static short findnearest_fcurve_vert (bAnimContext *ac, int mval[2], FCurve **fc
for (ale= anim_data.first; ale; ale= ale->next) {
FCurve *fcu= (FCurve *)ale->key_data;
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
/* try to progressively get closer to the right point... */
if (fcu->bezt) {
BezTriple *bezt1=fcu->bezt, *prevbezt=NULL;
/* apply NLA mapping to all the keyframes */
if (adt)
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
for (i=0; i < fcu->totvert; i++, prevbezt=bezt1, bezt1++) {
/* convert beztriple points to screen-space */
UI_view2d_to_region_no_clip(v2d, bezt1->vec[0][0], bezt1->vec[0][1], &sco[0][0], &sco[0][1]);
@ -624,6 +633,10 @@ static short findnearest_fcurve_vert (bAnimContext *ac, int mval[2], FCurve **fc
}
}
}
/* un-apply NLA mapping from all the keyframes */
if (adt)
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
}
}
@ -722,7 +735,7 @@ static void mouse_graph_keys (bAnimContext *ac, int mval[], short select_mode, s
/* set active F-Curve (NOTE: sync the filter flags with findnearest_fcurve_vert) */
if (fcu->flag & FCURVE_SELECTED) {
filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY);
ANIM_set_active_channel(ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
}
}
@ -753,7 +766,7 @@ static void graphkeys_mselect_leftright (bAnimContext *ac, short leftright, shor
memset(&bed, 0, sizeof(BeztEditFunc));
if (leftright == GRAPHKEYS_LRSEL_LEFT) {
bed.f1 = -MAXFRAMEF;
bed.f1 = MINAFRAMEF;
bed.f2 = (float)(CFRA + 0.1f);
}
else {
@ -767,12 +780,12 @@ static void graphkeys_mselect_leftright (bAnimContext *ac, short leftright, shor
/* select keys on the side where most data occurs */
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= ANIM_nla_mapping_get(ac, ale);
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
if (nob) {
ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1);
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
}
else
ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
@ -827,11 +840,11 @@ static void graphkeys_mselect_column (bAnimContext *ac, int mval[2], short selec
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= ANIM_nla_mapping_get(ac, ale);
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
/* set frame for validation callback to refer to */
if (nob)
bed.f1= get_action_frame(nob, selx);
if (adt)
bed.f1= BKE_nla_tweakedit_remap(adt, selx, NLATIME_CONVERT_UNMAP);
else
bed.f1= selx;
@ -901,22 +914,22 @@ static int graphkeys_clickselect_invoke(bContext *C, wmOperator *op, wmEvent *ev
mouse_graph_keys(&ac, mval, selectmode, 0);
}
/* set notifier that things have changed */
ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
/* set notifier that keyframe selection (and also channel selection in some cases) has changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_SELECT|ND_ANIMCHAN_SELECT, NULL);
/* for tweak grab to work */
return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
}
void GRAPHEDIT_OT_keyframes_clickselect (wmOperatorType *ot)
void GRAPH_OT_clickselect (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Mouse Select Keys";
ot->idname= "GRAPHEDIT_OT_keyframes_clickselect";
ot->idname= "GRAPH_OT_clickselect";
/* api callbacks */
ot->invoke= graphkeys_clickselect_invoke;
ot->poll= ED_operator_areaactive;
ot->poll= graphop_visible_keyframes_poll;
/* id-props */
// XXX should we make this into separate operators?

@ -0,0 +1,288 @@
/**
* $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) 2009 Blender Foundation.
* All rights reserved.
*
*
* Contributor(s): Blender Foundation, Joshua Leung
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <float.h>
#include "DNA_anim_types.h"
#include "DNA_action_types.h"
#include "DNA_object_types.h"
#include "DNA_space_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
#include "MEM_guardedalloc.h"
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
#include "BLI_editVert.h"
#include "BLI_rand.h"
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_customdata.h"
#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_object.h"
#include "BKE_global.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_utildefines.h"
#include "BIF_gl.h"
#include "WM_api.h"
#include "WM_types.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "ED_anim_api.h"
#include "ED_keyframing.h"
#include "ED_screen.h"
#include "ED_types.h"
#include "ED_util.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "UI_view2d.h"
#include "graph_intern.h" // own include
/* ************************************************************** */
/* Active F-Curve */
/* Find 'active' F-Curve. It must be editable, since that's the purpose of these buttons (subject to change).
* We return the 'wrapper' since it contains valuable context info (about hierarchy), which will need to be freed
* when the caller is done with it.
*/
bAnimListElem *get_active_fcurve_channel (bAnimContext *ac)
{
ListBase anim_data = {NULL, NULL};
int filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_ACTIVE | ANIMFILTER_CURVESONLY);
int items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* We take the first F-Curve only, since some other ones may have had 'active' flag set
* if they were from linked data.
*/
if (items) {
bAnimListElem *ale= (bAnimListElem *)anim_data.first;
/* remove first item from list, then free the rest of the list and return the stored one */
BLI_remlink(&anim_data, ale);
BLI_freelistN(&anim_data);
return ale;
}
/* no active F-Curve */
return NULL;
}
/* ************************************************************** */
/* Operator Polling Callbacks */
/* check if any FModifiers to draw controls for - fcm is 'active' modifier
* used for the polling callbacks + also for drawing
*/
short fcurve_needs_draw_fmodifier_controls (FCurve *fcu, FModifier *fcm)
{
/* don't draw if there aren't any modifiers at all */
if (fcu->modifiers.first == NULL)
return 0;
/* if there's an active modifier - don't draw if it doesn't drastically
* alter the curve...
*/
if (fcm) {
switch (fcm->type) {
/* clearly harmless */
case FMODIFIER_TYPE_CYCLES:
return 0;
/* borderline... */
case FMODIFIER_TYPE_NOISE:
return 0;
}
}
/* if only one modifier - don't draw if it is muted or disabled */
if (fcu->modifiers.first == fcu->modifiers.last) {
fcm= fcu->modifiers.first;
if (fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED))
return 0;
}
/* if only active modifier - don't draw if it is muted or disabled */
if (fcm) {
if (fcm->flag & (FMODIFIER_FLAG_DISABLED|FMODIFIER_FLAG_MUTED))
return 0;
}
/* if we're still here, this means that there are modifiers with controls to be drawn */
// FIXME: what happens if all the modifiers were muted/disabled
return 1;
}
/* ------------------- */
/* Check if there are any visible keyframes (for selection tools) */
int graphop_visible_keyframes_poll (bContext *C)
{
bAnimContext ac;
bAnimListElem *ale;
ListBase anim_data = {NULL, NULL};
ScrArea *sa= CTX_wm_area(C);
int filter, items;
short found = 0;
/* firstly, check if in Graph Editor */
// TODO: also check for region?
if ((sa == NULL) || (sa->spacetype != SPACE_IPO))
return 0;
/* try to init Anim-Context stuff ourselves and check */
if (ANIM_animdata_get_context(C, &ac) == 0)
return 0;
/* loop over the visible (selection doesn't matter) F-Curves, and see if they're suitable
* stopping on the first successful match
*/
filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
if (items == 0)
return 0;
for (ale = anim_data.first; ale; ale= ale->next) {
FCurve *fcu= (FCurve *)ale->data;
FModifier *fcm;
/* visible curves for selection must fulfull the following criteria:
* - it has bezier keyframes
* - F-Curve modifiers do not interfere with the result too much
* (i.e. the modifier-control drawing check returns false)
*/
if (fcu->bezt == NULL)
continue;
fcm= find_active_fmodifier(&fcu->modifiers);
found= (fcurve_needs_draw_fmodifier_controls(fcu, fcm) == 0);
if (found) break;
}
/* cleanup and return findings */
BLI_freelistN(&anim_data);
return found;
}
/* Check if there are any visible + editable keyframes (for editing tools) */
int graphop_editable_keyframes_poll (bContext *C)
{
bAnimContext ac;
bAnimListElem *ale;
ListBase anim_data = {NULL, NULL};
ScrArea *sa= CTX_wm_area(C);
int filter, items;
short found = 0;
/* firstly, check if in Graph Editor */
// TODO: also check for region?
if ((sa == NULL) || (sa->spacetype != SPACE_IPO))
return 0;
/* try to init Anim-Context stuff ourselves and check */
if (ANIM_animdata_get_context(C, &ac) == 0)
return 0;
/* loop over the editable (selected + editable) F-Curves, and see if they're suitable
* stopping on the first successful match
*/
filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_CURVESONLY);
items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
if (items == 0)
return 0;
for (ale = anim_data.first; ale; ale= ale->next) {
FCurve *fcu= (FCurve *)ale->data;
FModifier *fcm;
/* editable curves must fulfull the following criteria:
* - it has bezier keyframes
* - it must not be protected from editing (this is already checked for with the foredit flag
* - F-Curve modifiers do not interfere with the result too much
* (i.e. the modifier-control drawing check returns false)
*/
if (fcu->bezt == NULL)
continue;
fcm= find_active_fmodifier(&fcu->modifiers);
found= (fcurve_needs_draw_fmodifier_controls(fcu, fcm) == 0);
if (found) break;
}
/* cleanup and return findings */
BLI_freelistN(&anim_data);
return found;
}
/* has active F-Curve that's editable */
int graphop_active_fcurve_poll (bContext *C)
{
bAnimContext ac;
bAnimListElem *ale;
ScrArea *sa= CTX_wm_area(C);
short has_fcurve= 0;
/* firstly, check if in Graph Editor */
// TODO: also check for region?
if ((sa == NULL) || (sa->spacetype != SPACE_IPO))
return 0;
/* try to init Anim-Context stuff ourselves and check */
if (ANIM_animdata_get_context(C, &ac) == 0)
return 0;
/* try to get the Active F-Curve */
ale= get_active_fcurve_channel(&ac);
if (ale == NULL)
return 0;
/* free temp data... */
has_fcurve= ((ale->data) && (ale->type == ANIMTYPE_FCURVE));
MEM_freeN(ale);
/* return success */
return has_fcurve;
}
/* ************************************************************** */

@ -72,19 +72,19 @@ ARegion *graph_has_buttons_region(ScrArea *sa)
if(ar->regiontype==RGN_TYPE_UI)
return ar;
/* add subdiv level; after channel */
/* add subdiv level; after main window */
for(ar= sa->regionbase.first; ar; ar= ar->next)
if(ar->regiontype==RGN_TYPE_CHANNELS)
if(ar->regiontype==RGN_TYPE_WINDOW)
break;
/* is error! */
if(ar==NULL) return NULL;
arnew= MEM_callocN(sizeof(ARegion), "buttons for view3d");
arnew= MEM_callocN(sizeof(ARegion), "buttons for nla");
BLI_insertlinkafter(&sa->regionbase, ar, arnew);
arnew->regiontype= RGN_TYPE_UI;
arnew->alignment= RGN_ALIGN_BOTTOM|RGN_SPLIT_PREV;
arnew->alignment= RGN_ALIGN_RIGHT;
arnew->flag = RGN_FLAG_HIDDEN;
@ -117,7 +117,7 @@ static SpaceLink *graph_new(const bContext *C)
ar->alignment= RGN_ALIGN_BOTTOM;
/* channels */
ar= MEM_callocN(sizeof(ARegion), "main area for graphedit");
ar= MEM_callocN(sizeof(ARegion), "channels area for graphedit");
BLI_addtail(&sipo->regionbase, ar);
ar->regiontype= RGN_TYPE_CHANNELS;
@ -126,11 +126,11 @@ static SpaceLink *graph_new(const bContext *C)
ar->v2d.scroll = (V2D_SCROLL_RIGHT|V2D_SCROLL_BOTTOM);
/* ui buttons */
ar= MEM_callocN(sizeof(ARegion), "main area for graphedit");
ar= MEM_callocN(sizeof(ARegion), "buttons area for graphedit");
BLI_addtail(&sipo->regionbase, ar);
ar->regiontype= RGN_TYPE_UI;
ar->alignment= RGN_ALIGN_TOP|RGN_SPLIT_PREV;
ar->alignment= RGN_ALIGN_RIGHT;
ar->flag = RGN_FLAG_HIDDEN;
/* main area */
@ -192,7 +192,7 @@ static SpaceLink *graph_duplicate(SpaceLink *sl)
SpaceIpo *sipon= MEM_dupallocN(sl);
/* clear or remove stuff from old */
//sipon->ipokey.first= sipon->ipokey.last= NULL;
BLI_duplicatelist(&sipon->ghostCurves, &((SpaceIpo *)sl)->ghostCurves);
sipon->ads= MEM_dupallocN(sipon->ads);
return (SpaceLink *)sipon;
@ -365,6 +365,9 @@ static void graph_region_listener(ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch(wmn->category) {
case NC_ANIMATION:
ED_region_tag_redraw(ar);
break;
case NC_SCENE:
switch(wmn->data) {
case ND_OB_ACTIVE:
@ -395,6 +398,9 @@ static void graph_listener(ScrArea *sa, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
case NC_ANIMATION:
ED_area_tag_refresh(sa);
break;
case NC_SCENE:
/*switch (wmn->data) {
case ND_OB_ACTIVE:
@ -566,7 +572,7 @@ void ED_spacetype_ipo(void)
/* regions: UI buttons */
art= MEM_callocN(sizeof(ARegionType), "spacetype graphedit region");
art->regionid = RGN_TYPE_UI;
art->minsizey= 200;
art->minsizex= 200;
art->keymapflag= ED_KEYMAP_UI;
art->listener= graph_region_listener;
art->init= graph_buttons_area_init;

@ -0,0 +1,426 @@
/**
* $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) 2009 Blender Foundation.
* All rights reserved.
*
*
* Contributor(s): Blender Foundation, Joshua Leung
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <float.h>
#include "DNA_anim_types.h"
#include "DNA_action_types.h"
#include "DNA_object_types.h"
#include "DNA_space_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
#include "MEM_guardedalloc.h"
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
#include "BLI_editVert.h"
#include "BLI_rand.h"
#include "BKE_animsys.h"
#include "BKE_nla.h"
#include "BKE_action.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_customdata.h"
#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_object.h"
#include "BKE_global.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_utildefines.h"
#include "BIF_gl.h"
#include "WM_api.h"
#include "WM_types.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "ED_anim_api.h"
#include "ED_keyframing.h"
#include "ED_screen.h"
#include "ED_types.h"
#include "ED_util.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "UI_view2d.h"
#include "nla_intern.h" // own include
/* ******************* nla editor space & buttons ************** */
#define B_NOP 1
#define B_REDR 2
/* -------------- */
static void do_nla_region_buttons(bContext *C, void *arg, int event)
{
//Scene *scene= CTX_data_scene(C);
switch(event) {
}
/* default for now */
WM_event_add_notifier(C, NC_SCENE|NC_OBJECT|ND_TRANSFORM, NULL);
}
static int nla_panel_context(const bContext *C, PointerRNA *nlt_ptr, PointerRNA *strip_ptr)
{
bAnimContext ac;
bAnimListElem *ale= NULL;
ListBase anim_data = {NULL, NULL};
short found=0;
int filter;
/* for now, only draw if we could init the anim-context info (necessary for all animation-related tools)
* to work correctly is able to be correctly retrieved. There's no point showing empty panels?
*/
if (ANIM_animdata_get_context(C, &ac) == 0)
return 0;
/* extract list of active channel(s), of which we should only take the first one (expecting it to be an NLA track) */
filter= (ANIMFILTER_VISIBLE|ANIMFILTER_ACTIVE);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
for (ale= anim_data.first; ale; ale= ale->next) {
if (ale->type == ANIMTYPE_NLATRACK) {
NlaTrack *nlt= (NlaTrack *)ale->data;
/* found it, now set the pointers */
if (nlt_ptr) {
/* NLA-Track pointer */
RNA_pointer_create(ale->id, &RNA_NlaTrack, nlt, nlt_ptr);
}
if (strip_ptr) {
/* NLA-Strip pointer */
NlaStrip *strip= BKE_nlastrip_find_active(nlt);
RNA_pointer_create(ale->id, &RNA_NlaStrip, strip, strip_ptr);
}
found= 1;
break;
}
}
/* free temp data */
BLI_freelistN(&anim_data);
return found;
}
#if 0
static int nla_panel_poll(const bContext *C, PanelType *pt)
{
return nla_panel_context(C, NULL, NULL);
}
#endif
static int nla_track_panel_poll(const bContext *C, PanelType *pt)
{
PointerRNA ptr;
return (nla_panel_context(C, &ptr, NULL) && (ptr.data != NULL));
}
static int nla_strip_panel_poll(const bContext *C, PanelType *pt)
{
PointerRNA ptr;
return (nla_panel_context(C, NULL, &ptr) && (ptr.data != NULL));
}
static int nla_strip_actclip_panel_poll(const bContext *C, PanelType *pt)
{
PointerRNA ptr;
NlaStrip *strip;
if (!nla_panel_context(C, NULL, &ptr))
return 0;
if (ptr.data == NULL)
return 0;
strip= ptr.data;
return (strip->type == NLASTRIP_TYPE_CLIP);
}
/* -------------- */
/* active NLA-Track */
static void nla_panel_track (const bContext *C, Panel *pa)
{
PointerRNA nlt_ptr;
uiLayout *layout= pa->layout;
uiLayout *row;
uiBlock *block;
/* check context and also validity of pointer */
if (!nla_panel_context(C, &nlt_ptr, NULL))
return;
block= uiLayoutGetBlock(layout);
uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
/* Info - Active NLA-Context:Track ---------------------- */
row= uiLayoutRow(layout, 1);
uiItemR(row, NULL, ICON_NLA, &nlt_ptr, "name", 0, 0, 0);
}
/* generic settings for active NLA-Strip */
static void nla_panel_properties(const bContext *C, Panel *pa)
{
PointerRNA strip_ptr;
uiLayout *layout= pa->layout;
uiLayout *column, *row, *subcol;
uiBlock *block;
if (!nla_panel_context(C, NULL, &strip_ptr))
return;
block= uiLayoutGetBlock(layout);
uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
/* Strip Properties ------------------------------------- */
/* strip type */
row= uiLayoutColumn(layout, 1);
uiItemR(row, NULL, ICON_NLA, &strip_ptr, "name", 0, 0, 0); // XXX icon?
uiItemR(row, NULL, 0, &strip_ptr, "type", 0, 0, 0);
/* strip extents */
column= uiLayoutColumn(layout, 1);
uiItemL(column, "Strip Extents:", 0);
uiItemR(column, NULL, 0, &strip_ptr, "start_frame", 0, 0, 0);
uiItemR(column, NULL, 0, &strip_ptr, "end_frame", 0, 0, 0);
/* extrapolation */
row= uiLayoutRow(layout, 1);
uiItemR(row, NULL, 0, &strip_ptr, "extrapolation", 0, 0, 0);
/* blending */
row= uiLayoutRow(layout, 1);
uiItemR(row, NULL, 0, &strip_ptr, "blending", 0, 0, 0);
/* blend in/out + autoblending
* - blend in/out can only be set when autoblending is off
*/
column= uiLayoutColumn(layout, 1);
uiLayoutSetActive(column, RNA_boolean_get(&strip_ptr, "animated_influence")==0);
uiItemR(column, NULL, 0, &strip_ptr, "auto_blending", 0, 0, 0); // XXX as toggle?
subcol= uiLayoutColumn(column, 1);
uiLayoutSetActive(subcol, RNA_boolean_get(&strip_ptr, "auto_blending")==0);
uiItemR(subcol, NULL, 0, &strip_ptr, "blend_in", 0, 0, 0);
uiItemR(subcol, NULL, 0, &strip_ptr, "blend_out", 0, 0, 0);
/* settings */
column= uiLayoutColumn(layout, 1);
uiLayoutSetActive(column, !(RNA_boolean_get(&strip_ptr, "animated_influence") || RNA_boolean_get(&strip_ptr, "animated_time")));
uiItemL(column, "Playback Settings:", 0);
uiItemR(column, NULL, 0, &strip_ptr, "muted", 0, 0, 0);
uiItemR(column, NULL, 0, &strip_ptr, "reversed", 0, 0, 0);
}
/* action-clip only settings for active NLA-Strip */
static void nla_panel_actclip(const bContext *C, Panel *pa)
{
PointerRNA strip_ptr;
uiLayout *layout= pa->layout;
uiLayout *column, *row;
uiBlock *block;
/* check context and also validity of pointer */
if (!nla_panel_context(C, NULL, &strip_ptr))
return;
block= uiLayoutGetBlock(layout);
uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
/* Strip Properties ------------------------------------- */
/* action pointer */
row= uiLayoutRow(layout, 1);
uiItemR(row, NULL, ICON_ACTION, &strip_ptr, "action", 0, 0, 0);
/* action extents */
// XXX custom names were used here (to avoid the prefixes)... probably not necessary in future?
column= uiLayoutColumn(layout, 1);
uiItemL(column, "Action Extents:", 0);
uiItemR(column, "Start Frame", 0, &strip_ptr, "action_start_frame", 0, 0, 0);
uiItemR(column, "End Frame", 0, &strip_ptr, "action_end_frame", 0, 0, 0);
/* action usage */
column= uiLayoutColumn(layout, 1);
uiLayoutSetActive(column, RNA_boolean_get(&strip_ptr, "animated_time")==0);
uiItemL(column, "Playback Settings:", 0);
uiItemR(column, NULL, 0, &strip_ptr, "scale", 0, 0, 0);
uiItemR(column, NULL, 0, &strip_ptr, "repeat", 0, 0, 0);
}
/* evaluation settings for active NLA-Strip */
static void nla_panel_evaluation(const bContext *C, Panel *pa)
{
PointerRNA strip_ptr;
uiLayout *layout= pa->layout;
uiLayout *column, *subcolumn;
uiBlock *block;
/* check context and also validity of pointer */
if (!nla_panel_context(C, NULL, &strip_ptr))
return;
block= uiLayoutGetBlock(layout);
uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
column= uiLayoutColumn(layout, 1);
uiItemR(column, NULL, 0, &strip_ptr, "animated_influence", 0, 0, 0);
subcolumn= uiLayoutColumn(column, 1);
uiLayoutSetEnabled(subcolumn, RNA_boolean_get(&strip_ptr, "animated_influence"));
uiItemR(subcolumn, NULL, 0, &strip_ptr, "influence", 0, 0, 0);
column= uiLayoutColumn(layout, 1);
uiItemR(column, NULL, 0, &strip_ptr, "animated_time", 0, 0, 0);
subcolumn= uiLayoutColumn(column, 1);
uiLayoutSetEnabled(subcolumn, RNA_boolean_get(&strip_ptr, "animated_time"));
uiItemR(subcolumn, NULL, 0, &strip_ptr, "strip_time", 0, 0, 0);
}
/* F-Modifiers for active NLA-Strip */
static void nla_panel_modifiers(const bContext *C, Panel *pa)
{
PointerRNA strip_ptr;
NlaStrip *strip;
FModifier *fcm;
uiLayout *col, *row;
uiBlock *block;
/* check context and also validity of pointer */
if (!nla_panel_context(C, NULL, &strip_ptr))
return;
strip= strip_ptr.data;
block= uiLayoutGetBlock(pa->layout);
uiBlockSetHandleFunc(block, do_nla_region_buttons, NULL);
/* 'add modifier' button at top of panel */
{
row= uiLayoutRow(pa->layout, 0);
block= uiLayoutGetBlock(row);
// XXX for now, this will be a operator button which calls a temporary 'add modifier' operator
// FIXME: we need to set the only-active property so that this will only add modifiers for the active strip (not all selected)
uiDefButO(block, BUT, "NLA_OT_fmodifier_add", WM_OP_INVOKE_REGION_WIN, "Add Modifier", 10, 0, 150, 20, "Adds a new F-Modifier for the active NLA Strip");
}
/* draw each modifier */
for (fcm= strip->modifiers.first; fcm; fcm= fcm->next) {
col= uiLayoutColumn(pa->layout, 1);
ANIM_uiTemplate_fmodifier_draw(col, strip_ptr.id.data, &strip->modifiers, fcm);
}
}
/* ******************* general ******************************** */
void nla_buttons_register(ARegionType *art)
{
PanelType *pt;
pt= MEM_callocN(sizeof(PanelType), "spacetype nla panel track");
strcpy(pt->idname, "NLA_PT_track");
strcpy(pt->label, "Active Track");
pt->draw= nla_panel_track;
pt->poll= nla_track_panel_poll;
BLI_addtail(&art->paneltypes, pt);
pt= MEM_callocN(sizeof(PanelType), "spacetype nla panel properties");
strcpy(pt->idname, "NLA_PT_properties");
strcpy(pt->label, "Active Strip");
pt->draw= nla_panel_properties;
pt->poll= nla_strip_panel_poll;
BLI_addtail(&art->paneltypes, pt);
pt= MEM_callocN(sizeof(PanelType), "spacetype nla panel properties");
strcpy(pt->idname, "NLA_PT_actionclip");
strcpy(pt->label, "Action Clip");
pt->draw= nla_panel_actclip;
pt->poll= nla_strip_actclip_panel_poll;
BLI_addtail(&art->paneltypes, pt);
pt= MEM_callocN(sizeof(PanelType), "spacetype nla panel evaluation");
strcpy(pt->idname, "NLA_PT_evaluation");
strcpy(pt->label, "Evaluation");
pt->draw= nla_panel_evaluation;
pt->poll= nla_strip_panel_poll;
BLI_addtail(&art->paneltypes, pt);
pt= MEM_callocN(sizeof(PanelType), "spacetype nla panel modifiers");
strcpy(pt->idname, "NLA_PT_modifiers");
strcpy(pt->label, "Modifiers");
pt->draw= nla_panel_modifiers;
pt->poll= nla_strip_panel_poll;
BLI_addtail(&art->paneltypes, pt);
}
static int nla_properties(bContext *C, wmOperator *op)
{
ScrArea *sa= CTX_wm_area(C);
ARegion *ar= nla_has_buttons_region(sa);
if(ar) {
ar->flag ^= RGN_FLAG_HIDDEN;
ar->v2d.flag &= ~V2D_IS_INITIALISED; /* XXX should become hide/unhide api? */
ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
ED_area_tag_redraw(sa);
}
return OPERATOR_FINISHED;
}
void NLA_OT_properties(wmOperatorType *ot)
{
ot->name= "Properties";
ot->idname= "NLA_OT_properties";
ot->exec= nla_properties;
ot->poll= ED_operator_nla_active;
/* flags */
ot->flag= 0;
}

@ -0,0 +1,516 @@
/**
* $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) 2009 Blender Foundation, Joshua Leung
* All rights reserved.
*
*
* Contributor(s): Joshua Leung (major recode)
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#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_screen_types.h"
#include "DNA_scene_types.h"
#include "DNA_space_types.h"
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_world_types.h"
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BLI_arithb.h"
#include "BLI_rand.h"
#include "BKE_animsys.h"
#include "BKE_nla.h"
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_utildefines.h"
#include "ED_anim_api.h"
#include "ED_keyframes_edit.h"
#include "ED_markers.h"
#include "ED_space_api.h"
#include "ED_screen.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "WM_api.h"
#include "WM_types.h"
#include "UI_interface.h"
#include "UI_interface_icons.h"
#include "UI_resources.h"
#include "UI_view2d.h"
#include "nla_intern.h" // own include
/* *********************************************** */
/* Operators for NLA channels-list which need to be different from the standard Animation Editor ones */
/* ******************** Mouse-Click Operator *********************** */
/* Depending on the channel that was clicked on, the mouse click will activate whichever
* part of the channel is relevant.
*
* NOTE: eventually, this should probably be phased out when many of these things are replaced with buttons
*/
static int mouse_nla_channels (bAnimContext *ac, float x, int channel_index, short selectmode)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
int notifierFlags = 0;
/* get the channel that was clicked on */
/* filter channels */
filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
filter= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* get channel from index */
ale= BLI_findlink(&anim_data, channel_index);
if (ale == NULL) {
/* channel not found */
printf("Error: animation channel (index = %d) not found in mouse_anim_channels() \n", channel_index);
BLI_freelistN(&anim_data);
return 0;
}
/* action to take depends on what channel we've got */
switch (ale->type) {
case ANIMTYPE_SCENE:
{
Scene *sce= (Scene *)ale->data;
if (x < 16) {
/* toggle expand */
sce->flag ^= SCE_DS_COLLAPSED;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
else {
/* set selection status */
if (selectmode == SELECT_INVERT) {
/* swap select */
sce->flag ^= SCE_DS_SELECTED;
}
else {
sce->flag |= SCE_DS_SELECTED;
}
notifierFlags |= ND_ANIMCHAN_SELECT;
}
}
break;
case ANIMTYPE_OBJECT:
{
bDopeSheet *ads= (bDopeSheet *)ac->data;
Scene *sce= (Scene *)ads->source;
Base *base= (Base *)ale->data;
Object *ob= base->object;
if (x < 16) {
/* toggle expand */
ob->nlaflag ^= OB_ADS_COLLAPSED; // XXX
notifierFlags |= ND_ANIMCHAN_EDIT;
}
else if (nlaedit_is_tweakmode_on(ac) == 0) {
/* set selection status */
if (selectmode == SELECT_INVERT) {
/* swap select */
base->flag ^= SELECT;
ob->flag= base->flag;
}
else {
Base *b;
/* deleselect all */
for (b= sce->base.first; b; b= b->next) {
b->flag &= ~SELECT;
b->object->flag= b->flag;
}
/* select object now */
base->flag |= SELECT;
ob->flag |= SELECT;
}
/* xxx should be ED_base_object_activate(), but we need context pointer for that... */
//set_active_base(base);
/* notifiers - channel was selected */
notifierFlags |= ND_ANIMCHAN_SELECT;
}
}
break;
case ANIMTYPE_FILLMATD:
{
Object *ob= (Object *)ale->data;
ob->nlaflag ^= OB_ADS_SHOWMATS; // XXX
notifierFlags |= ND_ANIMCHAN_EDIT;
}
break;
case ANIMTYPE_DSMAT:
{
Material *ma= (Material *)ale->data;
ma->flag ^= MA_DS_EXPAND;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
break;
case ANIMTYPE_DSLAM:
{
Lamp *la= (Lamp *)ale->data;
la->flag ^= LA_DS_EXPAND;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
break;
case ANIMTYPE_DSCAM:
{
Camera *ca= (Camera *)ale->data;
ca->flag ^= CAM_DS_EXPAND;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
break;
case ANIMTYPE_DSCUR:
{
Curve *cu= (Curve *)ale->data;
cu->flag ^= CU_DS_EXPAND;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
break;
case ANIMTYPE_DSSKEY:
{
Key *key= (Key *)ale->data;
key->flag ^= KEYBLOCK_DS_EXPAND;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
break;
case ANIMTYPE_DSWOR:
{
World *wo= (World *)ale->data;
wo->flag ^= WO_DS_EXPAND;
notifierFlags |= ND_ANIMCHAN_EDIT;
}
break;
case ANIMTYPE_NLATRACK:
{
NlaTrack *nlt= (NlaTrack *)ale->data;
AnimData *adt= BKE_animdata_from_id(ale->id);
short offset;
/* offset for start of channel (on LHS of channel-list) */
if (ale->id) {
/* special exception for materials */
if (GS(ale->id->name) == ID_MA)
offset= 21 + NLACHANNEL_BUTTON_WIDTH;
else
offset= 14;
}
else
offset= 0;
if (x >= (NLACHANNEL_NAMEWIDTH-NLACHANNEL_BUTTON_WIDTH)) {
/* toggle protection (only if there's a toggle there) */
nlt->flag ^= NLATRACK_PROTECTED;
/* notifier flags - channel was edited */
notifierFlags |= ND_ANIMCHAN_EDIT;
}
else if (x >= (NLACHANNEL_NAMEWIDTH-2*NLACHANNEL_BUTTON_WIDTH)) {
/* toggle mute */
nlt->flag ^= NLATRACK_MUTED;
/* notifier flags - channel was edited */
notifierFlags |= ND_ANIMCHAN_EDIT;
}
else if (x <= ((NLACHANNEL_BUTTON_WIDTH*2)+offset)) {
/* toggle 'solo' */
BKE_nlatrack_solo_toggle(adt, nlt);
/* notifier flags - channel was edited */
notifierFlags |= ND_ANIMCHAN_EDIT;
}
else if (nlaedit_is_tweakmode_on(ac) == 0) {
/* set selection */
if (selectmode == SELECT_INVERT) {
/* inverse selection status of this F-Curve only */
nlt->flag ^= NLATRACK_SELECTED;
}
else {
/* select F-Curve by itself */
ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
nlt->flag |= NLATRACK_SELECTED;
}
/* if NLA-Track is selected now, make NLA-Track the 'active' one in the visible list */
if (nlt->flag & NLATRACK_SELECTED)
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nlt, ANIMTYPE_NLATRACK);
/* notifier flags - channel was selected */
notifierFlags |= ND_ANIMCHAN_SELECT;
}
}
break;
case ANIMTYPE_NLAACTION:
{
AnimData *adt= BKE_animdata_from_id(ale->owner); /* this won't crash, right? */
if (x >= (NLACHANNEL_NAMEWIDTH-NLACHANNEL_BUTTON_WIDTH)) {
if (nlaedit_is_tweakmode_on(ac) == 0) {
/* 'push-down' action - only usable when not in TweakMode */
// TODO: make this use the operator instead of calling the function directly
// however, calling the operator requires that we supply the args, and that works with proper buttons only
BKE_nla_action_pushdown(adt);
}
else {
/* when in tweakmode, this button becomes the toggle for mapped editing */
adt->flag ^= ADT_NLA_EDIT_NOMAP;
}
/* changes to NLA-Action occurred */
notifierFlags |= ND_NLA_ACTCHANGE;
}
}
break;
default:
printf("Error: Invalid channel type in mouse_nla_channels() \n");
}
/* free channels */
BLI_freelistN(&anim_data);
/* return the notifier-flags set */
return notifierFlags;
}
/* ------------------- */
/* handle clicking */
static int nlachannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
bAnimContext ac;
Scene *scene;
ARegion *ar;
View2D *v2d;
int mval[2], channel_index;
int notifierFlags = 0;
short selectmode;
float x, y;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
/* get useful pointers from animation context data */
scene= ac.scene;
ar= ac.ar;
v2d= &ar->v2d;
/* get mouse coordinates (in region coordinates) */
mval[0]= (event->x - ar->winrct.xmin);
mval[1]= (event->y - ar->winrct.ymin);
/* select mode is either replace (deselect all, then add) or add/extend */
if (RNA_boolean_get(op->ptr, "extend"))
selectmode= SELECT_INVERT;
else
selectmode= SELECT_REPLACE;
/* figure out which channel user clicked in
* Note: although channels technically start at y= NLACHANNEL_FIRST, we need to adjust by half a channel's height
* so that the tops of channels get caught ok. Since NLACHANNEL_FIRST is really NLACHANNEL_HEIGHT, we simply use
* NLACHANNEL_HEIGHT_HALF.
*/
UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
UI_view2d_listview_view_to_cell(v2d, NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP, 0, (float)NLACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
/* handle mouse-click in the relevant channel then */
notifierFlags= mouse_nla_channels(&ac, x, channel_index, selectmode);
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION|notifierFlags, NULL);
return OPERATOR_FINISHED;
}
void NLA_OT_channels_click (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Mouse Click on Channels";
ot->idname= "NLA_OT_channels_click";
/* api callbacks */
ot->invoke= nlachannels_mouseclick_invoke;
ot->poll= ED_operator_nla_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* id-props */
RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY
}
/* *********************************************** */
/* Special Operators */
/* ******************** Add Tracks Operator ***************************** */
/* Add NLA Tracks to the same AnimData block as a selected track, or above the selected tracks */
static int nlaedit_add_tracks_exec (bContext *C, wmOperator *op)
{
bAnimContext ac;
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
AnimData *lastAdt = NULL;
short above_sel= RNA_boolean_get(op->ptr, "above_selected");
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
/* get a list of the AnimData blocks being shown in the NLA */
filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_SEL);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* add tracks... */
for (ale= anim_data.first; ale; ale= ale->next) {
NlaTrack *nlt= (NlaTrack *)ale->data;
AnimData *adt= BKE_animdata_from_id(ale->id);
/* check if just adding a new track above this one,
* or whether we're adding a new one to the top of the stack that this one belongs to
*/
if (above_sel) {
/* just add a new one above this one */
add_nlatrack(adt, nlt);
}
else if ((lastAdt == NULL) || (adt != lastAdt)) {
/* add one track to the top of the owning AnimData's stack, then don't add anymore to this stack */
add_nlatrack(adt, NULL);
lastAdt= adt;
}
}
/* free temp data */
BLI_freelistN(&anim_data);
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
/* done */
return OPERATOR_FINISHED;
}
void NLA_OT_add_tracks (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Add Track(s)";
ot->idname= "NLA_OT_add_tracks";
ot->description= "Add NLA-Tracks above/after the selected tracks.";
/* api callbacks */
ot->exec= nlaedit_add_tracks_exec;
ot->poll= nlaop_poll_tweakmode_off;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* properties */
RNA_def_boolean(ot->srna, "above_selected", 0, "Above Selected", "Add a new NLA Track above every existing selected one.");
}
/* ******************** Delete Tracks Operator ***************************** */
/* Delete selected NLA Tracks */
static int nlaedit_delete_tracks_exec (bContext *C, wmOperator *op)
{
bAnimContext ac;
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
/* get a list of the AnimData blocks being shown in the NLA */
filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_SEL);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* delete tracks */
for (ale= anim_data.first; ale; ale= ale->next) {
NlaTrack *nlt= (NlaTrack *)ale->data;
AnimData *adt= BKE_animdata_from_id(ale->id);
/* call delete on this track - deletes all strips too */
free_nlatrack(&adt->nla_tracks, nlt);
}
/* free temp data */
BLI_freelistN(&anim_data);
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_EDIT, NULL);
/* done */
return OPERATOR_FINISHED;
}
void NLA_OT_delete_tracks (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Delete Tracks";
ot->idname= "NLA_OT_delete_tracks";
ot->description= "Delete selected NLA-Tracks and the strips they contain.";
/* api callbacks */
ot->exec= nlaedit_delete_tracks_exec;
ot->poll= nlaop_poll_tweakmode_off;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
}
/* *********************************************** */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -29,6 +29,10 @@
#include <string.h>
#include <stdio.h>
#include "DNA_anim_types.h"
#include "DNA_action_types.h"
#include "DNA_nla_types.h"
#include "DNA_object_types.h"
#include "DNA_space_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
@ -37,19 +41,29 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BLI_arithb.h"
#include "BLI_rand.h"
#include "BKE_animsys.h"
#include "BKE_nla.h"
#include "BKE_context.h"
#include "BKE_report.h"
#include "BKE_screen.h"
#include "ED_screen.h"
#include "ED_types.h"
#include "ED_util.h"
#include "WM_api.h"
#include "WM_types.h"
#include "ED_anim_api.h"
#include "ED_markers.h"
#include "ED_space_api.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
#include "RNA_access.h"
#include "WM_api.h"
#include "WM_types.h"
#include "UI_interface.h"
#include "UI_resources.h"
@ -57,49 +71,146 @@
#include "nla_intern.h"
/* button events */
enum {
B_REDR = 0,
} eActHeader_ButEvents;
/* ************************ header area region *********************** */
static void do_viewmenu(bContext *C, void *arg, int event)
{
static void nla_viewmenu(bContext *C, uiLayout *layout, void *arg_unused)
{
bScreen *sc= CTX_wm_screen(C);
ScrArea *sa= CTX_wm_area(C);
Scene *scene= CTX_data_scene(C);
SpaceNla *snla= (SpaceNla*)CTX_wm_space_data(C);
PointerRNA spaceptr;
/* retrieve state */
RNA_pointer_create(&sc->id, &RNA_SpaceNLA, snla, &spaceptr);
/* create menu */
uiItemO(layout, NULL, ICON_MENU_PANEL, "NLA_OT_properties");
uiItemS(layout);
uiItemR(layout, NULL, 0, &spaceptr, "show_cframe_indicator", 0, 0, 0);
if (snla->flag & SNLA_DRAWTIME)
uiItemO(layout, "Show Frames", 0, "ANIM_OT_time_toggle");
else
uiItemO(layout, "Show Seconds", 0, "ANIM_OT_time_toggle");
uiItemS(layout);
if (scene->flag & SCE_NLA_EDIT_ON)
uiItemO(layout, NULL, 0, "NLA_OT_tweakmode_exit");
else
uiItemO(layout, NULL, 0, "NLA_OT_tweakmode_enter");
uiItemS(layout);
uiItemO(layout, NULL, 0, "ANIM_OT_previewrange_set");
uiItemO(layout, NULL, 0, "ANIM_OT_previewrange_clear");
uiItemS(layout);
//uiItemO(layout, NULL, 0, "NLA_OT_view_all");
if (sa->full)
uiItemO(layout, NULL, 0, "SCREEN_OT_screen_full_area"); // "Tile Window", Ctrl UpArrow
else
uiItemO(layout, NULL, 0, "SCREEN_OT_screen_full_area"); // "Maximize Window", Ctr DownArrow
}
static uiBlock *dummy_viewmenu(bContext *C, ARegion *ar, void *arg_unused)
static void nla_selectmenu(bContext *C, uiLayout *layout, void *arg_unused)
{
ScrArea *curarea= CTX_wm_area(C);
uiBlock *block;
short yco= 0, menuwidth=120;
uiItemO(layout, NULL, 0, "NLA_OT_select_all_toggle");
uiItemBooleanO(layout, "Invert All", 0, "NLA_OT_select_all_toggle", "invert", 1);
block= uiBeginBlock(C, ar, "dummy_viewmenu", UI_EMBOSSP);
uiBlockSetButmFunc(block, do_viewmenu, NULL);
uiItemS(layout);
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Nothing yet", 0, yco-=20,
menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
if(curarea->headertype==HEADERTOP) {
uiBlockSetDirection(block, UI_DOWN);
}
else {
uiBlockSetDirection(block, UI_TOP);
uiBlockFlipOrder(block);
}
uiTextBoundsBlock(block, 50);
uiEndBlock(C, block);
return block;
uiItemO(layout, NULL, 0, "NLA_OT_select_border");
uiItemBooleanO(layout, "Border Axis Range", 0, "NLA_OT_select_border", "axis_range", 1);
}
static void nla_edit_transformmenu(bContext *C, uiLayout *layout, void *arg_unused)
{
// XXX these operators may change for NLA...
uiItemEnumO(layout, "Grab/Move", 0, "TFM_OT_transform", "mode", TFM_TRANSLATION);
uiItemEnumO(layout, "Extend", 0, "TFM_OT_transform", "mode", TFM_TIME_EXTEND);
uiItemEnumO(layout, "Scale", 0, "TFM_OT_transform", "mode", TFM_TIME_SCALE);
}
static void nla_edit_snapmenu(bContext *C, uiLayout *layout, void *arg_unused)
{
uiItemEnumO(layout, NULL, 0, "NLA_OT_snap", "type", NLAEDIT_SNAP_CFRA);
uiItemEnumO(layout, NULL, 0, "NLA_OT_snap", "type", NLAEDIT_SNAP_NEAREST_FRAME);
uiItemEnumO(layout, NULL, 0, "NLA_OT_snap", "type", NLAEDIT_SNAP_NEAREST_SECOND);
uiItemEnumO(layout, NULL, 0, "NLA_OT_snap", "type", NLAEDIT_SNAP_NEAREST_MARKER);
}
static void nla_editmenu(bContext *C, uiLayout *layout, void *arg_unused)
{
uiItemMenuF(layout, "Transform", 0, nla_edit_transformmenu);
uiItemMenuF(layout, "Snap", 0, nla_edit_snapmenu);
uiItemS(layout);
uiItemO(layout, NULL, 0, "NLA_OT_duplicate");
uiItemO(layout, NULL, 0, "NLA_OT_split");
uiItemS(layout);
uiItemO(layout, NULL, 0, "NLA_OT_delete");
uiItemS(layout);
uiItemO(layout, NULL, 0, "NLA_OT_mute_toggle");
uiItemS(layout);
uiItemO(layout, NULL, 0, "NLA_OT_apply_scale");
uiItemO(layout, NULL, 0, "NLA_OT_clear_scale");
uiItemS(layout);
uiItemO(layout, NULL, 0, "NLA_OT_move_up");
uiItemO(layout, NULL, 0, "NLA_OT_move_down");
}
static void nla_addmenu(bContext *C, uiLayout *layout, void *arg_unused)
{
uiItemO(layout, NULL, 0, "NLA_OT_add_actionclip");
uiItemO(layout, NULL, 0, "NLA_OT_add_transition");
uiItemS(layout);
uiItemO(layout, NULL, 0, "NLA_OT_add_meta");
uiItemO(layout, NULL, 0, "NLA_OT_remove_meta");
uiItemS(layout);
uiItemO(layout, NULL, 0, "NLA_OT_add_tracks");
uiItemBooleanO(layout, "Add Tracks Above Selected", 0, "NLA_OT_add_tracks", "above_selected", 1);
}
/* ------------------ */
static void do_nla_buttons(bContext *C, void *arg, int event)
{
switch(event) {
switch (event) {
case B_REDR:
ED_area_tag_redraw(CTX_wm_area(C));
break;
}
}
void nla_header_buttons(const bContext *C, ARegion *ar)
{
SpaceNla *snla= (SpaceNla *)CTX_wm_space_data(C);
ScrArea *sa= CTX_wm_area(C);
uiBlock *block;
int xco, yco= 3;
@ -109,17 +220,68 @@ void nla_header_buttons(const bContext *C, ARegion *ar)
xco= ED_area_header_standardbuttons(C, block, yco);
if((sa->flag & HEADER_NO_PULLDOWN)==0) {
if ((sa->flag & HEADER_NO_PULLDOWN)==0) {
int xmax;
xmax= GetButStringLength("View");
uiDefPulldownBut(block, dummy_viewmenu, CTX_wm_area(C),
"View", xco, yco-2, xmax-3, 24, "");
xco+=XIC+xmax;
uiDefMenuBut(block, nla_viewmenu, NULL, "View", xco, yco, xmax-3, 20, "");
xco+= xmax;
xmax= GetButStringLength("Select");
uiDefMenuBut(block, nla_selectmenu, NULL, "Select", xco, yco, xmax-3, 20, "");
xco+= xmax;
xmax= GetButStringLength("Edit");
uiDefMenuBut(block, nla_editmenu, NULL, "Edit", xco, yco, xmax-3, 20, "");
xco+= xmax;
xmax= GetButStringLength("Add");
uiDefMenuBut(block, nla_addmenu, NULL, "Add", xco, yco, xmax-3, 20, "");
xco+= xmax;
}
uiBlockSetEmboss(block, UI_EMBOSS);
/* filtering buttons */
if (snla->ads) {
uiBlockBeginAlign(block);
uiDefIconButBitI(block, TOG, ADS_FILTER_ONLYSEL, B_REDR, ICON_RESTRICT_SELECT_OFF, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Only display selected Objects");
uiDefIconButBitI(block, TOGN, ADS_FILTER_NLA_NOACT, B_REDR, ICON_ACTION, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Include AnimData blocks with no NLA Data");
uiBlockEndAlign(block);
xco += 5;
uiBlockBeginAlign(block);
uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSCE, B_REDR, ICON_SCENE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Scene Animation");
uiDefIconButBitI(block, TOGN, ADS_FILTER_NOWOR, B_REDR, ICON_WORLD_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display World Animation");
uiDefIconButBitI(block, TOGN, ADS_FILTER_NOSHAPEKEYS, B_REDR, ICON_SHAPEKEY_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display ShapeKeys");
uiDefIconButBitI(block, TOGN, ADS_FILTER_NOMAT, B_REDR, ICON_MATERIAL_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Materials");
uiDefIconButBitI(block, TOGN, ADS_FILTER_NOLAM, B_REDR, ICON_LAMP_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Lamps");
uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCAM, B_REDR, ICON_CAMERA_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Cameras");
uiDefIconButBitI(block, TOGN, ADS_FILTER_NOCUR, B_REDR, ICON_CURVE_DATA, (short)(xco+=XIC),yco,XIC,YIC, &(snla->ads->filterflag), 0, 0, 0, 0, "Display Curves");
uiBlockEndAlign(block);
xco += 15;
}
else {
// XXX this case shouldn't happen at all... for now, just pad out same amount of space
xco += 7*XIC + 15;
}
xco += (XIC + 8);
/* auto-snap selector */
if (snla->flag & SNLA_DRAWTIME) {
uiDefButS(block, MENU, B_REDR,
"Auto-Snap Keyframes %t|No Time-Snap %x0|Nearest Second %x2|Nearest Marker %x3",
xco,yco,90,YIC, &snla->autosnap, 0, 1, 0, 0,
"Auto-snapping mode for times when transforming");
}
else {
uiDefButS(block, MENU, B_REDR,
"Auto-Snap Keyframes %t|No Time-Snap %x0|Nearest Frame %x2|Nearest Marker %x3",
xco,yco,90,YIC, &snla->autosnap, 0, 1, 0, 0,
"Auto-snapping mode for times when transforming");
}
xco += 98;
/* always as last */
UI_view2d_totRect_set(&ar->v2d, xco+XIC+80, ar->v2d.tot.ymax-ar->v2d.tot.ymin);

@ -17,11 +17,11 @@
* 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) 2008 Blender Foundation.
* The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung.
* All rights reserved.
*
*
* Contributor(s): Blender Foundation
* Contributor(s): Blender Foundation, Joshua Leung
*
* ***** END GPL LICENSE BLOCK *****
*/
@ -30,10 +30,107 @@
/* internal exports only */
/* **************************************** */
/* Macros, etc. only used by NLA */
/* **************************************** */
/* space_nla.c / nla_buttons.c */
ARegion *nla_has_buttons_region(ScrArea *sa);
void nla_buttons_register(ARegionType *art);
void NLA_OT_properties(wmOperatorType *ot);
/* **************************************** */
/* nla_draw.c */
void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar);
void draw_nla_channel_list(bAnimContext *ac, SpaceNla *snla, ARegion *ar);
/* **************************************** */
/* nla_header.c */
void nla_header_buttons(const bContext *C, ARegion *ar);
/* **************************************** */
/* nla_select.c */
/* defines for left-right select tool */
enum {
NLAEDIT_LRSEL_TEST = -1,
NLAEDIT_LRSEL_NONE,
NLAEDIT_LRSEL_LEFT,
NLAEDIT_LRSEL_RIGHT,
} eNlaEdit_LeftRightSelect_Mode;
/* --- */
void NLA_OT_select_all_toggle(wmOperatorType *ot);
void NLA_OT_select_border(wmOperatorType *ot);
void NLA_OT_click_select(wmOperatorType *ot);
/* **************************************** */
/* nla_edit.c */
/* defines for snap strips
*/
enum {
NLAEDIT_SNAP_CFRA = 1,
NLAEDIT_SNAP_NEAREST_FRAME,
NLAEDIT_SNAP_NEAREST_SECOND,
NLAEDIT_SNAP_NEAREST_MARKER,
} eNlaEdit_Snap_Mode;
/* --- */
void NLA_OT_tweakmode_enter(wmOperatorType *ot);
void NLA_OT_tweakmode_exit(wmOperatorType *ot);
/* --- */
void NLA_OT_add_actionclip(wmOperatorType *ot);
void NLA_OT_add_transition(wmOperatorType *ot);
void NLA_OT_add_meta(wmOperatorType *ot);
void NLA_OT_remove_meta(wmOperatorType *ot);
void NLA_OT_duplicate(wmOperatorType *ot);
void NLA_OT_delete(wmOperatorType *ot);
void NLA_OT_split(wmOperatorType *ot);
void NLA_OT_mute_toggle(wmOperatorType *ot);
void NLA_OT_move_up(wmOperatorType *ot);
void NLA_OT_move_down(wmOperatorType *ot);
void NLA_OT_apply_scale(wmOperatorType *ot);
void NLA_OT_clear_scale(wmOperatorType *ot);
void NLA_OT_snap(wmOperatorType *ot);
void NLA_OT_fmodifier_add(wmOperatorType *ot);
/* **************************************** */
/* nla_channels.c */
void NLA_OT_channels_click(wmOperatorType *ot);
void NLA_OT_add_tracks(wmOperatorType *ot);
void NLA_OT_delete_tracks(wmOperatorType *ot);
/* **************************************** */
/* nla_ops.c */
int nlaop_poll_tweakmode_off(bContext *C);
int nlaop_poll_tweakmode_on (bContext *C);
short nlaedit_is_tweakmode_on(bAnimContext *ac);
/* --- */
void nla_operatortypes(void);
void nla_keymap(wmWindowManager *wm);
#endif /* ED_NLA_INTERN_H */

@ -0,0 +1,307 @@
/**
* $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) 2009 Blender Foundation, Joshua Leung
* All rights reserved.
*
*
* Contributor(s): Joshua Leung (major recode)
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <string.h>
#include <stdio.h>
#include "DNA_anim_types.h"
#include "DNA_action_types.h"
#include "DNA_nla_types.h"
#include "DNA_object_types.h"
#include "DNA_space_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BLI_arithb.h"
#include "BLI_rand.h"
#include "BKE_animsys.h"
#include "BKE_nla.h"
#include "BKE_context.h"
#include "BKE_report.h"
#include "BKE_screen.h"
#include "ED_anim_api.h"
#include "ED_space_api.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "WM_api.h"
#include "WM_types.h"
#include "RNA_access.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "UI_view2d.h"
#include "nla_intern.h" // own include
/* ************************** poll callbacks for operators **********************************/
/* tweakmode is NOT enabled */
int nlaop_poll_tweakmode_off (bContext *C)
{
Scene *scene;
/* for now, we check 2 things:
* 1) active editor must be NLA
* 2) tweakmode is currently set as a 'per-scene' flag
* so that it will affect entire NLA data-sets,
* but not all AnimData blocks will be in tweakmode for
* various reasons
*/
if (ED_operator_nla_active(C) == 0)
return 0;
scene= CTX_data_scene(C);
if ((scene == NULL) || (scene->flag & SCE_NLA_EDIT_ON))
return 0;
return 1;
}
/* tweakmode IS enabled */
int nlaop_poll_tweakmode_on (bContext *C)
{
Scene *scene;
/* for now, we check 2 things:
* 1) active editor must be NLA
* 2) tweakmode is currently set as a 'per-scene' flag
* so that it will affect entire NLA data-sets,
* but not all AnimData blocks will be in tweakmode for
* various reasons
*/
if (ED_operator_nla_active(C) == 0)
return 0;
scene= CTX_data_scene(C);
if ((scene == NULL) || !(scene->flag & SCE_NLA_EDIT_ON))
return 0;
return 1;
}
/* is tweakmode enabled - for use in NLA operator code */
short nlaedit_is_tweakmode_on (bAnimContext *ac)
{
if (ac && ac->scene)
return (ac->scene->flag & SCE_NLA_EDIT_ON);
return 0;
}
/* ************************** registration - operator types **********************************/
void nla_operatortypes(void)
{
/* view */
WM_operatortype_append(NLA_OT_properties);
/* channels */
WM_operatortype_append(NLA_OT_channels_click);
WM_operatortype_append(NLA_OT_add_tracks);
WM_operatortype_append(NLA_OT_delete_tracks);
/* select */
WM_operatortype_append(NLA_OT_click_select);
WM_operatortype_append(NLA_OT_select_border);
WM_operatortype_append(NLA_OT_select_all_toggle);
/* edit */
WM_operatortype_append(NLA_OT_tweakmode_enter);
WM_operatortype_append(NLA_OT_tweakmode_exit);
WM_operatortype_append(NLA_OT_add_actionclip);
WM_operatortype_append(NLA_OT_add_transition);
WM_operatortype_append(NLA_OT_add_meta);
WM_operatortype_append(NLA_OT_remove_meta);
WM_operatortype_append(NLA_OT_duplicate);
WM_operatortype_append(NLA_OT_delete);
WM_operatortype_append(NLA_OT_split);
WM_operatortype_append(NLA_OT_mute_toggle);
WM_operatortype_append(NLA_OT_move_up);
WM_operatortype_append(NLA_OT_move_down);
WM_operatortype_append(NLA_OT_apply_scale);
WM_operatortype_append(NLA_OT_clear_scale);
WM_operatortype_append(NLA_OT_snap);
WM_operatortype_append(NLA_OT_fmodifier_add);
}
/* ************************** registration - keymaps **********************************/
static void nla_keymap_channels (wmWindowManager *wm, ListBase *keymap)
{
/* NLA-specific (different to standard channels keymap) -------------------------- */
/* selection */
/* click-select */
// XXX for now, only leftmouse....
WM_keymap_add_item(keymap, "NLA_OT_channels_click", LEFTMOUSE, KM_PRESS, 0, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "NLA_OT_channels_click", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1);
/* channel operations */
/* add tracks */
WM_keymap_add_item(keymap, "NLA_OT_add_tracks", AKEY, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "NLA_OT_add_tracks", AKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0)->ptr, "above_selected", 1);
/* delete tracks */
WM_keymap_add_item(keymap, "NLA_OT_delete_tracks", XKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "NLA_OT_delete_tracks", DELKEY, KM_PRESS, 0, 0);
/* General Animation Channels keymap (see anim_channels.c) ----------------------- */
/* selection */
/* borderselect - not in tweakmode */
WM_keymap_add_item(keymap, "ANIM_OT_channels_select_border", BKEY, KM_PRESS, 0, 0);
/* deselect all - not in tweakmode */
WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", AKEY, KM_PRESS, 0, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1);
/* settings */
WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_toggle", WKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_enable", WKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_disable", WKEY, KM_PRESS, KM_ALT, 0);
/* settings - specialised hotkeys */
WM_keymap_add_item(keymap, "ANIM_OT_channels_editable_toggle", TABKEY, KM_PRESS, 0, 0);
/* expand/collapse */
WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, 0, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, KM_CTRL, 0)->ptr, "all", 1);
RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, KM_CTRL, 0)->ptr, "all", 1);
}
static void nla_keymap_main (wmWindowManager *wm, ListBase *keymap)
{
wmKeymapItem *kmi;
/* selection */
/* click select */
WM_keymap_add_item(keymap, "NLA_OT_click_select", SELECTMOUSE, KM_PRESS, 0, 0);
kmi= WM_keymap_add_item(keymap, "NLA_OT_click_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "extend", 1);
kmi= WM_keymap_add_item(keymap, "NLA_OT_click_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
RNA_enum_set(kmi->ptr, "left_right", NLAEDIT_LRSEL_TEST);
/* deselect all */
WM_keymap_add_item(keymap, "NLA_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "NLA_OT_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1);
/* borderselect */
WM_keymap_add_item(keymap, "NLA_OT_select_border", BKEY, KM_PRESS, 0, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "NLA_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0)->ptr, "axis_range", 1);
/* editing */
/* tweakmode
* - enter and exit are separate operators with the same hotkey...
* This works as they use different poll()'s
*/
WM_keymap_add_item(keymap, "NLA_OT_tweakmode_enter", TABKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "NLA_OT_tweakmode_exit", TABKEY, KM_PRESS, 0, 0);
/* add strips */
WM_keymap_add_item(keymap, "NLA_OT_add_actionclip", AKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "NLA_OT_add_transition", TKEY, KM_PRESS, KM_SHIFT, 0);
/* meta-strips */
WM_keymap_add_item(keymap, "NLA_OT_add_meta", GKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "NLA_OT_remove_meta", GKEY, KM_PRESS, KM_ALT, 0);
/* duplicate */
WM_keymap_add_item(keymap, "NLA_OT_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
/* delete */
WM_keymap_add_item(keymap, "NLA_OT_delete", XKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "NLA_OT_delete", DELKEY, KM_PRESS, 0, 0);
/* split */
WM_keymap_add_item(keymap, "NLA_OT_split", YKEY, KM_PRESS, 0, 0);
/* toggles */
WM_keymap_add_item(keymap, "NLA_OT_mute_toggle", HKEY, KM_PRESS, 0, 0);
/* move up */
WM_keymap_add_item(keymap, "NLA_OT_move_up", PAGEUPKEY, KM_PRESS, 0, 0);
/* move down */
WM_keymap_add_item(keymap, "NLA_OT_move_down", PAGEDOWNKEY, KM_PRESS, 0, 0);
/* apply scale */
WM_keymap_add_item(keymap, "NLA_OT_apply_scale", AKEY, KM_PRESS, KM_CTRL, 0);
/* clear scale */
WM_keymap_add_item(keymap, "NLA_OT_clear_scale", SKEY, KM_PRESS, KM_ALT, 0);
/* snap */
WM_keymap_add_item(keymap, "NLA_OT_snap", SKEY, KM_PRESS, KM_SHIFT, 0);
/* add f-modifier */
WM_keymap_add_item(keymap, "NLA_OT_fmodifier_add", MKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
/* transform system */
transform_keymap_for_space(wm, keymap, SPACE_NLA);
}
/* --------------- */
void nla_keymap(wmWindowManager *wm)
{
ListBase *keymap;
/* keymap for all regions */
keymap= WM_keymap_listbase(wm, "NLA Generic", SPACE_NLA, 0);
WM_keymap_add_item(keymap, "NLA_OT_properties", NKEY, KM_PRESS, 0, 0);
/* channels */
/* Channels are not directly handled by the NLA Editor module, but are inherited from the Animation module.
* Most of the relevant operations, keymaps, drawing, etc. can therefore all be found in that module instead, as there
* are many similarities with the other Animation Editors.
*
* However, those operations which involve clicking on channels and/or the placement of them in the view are implemented here instead
*/
keymap= WM_keymap_listbase(wm, "NLA Channels", SPACE_NLA, 0);
nla_keymap_channels(wm, keymap);
/* data */
keymap= WM_keymap_listbase(wm, "NLA Data", SPACE_NLA, 0);
nla_keymap_main(wm, keymap);
}

@ -0,0 +1,614 @@
/**
* $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) 2009 Blender Foundation, Joshua Leung
* All rights reserved.
*
*
* Contributor(s): Joshua Leung (major recode)
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <string.h>
#include <stdio.h>
#include "DNA_anim_types.h"
#include "DNA_action_types.h"
#include "DNA_nla_types.h"
#include "DNA_object_types.h"
#include "DNA_space_types.h"
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BLI_arithb.h"
#include "BLI_rand.h"
#include "BKE_animsys.h"
#include "BKE_nla.h"
#include "BKE_context.h"
#include "BKE_report.h"
#include "BKE_screen.h"
#include "ED_anim_api.h"
#include "ED_keyframes_edit.h"
#include "ED_markers.h"
#include "ED_space_api.h"
#include "ED_screen.h"
#include "RNA_access.h"
#include "RNA_define.h"
#include "WM_api.h"
#include "WM_types.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "UI_view2d.h"
#include "nla_intern.h" // own include
/* ******************** Utilities ***************************************** */
/* Convert SELECT_* flags to ACHANNEL_SETFLAG_* flags */
static short selmodes_to_flagmodes (short sel)
{
/* convert selection modes to selection modes */
switch (sel) {
case SELECT_SUBTRACT:
return ACHANNEL_SETFLAG_CLEAR;
break;
case SELECT_INVERT:
return ACHANNEL_SETFLAG_TOGGLE;
break;
case SELECT_ADD:
default:
return ACHANNEL_SETFLAG_ADD;
break;
}
}
/* ******************** Deselect All Operator ***************************** */
/* This operator works in one of three ways:
* 1) (de)select all (AKEY) - test if select all or deselect all
* 2) invert all (CTRL-IKEY) - invert selection of all keyframes
* 3) (de)select all - no testing is done; only for use internal tools as normal function...
*/
enum {
DESELECT_STRIPS_NOTEST = 0,
DESELECT_STRIPS_TEST,
DESELECT_STRIPS_CLEARACTIVE,
} eDeselectNlaStrips;
/* Deselects strips in the NLA Editor
* - This is called by the deselect all operator, as well as other ones!
*
* - test: check if select or deselect all (1) or clear all active (2)
* - sel: how to select keyframes
* 0 = deselect
* 1 = select
* 2 = invert
*/
static void deselect_nla_strips (bAnimContext *ac, short test, short sel)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
short smode;
/* determine type-based settings */
filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS);
/* filter data */
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* See if we should be selecting or deselecting */
if (test == DESELECT_STRIPS_TEST) {
for (ale= anim_data.first; ale; ale= ale->next) {
NlaTrack *nlt= (NlaTrack *)ale->data;
NlaStrip *strip;
/* if any strip is selected, break out, since we should now be deselecting */
for (strip= nlt->strips.first; strip; strip= strip->next) {
if (strip->flag & NLASTRIP_FLAG_SELECT) {
sel= SELECT_SUBTRACT;
break;
}
}
if (sel == SELECT_SUBTRACT)
break;
}
}
/* convert selection modes to selection modes */
smode= selmodes_to_flagmodes(sel);
/* Now set the flags */
for (ale= anim_data.first; ale; ale= ale->next) {
NlaTrack *nlt= (NlaTrack *)ale->data;
NlaStrip *strip;
/* apply same selection to all strips */
for (strip= nlt->strips.first; strip; strip= strip->next) {
/* set selection */
if (test != DESELECT_STRIPS_CLEARACTIVE)
ACHANNEL_SET_FLAG(strip, smode, NLASTRIP_FLAG_SELECT);
/* clear active flag */
// TODO: for clear active, do we want to limit this to only doing this on a certain set of tracks though?
strip->flag &= ~NLASTRIP_FLAG_ACTIVE;
}
}
/* Cleanup */
BLI_freelistN(&anim_data);
}
/* ------------------- */
static int nlaedit_deselectall_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
/* 'standard' behaviour - check if selected, then apply relevant selection */
if (RNA_boolean_get(op->ptr, "invert"))
deselect_nla_strips(&ac, DESELECT_STRIPS_NOTEST, SELECT_INVERT);
else
deselect_nla_strips(&ac, DESELECT_STRIPS_TEST, SELECT_ADD);
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_SELECT, NULL);
return OPERATOR_FINISHED;
}
void NLA_OT_select_all_toggle (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Select All";
ot->idname= "NLA_OT_select_all_toggle";
/* api callbacks */
ot->exec= nlaedit_deselectall_exec;
ot->poll= nlaop_poll_tweakmode_off;
/* flags */
ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
/* props */
RNA_def_boolean(ot->srna, "invert", 0, "Invert", "");
}
/* ******************** Border Select Operator **************************** */
/* This operator currently works in one of three ways:
* -> BKEY - 1) all strips within region are selected (ACTKEYS_BORDERSEL_ALLSTRIPS)
* -> ALT-BKEY - depending on which axis of the region was larger...
* -> 2) x-axis, so select all frames within frame range (ACTKEYS_BORDERSEL_FRAMERANGE)
* -> 3) y-axis, so select all frames within channels that region included (ACTKEYS_BORDERSEL_CHANNELS)
*/
/* defines for borderselect mode */
enum {
NLA_BORDERSEL_ALLSTRIPS = 0,
NLA_BORDERSEL_FRAMERANGE,
NLA_BORDERSEL_CHANNELS,
} eActKeys_BorderSelect_Mode;
static void borderselect_nla_strips (bAnimContext *ac, rcti rect, short mode, short selectmode)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
View2D *v2d= &ac->ar->v2d;
rctf rectf;
float ymin=(float)(-NLACHANNEL_HEIGHT), ymax=0;
/* convert border-region to view coordinates */
UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin+2, &rectf.xmin, &rectf.ymin);
UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax-2, &rectf.xmax, &rectf.ymax);
/* filter data */
filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* convert selection modes to selection modes */
selectmode= selmodes_to_flagmodes(selectmode);
/* loop over data, doing border select */
for (ale= anim_data.first; ale; ale= ale->next) {
ymin= ymax - NLACHANNEL_STEP;
/* perform vertical suitability check (if applicable) */
if ( (mode == NLA_BORDERSEL_FRAMERANGE) ||
!((ymax < rectf.ymin) || (ymin > rectf.ymax)) )
{
/* loop over data selecting (only if NLA-Track) */
if (ale->type == ANIMTYPE_NLATRACK) {
NlaTrack *nlt= (NlaTrack *)ale->data;
NlaStrip *strip;
/* only select strips if they fall within the required ranges (if applicable) */
for (strip= nlt->strips.first; strip; strip= strip->next) {
if ( (mode == NLA_BORDERSEL_CHANNELS) ||
BKE_nlastrip_within_bounds(strip, rectf.xmin, rectf.xmax) )
{
/* set selection */
ACHANNEL_SET_FLAG(strip, selectmode, NLASTRIP_FLAG_SELECT);
/* clear active flag */
strip->flag &= ~NLASTRIP_FLAG_ACTIVE;
}
}
}
}
/* set minimum extent to be the maximum of the next channel */
ymax= ymin;
}
/* cleanup */
BLI_freelistN(&anim_data);
}
/* ------------------- */
static int nlaedit_borderselect_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
rcti rect;
short mode=0, selectmode=0;
int event;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
/* get settings from operator */
rect.xmin= RNA_int_get(op->ptr, "xmin");
rect.ymin= RNA_int_get(op->ptr, "ymin");
rect.xmax= RNA_int_get(op->ptr, "xmax");
rect.ymax= RNA_int_get(op->ptr, "ymax");
event= RNA_int_get(op->ptr, "event_type");
if (event == LEFTMOUSE) // FIXME... hardcoded
selectmode = SELECT_ADD;
else
selectmode = SELECT_SUBTRACT;
/* selection 'mode' depends on whether borderselect region only matters on one axis */
if (RNA_boolean_get(op->ptr, "axis_range")) {
/* mode depends on which axis of the range is larger to determine which axis to use
* - checking this in region-space is fine, as it's fundamentally still going to be a different rect size
* - the frame-range select option is favoured over the channel one (x over y), as frame-range one is often
* used for tweaking timing when "blocking", while channels is not that useful...
*/
if ((rect.xmax - rect.xmin) >= (rect.ymax - rect.ymin))
mode= NLA_BORDERSEL_FRAMERANGE;
else
mode= NLA_BORDERSEL_CHANNELS;
}
else
mode= NLA_BORDERSEL_ALLSTRIPS;
/* apply borderselect action */
borderselect_nla_strips(&ac, rect, mode, selectmode);
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_SELECT, NULL);
return OPERATOR_FINISHED;
}
void NLA_OT_select_border(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Border Select";
ot->idname= "NLA_OT_select_border";
/* api callbacks */
ot->invoke= WM_border_select_invoke;
ot->exec= nlaedit_borderselect_exec;
ot->modal= WM_border_select_modal;
ot->poll= nlaop_poll_tweakmode_off;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* rna */
RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", "");
}
/* ******************** Mouse-Click Select Operator *********************** */
/* This operator works in one of 2 ways:
* 1) Select the strip directly under the mouse
* 2) Select all the strips to one side of the mouse
*/
/* defines for left-right select tool */
static EnumPropertyItem prop_nlaedit_leftright_select_types[] = {
{NLAEDIT_LRSEL_TEST, "CHECK", 0, "Check if Select Left or Right", ""},
{NLAEDIT_LRSEL_NONE, "OFF", 0, "Don't select", ""},
{NLAEDIT_LRSEL_LEFT, "LEFT", 0, "Before current frame", ""},
{NLAEDIT_LRSEL_RIGHT, "RIGHT", 0, "After current frame", ""},
{0, NULL, 0, NULL, NULL}
};
/* sensitivity factor for frame-selections */
#define FRAME_CLICK_THRESH 0.1f
/* ------------------- */
/* option 1) select strip directly under mouse */
static void mouse_nla_strips (bContext *C, bAnimContext *ac, int mval[2], short select_mode)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale = NULL;
int filter;
View2D *v2d= &ac->ar->v2d;
Scene *scene= ac->scene;
NlaStrip *strip = NULL;
int channel_index;
float xmin, xmax, dummy;
float x, y;
/* use View2D to determine the index of the channel (i.e a row in the list) where keyframe was */
UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
UI_view2d_listview_view_to_cell(v2d, 0, NLACHANNEL_STEP, 0, (float)NLACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
/* x-range to check is +/- 7 (in screen/region-space) on either side of mouse click
* (that is the size of keyframe icons, so user should be expecting similar tolerances)
*/
UI_view2d_region_to_view(v2d, mval[0]-7, mval[1], &xmin, &dummy);
UI_view2d_region_to_view(v2d, mval[0]+7, mval[1], &xmax, &dummy);
/* filter data */
filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* try to get channel */
ale= BLI_findlink(&anim_data, channel_index);
if (ale == NULL) {
/* channel not found */
printf("Error: animation channel (index = %d) not found in mouse_nla_strips() \n", channel_index);
BLI_freelistN(&anim_data);
return;
}
else {
/* found some channel - we only really should do somethign when its an Nla-Track */
if (ale->type == ANIMTYPE_NLATRACK) {
NlaTrack *nlt= (NlaTrack *)ale->data;
/* loop over NLA-strips in this track, trying to find one which occurs in the necessary bounds */
for (strip= nlt->strips.first; strip; strip= strip->next) {
if (BKE_nlastrip_within_bounds(strip, xmin, xmax))
break;
}
}
/* remove active channel from list of channels for separate treatment (since it's needed later on) */
BLI_remlink(&anim_data, ale);
/* free list of channels, since it's not used anymore */
BLI_freelistN(&anim_data);
}
/* if currently in tweakmode, exit tweakmode before changing selection states
* now that we've found our target...
*/
if (scene->flag & SCE_NLA_EDIT_ON)
WM_operator_name_call(C, "NLA_OT_tweakmode_exit", WM_OP_EXEC_DEFAULT, NULL);
/* for replacing selection, firstly need to clear existing selection */
if (select_mode == SELECT_REPLACE) {
/* reset selection mode for next steps */
select_mode = SELECT_ADD;
/* deselect all strips */
deselect_nla_strips(ac, 0, SELECT_SUBTRACT);
/* deselect all other channels first */
ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
/* Highlight NLA-Track */
if (ale->type == ANIMTYPE_NLATRACK) {
NlaTrack *nlt= (NlaTrack *)ale->data;
nlt->flag |= NLATRACK_SELECTED;
ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nlt, ANIMTYPE_NLATRACK);
}
}
/* only select strip if we clicked on a valid channel and hit something */
if (ale) {
/* select the strip accordingly (if a matching one was found) */
if (strip) {
select_mode= selmodes_to_flagmodes(select_mode);
ACHANNEL_SET_FLAG(strip, select_mode, NLASTRIP_FLAG_SELECT);
/* if we selected it, we can make it active too
* - we always need to clear the active strip flag though...
*/
deselect_nla_strips(ac, DESELECT_STRIPS_CLEARACTIVE, 0);
if (strip->flag & NLASTRIP_FLAG_SELECT)
strip->flag |= NLASTRIP_FLAG_ACTIVE;
}
/* free this channel */
MEM_freeN(ale);
}
}
/* Option 2) Selects all the strips on either side of the current frame (depends on which side the mouse is on) */
static void nlaedit_mselect_leftright (bContext *C, bAnimContext *ac, short leftright, short select_mode)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
Scene *scene= ac->scene;
float xmin, xmax;
/* if currently in tweakmode, exit tweakmode first */
if (scene->flag & SCE_NLA_EDIT_ON)
WM_operator_name_call(C, "NLA_OT_tweakmode_exit", WM_OP_EXEC_DEFAULT, NULL);
/* if select mode is replace, deselect all keyframes (and channels) first */
if (select_mode==SELECT_REPLACE) {
select_mode= SELECT_ADD;
/* deselect all other channels and keyframes */
ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
deselect_nla_strips(ac, 0, SELECT_SUBTRACT);
}
/* get range, and get the right flag-setting mode */
if (leftright == NLAEDIT_LRSEL_LEFT) {
xmin = MINAFRAMEF;
xmax = (float)(CFRA + FRAME_CLICK_THRESH);
}
else {
xmin = (float)(CFRA - FRAME_CLICK_THRESH);
xmax = MAXFRAMEF;
}
select_mode= selmodes_to_flagmodes(select_mode);
/* filter data */
filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* select strips on the side where most data occurs */
for (ale= anim_data.first; ale; ale= ale->next) {
NlaTrack *nlt= (NlaTrack *)ale->data;
NlaStrip *strip;
/* check each strip to see if it is appropriate */
for (strip= nlt->strips.first; strip; strip= strip->next) {
if (BKE_nlastrip_within_bounds(strip, xmin, xmax)) {
ACHANNEL_SET_FLAG(strip, select_mode, NLASTRIP_FLAG_SELECT);
}
}
}
/* Cleanup */
BLI_freelistN(&anim_data);
}
/* ------------------- */
/* handle clicking */
static int nlaedit_clickselect_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
bAnimContext ac;
Scene *scene;
ARegion *ar;
View2D *v2d;
short selectmode;
int mval[2];
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
return OPERATOR_CANCELLED;
/* get useful pointers from animation context data */
scene= ac.scene;
ar= ac.ar;
v2d= &ar->v2d;
/* get mouse coordinates (in region coordinates) */
mval[0]= (event->x - ar->winrct.xmin);
mval[1]= (event->y - ar->winrct.ymin);
/* select mode is either replace (deselect all, then add) or add/extend */
if (RNA_boolean_get(op->ptr, "extend"))
selectmode= SELECT_INVERT;
else
selectmode= SELECT_REPLACE;
/* figure out action to take */
if (RNA_enum_get(op->ptr, "left_right")) {
/* select all keys on same side of current frame as mouse */
float x;
UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, NULL);
if (x < CFRA)
RNA_int_set(op->ptr, "left_right", NLAEDIT_LRSEL_LEFT);
else
RNA_int_set(op->ptr, "left_right", NLAEDIT_LRSEL_RIGHT);
nlaedit_mselect_leftright(C, &ac, RNA_enum_get(op->ptr, "left_right"), selectmode);
}
else {
/* select strips based upon mouse position */
mouse_nla_strips(C, &ac, mval, selectmode);
}
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_SELECT, NULL);
/* for tweak grab to work */
return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
}
void NLA_OT_click_select (wmOperatorType *ot)
{
/* identifiers */
ot->name= "Mouse Select";
ot->idname= "NLA_OT_click_select";
/* api callbacks - absolutely no exec() this yet... */
ot->invoke= nlaedit_clickselect_invoke;
ot->poll= ED_operator_nla_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
/* id-props */
// XXX should we make this into separate operators?
RNA_def_enum(ot->srna, "left_right", prop_nlaedit_leftright_select_types, 0, "Left Right", ""); // CTRLKEY
RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY
}
/* *********************************************** */

@ -29,6 +29,7 @@
#include <string.h>
#include <stdio.h>
#include "DNA_anim_types.h"
#include "DNA_nla_types.h"
#include "DNA_object_types.h"
#include "DNA_space_types.h"
@ -41,10 +42,16 @@
#include "BLI_arithb.h"
#include "BLI_rand.h"
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_nla.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_utildefines.h"
#include "ED_anim_api.h"
#include "ED_markers.h"
#include "ED_space_api.h"
#include "ED_screen.h"
@ -57,20 +64,58 @@
#include "UI_resources.h"
#include "UI_view2d.h"
#include "ED_markers.h"
#include "nla_intern.h" // own include
/* ******************** manage regions ********************* */
ARegion *nla_has_buttons_region(ScrArea *sa)
{
ARegion *ar, *arnew;
for (ar= sa->regionbase.first; ar; ar= ar->next) {
if (ar->regiontype==RGN_TYPE_UI)
return ar;
}
/* add subdiv level; after main */
for (ar= sa->regionbase.first; ar; ar= ar->next) {
if (ar->regiontype==RGN_TYPE_WINDOW)
break;
}
/* is error! */
if (ar==NULL) return NULL;
arnew= MEM_callocN(sizeof(ARegion), "buttons for nla");
BLI_insertlinkafter(&sa->regionbase, ar, arnew);
arnew->regiontype= RGN_TYPE_UI;
arnew->alignment= RGN_ALIGN_RIGHT;
arnew->flag = RGN_FLAG_HIDDEN;
return arnew;
}
/* ******************** default callbacks for nla space ***************** */
static SpaceLink *nla_new(const bContext *C)
{
Scene *scene= CTX_data_scene(C);
ARegion *ar;
SpaceNla *snla;
snla= MEM_callocN(sizeof(SpaceNla), "initnla");
snla->spacetype= SPACE_NLA;
/* allocate DopeSheet data for NLA Editor */
snla->ads= MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet");
/* set auto-snapping settings */
snla->autosnap = SACTSNAP_FRAME;
/* header */
ar= MEM_callocN(sizeof(ARegion), "header for nla");
@ -78,13 +123,23 @@ static SpaceLink *nla_new(const bContext *C)
ar->regiontype= RGN_TYPE_HEADER;
ar->alignment= RGN_ALIGN_BOTTOM;
/* channel list region XXX */
ar= MEM_callocN(sizeof(ARegion), "area region from do_versions");
/* channel list region */
ar= MEM_callocN(sizeof(ARegion), "channel list for nla");
BLI_addtail(&snla->regionbase, ar);
ar->regiontype= RGN_TYPE_CHANNELS;
ar->alignment= RGN_ALIGN_LEFT;
ar->v2d.scroll = (V2D_SCROLL_RIGHT|V2D_SCROLL_BOTTOM);
/* only need to set these settings since this will use the 'stack' configuration */
ar->v2d.scroll = V2D_SCROLL_BOTTOM;
ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL;
/* ui buttons */
ar= MEM_callocN(sizeof(ARegion), "buttons area for nla");
BLI_addtail(&snla->regionbase, ar);
ar->regiontype= RGN_TYPE_UI;
ar->alignment= RGN_ALIGN_RIGHT;
ar->flag = RGN_FLAG_HIDDEN;
/* main area */
ar= MEM_callocN(sizeof(ARegion), "main area for nla");
@ -92,29 +147,26 @@ static SpaceLink *nla_new(const bContext *C)
BLI_addtail(&snla->regionbase, ar);
ar->regiontype= RGN_TYPE_WINDOW;
ar->v2d.tot.xmin= 1.0f;
ar->v2d.tot.ymin= 0.0f;
ar->v2d.tot.xmax= 1000.0f;
ar->v2d.tot.ymax= 1000.0f;
ar->v2d.tot.xmin= (float)(SFRA-10);
ar->v2d.tot.ymin= -500.0f;
ar->v2d.tot.xmax= (float)(EFRA+10);
ar->v2d.tot.ymax= 0.0f;
ar->v2d.cur.xmin= -5.0f;
ar->v2d.cur.ymin= 0.0f;
ar->v2d.cur.xmax= 65.0f;
ar->v2d.cur.ymax= 1000.0f;
ar->v2d.cur = ar->v2d.tot;
ar->v2d.min[0]= 0.0f;
ar->v2d.min[1]= 0.0f;
ar->v2d.min[1]= 0.0f;
ar->v2d.max[0]= MAXFRAMEF;
ar->v2d.max[1]= 1000.0f;
ar->v2d.max[1]= 10000.0f;
ar->v2d.minzoom= 0.1f;
ar->v2d.maxzoom= 50.0f;
ar->v2d.scroll |= (V2D_SCROLL_BOTTOM|V2D_SCROLL_SCALE_HORIZONTAL);
ar->v2d.minzoom= 0.01f;
ar->v2d.maxzoom= 50;
ar->v2d.scroll = (V2D_SCROLL_BOTTOM|V2D_SCROLL_SCALE_HORIZONTAL);
ar->v2d.scroll |= (V2D_SCROLL_RIGHT);
ar->v2d.keepzoom= V2D_LOCKZOOM_Y;
ar->v2d.align= V2D_ALIGN_NO_POS_Y;
ar->v2d.flag = V2D_VIEWSYNC_AREA_VERTICAL;
return (SpaceLink *)snla;
}
@ -122,15 +174,25 @@ static SpaceLink *nla_new(const bContext *C)
/* not spacelink itself */
static void nla_free(SpaceLink *sl)
{
// SpaceNla *snla= (SpaceNla*) sl;
SpaceNla *snla= (SpaceNla*) sl;
if (snla->ads) {
BLI_freelistN(&snla->ads->chanbase);
MEM_freeN(snla->ads);
}
}
/* spacetype; init callback */
static void nla_init(struct wmWindowManager *wm, ScrArea *sa)
{
SpaceNla *snla= (SpaceNla *)sa->spacedata.first;
/* init dopesheet data if non-existant (i.e. for old files) */
if (snla->ads == NULL)
snla->ads= MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet");
ED_area_tag_refresh(sa);
}
static SpaceLink *nla_duplicate(SpaceLink *sl)
@ -138,15 +200,33 @@ static SpaceLink *nla_duplicate(SpaceLink *sl)
SpaceNla *snlan= MEM_dupallocN(sl);
/* clear or remove stuff from old */
snlan->ads= MEM_dupallocN(snlan->ads);
return (SpaceLink *)snlan;
}
/* add handlers, stuff you only do once or on area/region changes */
static void nla_channel_area_init(wmWindowManager *wm, ARegion *ar)
{
ListBase *keymap;
UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy);
/* own keymap */
// TODO: cannot use generic copy, need special NLA version
keymap= WM_keymap_listbase(wm, "NLA Channels", SPACE_NLA, 0); /* XXX weak? */
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
keymap= WM_keymap_listbase(wm, "NLA Generic", SPACE_NLA, 0);
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
}
/* draw entirely, view changes should be handled here */
static void nla_channel_area_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
// SpaceNla *snla= (SpaceNla*)CTX_wm_space_data(C);
// View2D *v2d= &ar->v2d;
SpaceNla *snla= (SpaceNla*)CTX_wm_space_data(C);
bAnimContext ac;
View2D *v2d= &ar->v2d;
View2DScrollers *scrollers;
float col[3];
/* clear and setup matrix */
@ -154,15 +234,20 @@ static void nla_channel_area_draw(const bContext *C, ARegion *ar)
glClearColor(col[0], col[1], col[2], 0.0);
glClear(GL_COLOR_BUFFER_BIT);
// UI_view2d_view_ortho(C, v2d);
/* data... */
UI_view2d_view_ortho(C, v2d);
/* data */
if (ANIM_animdata_get_context(C, &ac)) {
draw_nla_channel_list(&ac, snla, ar);
}
/* reset view matrix */
//UI_view2d_view_restore(C);
UI_view2d_view_restore(C);
/* scrollers? */
/* scrollers */
scrollers= UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
UI_view2d_scrollers_draw(C, v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
}
@ -174,16 +259,22 @@ static void nla_main_area_init(wmWindowManager *wm, ARegion *ar)
UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
/* own keymap */
keymap= WM_keymap_listbase(wm, "NLA", SPACE_NLA, 0); /* XXX weak? */
keymap= WM_keymap_listbase(wm, "NLA Data", SPACE_NLA, 0); /* XXX weak? */
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
keymap= WM_keymap_listbase(wm, "NLA Generic", SPACE_NLA, 0);
WM_event_add_keymap_handler(&ar->handlers, keymap);
}
static void nla_main_area_draw(const bContext *C, ARegion *ar)
{
/* draw entirely, view changes should be handled here */
// SpaceNla *snla= (SpaceNla*)CTX_wm_space_data(C);
SpaceNla *snla= (SpaceNla*)CTX_wm_space_data(C);
bAnimContext ac;
View2D *v2d= &ar->v2d;
View2DGrid *grid;
View2DScrollers *scrollers;
float col[3];
short unit=0, flag=0;
/* clear and setup matrix */
UI_GetThemeColor3fv(TH_BACK, col);
@ -192,24 +283,45 @@ static void nla_main_area_draw(const bContext *C, ARegion *ar)
UI_view2d_view_ortho(C, v2d);
/* data... */
/* time grid */
unit= (snla->flag & SNLA_DRAWTIME)? V2D_UNIT_SECONDS : V2D_UNIT_FRAMES;
grid= UI_view2d_grid_calc(C, v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY, ar->winx, ar->winy);
UI_view2d_grid_draw(C, v2d, grid, V2D_GRIDLINES_ALL);
UI_view2d_grid_free(grid);
/* data */
if (ANIM_animdata_get_context(C, &ac)) {
/* strips and backdrops */
draw_nla_main_data(&ac, snla, ar);
/* text draw cached, in pixelspace now */
UI_view2d_text_cache_draw(ar);
}
UI_view2d_view_ortho(C, v2d);
/* current frame */
if (snla->flag & SNLA_DRAWTIME) flag |= DRAWCFRA_UNIT_SECONDS;
if ((snla->flag & SNLA_NODRAWCFRANUM)==0) flag |= DRAWCFRA_SHOW_NUMBOX;
ANIM_draw_cfra(C, v2d, flag);
/* markers */
UI_view2d_view_orthoSpecial(C, v2d, 1);
draw_markers_time(C, 0);
/* preview range */
UI_view2d_view_ortho(C, v2d);
ANIM_draw_previewrange(C, v2d);
/* reset view matrix */
UI_view2d_view_restore(C);
/* scrollers? */
/* scrollers */
scrollers= UI_view2d_scrollers_calc(C, v2d, unit, V2D_GRID_CLAMP, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
UI_view2d_scrollers_draw(C, v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
}
void nla_operatortypes(void)
{
}
void nla_keymap(struct wmWindowManager *wm)
{
}
/* add handlers, stuff you only do once or on area/region changes */
static void nla_header_area_init(wmWindowManager *wm, ARegion *ar)
@ -239,9 +351,144 @@ static void nla_header_area_draw(const bContext *C, ARegion *ar)
UI_view2d_view_restore(C);
}
/* add handlers, stuff you only do once or on area/region changes */
static void nla_buttons_area_init(wmWindowManager *wm, ARegion *ar)
{
ListBase *keymap;
ED_region_panels_init(wm, ar);
keymap= WM_keymap_listbase(wm, "NLA Generic", SPACE_NLA, 0);
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
}
static void nla_buttons_area_draw(const bContext *C, ARegion *ar)
{
ED_region_panels(C, ar, 1, NULL);
}
static void nla_region_listener(ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch(wmn->category) {
case NC_ANIMATION:
ED_region_tag_redraw(ar);
break;
case NC_SCENE:
switch(wmn->data) {
case ND_OB_ACTIVE:
case ND_FRAME:
case ND_MARKERS:
ED_region_tag_redraw(ar);
break;
}
break;
case NC_OBJECT:
switch(wmn->data) {
case ND_BONE_ACTIVE:
case ND_BONE_SELECT:
case ND_KEYS:
ED_region_tag_redraw(ar);
break;
}
break;
default:
if(wmn->data==ND_KEYS)
ED_region_tag_redraw(ar);
break;
}
}
static void nla_main_area_listener(ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch(wmn->category) {
case NC_ANIMATION:
ED_region_tag_redraw(ar);
break;
case NC_SCENE:
switch(wmn->data) {
case ND_OB_ACTIVE:
case ND_FRAME:
case ND_MARKERS:
ED_region_tag_redraw(ar);
break;
}
break;
case NC_OBJECT:
switch(wmn->data) {
case ND_BONE_ACTIVE:
case ND_BONE_SELECT:
case ND_KEYS:
case ND_TRANSFORM:
ED_region_tag_redraw(ar);
break;
}
break;
default:
if(wmn->data==ND_KEYS)
ED_region_tag_redraw(ar);
}
}
static void nla_channel_area_listener(ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch(wmn->category) {
case NC_ANIMATION:
ED_region_tag_redraw(ar);
break;
case NC_SCENE:
switch(wmn->data) {
case ND_OB_ACTIVE:
ED_region_tag_redraw(ar);
break;
}
break;
case NC_OBJECT:
switch(wmn->data) {
case ND_BONE_ACTIVE:
case ND_BONE_SELECT:
case ND_KEYS:
ED_region_tag_redraw(ar);
break;
}
break;
default:
if(wmn->data==ND_KEYS)
ED_region_tag_redraw(ar);
}
}
/* editor level listener */
static void nla_listener(ScrArea *sa, wmNotifier *wmn)
{
/* context changes */
switch (wmn->category) {
case NC_ANIMATION:
// TODO: filter specific types of changes?
ED_area_tag_refresh(sa);
break;
case NC_SCENE:
/*switch (wmn->data) {
case ND_OB_ACTIVE:
case ND_OB_SELECT:
ED_area_tag_refresh(sa);
break;
}*/
ED_area_tag_refresh(sa);
break;
case NC_OBJECT:
/*switch (wmn->data) {
case ND_BONE_SELECT:
case ND_BONE_ACTIVE:
ED_area_tag_refresh(sa);
break;
}*/
ED_area_tag_refresh(sa);
break;
}
}
/* only called once, from space/spacetypes.c */
@ -257,6 +504,7 @@ void ED_spacetype_nla(void)
st->init= nla_init;
st->duplicate= nla_duplicate;
st->operatortypes= nla_operatortypes;
st->listener= nla_listener;
st->keymap= nla_keymap;
/* regions: main window */
@ -265,7 +513,7 @@ void ED_spacetype_nla(void)
art->init= nla_main_area_init;
art->draw= nla_main_area_draw;
art->listener= nla_main_area_listener;
art->keymapflag= ED_KEYMAP_VIEW2D|ED_KEYMAP_FRAMES;
art->keymapflag= ED_KEYMAP_VIEW2D/*|ED_KEYMAP_MARKERS*/|ED_KEYMAP_ANIMATION|ED_KEYMAP_FRAMES;
BLI_addhead(&st->regiontypes, art);
@ -286,11 +534,25 @@ void ED_spacetype_nla(void)
art->minsizex= 200;
art->keymapflag= ED_KEYMAP_UI|ED_KEYMAP_VIEW2D;
//art->init= nla_channel_area_init;
art->init= nla_channel_area_init;
art->draw= nla_channel_area_draw;
art->listener= nla_channel_area_listener;
BLI_addhead(&st->regiontypes, art);
/* regions: UI buttons */
art= MEM_callocN(sizeof(ARegionType), "spacetype nla region");
art->regionid = RGN_TYPE_UI;
art->minsizex= 200;
art->keymapflag= ED_KEYMAP_UI;
art->listener= nla_region_listener;
art->init= nla_buttons_area_init;
art->draw= nla_buttons_area_draw;
BLI_addhead(&st->regiontypes, art);
nla_buttons_register(art);
BKE_spacetype_register(st);
}

@ -949,7 +949,6 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
/* NLA Data */
if (adt->nla_tracks.first) {
#if 0
TreeElement *tenla= outliner_add_element(soops, &te->subtree, adt, te, TSE_NLA, 0);
NlaTrack *nlt;
int a= 0;
@ -957,17 +956,18 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
tenla->name= "NLA Tracks";
for (nlt= adt->nla_tracks.first; nlt; nlt= nlt->next) {
TreeElement *tenlt= outliner_add_element(soops, &te->subtree, nlt, te, TSE_NLA_TRACK, a);
bActionStrip *strip;
TreeElement *tenlt= outliner_add_element(soops, &tenla->subtree, nlt, tenla, TSE_NLA_TRACK, a);
NlaStrip *strip;
TreeElement *ten;
int b= 0;
for (strip=nlt->strips.first; strip; strip=strip->next, a++) {
ten= outliner_add_element(soops, &tenla->subtree, strip->act, tenla, TSE_NLA_ACTION, a);
tenlt->name= nlt->name;
for (strip=nlt->strips.first; strip; strip=strip->next, b++) {
ten= outliner_add_element(soops, &tenlt->subtree, strip->act, tenlt, TSE_NLA_ACTION, b);
if(ten) ten->directdata= strip;
}
}
#endif
}
}
else if(type==TSE_SEQUENCE) {
@ -3518,6 +3518,8 @@ static void tselem_draw_icon(float x, float y, TreeStoreElem *tselem, TreeElemen
UI_icon_draw(x, y, ICON_ANIM_DATA); break; // xxx
case TSE_NLA:
UI_icon_draw(x, y, ICON_NLA); break;
case TSE_NLA_TRACK:
UI_icon_draw(x, y, ICON_NLA); break; // XXX
case TSE_NLA_ACTION:
UI_icon_draw(x, y, ICON_ACTION); break;
case TSE_DEFGROUP_BASE:

@ -94,6 +94,7 @@ typedef struct TreeElement {
#define TSE_RNA_STRUCT 30
#define TSE_RNA_PROPERTY 31
#define TSE_RNA_ARRAY_ELEM 32
#define TSE_NLA_TRACK 33
/* outliner search flags */
#define OL_FIND 0

@ -373,6 +373,7 @@ static uiBlock *time_framemenu(bContext *C, ARegion *ar, void *arg_unused)
#define B_REDRAWALL 750
#define B_TL_REW 751
#define B_TL_PLAY 752
#define B_TL_RPLAY 760
#define B_TL_FF 753
#define B_TL_PREVKEY 754
#define B_TL_NEXTKEY 755
@ -415,6 +416,18 @@ void do_time_buttons(bContext *C, void *arg, int event)
sad->ar= time_top_left_3dwindow(screen);
}
break;
case B_TL_RPLAY:
ED_screen_animation_timer(C, stime->redraws, -1);
/* update region if TIME_REGION was set, to leftmost 3d window */
if(screen->animtimer && (stime->redraws & TIME_REGION)) {
wmTimer *wt= screen->animtimer;
ScreenAnimData *sad= wt->customdata;
sad->ar= time_top_left_3dwindow(screen);
}
break;
case B_TL_STOP:
ED_screen_animation_timer(C, 0, 0);
@ -536,9 +549,12 @@ void time_header_buttons(const bContext *C, ARegion *ar)
xco += (short)(4.5 * XIC + 16);
/* MINAFRAMEF not MINFRAMEF, since MINAFRAMEF allows to set current frame negative
* to facilitate easier keyframing in some situations
*/
uiDefButI(block, NUM, B_NEWFRAME, "",
xco,yco, (int)3.5*XIC,YIC,
&(scene->r.cfra), MINFRAMEF, MAXFRAMEF, 0, 0,
&(scene->r.cfra), MINAFRAMEF, MAXFRAMEF, 0, 0,
"Displays Current Frame of animation");
xco += (short)(3.5 * XIC + 16);
@ -550,14 +566,27 @@ void time_header_buttons(const bContext *C, ARegion *ar)
xco, yco, XIC, YIC, 0, 0, 0, 0, 0, "Skip to previous keyframe (Ctrl PageDown)");
xco+= XIC+4;
if(CTX_wm_screen(C)->animtimer)
if(CTX_wm_screen(C)->animtimer) {
/* pause button is drawn centered between the two other buttons for now (saves drawing 2 buttons, or having position changes) */
xco+= XIC/2 + 2;
uiDefIconBut(block, BUT, B_TL_STOP, ICON_PAUSE,
xco, yco, XIC, YIC, 0, 0, 0, 0, 0, "Stop Playing Timeline");
else
xco+= XIC/2 + 2;
}
else {
// FIXME: the icon for this is crap
uiDefIconBut(block, BUT, B_TL_RPLAY, ICON_REW/*ICON_PLAY*/,
xco, yco, XIC, YIC, 0, 0, 0, 0, 0, "Play Timeline in Reverse");
xco+= XIC+4;
uiDefIconBut(block, BUT, B_TL_PLAY, ICON_PLAY,
xco, yco, XIC, YIC, 0, 0, 0, 0, 0, "Play Timeline ");
}
xco+= XIC+4;
uiDefIconBut(block, BUT, B_TL_NEXTKEY, ICON_NEXT_KEYFRAME,
xco, yco, XIC, YIC, 0, 0, 0, 0, 0, "Skip to next keyframe (Ctrl PageUp)");
xco+= XIC+4;

@ -37,6 +37,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
#include "DNA_action_types.h"
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
@ -52,6 +53,7 @@
#include "BLI_blenlib.h"
#include "BLI_arithb.h"
#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_constraint.h"
@ -61,6 +63,7 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_nla.h"
#include "BKE_object.h"
#include "BKE_utildefines.h"
@ -2019,10 +2022,9 @@ static void draw_ebones(View3D *v3d, RegionView3D *rv3d, Object *ob, int dt)
*/
static void draw_pose_paths(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob)
{
AnimData *adt= BKE_animdata_from_id(&ob->id);
bArmature *arm= ob->data;
bPoseChannel *pchan;
// bAction *act; // XXX old animsys - watch it!
// bActionChannel *achan;
ActKeyColumn *ak;
ListBase keys;
float *fp, *fp_start;
@ -2168,14 +2170,11 @@ static void draw_pose_paths(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
/* build list of all keyframes in active action for pchan */
keys.first = keys.last = NULL;
#if 0 // XXX old animation system
act= ob->action;
if (act) {
achan= get_action_channel(act, pchan->name);
if (achan)
ipo_to_keylist(achan->ipo, &keys, NULL, NULL);
if (adt) {
bActionGroup *agrp= action_groups_find_named(adt->action, pchan->name);
if (agrp)
agroup_to_keylist(adt, agrp, &keys, NULL);
}
#endif // XXX old animation system
/* Draw slightly-larger yellow dots at each keyframe */
UI_ThemeColor(TH_VERTEX_SELECT);
@ -2254,6 +2253,7 @@ static void ghost_poses_tag_unselected(Object *ob, short unset)
static void draw_ghost_poses_range(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base)
{
Object *ob= base->object;
AnimData *adt= BKE_animdata_from_id(&ob->id);
bArmature *arm= ob->data;
bPose *posen, *poseo;
float start, end, stepsize, range, colfac;
@ -2290,7 +2290,7 @@ static void draw_ghost_poses_range(Scene *scene, View3D *v3d, RegionView3D *rv3d
colfac = (end - (float)CFRA) / range;
UI_ThemeColorShadeAlpha(TH_WIRE, 0, -128-(int)(120.0*sqrt(colfac)));
//do_all_pose_actions(scene, ob); // XXX old animation system
BKE_animsys_evaluate_animdata(&ob->id, adt, (float)CFRA, ADT_RECALC_ALL);
where_is_pose(scene, ob);
draw_pose_channels(scene, v3d, rv3d, base, OB_WIRE);
}
@ -2315,22 +2315,22 @@ static void draw_ghost_poses_range(Scene *scene, View3D *v3d, RegionView3D *rv3d
static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base)
{
Object *ob= base->object;
bAction *act= ob->action; // XXX old animsys stuff... watch it!
AnimData *adt= BKE_animdata_from_id(&ob->id);
bAction *act= (adt) ? adt->action : NULL;
bArmature *arm= ob->data;
bPose *posen, *poseo;
ListBase keys= {NULL, NULL};
ActKeysInc aki = {0, 0, 0};
ActKeyColumn *ak, *akn;
float start, end, range, colfac, i;
int cfrao, flago;
aki.start= start = (float)arm->ghostsf;
aki.end= end = (float)arm->ghostef;
start = (float)arm->ghostsf;
end = (float)arm->ghostef;
if (end <= start)
return;
/* get keyframes - then clip to only within range */
action_to_keylist(act, &keys, NULL, &aki);
action_to_keylist(adt, act, &keys, NULL);
range= 0;
for (ak= keys.first; ak; ak= akn) {
akn= ak->next;
@ -2366,7 +2366,7 @@ static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, RegionView3D *rv3d,
CFRA= (int)ak->cfra;
//do_all_pose_actions(scene, ob); // XXX old animation system
BKE_animsys_evaluate_animdata(&ob->id, adt, (float)CFRA, ADT_RECALC_ALL);
where_is_pose(scene, ob);
draw_pose_channels(scene, v3d, rv3d, base, OB_WIRE);
}
@ -2391,38 +2391,27 @@ static void draw_ghost_poses_keys(Scene *scene, View3D *v3d, RegionView3D *rv3d,
static void draw_ghost_poses(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base)
{
Object *ob= base->object;
AnimData *adt= BKE_animdata_from_id(&ob->id);
bArmature *arm= ob->data;
bPose *posen, *poseo;
//bActionStrip *strip;
float cur, start, end, stepsize, range, colfac, actframe, ctime;
int cfrao, maptime, flago;
int cfrao, flago;
/* pre conditions, get an action with sufficient frames */
//if (ob->action==NULL)
// return;
if ELEM(NULL, adt, adt->action)
return;
calc_action_range(ob->action, &start, &end, 0);
calc_action_range(adt->action, &start, &end, 0);
if (start == end)
return;
stepsize= (float)(arm->ghostsize);
range= (float)(arm->ghostep)*stepsize + 0.5f; /* plus half to make the for loop end correct */
#if 0 // XXX old animation system
/* we only map time for armature when an active strip exists */
for (strip=ob->nlastrips.first; strip; strip=strip->next)
if (strip->flag & ACTSTRIP_ACTIVE)
break;
#endif // XXX old animsys
//maptime= (strip!=NULL);
maptime= 0;
/* store values */
ob->flag &= ~OB_POSEMODE;
cfrao= CFRA;
if (maptime) actframe= get_action_frame(ob, (float)CFRA);
else actframe= (float)CFRA;
actframe= BKE_nla_tweakedit_remap(adt, (float)CFRA, 0);
flago= arm->flag;
arm->flag &= ~(ARM_DRAWNAMES|ARM_DRAWAXES);
@ -2444,11 +2433,10 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
/* only within action range */
if (actframe+ctime >= start && actframe+ctime <= end) {
if (maptime) CFRA= (int)get_action_frame_inv(ob, actframe+ctime);
else CFRA= (int)floor(actframe+ctime);
CFRA= (int)BKE_nla_tweakedit_remap(adt, actframe+ctime, NLATIME_CONVERT_MAP);
if (CFRA != cfrao) {
//do_all_pose_actions(scene, ob); // xxx old animation system crap
BKE_animsys_evaluate_animdata(&ob->id, adt, (float)CFRA, ADT_RECALC_ALL);
where_is_pose(scene, ob);
draw_pose_channels(scene, v3d, rv3d, base, OB_WIRE);
}
@ -2460,11 +2448,10 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base
/* only within action range */
if ((actframe-ctime >= start) && (actframe-ctime <= end)) {
if (maptime) CFRA= (int)get_action_frame_inv(ob, actframe-ctime);
else CFRA= (int)floor(actframe-ctime);
CFRA= (int)BKE_nla_tweakedit_remap(adt, actframe-ctime, NLATIME_CONVERT_MAP);
if (CFRA != cfrao) {
//do_all_pose_actions(scene, ob); // XXX old animation system crap...
BKE_animsys_evaluate_animdata(&ob->id, adt, (float)CFRA, ADT_RECALC_ALL);
where_is_pose(scene, ob);
draw_pose_channels(scene, v3d, rv3d, base, OB_WIRE);
}

@ -409,6 +409,15 @@ static void view3d_main_area_listener(ARegion *ar, wmNotifier *wmn)
{
/* context changes */
switch(wmn->category) {
case NC_ANIMATION:
switch(wmn->data) {
case ND_KEYFRAME_EDIT:
case ND_KEYFRAME_PROP:
case ND_NLA_ACTCHANGE:
case ND_ANIMCHAN_SELECT:
ED_region_tag_redraw(ar);
break;
}
case NC_SCENE:
switch(wmn->data) {
case ND_TRANSFORM:

@ -118,7 +118,6 @@
if( (v3d->lay & obedit->lay)==0 ) return;
/* XXX port over */
static void handle_view3d_lock(void) {}
static void countall(void) {}
extern void borderselect();
static int retopo_mesh_paint_check() {return 0;}
@ -201,6 +200,25 @@ static RegionView3D *wm_region_view3d(const bContext *C)
return NULL;
}
// XXX quickly ported across
static void handle_view3d_lock(bContext *C)
{
Scene *scene= CTX_data_scene(C);
ScrArea *sa= CTX_wm_area(C);
View3D *v3d= (View3D *)CTX_wm_space_data(C);
if (v3d != NULL && sa != NULL) {
if(v3d->localview==0 && v3d->scenelock && sa->spacetype==SPACE_VIEW3D) {
/* copy to scene */
scene->lay= v3d->lay;
scene->camera= v3d->camera;
//copy_view3d_lock(REDRAW);
}
}
}
/* XXX; all this context stuff... should become operator */
void do_layer_buttons(bContext *C, short event)
{
@ -230,7 +248,7 @@ void do_layer_buttons(bContext *C, short event)
v3d->lay= (1<<20)-1;
}
if(v3d->scenelock) handle_view3d_lock();
if(v3d->scenelock) handle_view3d_lock(C);
/* new layers might need unflushed events events */
DAG_scene_update_flags(scene, v3d->lay); /* tags all that moves and flushes */
@ -266,7 +284,7 @@ static int layers_exec(bContext *C, wmOperator *op)
else
v3d->lay = (1<<nr);
if(v3d->scenelock) handle_view3d_lock();
if(v3d->scenelock) handle_view3d_lock(C);
/* new layers might need unflushed events events */
DAG_scene_update_flags(scene, v3d->lay); /* tags all that moves and flushes */
@ -4303,7 +4321,7 @@ static void do_view3d_header_buttons(bContext *C, void *arg, int event)
v3d->layact= v3d->lay;
}
if(v3d->scenelock) handle_view3d_lock();
if(v3d->scenelock) handle_view3d_lock(C);
ED_area_tag_redraw(sa);
countall();

@ -45,6 +45,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_action_types.h" /* for some special action-editor settings */
#include "DNA_constraint_types.h"
@ -76,9 +77,9 @@
//#include "BIF_editmesh.h"
//#include "BIF_editsima.h"
//#include "BIF_editparticle.h"
//#include "BIF_editaction.h"
#include "BKE_action.h" /* get_action_frame */
#include "BKE_action.h"
#include "BKE_nla.h"
//#include "BKE_bad_level_calls.h"/* popmenu and error */
#include "BKE_bmesh.h"
#include "BKE_context.h"
@ -89,7 +90,6 @@
#include "BKE_utildefines.h"
#include "BKE_context.h"
//#include "BSE_editaction_types.h"
//#include "BSE_view.h"
#include "ED_image.h"
@ -162,7 +162,7 @@ void convertViewVec(TransInfo *t, float *vec, short dx, short dy)
vec[1]= aspy*(v2d->cur.ymax-v2d->cur.ymin)*(dy)/divy;
vec[2]= 0.0f;
}
else if(t->spacetype==SPACE_IPO) {
else if(ELEM(t->spacetype, SPACE_IPO, SPACE_NLA)) {
View2D *v2d = t->view;
float divx, divy;
@ -212,7 +212,7 @@ void projectIntView(TransInfo *t, float *vec, int *adr)
UI_view2d_to_region_no_clip(t->view, v[0], v[1], adr, adr+1);
}
else if(t->spacetype==SPACE_IPO) {
else if(ELEM(t->spacetype, SPACE_IPO, SPACE_NLA)) {
int out[2] = {0, 0};
UI_view2d_view_to_region((View2D *)t->view, vec[0], vec[1], out, out+1);
@ -241,7 +241,7 @@ void projectFloatView(TransInfo *t, float *vec, float *adr)
adr[0]= a[0];
adr[1]= a[1];
}
else if(t->spacetype==SPACE_IPO) {
else if(ELEM(t->spacetype, SPACE_IPO, SPACE_NLA)) {
int a[2];
projectIntView(t, vec, a);
@ -300,24 +300,15 @@ static void viewRedrawForce(bContext *C, TransInfo *t)
WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
}
else if (t->spacetype == SPACE_ACTION) {
SpaceAction *saction= (SpaceAction *)t->sa->spacedata.first;
// TRANSFORM_FIX_ME
if (saction->lock) {
// whole window...
}
else
ED_area_tag_redraw(t->sa);
//SpaceAction *saction= (SpaceAction *)t->sa->spacedata.first;
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
}
else if (t->spacetype == SPACE_IPO) {
SpaceIpo *sipo= (SpaceIpo *)t->sa->spacedata.first;
// TRANSFORM_FIX_ME
if (sipo->lock) {
// whole window...
}
else
ED_area_tag_redraw(t->sa);
//SpaceIpo *sipo= (SpaceIpo *)t->sa->spacedata.first;
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
}
else if (t->spacetype == SPACE_NLA) {
WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
}
else if(t->spacetype == SPACE_NODE)
{
@ -1323,10 +1314,10 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event, int
case TFM_TIME_EXTEND:
/* now that transdata has been made, do like for TFM_TIME_TRANSLATE (for most Animation
* Editors because they have only 1D transforms for time values) or TFM_TRANSLATION
* (for Graph Editor only since it uses 'standard' transforms to get 2D movement)
* (for Graph/NLA Editors only since they uses 'standard' transforms to get 2D movement)
* depending on which editor this was called from
*/
if (t->spacetype == SPACE_IPO)
if ELEM(t->spacetype, SPACE_IPO, SPACE_NLA)
initTranslation(t);
else
initTimeTranslate(t);
@ -4355,7 +4346,7 @@ static short getAnimEdit_DrawTime(TransInfo *t)
/* This function is used by Animation Editor specific transform functions to do
* the Snap Keyframe to Nearest Frame/Marker
*/
static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, Object *ob, short autosnap)
static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, AnimData *adt, short autosnap)
{
/* snap key to nearest frame? */
if (autosnap == SACTSNAP_FRAME) {
@ -4365,8 +4356,8 @@ static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, Object *ob, short
double val;
/* convert frame to nla-action time (if needed) */
if (ob)
val= get_action_frame_inv(ob, *(td->val));
if (adt)
val= BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_MAP);
else
val= *(td->val);
@ -4377,8 +4368,8 @@ static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, Object *ob, short
val= (float)( floor(val+0.5f) );
/* convert frame out of nla-action time */
if (ob)
*(td->val)= get_action_frame(ob, val);
if (adt)
*(td->val)= BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP);
else
*(td->val)= val;
}
@ -4387,8 +4378,8 @@ static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, Object *ob, short
float val;
/* convert frame to nla-action time (if needed) */
if (ob)
val= get_action_frame_inv(ob, *(td->val));
if (adt)
val= BKE_nla_tweakedit_remap(adt, *(td->val), NLATIME_CONVERT_MAP);
else
val= *(td->val);
@ -4397,8 +4388,8 @@ static void doAnimEdit_SnapFrame(TransInfo *t, TransData *td, Object *ob, short
val= (float)ED_markers_find_nearest_marker_time(&t->scene->markers, val);
/* convert frame out of nla-action time */
if (ob)
*(td->val)= get_action_frame(ob, val);
if (adt)
*(td->val)= BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP);
else
*(td->val)= val;
}
@ -4471,13 +4462,14 @@ static void applyTimeTranslate(TransInfo *t, float sval)
/* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
for (i = 0 ; i < t->total; i++, td++) {
/* it is assumed that td->ob is a pointer to the object,
/* it is assumed that td->extra is a pointer to the AnimData,
* whose active action is where this keyframe comes from
* (this is only valid when not in NLA)
*/
Object *ob= td->ob;
AnimData *adt= (t->spacetype != SPACE_NLA) ? td->extra : NULL;
/* check if any need to apply nla-scaling */
if (ob) {
/* check if any need to apply nla-mapping */
if (adt) {
deltax = t->values[0];
if (autosnap == SACTSNAP_STEP) {
@ -4487,9 +4479,9 @@ static void applyTimeTranslate(TransInfo *t, float sval)
deltax= (float)( floor(deltax + 0.5f) );
}
val = get_action_frame_inv(ob, td->ival);
val = BKE_nla_tweakedit_remap(adt, td->ival, NLATIME_CONVERT_MAP);
val += deltax;
*(td->val) = get_action_frame(ob, val);
*(td->val) = BKE_nla_tweakedit_remap(adt, val, NLATIME_CONVERT_UNMAP);
}
else {
deltax = val = t->values[0];
@ -4505,7 +4497,7 @@ static void applyTimeTranslate(TransInfo *t, float sval)
}
/* apply nearest snapping */
doAnimEdit_SnapFrame(t, td, ob, autosnap);
doAnimEdit_SnapFrame(t, td, adt, autosnap);
}
}
@ -4605,15 +4597,16 @@ static void applyTimeSlide(TransInfo *t, float sval)
/* it doesn't matter whether we apply to t->data or t->data2d, but t->data2d is more convenient */
for (i = 0 ; i < t->total; i++, td++) {
/* it is assumed that td->ob is a pointer to the object,
/* it is assumed that td->extra is a pointer to the AnimData,
* whose active action is where this keyframe comes from
* (this is only valid when not in NLA)
*/
Object *ob= td->ob;
AnimData *adt= (t->spacetype != SPACE_NLA) ? td->extra : NULL;
float cval = t->values[0];
/* apply scaling to necessary values */
if (ob)
cval= get_action_frame(ob, cval);
/* apply NLA-mapping to necessary values */
if (adt)
cval= BKE_nla_tweakedit_remap(adt, cval, NLATIME_CONVERT_UNMAP);
/* only apply to data if in range */
if ((sval > minx) && (sval < maxx)) {
@ -4708,10 +4701,11 @@ static void applyTimeScale(TransInfo *t) {
for (i = 0 ; i < t->total; i++, td++) {
/* it is assumed that td->ob is a pointer to the object,
/* it is assumed that td->extra is a pointer to the AnimData,
* whose active action is where this keyframe comes from
* (this is only valid when not in NLA)
*/
Object *ob= td->ob;
AnimData *adt= (t->spacetype != SPACE_NLA) ? td->extra : NULL;
float startx= CFRA;
float fac= t->values[0];
@ -4722,9 +4716,9 @@ static void applyTimeScale(TransInfo *t) {
fac= (float)( floor(fac + 0.5f) );
}
/* check if any need to apply nla-scaling */
if (ob)
startx= get_action_frame(ob, startx);
/* check if any need to apply nla-mapping */
if (adt)
startx= BKE_nla_tweakedit_remap(adt, startx, NLATIME_CONVERT_UNMAP);
/* now, calculate the new value */
*(td->val) = td->ival - startx;
@ -4732,7 +4726,7 @@ static void applyTimeScale(TransInfo *t) {
*(td->val) += startx;
/* apply nearest snapping */
doAnimEdit_SnapFrame(t, td, ob, autosnap);
doAnimEdit_SnapFrame(t, td, adt, autosnap);
}
}
@ -4746,18 +4740,6 @@ int TimeScale(TransInfo *t, short mval[2])
sval= t->imval[0];
cval= mval[0];
// XXX ewww... we need a better factor!
#if 0 // TRANSFORM_FIX_ME
switch (t->spacetype) {
case SPACE_ACTION:
width= ACTWIDTH;
break;
case SPACE_NLA:
width= NLAWIDTH;
break;
}
#endif
/* calculate scaling factor */
startx= sval-(width/2+(t->ar->winx)/2);
deltax= cval-(width/2+(t->ar->winx)/2);

@ -161,6 +161,21 @@ typedef struct TransDataSeq {
} TransDataSeq;
/* for NLA transform (stored in td->extra pointer) */
typedef struct TransDataNla {
struct NlaTrack *oldTrack; /* Original NLA-Track that the strip belongs to */
struct NlaTrack *nlt; /* Current NLA-Track that the strip belongs to */
struct NlaStrip *strip; /* NLA-strip this data represents */
/* dummy values for transform to write in - must have 3 elements... */
float h1[3]; /* start handle */
float h2[3]; /* end handle */
int trackIndex; /* index of track that strip is currently in */
int handle; /* handle-index: 0 for dummy entry, -1 for start, 1 for end, 2 for both ends */
} TransDataNla;
typedef struct TransData {
float dist; /* Distance needed to affect element (for Proportionnal Editing) */
float rdist; /* Distance to the nearest element (for Proportionnal Editing) */

@ -90,6 +90,7 @@
#include "BKE_mball.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_nla.h"
#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_sequence.h"
@ -100,16 +101,13 @@
#include "BKE_context.h"
#include "BKE_report.h"
//#include "BIF_editaction.h"
//#include "BIF_editview.h"
//#include "BIF_editlattice.h"
//#include "BIF_editconstraint.h"
//#include "BIF_editmesh.h"
//#include "BIF_editnla.h"
//#include "BIF_editsima.h"
//#include "BIF_editparticle.h"
#include "BIF_gl.h"
//#include "BIF_keyframing.h"
//#include "BIF_poseobject.h"
//#include "BIF_meshtools.h"
//#include "BIF_mywindow.h"
@ -125,6 +123,7 @@
#include "ED_keyframing.h"
#include "ED_keyframes_edit.h"
#include "ED_object.h"
#include "ED_markers.h"
#include "ED_mesh.h"
#include "ED_retopo.h"
#include "ED_types.h"
@ -133,13 +132,7 @@
#include "UI_view2d.h"
//#include "BSE_drawipo.h"
//#include "BSE_edit.h"
//#include "BSE_editipo.h"
//#include "BSE_editipo_types.h"
//#include "BSE_editaction_types.h"
//#include "BDR_drawaction.h" // list of keyframes in action
//#include "BDR_editobject.h" // reset_slowparents()
//#include "BDR_gpencil.h"
@ -2559,7 +2552,216 @@ int clipUVTransform(TransInfo *t, float *vec, int resize)
return (clipx || clipy);
}
/* ********************* ACTION/NLA EDITOR ****************** */
/* ********************* ANIMATION EDITORS (GENERAL) ************************* */
/* This function tests if a point is on the "mouse" side of the cursor/frame-marking */
static short FrameOnMouseSide(char side, float frame, float cframe)
{
/* both sides, so it doesn't matter */
if (side == 'B') return 1;
/* only on the named side */
if (side == 'R')
return (frame >= cframe) ? 1 : 0;
else
return (frame <= cframe) ? 1 : 0;
}
/* ********************* NLA EDITOR ************************* */
static void createTransNlaData(bContext *C, TransInfo *t)
{
Scene *scene= CTX_data_scene(C);
TransData *td = NULL;
TransDataNla *tdn = NULL;
bAnimContext ac;
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
int count=0;
char side;
/* determine what type of data we are operating on */
if (ANIM_animdata_get_context(C, &ac) == 0)
return;
/* filter data */
filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* which side of the current frame should be allowed */
if (t->mode == TFM_TIME_EXTEND) {
/* only side on which mouse is gets transformed */
float xmouse, ymouse;
UI_view2d_region_to_view(&ac.ar->v2d, t->imval[0], t->imval[1], &xmouse, &ymouse);
side = (xmouse > CFRA) ? 'R' : 'L'; // XXX use t->frame_side
}
else {
/* normal transform - both sides of current frame are considered */
side = 'B';
}
/* loop 1: count how many strips are selected (consider each strip as 2 points) */
for (ale= anim_data.first; ale; ale= ale->next) {
NlaTrack *nlt= (NlaTrack *)ale->data;
NlaStrip *strip;
/* make some meta-strips for chains of selected strips */
BKE_nlastrips_make_metas(&nlt->strips, 1);
/* only consider selected strips */
for (strip= nlt->strips.first; strip; strip= strip->next) {
// TODO: we can make strips have handles later on...
/* transition strips can't get directly transformed */
if (strip->type != NLASTRIP_TYPE_TRANSITION) {
if (strip->flag & NLASTRIP_FLAG_SELECT) {
if (FrameOnMouseSide(side, strip->start, (float)CFRA)) count++;
if (FrameOnMouseSide(side, strip->end, (float)CFRA)) count++;
}
}
}
}
/* stop if trying to build list if nothing selected */
if (count == 0) {
/* cleanup temp list */
BLI_freelistN(&anim_data);
return;
}
/* allocate memory for data */
t->total= count;
t->data= MEM_callocN(t->total*sizeof(TransData), "TransData(NLA Editor)");
td= t->data;
t->customData= MEM_callocN(t->total*sizeof(TransDataNla), "TransDataNla (NLA Editor)");
tdn= t->customData;
/* loop 2: build transdata array */
for (ale= anim_data.first; ale; ale= ale->next) {
/* only if a real NLA-track */
if (ale->type == ANIMTYPE_NLATRACK) {
NlaTrack *nlt= (NlaTrack *)ale->data;
NlaStrip *strip;
/* only consider selected strips */
for (strip= nlt->strips.first; strip; strip= strip->next) {
// TODO: we can make strips have handles later on...
/* transition strips can't get directly transformed */
if (strip->type != NLASTRIP_TYPE_TRANSITION) {
if (strip->flag & NLASTRIP_FLAG_SELECT) {
/* our transform data is constructed as follows:
* - only the handles on the right side of the current-frame get included
* - td structs are transform-elements operated on by the transform system
* and represent a single handle. The storage/pointer used (val or loc) depends on
* whether we're scaling or transforming. Ultimately though, the handles
* the td writes to will simply be a dummy in tdn
* - for each strip being transformed, a single tdn struct is used, so in some
* cases, there will need to be 1 of these tdn elements in the array skipped...
*/
float center[3], yval;
/* firstly, init tdn settings */
tdn->oldTrack= tdn->nlt= nlt;
tdn->strip= strip;
tdn->trackIndex= BLI_findindex(&nlt->strips, strip);
yval= (float)(tdn->trackIndex * NLACHANNEL_STEP);
tdn->h1[0]= strip->start;
tdn->h1[1]= yval;
tdn->h2[0]= strip->end;
tdn->h2[1]= yval;
center[0]= (float)CFRA;
center[1]= yval;
center[2]= 0.0f;
/* set td's based on which handles are applicable */
if (FrameOnMouseSide(side, strip->start, (float)CFRA))
{
/* just set tdn to assume that it only has one handle for now */
tdn->handle= -1;
/* now, link the transform data up to this data */
if (t->mode == TFM_TRANSLATION) {
td->loc= tdn->h1;
VECCOPY(td->iloc, tdn->h1);
/* store all the other gunk that is required by transform */
VECCOPY(td->center, center);
memset(td->axismtx, 0, sizeof(td->axismtx));
td->axismtx[2][2] = 1.0f;
td->ext= NULL; td->tdi= NULL; td->val= NULL;
td->flag |= TD_SELECTED;
td->dist= 0.0f;
Mat3One(td->mtx);
Mat3One(td->smtx);
}
else {
td->val= &tdn->h1[0];
td->ival= tdn->h1[0];
}
td->extra= tdn;
td++;
}
if (FrameOnMouseSide(side, strip->end, (float)CFRA))
{
/* if tdn is already holding the start handle, then we're doing both, otherwise, only end */
tdn->handle= (tdn->handle) ? 2 : 1;
/* now, link the transform data up to this data */
if (t->mode == TFM_TRANSLATION) {
td->loc= tdn->h2;
VECCOPY(td->iloc, tdn->h2);
/* store all the other gunk that is required by transform */
VECCOPY(td->center, center);
memset(td->axismtx, 0, sizeof(td->axismtx));
td->axismtx[2][2] = 1.0f;
td->ext= NULL; td->tdi= NULL; td->val= NULL;
td->flag |= TD_SELECTED;
td->dist= 0.0f;
Mat3One(td->mtx);
Mat3One(td->smtx);
}
else {
td->val= &tdn->h2[0];
td->ival= tdn->h2[0];
}
td->extra= tdn;
td++;
}
/* if both handles were used, skip the next tdn (i.e. leave it blank) since the counting code is dumb...
* otherwise, just advance to the next one...
*/
if (tdn->handle == 2)
tdn += 2;
else
tdn++;
}
}
}
}
}
/* cleanup temp list */
BLI_freelistN(&anim_data);
}
/* ********************* ACTION EDITOR ****************** */
/* Called by special_aftertrans_update to make sure selected gp-frames replace
* any other gp-frames which may reside on that frame (that are not selected).
@ -2730,12 +2932,12 @@ static void posttrans_action_clean (bAnimContext *ac, bAction *act)
* - all keyframes are converted in/out of global time
*/
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= ANIM_nla_mapping_get(ac, ale);
AnimData *adt= ANIM_nla_mapping_get(ac, ale);
if (nob) {
//ANIM_nla_mapping_apply_ipocurve(nob, ale->key_data, 0, 1);
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
posttrans_fcurve_clean(ale->key_data);
//ANIM_nla_mapping_apply_ipocurve(nob, ale->key_data, 1, 1);
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
}
else
posttrans_fcurve_clean(ale->key_data);
@ -2747,19 +2949,6 @@ static void posttrans_action_clean (bAnimContext *ac, bAction *act)
/* ----------------------------- */
/* This function tests if a point is on the "mouse" side of the cursor/frame-marking */
static short FrameOnMouseSide(char side, float frame, float cframe)
{
/* both sides, so it doesn't matter */
if (side == 'B') return 1;
/* only on the named side */
if (side == 'R')
return (frame >= cframe) ? 1 : 0;
else
return (frame <= cframe) ? 1 : 0;
}
/* fully select selected beztriples, but only include if it's on the right side of cfra */
static int count_fcurve_keys(FCurve *fcu, char side, float cfra)
{
@ -2808,17 +2997,16 @@ static int count_gplayer_frames(bGPDlayer *gpl, char side, float cfra)
#endif
/* This function assigns the information to transdata */
static void TimeToTransData(TransData *td, float *time, Object *ob)
static void TimeToTransData(TransData *td, float *time, AnimData *adt)
{
/* memory is calloc'ed, so that should zero everything nicely for us */
td->val = time;
td->ival = *(time);
/* store the Object where this keyframe exists as a keyframe of the
* active action as td->ob. Usually, this member is only used for constraints
* drawing
/* store the AnimData where this keyframe exists as a keyframe of the
* active action as td->extra.
*/
td->ob= ob;
td->extra= adt;
}
/* This function advances the address to which td points to, so it must return
@ -2828,7 +3016,7 @@ static void TimeToTransData(TransData *td, float *time, Object *ob)
* The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
* on the named side are used.
*/
static TransData *FCurveToTransData(TransData *td, FCurve *fcu, Object *ob, char side, float cfra)
static TransData *FCurveToTransData(TransData *td, FCurve *fcu, AnimData *adt, char side, float cfra)
{
BezTriple *bezt;
int i;
@ -2842,13 +3030,13 @@ static TransData *FCurveToTransData(TransData *td, FCurve *fcu, Object *ob, char
/* only add if on the right 'side' of the current frame */
if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
/* each control point needs to be added separetely */
TimeToTransData(td, bezt->vec[0], ob);
TimeToTransData(td, bezt->vec[0], adt);
td++;
TimeToTransData(td, bezt->vec[1], ob);
TimeToTransData(td, bezt->vec[1], adt);
td++;
TimeToTransData(td, bezt->vec[2], ob);
TimeToTransData(td, bezt->vec[2], adt);
td++;
}
}
@ -2958,13 +3146,13 @@ static void createTransActionData(bContext *C, TransInfo *t)
/* loop 1: fully select ipo-keys and count how many BezTriples are selected */
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= ANIM_nla_mapping_get(&ac, ale);
AnimData *adt= ANIM_nla_mapping_get(&ac, ale);
/* convert current-frame to action-time (slightly less accurate, espcially under
* higher scaling ratios, but is faster than converting all points)
*/
if (nob)
cfra = get_action_frame(nob, (float)CFRA);
if (adt)
cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
else
cfra = (float)CFRA;
@ -3011,18 +3199,18 @@ static void createTransActionData(bContext *C, TransInfo *t)
// tfd += i;
//}
//else {
Object *nob= ANIM_nla_mapping_get(&ac, ale);
AnimData *adt= ANIM_nla_mapping_get(&ac, ale);
FCurve *fcu= (FCurve *)ale->key_data;
/* convert current-frame to action-time (slightly less accurate, espcially under
* higher scaling ratios, but is faster than converting all points)
*/
if (nob)
cfra = get_action_frame(nob, (float)CFRA);
if (adt)
cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
else
cfra = (float)CFRA;
td= FCurveToTransData(td, fcu, nob, side, cfra);
td= FCurveToTransData(td, fcu, adt, side, cfra);
//}
}
@ -3051,28 +3239,26 @@ static void createTransActionData(bContext *C, TransInfo *t)
/* ********************* GRAPH EDITOR ************************* */
/* Helper function for createTransGraphEditData, which is reponsible for associating
* source data with transform data
*/
static void bezt_to_transdata (TransData *td, TransData2D *td2d, Object *nob, float *loc, float *cent, short selected, short ishandle, short intvals)
static void bezt_to_transdata (TransData *td, TransData2D *td2d, AnimData *adt, float *loc, float *cent, short selected, short ishandle, short intvals)
{
/* New location from td gets dumped onto the old-location of td2d, which then
* gets copied to the actual data at td2d->loc2d (bezt->vec[n])
*
* Due to NLA scaling, we apply NLA scaling to some of the verts here,
* and then that scaling will be undone after transform is done.
* Due to NLA mapping, we apply NLA mapping to some of the verts here,
* and then that mapping will be undone after transform is done.
*/
if (nob) {
td2d->loc[0] = get_action_frame_inv(nob, loc[0]);
if (adt) {
td2d->loc[0] = BKE_nla_tweakedit_remap(adt, loc[0], NLATIME_CONVERT_UNMAP);
td2d->loc[1] = loc[1];
td2d->loc[2] = 0.0f;
td2d->loc2d = loc;
td->loc = td2d->loc;
td->center[0] = get_action_frame_inv(nob, cent[0]);
td->center[0] = BKE_nla_tweakedit_remap(adt, cent[0], NLATIME_CONVERT_UNMAP);
td->center[1] = cent[1];
td->center[2] = 0.0f;
@ -3094,6 +3280,9 @@ static void bezt_to_transdata (TransData *td, TransData2D *td2d, Object *nob, fl
td->ext= NULL; td->tdi= NULL; td->val= NULL;
/* store AnimData info in td->extra, for applying mapping when flushing */
td->extra= adt;
if (selected) {
td->flag |= TD_SELECTED;
td->dist= 0.0f;
@ -3153,14 +3342,14 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
/* loop 1: count how many BezTriples (specifically their verts) are selected (or should be edited) */
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= NULL; //ANIM_nla_mapping_get(&ac, ale); // XXX we don't handle NLA mapping for now here...
AnimData *adt= ANIM_nla_mapping_get(&ac, ale);
FCurve *fcu= (FCurve *)ale->key_data;
/* convert current-frame to action-time (slightly less accurate, espcially under
* higher scaling ratios, but is faster than converting all points)
*/
if (nob)
cfra = get_action_frame(nob, (float)CFRA);
if (adt)
cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
else
cfra = (float)CFRA;
@ -3210,13 +3399,19 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
td2d= t->data2d;
/* loop 2: build transdata arrays */
cfra = (float)CFRA;
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= NULL; //ANIM_nla_mapping_get(&ac, ale); // XXX we don't handle NLA mapping here yet
AnimData *adt= ANIM_nla_mapping_get(&ac, ale);
FCurve *fcu= (FCurve *)ale->key_data;
short intvals= (fcu->flag & FCURVE_INT_VALUES);
/* convert current-frame to action-time (slightly less accurate, espcially under
* higher scaling ratios, but is faster than converting all points)
*/
if (adt)
cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
else
cfra = (float)CFRA;
/* only include BezTriples whose 'keyframe' occurs on the same side of the current frame as mouse (if applicable) */
bezt= fcu->bezt;
prevbezt= NULL;
@ -3230,7 +3425,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
if ( (!prevbezt && (bezt->ipo==BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo==BEZT_IPO_BEZ)) ) {
if (bezt->f1 & SELECT) {
hdata = initTransDataCurveHandes(td, bezt);
bezt_to_transdata(td++, td2d++, nob, bezt->vec[0], bezt->vec[1], 1, 1, intvals);
bezt_to_transdata(td++, td2d++, adt, bezt->vec[0], bezt->vec[1], 1, 1, intvals);
}
else
h1= 0;
@ -3239,7 +3434,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
if (bezt->f3 & SELECT) {
if (hdata==NULL)
hdata = initTransDataCurveHandes(td, bezt);
bezt_to_transdata(td++, td2d++, nob, bezt->vec[2], bezt->vec[1], 1, 1, intvals);
bezt_to_transdata(td++, td2d++, adt, bezt->vec[2], bezt->vec[1], 1, 1, intvals);
}
else
h2= 0;
@ -3255,7 +3450,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
hdata = initTransDataCurveHandes(td, bezt);
}
bezt_to_transdata(td++, td2d++, nob, bezt->vec[1], bezt->vec[1], 1, 0, intvals);
bezt_to_transdata(td++, td2d++, adt, bezt->vec[1], bezt->vec[1], 1, 0, intvals);
}
/* special hack (must be done after initTransDataCurveHandes(), as that stores handle settings to restore...):
@ -3475,30 +3670,37 @@ void flushTransGraphData(TransInfo *t)
SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
TransData *td;
TransData2D *td2d;
Scene *scene= t->scene;
double secf= FPS;
int a;
/* flush to 2d vector from internally used 3d vector */
for (a=0, td= t->data, td2d=t->data2d; a<t->total; a++, td++, td2d++) {
AnimData *adt= (AnimData *)td->extra; /* pointers to relevant AnimData blocks are stored in the td->extra pointers */
/* handle snapping for time values
* - we should still be in NLA-mapping timespace
* - only apply to keyframes (but never to handles)
*/
if ((td->flag & TD_NOTIMESNAP)==0) {
switch (sipo->autosnap) {
case SACTSNAP_FRAME: /* snap to nearest frame */
td2d->loc[0]= (float)( floor(td2d->loc[0]+0.5f) );
case SACTSNAP_FRAME: /* snap to nearest frame (or second if drawing seconds) */
if (sipo->flag & SIPO_DRAWTIME)
td2d->loc[0]= (float)( floor((td2d->loc[0]/secf) + 0.5f) * secf );
else
td2d->loc[0]= (float)( floor(td2d->loc[0]+0.5f) );
break;
case SACTSNAP_MARKER: /* snap to nearest marker */
//td2d->loc[0]= (float)find_nearest_marker_time(td2d->loc[0]);
td2d->loc[0]= (float)ED_markers_find_nearest_marker_time(&t->scene->markers, td2d->loc[0]);
break;
}
}
/* we need to unapply the nla-scaling from the time in some situations */
//if (NLA_IPO_SCALED)
// td2d->loc2d[0]= get_action_frame(OBACT, td2d->loc[0]);
//else
if (adt)
td2d->loc2d[0]= BKE_nla_tweakedit_remap(adt, td2d->loc[0], NLATIME_CONVERT_UNMAP);
else
td2d->loc2d[0]= td2d->loc[0];
/* if int-values only, truncate to integers */
@ -3509,7 +3711,6 @@ void flushTransGraphData(TransInfo *t)
}
}
/* **************** IpoKey stuff, for Object TransData ********** */
/* while transforming */
@ -4477,16 +4678,16 @@ void special_aftertrans_update(TransInfo *t)
/* these should all be ipo-blocks */
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= ANIM_nla_mapping_get(&ac, ale);
AnimData *adt= ANIM_nla_mapping_get(&ac, ale);
FCurve *fcu= (FCurve *)ale->key_data;
if ( (saction->flag & SACTION_NOTRANSKEYCULL)==0 &&
((cancelled == 0) || (duplicate)) )
{
if (nob) {
ANIM_nla_mapping_apply_fcurve(nob, fcu, 0, 1);
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 1);
posttrans_fcurve_clean(fcu);
ANIM_nla_mapping_apply_fcurve(nob, fcu, 1, 1);
ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 1);
}
else
posttrans_fcurve_clean(fcu);
@ -4588,16 +4789,16 @@ void special_aftertrans_update(TransInfo *t)
/* these should all be ipo-blocks */
for (ale= anim_data.first; ale; ale= ale->next) {
Object *nob= ANIM_nla_mapping_get(&ac, ale);
AnimData *adt= ANIM_nla_mapping_get(&ac, ale);
FCurve *fcu= (FCurve *)ale->key_data;
if ( (sipo->flag & SIPO_NOTRANSKEYCULL)==0 &&
((cancelled == 0) || (duplicate)) )
{
if (nob) {
ANIM_nla_mapping_apply_fcurve(nob, fcu, 0, 1);
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, fcu, 0, 1);
posttrans_fcurve_clean(fcu);
ANIM_nla_mapping_apply_fcurve(nob, fcu, 1, 1);
ANIM_nla_mapping_apply_fcurve(adt, fcu, 1, 1);
}
else
posttrans_fcurve_clean(fcu);
@ -4611,6 +4812,51 @@ void special_aftertrans_update(TransInfo *t)
/* make sure all F-Curves are set correctly */
ANIM_editkeyframes_refresh(&ac);
}
else if (t->spacetype == SPACE_NLA) {
Scene *scene;
bAnimContext ac;
/* initialise relevant anim-context 'context' data from TransInfo data */
/* NOTE: sync this with the code in ANIM_animdata_get_context() */
memset(&ac, 0, sizeof(bAnimContext));
scene= ac.scene= t->scene;
ob= ac.obact= OBACT;
ac.sa= t->sa;
ac.ar= t->ar;
ac.spacetype= (t->sa)? t->sa->spacetype : 0;
ac.regiontype= (t->ar)? t->ar->regiontype : 0;
if (ANIM_animdata_context_getdata(&ac) == 0)
return;
if (ac.datatype)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
short filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NLATRACKS);
/* get channels to work on */
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
for (ale= anim_data.first; ale; ale= ale->next) {
NlaTrack *nlt= (NlaTrack *)ale->data;
/* make sure strips are in order again */
BKE_nlatrack_sort_strips(nlt);
/* remove the temp metas */
BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
}
/* free temp memory */
BLI_freelistN(&anim_data);
}
// XXX check on the calls below... we need some of these sanity checks
//synchronize_action_strips();
//ANIM_editkeyframes_refresh(&ac);
}
else if (t->obedit) {
// TRANSFORM_FIX_ME
// if (t->mode==TFM_BONESIZE || t->mode==TFM_BONE_ENVELOPE)
@ -4695,24 +4941,6 @@ void special_aftertrans_update(TransInfo *t)
}
}
#if 0 // TRANSFORM_FIX_ME
else if (t->spacetype == SPACE_NLA) {
recalc_all_ipos(); // bad
synchronize_action_strips();
/* cleanup */
for (base=t->scene->base.first; base; base=base->next)
base->flag &= ~(BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA);
/* after transform, remove duplicate keyframes on a frame that resulted from transform */
if ( (G.snla->flag & SNLA_NOTRANSKEYCULL)==0 &&
((cancelled == 0) || (duplicate)) )
{
posttrans_nla_clean(t);
}
}
#endif
clear_trans_object_base_flags(t);
#if 0 // TRANSFORM_FIX_ME
@ -4945,8 +5173,7 @@ void createTransData(bContext *C, TransInfo *t)
}
else if (t->spacetype == SPACE_NLA) {
t->flag |= T_POINTS|T_2D_EDIT;
// TRANSFORM_FIX_ME
//createTransNlaData(C, t);
createTransNlaData(C, t);
}
else if (t->spacetype == SPACE_SEQ) {
t->flag |= T_POINTS|T_2D_EDIT;

@ -59,9 +59,7 @@
//#include "BIF_screen.h"
//#include "BIF_mywindow.h"
#include "BIF_gl.h"
//#include "BIF_editaction.h"
//#include "BIF_editmesh.h"
//#include "BIF_editnla.h"
//#include "BIF_editsima.h"
//#include "BIF_editparticle.h"
//#include "BIF_meshtools.h"
@ -81,6 +79,7 @@
#include "BKE_key.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_nla.h"
#include "BKE_object.h"
#include "BKE_utildefines.h"
#include "BKE_context.h"
@ -89,6 +88,7 @@
#include "ED_armature.h"
#include "ED_image.h"
#include "ED_keyframing.h"
#include "ED_markers.h"
#include "ED_mesh.h"
#include "ED_retopo.h"
#include "ED_space_api.h"
@ -102,6 +102,8 @@
#include "BLI_editVert.h"
#include "BLI_rand.h"
#include "RNA_access.h"
#include "WM_types.h"
#include "UI_resources.h"
@ -268,92 +270,6 @@ void recalcData(TransInfo *t)
Scene *scene = t->scene;
Base *base;
#if 0 // TRANSFORM_FIX_ME
if (t->spacetype == SPACE_ACTION) {
Object *ob= OBACT;
void *data;
short context;
/* determine what type of data we are operating on */
data = get_action_context(&context);
if (data == NULL) return;
/* always flush data if gpencil context */
if (context == ACTCONT_GPENCIL) {
flushTransGPactionData(t);
}
if (G.saction->lock) {
if (context == ACTCONT_ACTION) {
if(ob) {
ob->ctime= -1234567.0f;
if(ob->pose || ob_get_key(ob))
DAG_object_flush_update(G.scene, ob, OB_RECALC);
else
DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
}
}
else if (context == ACTCONT_SHAPEKEY) {
DAG_object_flush_update(G.scene, OBACT, OB_RECALC_OB|OB_RECALC_DATA);
}
}
}
else if (t->spacetype == SPACE_NLA) {
if (G.snla->lock) {
for (base=G.scene->base.first; base; base=base->next) {
if (base->flag & BA_HAS_RECALC_OB)
base->object->recalc |= OB_RECALC_OB;
if (base->flag & BA_HAS_RECALC_DATA)
base->object->recalc |= OB_RECALC_DATA;
if (base->object->recalc)
base->object->ctime= -1234567.0f; // eveil!
/* recalculate scale of selected nla-strips */
if (base->object->nlastrips.first) {
Object *bob= base->object;
bActionStrip *strip;
for (strip= bob->nlastrips.first; strip; strip= strip->next) {
if (strip->flag & ACTSTRIP_SELECT) {
float actlen= strip->actend - strip->actstart;
float len= strip->end - strip->start;
strip->scale= len / (actlen * strip->repeat);
}
}
}
}
DAG_scene_flush_update(G.scene, screen_view3d_layers(), 0);
}
else {
for (base=G.scene->base.first; base; base=base->next) {
/* recalculate scale of selected nla-strips */
if (base->object && base->object->nlastrips.first) {
Object *bob= base->object;
bActionStrip *strip;
for (strip= bob->nlastrips.first; strip; strip= strip->next) {
if (strip->flag & ACTSTRIP_SELECT) {
float actlen= strip->actend - strip->actstart;
float len= strip->end - strip->start;
/* prevent 'negative' scaling */
if (len < 0) {
SWAP(float, strip->start, strip->end);
len= fabs(len);
}
/* calculate new scale */
strip->scale= len / (actlen * strip->repeat);
}
}
}
}
}
}
#endif
if (t->obedit) {
}
else if(G.f & G_PARTICLEEDIT) {
@ -420,6 +336,179 @@ void recalcData(TransInfo *t)
}
}
else if (t->spacetype == SPACE_NLA) {
TransDataNla *tdn= (TransDataNla *)t->customData;
SpaceNla *snla= (SpaceNla *)t->sa->spacedata.first;
Scene *scene= t->scene;
double secf= FPS;
int i;
/* for each strip we've got, perform some additional validation of the values that got set before
* using RNA to set the value (which does some special operations when setting these values to make
* sure that everything works ok)
*/
for (i = 0; i < t->total; i++, tdn++) {
NlaStrip *strip= tdn->strip;
PointerRNA strip_ptr;
short pExceeded, nExceeded, iter;
int delta_y1, delta_y2;
/* if this tdn has no handles, that means it is just a dummy that should be skipped */
if (tdn->handle == 0)
continue;
/* if cancelling transform, just write the values without validating, then move on */
if (t->state == TRANS_CANCEL) {
/* clear the values by directly overwriting the originals, but also need to restore
* endpoints of neighboring transition-strips
*/
/* start */
strip->start= tdn->h1[0];
if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION))
strip->prev->end= tdn->h1[0];
/* end */
strip->end= tdn->h2[0];
if ((strip->next) && (strip->next->type == NLASTRIP_TYPE_TRANSITION))
strip->next->start= tdn->h2[0];
/* flush transforms to child strips (since this should be a meta) */
BKE_nlameta_flush_transforms(strip);
/* restore to original track (if needed) */
if (tdn->oldTrack != tdn->nlt) {
/* just append to end of list for now, since strips get sorted in special_aftertrans_update() */
BLI_remlink(&tdn->nlt->strips, strip);
BLI_addtail(&tdn->oldTrack->strips, strip);
}
continue;
}
/* firstly, check if the proposed transform locations would overlap with any neighbouring strips
* (barring transitions) which are absolute barriers since they are not being moved
*
* this is done as a iterative procedure (done 5 times max for now)
*/
for (iter=0; iter < 5; iter++) {
pExceeded= ((strip->prev) && (strip->prev->type != NLASTRIP_TYPE_TRANSITION) && (tdn->h1[0] < strip->prev->end));
nExceeded= ((strip->next) && (strip->next->type != NLASTRIP_TYPE_TRANSITION) && (tdn->h2[0] > strip->next->start));
if ((pExceeded && nExceeded) || (iter == 4) ) {
/* both endpoints exceeded (or iteration ping-pong'd meaning that we need a compromise)
* - simply crop strip to fit within the bounds of the strips bounding it
* - if there were no neighbours, clear the transforms (make it default to the strip's current values)
*/
if (strip->prev && strip->next) {
tdn->h1[0]= strip->prev->end;
tdn->h2[0]= strip->next->start;
}
else {
tdn->h1[0]= strip->start;
tdn->h2[0]= strip->end;
}
}
else if (nExceeded) {
/* move backwards */
float offset= tdn->h2[0] - strip->next->start;
tdn->h1[0] -= offset;
tdn->h2[0] -= offset;
}
else if (pExceeded) {
/* more forwards */
float offset= strip->prev->end - tdn->h1[0];
tdn->h1[0] += offset;
tdn->h2[0] += offset;
}
else /* all is fine and well */
break;
}
/* handle auto-snapping */
switch (snla->autosnap) {
case SACTSNAP_FRAME: /* snap to nearest frame/time */
if (snla->flag & SNLA_DRAWTIME) {
tdn->h1[0]= (float)( floor((tdn->h1[0]/secf) + 0.5f) * secf );
tdn->h2[0]= (float)( floor((tdn->h2[0]/secf) + 0.5f) * secf );
}
else {
tdn->h1[0]= (float)( floor(tdn->h1[0]+0.5f) );
tdn->h2[0]= (float)( floor(tdn->h2[0]+0.5f) );
}
break;
case SACTSNAP_MARKER: /* snap to nearest marker */
tdn->h1[0]= (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h1[0]);
tdn->h2[0]= (float)ED_markers_find_nearest_marker_time(&t->scene->markers, tdn->h2[0]);
break;
}
/* use RNA to write the values... */
// TODO: do we need to write in 2 passes to make sure that no truncation goes on?
RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
RNA_float_set(&strip_ptr, "start_frame", tdn->h1[0]);
RNA_float_set(&strip_ptr, "end_frame", tdn->h2[0]);
/* flush transforms to child strips (since this should be a meta) */
BKE_nlameta_flush_transforms(strip);
/* now, check if we need to try and move track
* - we need to calculate both, as only one may have been altered by transform if only 1 handle moved
*/
delta_y1= ((int)tdn->h1[1] / NLACHANNEL_STEP - tdn->trackIndex);
delta_y2= ((int)tdn->h2[1] / NLACHANNEL_STEP - tdn->trackIndex);
if (delta_y1 || delta_y2) {
NlaTrack *track;
int delta = (delta_y2) ? delta_y2 : delta_y1;
int n;
/* move in the requested direction, checking at each layer if there's space for strip to pass through,
* stopping on the last track available or that we're able to fit in
*/
if (delta > 0) {
for (track=tdn->nlt->next, n=0; (track) && (n < delta); track=track->next, n++) {
/* check if space in this track for the strip */
if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
/* move strip to this track */
BLI_remlink(&tdn->nlt->strips, strip);
BKE_nlatrack_add_strip(track, strip);
tdn->nlt= track;
tdn->trackIndex += (n + 1); /* + 1, since n==0 would mean that we didn't change track */
}
else /* can't move any further */
break;
}
}
else {
/* make delta 'positive' before using it, since we now know to go backwards */
delta= -delta;
for (track=tdn->nlt->prev, n=0; (track) && (n < delta); track=track->prev, n++) {
/* check if space in this track for the strip */
if (BKE_nlatrack_has_space(track, strip->start, strip->end)) {
/* move strip to this track */
BLI_remlink(&tdn->nlt->strips, strip);
BKE_nlatrack_add_strip(track, strip);
tdn->nlt= track;
tdn->trackIndex -= (n - 1); /* - 1, since n==0 would mean that we didn't change track */
}
else /* can't move any further */
break;
}
}
}
}
}
else if (t->obedit) {
if ELEM(t->obedit->type, OB_CURVE, OB_SURF) {
Curve *cu= t->obedit->data;
@ -867,7 +956,7 @@ void postTrans (TransInfo *t)
if(sima->flag & SI_LIVE_UNWRAP)
ED_uvedit_live_unwrap_end(t->state == TRANS_CANCEL);
}
else if(t->spacetype==SPACE_ACTION) {
else if(ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) {
if (t->customData)
MEM_freeN(t->customData);
}

@ -634,6 +634,19 @@ void transform_keymap_for_space(struct wmWindowManager *wm, struct ListBase *key
km = WM_keymap_add_item(keymap, "TFM_OT_resize", SKEY, KM_PRESS, 0, 0);
break;
case SPACE_NLA:
km= WM_keymap_add_item(keymap, "TFM_OT_transform", GKEY, KM_PRESS, 0, 0);
RNA_int_set(km->ptr, "mode", TFM_TRANSLATION);
km= WM_keymap_add_item(keymap, "TFM_OT_transform", EVT_TWEAK_S, KM_ANY, 0, 0);
RNA_int_set(km->ptr, "mode", TFM_TRANSLATION);
km= WM_keymap_add_item(keymap, "TFM_OT_transform", EKEY, KM_PRESS, 0, 0);
RNA_int_set(km->ptr, "mode", TFM_TIME_EXTEND);
km= WM_keymap_add_item(keymap, "TFM_OT_transform", SKEY, KM_PRESS, 0, 0);
RNA_int_set(km->ptr, "mode", TFM_TIME_SCALE);
break;
case SPACE_NODE:
km= WM_keymap_add_item(keymap, "TFM_OT_translation", GKEY, KM_PRESS, 0, 0);

@ -225,10 +225,18 @@ typedef struct bActionGroup {
/* Action Group flags */
typedef enum eActionGroup_Flag {
/* group is selected */
AGRP_SELECTED = (1<<0),
/* group is 'active' / last selected one */
AGRP_ACTIVE = (1<<1),
/* keyframes/channels belonging to it cannot be edited */
AGRP_PROTECTED = (1<<2),
/* for UI, sub-channels are shown */
AGRP_EXPANDED = (1<<3),
/* sub-channels are not evaluated */
AGRP_MUTED = (1<<4),
/* sub-channels are not visible in Graph Editor */
AGRP_NOTVISIBLE = (1<<5),
AGRP_TEMP = (1<<30),
AGRP_MOVED = (1<<31)
@ -269,6 +277,7 @@ typedef enum eAction_Flags {
/* flags for evaluation/editing */
ACT_MUTED = (1<<9),
ACT_PROTECTED = (1<<10),
ACT_DISABLED = (1<<11),
} eAction_Flags;
@ -288,8 +297,10 @@ typedef struct bDopeSheet {
/* DopeSheet filter-flag */
typedef enum DOPESHEET_FILTERFLAG {
/* general filtering */
ADS_FILTER_ONLYSEL = (1<<0),
ADS_FILTER_ONLYDRIVERS = (1<<1),
ADS_FILTER_ONLYSEL = (1<<0), /* only include channels relating to selected data */
ADS_FILTER_ONLYDRIVERS = (1<<1), /* for 'Drivers' editor - only include Driver data from AnimData */
ADS_FILTER_ONLYNLA = (1<<2), /* for 'NLA' editor - only include NLA data from AnimData */
/* datatype-based filtering */
ADS_FILTER_NOSHAPEKEYS = (1<<6),
@ -300,9 +311,11 @@ typedef enum DOPESHEET_FILTERFLAG {
ADS_FILTER_NOWOR = (1<<14),
ADS_FILTER_NOSCE = (1<<15),
/* NLA-specific filters */
ADS_FILTER_NLA_NOACT = (1<<20), /* if the AnimData block has no NLA data, don't include to just show Action-line */
/* combination filters (some only used at runtime) */
ADS_FILTER_NOOBDATA = (ADS_FILTER_NOCAM|ADS_FILTER_NOMAT|ADS_FILTER_NOLAM|ADS_FILTER_NOCUR),
ADS_FILTER_NLADUMMY = (ADS_FILTER_NOSHAPEKEYS|ADS_FILTER_NOOBDATA),
} DOPESHEET_FILTERFLAG;
/* DopeSheet general flags */

@ -1,5 +1,28 @@
/* Testing code for new animation system in 2.5
* Copyright 2009, Joshua Leung
/**
* $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) 2009 Blender Foundation, Joshua Leung
* All rights reserved.
*
* Contributor(s): Joshua Leung (full recode)
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef DNA_ANIM_TYPES_H
@ -43,9 +66,10 @@ typedef struct FModifier {
enum {
FMODIFIER_TYPE_NULL = 0,
FMODIFIER_TYPE_GENERATOR,
FMODIFIER_TYPE_FN_GENERATOR,
FMODIFIER_TYPE_ENVELOPE,
FMODIFIER_TYPE_CYCLES,
FMODIFIER_TYPE_NOISE, /* unimplemented - generate variations using some basic noise generator... */
FMODIFIER_TYPE_NOISE,
FMODIFIER_TYPE_FILTER, /* unimplemented - for applying: fft, high/low pass filters, etc. */
FMODIFIER_TYPE_PYTHON,
FMODIFIER_TYPE_LIMITS,
@ -68,39 +92,55 @@ enum {
/* --- */
/* generator modifier data */
/* Generator modifier data */
typedef struct FMod_Generator {
/* generator based on PyExpression */
char expression[256]; /* python expression to use as generator */
/* general generator information */
float *coefficients; /* coefficients array */
unsigned int arraysize; /* size of the coefficients array */
short poly_order; /* order of polynomial generated (i.e. 1 for linear, 2 for quadratic) */
short func_type; /* builtin math function eFMod_Generator_Functions */
int pad;
int poly_order; /* order of polynomial generated (i.e. 1 for linear, 2 for quadratic) */
int mode; /* which 'generator' to use eFMod_Generator_Modes */
/* settings */
short flag; /* settings */
short mode; /* which 'generator' to use eFMod_Generator_Modes */
int flag; /* settings */
} FMod_Generator;
/* generator modes */
enum {
FCM_GENERATOR_POLYNOMIAL = 0,
FCM_GENERATOR_POLYNOMIAL_FACTORISED,
FCM_GENERATOR_FUNCTION,
FCM_GENERATOR_EXPRESSION,
} eFMod_Generator_Modes;
/* generator flags */
/* generator flags
* - shared by Generator and Function Generator
*/
enum {
/* generator works in conjunction with other modifiers (i.e. doesn't replace those before it) */
FCM_GENERATOR_ADDITIVE = (1<<0),
} eFMod_Generator_Flags;
/* 'Built-In Function' Generator modifier data
*
* This uses the general equation for equations:
* y = amplitude * fn(phase_multiplier*x + phase_offset) + y_offset
*
* where amplitude, phase_multiplier/offset, y_offset are user-defined coefficients,
* x is the evaluation 'time', and 'y' is the resultant value
*/
typedef struct FMod_FunctionGenerator {
/* coefficients for general equation (as above) */
float amplitude;
float phase_multiplier;
float phase_offset;
float value_offset;
/* flags */
int type; /* eFMod_Generator_Functions */
int flag; /* eFMod_Generator_flags */
} FMod_FunctionGenerator;
/* 'function' generator types */
enum {
FCM_GENERATOR_FN_SIN = 0,
@ -108,6 +148,7 @@ enum {
FCM_GENERATOR_FN_TAN,
FCM_GENERATOR_FN_SQRT,
FCM_GENERATOR_FN_LN,
FCM_GENERATOR_FN_SINC,
} eFMod_Generator_Functions;
@ -386,85 +427,104 @@ typedef struct AnimMapper {
/* ************************************************ */
/* NLA - Non-Linear Animation */
// TODO: the concepts here still need to be refined to solve any unresolved items
/* NLA Modifiers ---------------------------------- */
/* These differ from F-Curve modifiers, as although F-Curve modifiers also operate on a
* per-channel basis too (in general), they are part of the animation data itself, which
* means that their effects are inherited by all of their users. In order to counteract this,
* the modifiers here should be used to provide variation to pre-created motions only.
*/
/* NLA Strips ------------------------------------- */
/* NLA Strip (strip)
*
* A NLA Strip is a container for the reuse of Action data, defining parameters
* to control the remapping of the Action data to some destination. Actions being
* referenced by NLA-Strips SHOULD-NOT be editable, unless they were created in such
* a way that results in very little mapping distortion (i.e. for layered animation only,
* opposed to prebuilt 'blocks' which are quickly dumped into the NLA for crappymatic machima-type
* stuff)
* to control the remapping of the Action data to some destination.
*/
typedef struct NlaStrip {
struct NlaStrip *next, *prev;
bAction *act; /* Action that is referenced by this strip */
ListBase strips; /* 'Child' strips (used for 'meta' strips) */
bAction *act; /* Action that is referenced by this strip (strip is 'user' of the action) */
AnimMapper *remap; /* Remapping info this strip (for tweaking correspondance of action with context) */
ListBase modifiers; /* NLA Modifiers */
ListBase fcurves; /* F-Curves for controlling this strip's influence and timing */ // TODO: move out?
ListBase modifiers; /* F-Curve modifiers to be applied to the entire strip's referenced F-Curves */
char name[64]; /* User-Visible Identifier for Strip */
ListBase fcurves; /* F-Curves for controlling this strip's influence and timing */
float influence; /* Influence of strip */
float act_time; /* Current 'time' within action being used */
float strip_time; /* Current 'time' within action being used (automatically evaluated, but can be overridden) */
float start, end; /* extents of the strip */
float actstart, actend; /* range of the action to use */
float repeat; /* The number of times to repeat the action range (only when no F-Curves) */
float scale; /* The amount the action range is scaled by (only when no F-Curves) */
float repeat; /* The number of times to repeat the action range (only when no F-Curves) */
float scale; /* The amount the action range is scaled by (only when no F-Curves) */
float blendin, blendout; /* strip blending length (only used when there are no F-Curves) */
int blendmode; /* strip blending mode */
short blendmode; /* strip blending mode (layer-based mixing) */
short extendmode; /* strip extrapolation mode (time-based mixing) */
int flag; /* settings */
// umm... old unused cruft?
int stride_axis; /* axis for stridebone stuff - 0=x, 1=y, 2=z */
int pad;
float actoffs; /* Offset within action, for cycles and striding (only set for ACT_USESTRIDE) */
float stridelen; /* The stridelength (considered when flag & ACT_USESTRIDE) */
char stridechannel[32]; /* Instead of stridelen, it uses an action channel */
char offs_bone[32]; /* if repeat, use this bone/channel for defining offset */
short flag; /* settings */
short type; /* type of NLA strip */
} NlaStrip;
/* NLA Strip Blending Mode */
enum {
NLASTRIPMODE_BLEND = 0,
NLASTRIPMODE_ADD,
NLASTRIPMODE_SUBTRACT,
} eActStrip_Mode;
NLASTRIP_MODE_REPLACE = 0,
NLASTRIP_MODE_ADD,
NLASTRIP_MODE_SUBTRACT,
NLASTRIP_MODE_MULTIPLY,
} eNlaStrip_Blend_Mode;
/* NLA Strip Extrpolation Mode */
enum {
/* extend before first frame if no previous strips in track, and always hold+extend last frame */
NLASTRIP_EXTEND_HOLD = 0,
/* only hold+extend last frame */
NLASTRIP_EXTEND_HOLD_FORWARD,
/* don't contribute at all */
NLASTRIP_EXTEND_NOTHING,
} eNlaStrip_Extrapolate_Mode;
/* NLA Strip Settings */
// TODO: check on which of these are still useful...
enum {
NLASTRIP_SELECT = (1<<0),
NLASTRIP_USESTRIDE = (1<<1),
NLASTRIP_BLENDTONEXT = (1<<2), /* Not implemented. Is not used anywhere */
NLASTRIP_HOLDLASTFRAME = (1<<3),
NLASTRIP_ACTIVE = (1<<4),
NLASTRIP_LOCK_ACTION = (1<<5),
NLASTRIP_MUTE = (1<<6),
NLASTRIP_REVERSE = (1<<7), /* This has yet to be implemented. To indicate that a strip should be played backwards */
NLASTRIP_CYCLIC_USEX = (1<<8),
NLASTRIP_CYCLIC_USEY = (1<<9),
NLASTRIP_CYCLIC_USEZ = (1<<10),
NLASTRIP_AUTO_BLENDS = (1<<11),
NLASTRIP_TWEAK = (1<<12), /* This strip is a tweaking strip (only set if owner track is a tweak track) */
} eActionStrip_Flag;
/* UI selection flags */
/* NLA strip is the active one in the track (also indicates if strip is being tweaked) */
NLASTRIP_FLAG_ACTIVE = (1<<0),
/* NLA strip is selected for editing */
NLASTRIP_FLAG_SELECT = (1<<1),
// NLASTRIP_FLAG_SELECT_L = (1<<2), // left handle selected
// NLASTRIP_FLAG_SELECT_R = (1<<3), // right handle selected
/* NLA strip uses the same action that the action being tweaked uses (not set for the twaking one though) */
NLASTRIP_FLAG_TWEAKUSER = (1<<4),
/* controls driven by local F-Curves */
/* strip influence is controlled by local F-Curve */
NLASTRIP_FLAG_USR_INFLUENCE = (1<<5),
NLASTRIP_FLAG_USR_TIME = (1<<6),
/* playback flags (may be overriden by F-Curves) */
/* NLA strip blendin/out values are set automatically based on overlaps */
NLASTRIP_FLAG_AUTO_BLENDS = (1<<10),
/* NLA strip is played back in reverse order */
NLASTRIP_FLAG_REVERSE = (1<<11),
/* NLA strip is muted (i.e. doesn't contribute in any way) */
// TODO: this overlaps a lot with the functionality in track
NLASTRIP_FLAG_MUTED = (1<<12),
/* NLA strip length is synced to the length of the referenced action */
NLASTRIP_FLAG_SYNC_LENGTH = (1<<13),
/* temporary editing flags */
/* NLA-Strip is really just a temporary meta used to facilitate easier transform code */
NLASTRIP_FLAG_TEMP_META = (1<<14),
NLASTRIP_FLAG_EDIT_TOUCHED = (1<<15),
} eNlaStrip_Flag;
/* NLA Strip Type */
enum {
/* 'clip' - references an Action */
NLASTRIP_TYPE_CLIP = 0,
/* 'transition' - blends between the adjacent strips */
NLASTRIP_TYPE_TRANSITION,
/* 'meta' - a strip which acts as a container for a few others */
NLASTRIP_TYPE_META,
} eNlaStrip_Type;
/* NLA Tracks ------------------------------------- */
@ -483,14 +543,12 @@ typedef struct NlaTrack {
int flag; /* settings for this track */
int index; /* index of the track in the stack (NOTE: not really useful, but we need a pad var anyways!) */
char info[64]; /* short user-description of this track */
char name[64]; /* short user-description of this track */
} NlaTrack;
/* settings for track */
enum {
/* track is the one that settings can be modified on (doesn't indicate
* that it's for 'tweaking' though)
*/
/* track is the one that settings can be modified on, also indicates if track is being 'tweaked' */
NLATRACK_ACTIVE = (1<<0),
/* track is selected in UI for relevant editing operations */
NLATRACK_SELECTED = (1<<1),
@ -500,10 +558,9 @@ enum {
NLATRACK_SOLO = (1<<3),
/* track's settings (and strips) cannot be edited (to guard against unwanted changes) */
NLATRACK_PROTECTED = (1<<4),
/* strip is the 'last' one that should be evaluated, as the active action
* is being used to tweak the animation of the strips up to here
*/
NLATRACK_TWEAK = (1<<5),
/* track is not allowed to execute, usually as result of tweaking being enabled (internal flag) */
NLATRACK_DISABLED = (1<<10),
} eNlaTrack_Flag;
@ -646,11 +703,15 @@ typedef struct AnimOverride {
* blocks may override local settings.
*
* This datablock should be placed immediately after the ID block where it is used, so that
* the code which retrieves this data can do so in an easier manner. See blenkernel/internal/anim_sys.c for details.
* the code which retrieves this data can do so in an easier manner. See blenkernel/intern/anim_sys.c for details.
*/
typedef struct AnimData {
/* active action - acts as the 'tweaking track' for the NLA */
bAction *action;
/* temp-storage for the 'real' active action (i.e. the one used before the tweaking-action
* took over to be edited in the Animation Editors)
*/
bAction *tmpact;
/* remapping-info for active action - should only be used if needed
* (for 'foreign' actions that aren't working correctly)
*/
@ -658,6 +719,8 @@ typedef struct AnimData {
/* nla-tracks */
ListBase nla_tracks;
/* active NLA-strip (only set/used during tweaking, so no need to worry about dangling pointers) */
NlaStrip *actstrip;
/* 'drivers' for this ID-block's settings - FCurves, but are completely
* separate from those for animation data
@ -676,11 +739,20 @@ enum {
ADT_NLA_SOLO_TRACK = (1<<0),
/* don't use NLA */
ADT_NLA_EVAL_OFF = (1<<1),
/* don't execute drivers */
ADT_DRIVERS_DISABLED = (1<<2),
/* NLA is being 'tweaked' (i.e. in EditMode) */
ADT_NLA_EDIT_ON = (1<<2),
/* active Action for 'tweaking' does not have mapping applied for editing */
ADT_NLA_EDIT_NOMAP = (1<<3),
/* NLA-Strip F-Curves are expanded in UI */
ADT_NLA_SKEYS_COLLAPSED = (1<<4),
/* drivers expanded in UI */
ADT_DRIVERS_COLLAPSED = (1<<10),
/* don't execute drivers */
ADT_DRIVERS_DISABLED = (1<<11),
/* F-Curves from this AnimData block are not visible in the Graph Editor */
ADT_CURVES_NOT_VISIBLE = (1<<16),
} eAnimData_Flag;
/* Animation Data recalculation settings (to be set by depsgraph) */

@ -148,7 +148,7 @@ typedef struct Curve {
ListBase *editnurb; /* edited data, not in file, use pointer so we can check for it */
struct Object *bevobj, *taperobj, *textoncurve;
struct Ipo *ipo;
struct Ipo *ipo; // XXX depreceated... old animation system
Path *path;
struct Key *key;
struct Material **mat;
@ -193,7 +193,8 @@ typedef struct Curve {
int sepchar;
int totbox, actbox, pad;
float ctime; /* current evaltime - for use by Objects parented to curves */
int totbox, actbox;
struct TextBox *tb;
int selstart, selend;

@ -783,6 +783,10 @@ typedef struct Scene {
#define MINFRAME 1
#define MINFRAMEF 1.0f
/* (minimum frame number for current-frame) */
#define MINAFRAME -300000
#define MINAFRAMEF -300000.0f
/* depricate this! */
#define TESTBASE(v3d, base) ( ((base)->flag & SELECT) && ((base)->lay & v3d->lay) && (((base)->object->restrictflag & OB_RESTRICT_VIEW)==0) )
#define TESTBASELIB(v3d, base) ( ((base)->flag & SELECT) && ((base)->lay & v3d->lay) && ((base)->object->id.lib==0) && (((base)->object->restrictflag & OB_RESTRICT_VIEW)==0))
@ -851,6 +855,7 @@ typedef struct Scene {
/* sce->flag */
#define SCE_DS_SELECTED (1<<0)
#define SCE_DS_COLLAPSED (1<<1)
#define SCE_NLA_EDIT_ON (1<<2)
/* return flag next_object function */

@ -96,10 +96,6 @@ typedef struct SpaceIpo {
short blockhandler[8];
View2D v2d; /* depricated, copied to region */
// 'IPO keys' - vertical lines for editing multiple keyframes at once - use Dopesheet instead for this?
//ListBase ipokey; // XXX it's not clear how these will come back yet
//short showkey; // XXX this doesn't need to be restored until ipokeys come back
struct bDopeSheet *ads; /* settings for filtering animation data (NOTE: we use a pointer due to code-linking issues) */
ListBase ghostCurves; /* sampled snapshots of F-Curves used as in-session guides */
@ -107,7 +103,7 @@ typedef struct SpaceIpo {
short mode; /* mode for the Graph editor (eGraphEdit_Mode) */
short flag; /* settings for Graph editor */
short autosnap; /* time-transform autosnapping settings for Graph editor (eAnimEdit_AutoSnap in DNA_action_types.h) */
char pin, lock;
char pin, lock; // XXX old, unused vars that are probably going to be depreceated soon...
} SpaceIpo;
typedef struct SpaceButs {
@ -276,10 +272,11 @@ typedef struct SpaceNla {
short blockhandler[8];
short menunr, lock;
short autosnap; /* this uses the same settings as autosnap for Action Editor */
short flag;
int pad;
struct bDopeSheet *ads;
View2D v2d; /* depricated, copied to region */
} SpaceNla;
@ -751,8 +748,11 @@ enum {
#define IMS_INFILESLI 4
/* nla->flag */
// depreceated
#define SNLA_ALLKEYED (1<<0)
// depreceated
#define SNLA_ACTIVELAYERS (1<<1)
#define SNLA_DRAWTIME (1<<2)
#define SNLA_NOTRANSKEYCULL (1<<3)
#define SNLA_NODRAWCFRANUM (1<<4)

@ -174,12 +174,14 @@ extern StructRNA RNA_ExplodeModifier;
extern StructRNA RNA_ExpressionController;
extern StructRNA RNA_Event;
extern StructRNA RNA_FCurve;
extern StructRNA RNA_FCurveSample;
extern StructRNA RNA_FileSelectParams;
extern StructRNA RNA_FModifier;
extern StructRNA RNA_FModifierCycles;
extern StructRNA RNA_FModifierEnvelope;
extern StructRNA RNA_FModifierEnvelopeControlPoint;
extern StructRNA RNA_FModifierFunctionGenerator;
extern StructRNA RNA_FModifierGenerator;
extern StructRNA RNA_FModifierGenerator_Function;
extern StructRNA RNA_FModifierGenerator_PolyExpanded;
extern StructRNA RNA_FModifierLimits;
extern StructRNA RNA_FModifierNoise;
@ -274,6 +276,8 @@ extern StructRNA RNA_MultiresModifier;
extern StructRNA RNA_MusgraveTexture;
extern StructRNA RNA_NandController;
extern StructRNA RNA_NearSensor;
extern StructRNA RNA_NlaTrack;
extern StructRNA RNA_NlaStrip;
extern StructRNA RNA_Node;
extern StructRNA RNA_NodeTree;
extern StructRNA RNA_NoiseTexture;
@ -366,7 +370,10 @@ extern StructRNA RNA_SoundSequence;
extern StructRNA RNA_Space;
extern StructRNA RNA_Space3DView;
extern StructRNA RNA_SpaceButtonsWindow;
extern StructRNA RNA_SpaceDopeSheetEditor;
extern StructRNA RNA_SpaceGraphEditor;
extern StructRNA RNA_SpaceImageEditor;
extern StructRNA RNA_SpaceNLA;
extern StructRNA RNA_SpaceOutliner;
extern StructRNA RNA_SpaceSequenceEditor;
extern StructRNA RNA_SpaceTextEditor;

@ -1921,6 +1921,7 @@ RNAProcessItem PROCESS_ITEMS[]= {
{"rna_mesh.c", "rna_mesh_api.c", RNA_def_mesh},
{"rna_meta.c", NULL, RNA_def_meta},
{"rna_modifier.c", NULL, RNA_def_modifier},
{"rna_nla.c", NULL, RNA_def_nla},
{"rna_nodetree.c", NULL, RNA_def_nodetree},
{"rna_object.c", "rna_object_api.c", RNA_def_object},
{"rna_object_force.c", NULL, RNA_def_object_force},

@ -184,7 +184,7 @@ void rna_def_animdata(BlenderRNA *brna)
/* NLA */
prop= RNA_def_property(srna, "nla_tracks", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "nla_tracks", NULL);
RNA_def_property_struct_type(prop, "UnknownType"); // XXX!
RNA_def_property_struct_type(prop, "NlaTrack");
RNA_def_property_ui_text(prop, "NLA Tracks", "NLA Tracks (i.e. Animation Layers).");
/* Action */

@ -728,13 +728,13 @@ static void rna_def_constraint_action(BlenderRNA *brna)
prop= RNA_def_property(srna, "start_frame", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "start");
RNA_def_property_range(prop, MINFRAME, MAXFRAME);
RNA_def_property_range(prop, MINAFRAME, MAXFRAME);
RNA_def_property_ui_text(prop, "Start Frame", "First frame of the Action to use.");
RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update");
prop= RNA_def_property(srna, "end_frame", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "end");
RNA_def_property_range(prop, MINFRAME, MAXFRAME);
RNA_def_property_range(prop, MINAFRAME, MAXFRAME);
RNA_def_property_ui_text(prop, "End Frame", "Last frame of the Action to use.");
RNA_def_property_update(prop, NC_OBJECT|ND_CONSTRAINT, "rna_Constraint_update");

@ -31,6 +31,7 @@
#include "DNA_curve_types.h"
#include "DNA_material_types.h"
#include "DNA_scene_types.h"
EnumPropertyItem beztriple_handle_type_items[] = {
{HD_FREE, "FREE", 0, "Free", ""},
@ -558,6 +559,11 @@ static void rna_def_curve(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 1, 1024, 1, 0);
RNA_def_property_ui_text(prop, "Render Resolution V", "Surface resolution in V direction used while rendering. Zero skips this property.");
prop= RNA_def_property(srna, "eval_time", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "ctime");
RNA_def_property_ui_text(prop, "Evaluation Time", "Parametric position along the length of the curve that Objects 'following' it should be at.");
/* pointers */
prop= RNA_def_property(srna, "bevel_object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "bevobj");

@ -37,6 +37,7 @@
EnumPropertyItem fmodifier_type_items[] = {
{FMODIFIER_TYPE_NULL, "NULL", 0, "Invalid", ""},
{FMODIFIER_TYPE_GENERATOR, "GENERATOR", 0, "Generator", ""},
{FMODIFIER_TYPE_FN_GENERATOR, "FNGENERATOR", 0, "Built-In Function", ""},
{FMODIFIER_TYPE_ENVELOPE, "ENVELOPE", 0, "Envelope", ""},
{FMODIFIER_TYPE_CYCLES, "CYCLES", 0, "Cycles", ""},
{FMODIFIER_TYPE_NOISE, "NOISE", 0, "Noise", ""},
@ -47,62 +48,6 @@ EnumPropertyItem fmodifier_type_items[] = {
#ifdef RNA_RUNTIME
float FModGenFunc_amplitude_get(PointerRNA *ptr)
{
FModifier *fcm = (FModifier *)(ptr->data);
FMod_Generator *data= (FMod_Generator*)(fcm->data);
return (data->coefficients) ? (float)data->coefficients[0] : 1.0f;
}
void FModGenFunc_amplitude_set(PointerRNA *ptr, float value)
{
FModifier *fcm = (FModifier *)(ptr->data);
FMod_Generator *data= (FMod_Generator*)(fcm->data);
if (data->coefficients) data->coefficients[0]= value;
}
float FModGenFunc_pre_multiplier_get(PointerRNA *ptr)
{
FModifier *fcm = (FModifier *)(ptr->data);
FMod_Generator *data= (FMod_Generator*)(fcm->data);
return (data->coefficients) ? (float)data->coefficients[1] : 1.0f;
}
void FModGenFunc_pre_multiplier_set(PointerRNA *ptr, float value)
{
FModifier *fcm = (FModifier *)(ptr->data);
FMod_Generator *data= (FMod_Generator*)(fcm->data);
if (data->coefficients) data->coefficients[1]= value;
}
float FModGenFunc_x_offset_get(PointerRNA *ptr)
{
FModifier *fcm = (FModifier *)(ptr->data);
FMod_Generator *data= (FMod_Generator*)(fcm->data);
return (data->coefficients) ? (float)data->coefficients[2] : 0.0f;
}
void FModGenFunc_x_offset_set(PointerRNA *ptr, float value)
{
FModifier *fcm = (FModifier *)(ptr->data);
FMod_Generator *data= (FMod_Generator*)(fcm->data);
if (data->coefficients) data->coefficients[2]= value;
}
float FModGenFunc_y_offset_get(PointerRNA *ptr)
{
FModifier *fcm = (FModifier *)(ptr->data);
FMod_Generator *data= (FMod_Generator*)(fcm->data);
return (data->coefficients) ? (float)data->coefficients[3] : 0.0f;
}
void FModGenFunc_y_offset_set(PointerRNA *ptr, float value)
{
FModifier *fcm = (FModifier *)(ptr->data);
FMod_Generator *data= (FMod_Generator*)(fcm->data);
if (data->coefficients) data->coefficients[3]= value;
}
/* --------- */
StructRNA *rna_FModifierType_refine(struct PointerRNA *ptr)
@ -111,20 +56,9 @@ StructRNA *rna_FModifierType_refine(struct PointerRNA *ptr)
switch (fcm->type) {
case FMODIFIER_TYPE_GENERATOR:
{
FMod_Generator *gen= (FMod_Generator *)fcm->data;
switch (gen->mode) {
case FCM_GENERATOR_POLYNOMIAL:
return &RNA_FModifierGenerator_PolyExpanded;
//case FCM_GENERATOR_POLYNOMIAL_FACTORISED:
case FCM_GENERATOR_FUNCTION:
return &RNA_FModifierGenerator_Function;
//case FCM_GENERATOR_EXPRESSION:
default:
return &RNA_FModifierGenerator;
}
}
return &RNA_FModifierGenerator;
case FMODIFIER_TYPE_FN_GENERATOR:
return &RNA_FModifierFunctionGenerator;
case FMODIFIER_TYPE_ENVELOPE:
return &RNA_FModifierEnvelope;
case FMODIFIER_TYPE_CYCLES:
@ -215,21 +149,22 @@ static void rna_FCurve_RnaPath_set(PointerRNA *ptr, const char *value)
#else
static void rna_def_fmodifier_generator_common(StructRNA *srna)
static void rna_def_fmodifier_generator(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
static EnumPropertyItem prop_mode_items[] = {
{FCM_GENERATOR_POLYNOMIAL, "POLYNOMIAL", 0, "Expanded Polynomial", ""},
{FCM_GENERATOR_POLYNOMIAL_FACTORISED, "POLYNOMIAL_FACTORISED", 0, "Factorised Polynomial", ""},
{FCM_GENERATOR_FUNCTION, "FUNCTION", 0, "Built-In Function", ""},
{FCM_GENERATOR_EXPRESSION, "EXPRESSION", 0, "Expression", ""},
{0, NULL, 0, NULL, NULL}};
/* struct wrapping settings */
srna= RNA_def_struct(brna, "FModifierGenerator", "FModifier");
RNA_def_struct_ui_text(srna, "Generator F-Curve Modifier", "Deterministically generates values for the modified F-Curve.");
RNA_def_struct_sdna_from(srna, "FMod_Generator", "data");
/* settings */
/* define common props */
prop= RNA_def_property(srna, "additive", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FCM_GENERATOR_ADDITIVE);
RNA_def_property_ui_text(prop, "Additive", "Values generated by this modifier are applied on top of the existing values instead of overwriting them.");
@ -238,42 +173,23 @@ static void rna_def_fmodifier_generator_common(StructRNA *srna)
prop= RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_mode_items);
RNA_def_property_ui_text(prop, "Mode", "Type of generator to use.");
}
/* this is a temporary dummy generator-modifier wrapping (to be discarded) */
static void rna_def_fmodifier_generator(BlenderRNA *brna)
{
StructRNA *srna;
srna= RNA_def_struct(brna, "FModifierGenerator", "FModifier");
RNA_def_struct_ui_text(srna, "Generator F-Curve Modifier", "Deterministically generates values for the modified F-Curve.");
/* define common props */
rna_def_fmodifier_generator_common(srna);
}
static void rna_def_fmodifier_generator_polyexpanded(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna= RNA_def_struct(brna, "FModifierGenerator_PolyExpanded", "FModifier");
RNA_def_struct_ui_text(srna, "Expanded Polynomial Generator", "Generates values for the modified F-Curve using expanded polynomial expresion.");
/* define common props */
rna_def_fmodifier_generator_common(srna);
/* order of the polynomial */
// XXX this has a special validation func
prop= RNA_def_property(srna, "poly_order", PROP_INT, PROP_NONE);
RNA_def_property_ui_text(prop, "Polynomial Order", "The highest power of 'x' for this polynomial. (i.e. the number of coefficients - 1)");
RNA_def_property_ui_text(prop, "Polynomial Order", "The highest power of 'x' for this polynomial. (number of coefficients - 1)");
/* coefficients array */
//prop= RNA_def_property(srna, "coefficients", PROP_FLOAT, PROP_NONE);
//RNA_def_property_ui_text(prop, "Coefficients", "Coefficients for 'x' (starting from lowest power).");
// FIXME: this is quite difficult to try to wrap
//prop= RNA_def_property(srna, "coefficients", PROP_COLLECTION, PROP_NONE);
//RNA_def_property_collection_funcs(prop, "rna_FModifierGenerator_coefficients_begin", "rna_FModifierGenerator_coefficients_next", "rna_FModifierGenerator_coefficients_end", "rna_iterator_array_get", "rna_FModifierGenerator_coefficients_length", 0, 0, 0, 0);
//RNA_def_property_ui_text(prop, "Coefficients", "Coefficients for 'x' (starting from lowest power of x^0).");
}
static void rna_def_fmodifier_generator_function(BlenderRNA *brna)
/* --------- */
static void rna_def_fmodifier_function_generator(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
@ -284,48 +200,95 @@ static void rna_def_fmodifier_generator_function(BlenderRNA *brna)
{2, "TAN", 0, "Tangent", ""},
{3, "SQRT", 0, "Square Root", ""},
{4, "LN", 0, "Natural Logarithm", ""},
{5, "SINC", 0, "Normalised Sine", "sin(x) / x"},
{0, NULL, 0, NULL, NULL}};
srna= RNA_def_struct(brna, "FModifierGenerator_Function", "FModifier");
RNA_def_struct_ui_text(srna, "Built-In Function Generator", "Generates values for modified F-Curve using Built-In Function.");
/* common settings */
rna_def_fmodifier_generator_common(srna);
/* type */
prop= RNA_def_property(srna, "func_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_type_items);
RNA_def_property_ui_text(prop, "Type", "Type of Built-In function to use as generator.");
srna= RNA_def_struct(brna, "FModifierFunctionGenerator", "FModifier");
RNA_def_struct_ui_text(srna, "Built-In Function F-Modifier", "Generates values using a Built-In Function.");
RNA_def_struct_sdna_from(srna, "FMod_FunctionGenerator", "data");
/* coefficients */
prop= RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_funcs(prop, "FModGenFunc_amplitude_get", "FModGenFunc_amplitude_set", NULL);
RNA_def_property_ui_text(prop, "Amplitude", "Scale factor for y-values generated by the function.");
RNA_def_property_ui_text(prop, "Amplitude", "Scale factor determining the maximum/minimum values.");
prop= RNA_def_property(srna, "pre_multiplier", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_funcs(prop, "FModGenFunc_pre_multiplier_get", "FModGenFunc_pre_multiplier_set", NULL);
RNA_def_property_ui_text(prop, "PreMultiplier", "Scale factor for x-value inputs to function.");
prop= RNA_def_property(srna, "phase_multiplier", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(prop, "Phase Multiplier", "Scale factor determining the 'speed' of the function.");
prop= RNA_def_property(srna, "x_offset", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_funcs(prop, "FModGenFunc_x_offset_get", "FModGenFunc_x_offset_set", NULL);
RNA_def_property_ui_text(prop, "X Offset", "Offset for x-value inputs to function.");
prop= RNA_def_property(srna, "phase_offset", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(prop, "Phase Offset", "Constant factor to offset time by for function.");
prop= RNA_def_property(srna, "y_offset", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_funcs(prop, "FModGenFunc_y_offset_get", "FModGenFunc_y_offset_set", NULL);
RNA_def_property_ui_text(prop, "Y Offset", "Offset for y-values generated by the function.");
prop= RNA_def_property(srna, "value_offset", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(prop, "Value Offset", "Constant factor to offset values by.");
/* flags */
prop= RNA_def_property(srna, "additive", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", FCM_GENERATOR_ADDITIVE);
RNA_def_property_ui_text(prop, "Additive", "Values generated by this modifier are applied on top of the existing values instead of overwriting them.");
prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_type_items);
RNA_def_property_ui_text(prop, "Type", "Type of built-in function to use.");
}
/* --------- */
static void rna_def_fmodifier_envelope_ctrl(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna= RNA_def_struct(brna, "FModifierEnvelopeControlPoint", NULL);
RNA_def_struct_ui_text(srna, "Envelope Control Point", "Control point for envelope F-Modifier.");
RNA_def_struct_sdna(srna, "FCM_EnvelopeData");
/* min/max extents
* - for now, these are allowed to go past each other, so that we can have inverted action
* - technically, the range is limited by the settings in the envelope-modifier data, not here...
*/
prop= RNA_def_property(srna, "minimum", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "min");
RNA_def_property_ui_text(prop, "Minimum Value", "Lower bound of envelope at this control-point.");
prop= RNA_def_property(srna, "maximum", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "max");
RNA_def_property_ui_text(prop, "Maximum Value", "Upper bound of envelope at this control-point.");
/* Frame */
prop= RNA_def_property(srna, "frame", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "time");
RNA_def_property_ui_text(prop, "Frame", "Frame this control-point occurs on.");
// TODO:
// - selection flags (not implemented in UI yet though)
}
static void rna_def_fmodifier_envelope(BlenderRNA *brna)
{
StructRNA *srna;
//PropertyRNA *prop;
PropertyRNA *prop;
srna= RNA_def_struct(brna, "FModifierEnvelope", "FModifier");
RNA_def_struct_ui_text(srna, "Envelope F-Curve Modifier", "Scales the values of the modified F-Curve.");
RNA_def_struct_ui_text(srna, "Envelope F-Modifier", "Scales the values of the modified F-Curve.");
RNA_def_struct_sdna_from(srna, "FMod_Envelope", "data");
/* Collections */
prop= RNA_def_property(srna, "control_points", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "data", "totvert");
RNA_def_property_struct_type(prop, "FModifierEnvelopeControlPoint");
RNA_def_property_ui_text(prop, "Control Points", "Control points defining the shape of the envelope.");
/* Range Settings */
prop= RNA_def_property(srna, "reference_value", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "midval");
RNA_def_property_ui_text(prop, "Reference Value", "Value that envelope's influence is centered around / based on.");
prop= RNA_def_property(srna, "default_minimum", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "min");
RNA_def_property_ui_text(prop, "Default Minimum", "Lower distance from Reference Value for 1:1 default influence.");
prop= RNA_def_property(srna, "default_maximum", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "max");
RNA_def_property_ui_text(prop, "Default Maximum", "Upper distance from Reference Value for 1:1 default influence.");
}
/* --------- */
@ -343,7 +306,7 @@ static void rna_def_fmodifier_cycles(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}};
srna= RNA_def_struct(brna, "FModifierCycles", "FModifier");
RNA_def_struct_ui_text(srna, "Cycles F-Curve Modifier", "Repeats the values of the modified F-Curve.");
RNA_def_struct_ui_text(srna, "Cycles F-Modifier", "Repeats the values of the modified F-Curve.");
RNA_def_struct_sdna_from(srna, "FMod_Cycles", "data");
/* before */
@ -372,7 +335,7 @@ static void rna_def_fmodifier_python(BlenderRNA *brna)
//PropertyRNA *prop;
srna= RNA_def_struct(brna, "FModifierPython", "FModifier");
RNA_def_struct_ui_text(srna, "Python F-Curve Modifier", "Performs user-defined operation on the modified F-Curve.");
RNA_def_struct_ui_text(srna, "Python F-Modifier", "Performs user-defined operation on the modified F-Curve.");
RNA_def_struct_sdna_from(srna, "FMod_Python", "data");
}
@ -384,7 +347,7 @@ static void rna_def_fmodifier_limits(BlenderRNA *brna)
PropertyRNA *prop;
srna= RNA_def_struct(brna, "FModifierLimits", "FModifier");
RNA_def_struct_ui_text(srna, "Limits F-Curve Modifier", "Limits the time/value ranges of the modified F-Curve.");
RNA_def_struct_ui_text(srna, "Limits F-Modifier", "Limits the time/value ranges of the modified F-Curve.");
RNA_def_struct_sdna_from(srna, "FMod_Limits", "data");
prop= RNA_def_property(srna, "use_minimum_x", PROP_BOOLEAN, PROP_NONE);
@ -435,7 +398,7 @@ static void rna_def_fmodifier_noise(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}};
srna= RNA_def_struct(brna, "FModifierNoise", "FModifier");
RNA_def_struct_ui_text(srna, "Noise F-Curve Modifier", "Gives randomness to the modified F-Curve.");
RNA_def_struct_ui_text(srna, "Noise F-Modifier", "Gives randomness to the modified F-Curve.");
RNA_def_struct_sdna_from(srna, "FMod_Noise", "data");
prop= RNA_def_property(srna, "modification", PROP_ENUM, PROP_NONE);
@ -471,7 +434,7 @@ void rna_def_fmodifier(BlenderRNA *brna)
/* base struct definition */
srna= RNA_def_struct(brna, "FModifier", NULL);
RNA_def_struct_refine_func(srna, "rna_FModifierType_refine");
RNA_def_struct_ui_text(srna, "FCurve Modifier", "Modifier for values of F-Curve.");
RNA_def_struct_ui_text(srna, "F-Modifier", "Modifier for values of F-Curve.");
#if 0 // XXX not used yet
/* name */
@ -569,6 +532,27 @@ void rna_def_channeldriver(BlenderRNA *brna)
/* *********************** */
static void rna_def_fpoint(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna= RNA_def_struct(brna, "FCurveSample", NULL);
RNA_def_struct_sdna(srna, "FPoint");
RNA_def_struct_ui_text(srna, "F-Curve Sample", "Sample point for F-Curve.");
/* Boolean values */
prop= RNA_def_property(srna, "selected", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", 1);
RNA_def_property_ui_text(prop, "Selected", "Selection status");
/* Vector value */
prop= RNA_def_property(srna, "point", PROP_FLOAT, PROP_VECTOR);
RNA_def_property_array(prop, 2);
RNA_def_property_float_sdna(prop, NULL, "vec");
RNA_def_property_ui_text(prop, "Point", "Point coordinates");
}
void rna_def_fcurve(BlenderRNA *brna)
{
StructRNA *srna;
@ -619,7 +603,7 @@ void rna_def_fcurve(BlenderRNA *brna)
/* Collections */
prop= RNA_def_property(srna, "sampled_points", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "fpt", "totvert");
RNA_def_property_struct_type(prop, "CurvePoint"); // XXX FPoints not BPoints here! FPoints are much smaller!
RNA_def_property_struct_type(prop, "FCurveSample");
RNA_def_property_ui_text(prop, "Sampled Points", "Sampled animation data");
prop= RNA_def_property(srna, "keyframe_points", PROP_COLLECTION, PROP_NONE);
@ -637,6 +621,7 @@ void rna_def_fcurve(BlenderRNA *brna)
void RNA_def_fcurve(BlenderRNA *brna)
{
rna_def_fcurve(brna);
rna_def_fpoint(brna);
rna_def_drivertarget(brna);
rna_def_channeldriver(brna);
@ -644,9 +629,9 @@ void RNA_def_fcurve(BlenderRNA *brna)
rna_def_fmodifier(brna);
rna_def_fmodifier_generator(brna);
rna_def_fmodifier_generator_polyexpanded(brna);
rna_def_fmodifier_generator_function(brna);
rna_def_fmodifier_function_generator(brna);
rna_def_fmodifier_envelope(brna);
rna_def_fmodifier_envelope_ctrl(brna);
rna_def_fmodifier_cycles(brna);
rna_def_fmodifier_python(brna);
rna_def_fmodifier_limits(brna);

@ -139,6 +139,7 @@ void RNA_def_material(struct BlenderRNA *brna);
void RNA_def_mesh(struct BlenderRNA *brna);
void RNA_def_meta(struct BlenderRNA *brna);
void RNA_def_modifier(struct BlenderRNA *brna);
void RNA_def_nla(struct BlenderRNA *brna);
void RNA_def_nodetree(struct BlenderRNA *brna);
void RNA_def_object(struct BlenderRNA *brna);
void RNA_def_object_force(struct BlenderRNA *brna);

@ -506,7 +506,7 @@ static void rna_def_modifier_build(BlenderRNA *brna)
RNA_def_struct_ui_icon(srna, ICON_MOD_BUILD);
prop= RNA_def_property(srna, "start", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 1, MAXFRAMEF);
RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF);
RNA_def_property_ui_text(prop, "Start", "Specify the start frame of the effect.");
RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Modifier_update");
@ -660,18 +660,18 @@ static void rna_def_modifier_wave(BlenderRNA *brna)
prop= RNA_def_property(srna, "time_offset", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "timeoffs");
RNA_def_property_range(prop, -MAXFRAMEF, MAXFRAMEF);
RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF);
RNA_def_property_ui_text(prop, "Time Offset", "Either the starting frame (for positive speed) or ending frame (for negative speed.)");
RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Modifier_update");
prop= RNA_def_property(srna, "lifetime", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, -MAXFRAMEF, MAXFRAMEF);
RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF);
RNA_def_property_ui_text(prop, "Lifetime", "");
RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Modifier_update");
prop= RNA_def_property(srna, "damping_time", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "damp");
RNA_def_property_range(prop, -MAXFRAMEF, MAXFRAMEF);
RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF);
RNA_def_property_ui_text(prop, "Damping Time", "");
RNA_def_property_update(prop, NC_OBJECT|ND_MODIFIER, "rna_Modifier_update");

@ -0,0 +1,460 @@
/**
* $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.
*
* Contributor(s): Blender Foundation (2009), Joshua Leung
*
* ***** END GPL LICENSE BLOCK *****
*/
#include <stdlib.h>
#include "RNA_define.h"
#include "RNA_types.h"
#include "rna_internal.h"
#include "DNA_anim_types.h"
#include "DNA_action_types.h"
#include "DNA_scene_types.h"
#include "MEM_guardedalloc.h"
#ifdef RNA_RUNTIME
#include <stdio.h>
#include <math.h>
/* needed for some of the validation stuff... */
#include "BKE_animsys.h"
#include "BKE_nla.h"
/* temp constant defined for these funcs only... */
#define NLASTRIP_MIN_LEN_THRESH 0.1f
void rna_NlaStrip_name_set(PointerRNA *ptr, const char *value)
{
NlaStrip *data= (NlaStrip *)ptr->data;
/* copy the name first */
BLI_strncpy(data->name, value, sizeof(data->name));
/* validate if there's enough info to do so */
if (ptr->id.data) {
AnimData *adt= BKE_animdata_from_id(ptr->id.data);
BKE_nlastrip_validate_name(adt, data);
}
}
static void rna_NlaStrip_start_frame_set(PointerRNA *ptr, float value)
{
NlaStrip *data= (NlaStrip*)ptr->data;
/* clamp value to lie within valid limits
* - cannot start past the end of the strip + some flexibility threshold
* - cannot start before the previous strip (if present) ends
* -> but if it was a transition, we could go up to the start of the strip + some flexibility threshold
* as long as we re-adjust the transition afterwards
* - minimum frame is -MAXFRAME so that we don't get clipping on frame 0
*/
if (data->prev) {
if (data->prev->type == NLASTRIP_TYPE_TRANSITION) {
CLAMP(value, data->prev->start+NLASTRIP_MIN_LEN_THRESH, data->end-NLASTRIP_MIN_LEN_THRESH);
/* readjust the transition to stick to the endpoints of the action-clips */
data->prev->end= value;
}
else {
CLAMP(value, data->prev->end, data->end-NLASTRIP_MIN_LEN_THRESH);
}
}
else {
CLAMP(value, MINAFRAME, data->end);
}
data->start= value;
}
static void rna_NlaStrip_end_frame_set(PointerRNA *ptr, float value)
{
NlaStrip *data= (NlaStrip*)ptr->data;
/* clamp value to lie within valid limits
* - must not have zero or negative length strip, so cannot start before the first frame
* + some minimum-strip-length threshold
* - cannot end later than the start of the next strip (if present)
* -> but if it was a transition, we could go up to the start of the end - some flexibility threshold
* as long as we re-adjust the transition afterwards
*/
if (data->next) {
if (data->next->type == NLASTRIP_TYPE_TRANSITION) {
CLAMP(value, data->start+NLASTRIP_MIN_LEN_THRESH, data->next->end-NLASTRIP_MIN_LEN_THRESH);
/* readjust the transition to stick to the endpoints of the action-clips */
data->next->start= value;
}
else {
CLAMP(value, data->start+NLASTRIP_MIN_LEN_THRESH, data->next->start);
}
}
else {
CLAMP(value, data->start+NLASTRIP_MIN_LEN_THRESH, MAXFRAME);
}
data->end= value;
/* calculate the lengths the strip and its action (if applicable) */
if (data->type == NLASTRIP_TYPE_CLIP) {
float len, actlen;
len= data->end - data->start;
actlen= data->actend - data->actstart;
if (IS_EQ(actlen, 0.0f)) actlen= 1.0f;
/* now, adjust the 'scale' setting to reflect this (so that this change can be valid) */
data->scale= len / ((actlen) * data->repeat);
}
}
static void rna_NlaStrip_scale_set(PointerRNA *ptr, float value)
{
NlaStrip *data= (NlaStrip*)ptr->data;
float actlen, mapping;
/* set scale value */
CLAMP(value, 0.0001f, 1000.0f); /* NOTE: these need to be synced with the values in the property definition in rna_def_nlastrip() */
data->scale= value;
/* calculate existing factors */
actlen= data->actend - data->actstart;
if (IS_EQ(actlen, 0.0f)) actlen= 1.0f;
mapping= data->scale * data->repeat;
/* adjust endpoint of strip in response to this */
if (IS_EQ(mapping, 0.0f) == 0)
data->end = (actlen * mapping) + data->start;
else
printf("NlaStrip Set Scale Error (in RNA): Scale = %0.4f, Repeat = %0.4f \n", data->scale, data->repeat);
}
static void rna_NlaStrip_repeat_set(PointerRNA *ptr, float value)
{
NlaStrip *data= (NlaStrip*)ptr->data;
float actlen, mapping;
/* set scale value */
CLAMP(value, 0.01f, 1000.0f); /* NOTE: these need to be synced with the values in the property definition in rna_def_nlastrip() */
data->repeat= value;
/* calculate existing factors */
actlen= data->actend - data->actstart;
if (IS_EQ(actlen, 0.0f)) actlen= 1.0f;
mapping= data->scale * data->repeat;
/* adjust endpoint of strip in response to this */
if (IS_EQ(mapping, 0.0f) == 0)
data->end = (actlen * mapping) + data->start;
else
printf("NlaStrip Set Repeat Error (in RNA): Scale = %0.4f, Repeat = %0.4f \n", data->scale, data->repeat);
}
static void rna_NlaStrip_blend_in_set(PointerRNA *ptr, float value)
{
NlaStrip *data= (NlaStrip*)ptr->data;
float len;
/* blend-in is limited to the length of the strip, and also cannot overlap with blendout */
len= (data->end - data->start) - data->blendout;
CLAMP(value, 0, len);
data->blendin= value;
}
static void rna_NlaStrip_blend_out_set(PointerRNA *ptr, float value)
{
NlaStrip *data= (NlaStrip*)ptr->data;
float len;
/* blend-out is limited to the length of the strip */
len= (data->end - data->start);
CLAMP(value, 0, len);
/* it also cannot overlap with blendin */
if ((len - value) < data->blendin)
value= len - data->blendin;
data->blendout= value;
}
static void rna_NlaStrip_action_start_frame_set(PointerRNA *ptr, float value)
{
NlaStrip *data= (NlaStrip*)ptr->data;
CLAMP(value, MINAFRAME, data->actend);
data->actstart= value;
}
static void rna_NlaStrip_action_end_frame_set(PointerRNA *ptr, float value)
{
NlaStrip *data= (NlaStrip*)ptr->data;
CLAMP(value, data->actstart, MAXFRAME);
data->actend= value;
}
static void rna_NlaStrip_animated_influence_set(PointerRNA *ptr, int value)
{
NlaStrip *data= (NlaStrip*)ptr->data;
if (value) {
/* set the flag, then make sure a curve for this exists */
data->flag |= NLASTRIP_FLAG_USR_INFLUENCE;
BKE_nlastrip_validate_fcurves(data);
}
else
data->flag &= ~NLASTRIP_FLAG_USR_INFLUENCE;
}
static void rna_NlaStrip_animated_time_set(PointerRNA *ptr, int value)
{
NlaStrip *data= (NlaStrip*)ptr->data;
if (value) {
/* set the flag, then make sure a curve for this exists */
data->flag |= NLASTRIP_FLAG_USR_TIME;
BKE_nlastrip_validate_fcurves(data);
}
else
data->flag &= ~NLASTRIP_FLAG_USR_TIME;
}
#else
void rna_def_nlastrip(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
/* enum defs */
static EnumPropertyItem prop_type_items[] = {
{NLASTRIP_TYPE_CLIP, "CLIP", 0, "Action Clip", "NLA Strip references some Action."},
{NLASTRIP_TYPE_TRANSITION, "TRANSITION", 0, "Transition", "NLA Strip 'transitions' between adjacent strips."},
{NLASTRIP_TYPE_META, "META", 0, "Meta", "NLA Strip acts as a container for adjacent strips."},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem prop_mode_blend_items[] = {
{NLASTRIP_MODE_REPLACE, "REPLACE", 0, "Replace", "Result strip replaces the accumulated results by amount specified by influence."},
{NLASTRIP_MODE_ADD, "ADD", 0, "Add", "Weighted result of strip is added to the accumlated results."},
{NLASTRIP_MODE_SUBTRACT, "SUBTRACT", 0, "Subtract", "Weighted result of strip is removed from the accumlated results."},
{NLASTRIP_MODE_MULTIPLY, "MULITPLY", 0, "Multiply", "Weighted result of strip is multiplied with the accumlated results."},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem prop_mode_extend_items[] = {
{NLASTRIP_EXTEND_NOTHING, "NOTHING", 0, "Nothing", "Strip has no influence past its extents."},
{NLASTRIP_EXTEND_HOLD, "HOLD", 0, "Hold", "Hold the first frame if no previous strips in track, and always hold last frame."},
{NLASTRIP_EXTEND_HOLD_FORWARD, "HOLD_FORWARD", 0, "Hold Forward", "Only hold last frame."},
{0, NULL, 0, NULL, NULL}};
/* struct definition */
srna= RNA_def_struct(brna, "NlaStrip", NULL);
RNA_def_struct_ui_text(srna, "NLA Strip", "A container referencing an existing Action.");
RNA_def_struct_ui_icon(srna, ICON_NLA); // XXX
/* name property */
prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Name", "");
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_NlaStrip_name_set");
RNA_def_struct_name_property(srna, prop);
/* Enums */
prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_clear_flag(prop, PROP_EDITABLE); // XXX for now, not editable, since this is dangerous
RNA_def_property_enum_items(prop, prop_type_items);
RNA_def_property_ui_text(prop, "Type", "Type of NLA Strip.");
prop= RNA_def_property(srna, "extrapolation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "extendmode");
RNA_def_property_enum_items(prop, prop_mode_extend_items);
RNA_def_property_ui_text(prop, "Extrapolation", "Action to take for gaps past the strip extents.");
prop= RNA_def_property(srna, "blending", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "blendmode");
RNA_def_property_enum_items(prop, prop_mode_blend_items);
RNA_def_property_ui_text(prop, "Blending", "Method used for combining strip's result with accumulated result.");
/* Strip extents */
prop= RNA_def_property(srna, "start_frame", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "start");
RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_start_frame_set", NULL);
RNA_def_property_ui_text(prop, "Start Frame", "");
prop= RNA_def_property(srna, "end_frame", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "end");
RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_end_frame_set", NULL);
RNA_def_property_ui_text(prop, "End Frame", "");
/* Blending */
prop= RNA_def_property(srna, "blend_in", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "blendin");
RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_blend_in_set", NULL);
RNA_def_property_ui_text(prop, "Blend In", "Number of frames at start of strip to fade in influence.");
prop= RNA_def_property(srna, "blend_out", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "blendout");
RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_blend_out_set", NULL);
RNA_def_property_ui_text(prop, "Blend Out", "");
prop= RNA_def_property(srna, "auto_blending", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_AUTO_BLENDS);
RNA_def_property_ui_text(prop, "Auto Blend In/Out", "Number of frames for Blending In/Out is automatically determined from overlapping strips.");
/* Action */
prop= RNA_def_property(srna, "action", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "act");
RNA_def_property_ui_text(prop, "Action", "Action referenced by this strip.");
/* Action extents */
prop= RNA_def_property(srna, "action_start_frame", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "actstart");
RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_action_start_frame_set", NULL);
RNA_def_property_ui_text(prop, "Action Start Frame", "");
prop= RNA_def_property(srna, "action_end_frame", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "actend");
RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_action_end_frame_set", NULL);
RNA_def_property_ui_text(prop, "Action End Frame", "");
/* Action Reuse */
prop= RNA_def_property(srna, "repeat", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "repeat");
RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_repeat_set", NULL);
RNA_def_property_range(prop, 0.1f, 1000.0f); /* these limits have currently be chosen arbitarily, but could be extended (minimum should still be > 0 though) if needed... */
RNA_def_property_ui_text(prop, "Repeat", "Number of times to repeat the action range.");
prop= RNA_def_property(srna, "scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "scale");
RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_scale_set", NULL);
RNA_def_property_range(prop, 0.0001f, 1000.0f); /* these limits can be extended, but beyond this, we can get some crazy+annoying bugs due to numeric errors */
RNA_def_property_ui_text(prop, "Scale", "Scaling factor for action.");
/* Strip's F-Curves */
prop= RNA_def_property(srna, "fcurves", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "FCurve");
RNA_def_property_ui_text(prop, "F-Curves", "F-Curves for controlling the strip's influence and timing.");
/* Strip's F-Modifiers */
prop= RNA_def_property(srna, "modifiers", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "FModifier");
RNA_def_property_ui_text(prop, "Modifiers", "Modifiers affecting all the F-Curves in the referenced Action.");
/* Strip's Sub-Strips (for Meta-Strips) */
prop= RNA_def_property(srna, "strips", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "NlaStrip");
RNA_def_property_ui_text(prop, "NLA Strips", "NLA Strips that this strip acts as a container for (if it is of type Meta).");
/* Settings - Values necessary for evaluation */
prop= RNA_def_property(srna, "influence", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Influence", "Amount the strip contributes to the current result.");
prop= RNA_def_property(srna, "strip_time", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(prop, "Strip Time", "Frame of referenced Action to evaluate.");
// TODO: should the animated_influence/time settings be animatable themselves?
prop= RNA_def_property(srna, "animated_influence", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_USR_INFLUENCE);
RNA_def_property_boolean_funcs(prop, NULL, "rna_NlaStrip_animated_influence_set");
RNA_def_property_ui_text(prop, "Animated Influence", "Influence setting is controlled by an F-Curve rather than automatically determined.");
prop= RNA_def_property(srna, "animated_time", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_USR_TIME);
RNA_def_property_boolean_funcs(prop, NULL, "rna_NlaStrip_animated_time_set");
RNA_def_property_ui_text(prop, "Animated Strip Time", "Strip time is controlled by an F-Curve rather than automatically determined.");
/* settings */
prop= RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* can be made editable by hooking it up to the necessary NLA API methods */
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_ACTIVE);
RNA_def_property_ui_text(prop, "Active", "NLA Strip is active.");
prop= RNA_def_property(srna, "selected", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_SELECT);
RNA_def_property_ui_text(prop, "Selected", "NLA Strip is selected.");
prop= RNA_def_property(srna, "muted", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_MUTED);
RNA_def_property_ui_text(prop, "Muted", "NLA Strip is not evaluated.");
prop= RNA_def_property(srna, "reversed", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_REVERSE);
RNA_def_property_ui_text(prop, "Reversed", "NLA Strip is played back in reverse order (only when timing is automatically determined).");
// TODO:
// - sync length
}
void rna_def_nlatrack(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna= RNA_def_struct(brna, "NlaTrack", NULL);
RNA_def_struct_ui_text(srna, "NLA Track", "A animation layer containing Actions referenced as NLA strips.");
RNA_def_struct_ui_icon(srna, ICON_NLA);
/* strips collection */
prop= RNA_def_property(srna, "strips", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "NlaStrip");
RNA_def_property_ui_text(prop, "NLA Strips", "NLA Strips on this NLA-track.");
/* name property */
prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Name", "");
RNA_def_struct_name_property(srna, prop);
/* settings */
prop= RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* can be made editable by hooking it up to the necessary NLA API methods */
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_ACTIVE);
RNA_def_property_ui_text(prop, "Active", "NLA Track is active.");
prop= RNA_def_property(srna, "solo", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* can be made editable by hooking it up to the necessary NLA API methods */
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_SOLO);
RNA_def_property_ui_text(prop, "Solo", "NLA Track is evaluated itself (i.e. active Action and all other NLA Tracks in the same AnimData block are disabled).");
prop= RNA_def_property(srna, "selected", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_SELECTED);
RNA_def_property_ui_text(prop, "Selected", "NLA Track is selected.");
prop= RNA_def_property(srna, "muted", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_MUTED);
RNA_def_property_ui_text(prop, "Muted", "NLA Track is not evaluated.");
prop= RNA_def_property(srna, "locked", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", NLATRACK_PROTECTED);
RNA_def_property_ui_text(prop, "Locked", "NLA Track is locked.");
}
/* --------- */
void RNA_def_nla(BlenderRNA *brna)
{
rna_def_nlatrack(brna);
rna_def_nlastrip(brna);
}
#endif

@ -1170,7 +1170,7 @@ static void rna_def_object(BlenderRNA *brna)
prop= RNA_def_property(srna, "time_offset", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "sf");
RNA_def_property_range(prop, -MAXFRAMEF, MAXFRAMEF);
RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF);
RNA_def_property_ui_text(prop, "Time Offset", "Animation offset in frames for IPO's and dupligroup instances.");
RNA_def_property_update(prop, NC_OBJECT|ND_TRANSFORM, "rna_Object_update");
@ -1264,29 +1264,6 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Pose Mode", "Object with armature data is in pose mode.");
// XXX this stuff should be moved to AnimData...
/*
prop= RNA_def_property(srna, "nla_disable_path", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "nlaflag", OB_DISABLE_PATH);
RNA_def_property_ui_text(prop, "NLA Disable Path", "Disable path temporally, for editing cycles.");
prop= RNA_def_property(srna, "nla_collapsed", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "nlaflag", OB_NLA_COLLAPSED);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "NLA Collapsed", "");
prop= RNA_def_property(srna, "nla_override", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "nlaflag", OB_NLA_OVERRIDE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "NLA Override", "");
prop= RNA_def_property(srna, "nla_strips", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "nlastrips", NULL);
RNA_def_property_struct_type(prop, "UnknownType");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "NLA Strips", "NLA strips of the object.");
*/
/* shape keys */
prop= RNA_def_property(srna, "shape_key_lock", PROP_BOOLEAN, PROP_NONE);

@ -226,8 +226,8 @@ static void rna_PartSettings_start_set(struct PointerRNA *ptr, float value)
if(settings->type==PART_REACTOR && value < 1.0)
value = 1.0;
else if (value < -30000.0f) //TODO: replace 30000 with MAXFRAMEF when available in 2.5
value = -30000.0f;
else if (value < MINAFRAMEF)
value = MINAFRAMEF;
settings->sta = value;
}
@ -1090,19 +1090,19 @@ static void rna_def_particle_settings(BlenderRNA *brna)
/* general values */
prop= RNA_def_property(srna, "start", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "sta");//optional if prop names are the same
RNA_def_property_range(prop, -30000.0f, 30000.0f); //TODO: replace 30000 with MAXFRAMEF when available in 2.5
RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF);
RNA_def_property_float_funcs(prop, NULL, "rna_PartSettings_start_set", NULL);
RNA_def_property_ui_text(prop, "Start", "Frame # to start emitting particles.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
prop= RNA_def_property(srna, "end", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, -30000.0f, 30000.0f); //TODO: replace 30000 with MAXFRAMEF when available in 2.5
RNA_def_property_range(prop, MINAFRAMEF, MAXFRAMEF);
RNA_def_property_float_funcs(prop, NULL, "rna_PartSettings_end_set", NULL);
RNA_def_property_ui_text(prop, "End", "Frame # to stop emitting particles.");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");
prop= RNA_def_property(srna, "lifetime", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 1.0f, 30000.0f);
RNA_def_property_range(prop, 1.0f, MAXFRAMEF);
RNA_def_property_ui_text(prop, "Lifetime", "Specify the life span of the particles");
RNA_def_property_update(prop, NC_OBJECT|ND_PARTICLE, "rna_Particle_reset");

@ -975,7 +975,7 @@ void RNA_def_scene(BlenderRNA *brna)
prop= RNA_def_property(srna, "current_frame", PROP_INT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_ANIMATEABLE);
RNA_def_property_int_sdna(prop, NULL, "r.cfra");
RNA_def_property_range(prop, MINFRAME, MAXFRAME);
RNA_def_property_range(prop, MINAFRAME, MAXFRAME);
RNA_def_property_ui_text(prop, "Current Frame", "");
RNA_def_property_update(prop, NC_SCENE|ND_FRAME, "rna_Scene_frame_update");

@ -30,6 +30,7 @@
#include "rna_internal.h"
#include "DNA_action_types.h"
#include "DNA_object_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
@ -89,9 +90,8 @@ static StructRNA* rna_Space_refine(struct PointerRNA *ptr)
switch(space->spacetype) {
case SPACE_VIEW3D:
return &RNA_Space3DView;
/*case SPACE_IPO:
case SPACE_IPO:
return &RNA_SpaceGraphEditor;
*/
case SPACE_OUTLINER:
return &RNA_SpaceOutliner;
case SPACE_BUTS:
@ -109,12 +109,12 @@ static StructRNA* rna_Space_refine(struct PointerRNA *ptr)
//case SPACE_IMASEL:
// return &RNA_SpaceImageBrowser;
/*case SPACE_SOUND:
return &RNA_SpaceAudioWindow;
return &RNA_SpaceAudioWindow;*/
case SPACE_ACTION:
return &RNA_SpaceDopeSheetEditor;
case SPACE_NLA:
return &RNA_SpaceNLAEditor;
case SPACE_SCRIPT:
return &RNA_SpaceNLA;
/*case SPACE_SCRIPT:
return &RNA_SpaceScriptsWindow;
case SPACE_TIME:
return &RNA_SpaceTimeline;
@ -872,6 +872,117 @@ static void rna_def_space_text(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Replace Text", "Text to replace selected text with using the replace tool.");
}
static void rna_def_space_dopesheet(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
static EnumPropertyItem mode_items[] = {
{SACTCONT_DOPESHEET, "DOPESHEET", 0, "DopeSheet", ""},
{SACTCONT_ACTION, "ACTION", 0, "Action Editor", ""},
{SACTCONT_SHAPEKEY, "SHAPEKEY", 0, "ShapeKey Editor", ""}, // XXX to be depreceated?
{SACTCONT_GPENCIL, "GPENCIL", 0, "Grease Pencil", ""},
{0, NULL, 0, NULL, NULL}};
srna= RNA_def_struct(brna, "SpaceDopeSheetEditor", "Space");
RNA_def_struct_sdna(srna, "SpaceAction");
RNA_def_struct_ui_text(srna, "Space DopeSheet Editor", "DopeSheet space data.");
/* mode */
prop= RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mode");
RNA_def_property_enum_items(prop, mode_items);
RNA_def_property_ui_text(prop, "Mode", "Editing context being displayed.");
/* display */
prop= RNA_def_property(srna, "show_seconds", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SACTION_DRAWTIME);
RNA_def_property_clear_flag(prop, PROP_EDITABLE); // XXX for now, only set with operator
RNA_def_property_ui_text(prop, "Show Seconds", "Show timing in seconds not frames.");
prop= RNA_def_property(srna, "show_cframe_indicator", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SACTION_NODRAWCFRANUM);
RNA_def_property_ui_text(prop, "Show Frame Number Indicator", "Show frame number beside the current frame indicator line.");
prop= RNA_def_property(srna, "show_sliders", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SACTION_SLIDERS);
RNA_def_property_ui_text(prop, "Show Sliders", "Show sliders beside F-Curve channels.");
/* editing */
prop= RNA_def_property(srna, "automerge_keyframes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SACTION_NOTRANSKEYCULL);
RNA_def_property_ui_text(prop, "AutoMerge Keyframes", "Show handles of Bezier control points.");
// TODO... autosnap, dopesheet?
}
static void rna_def_space_graph(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
static EnumPropertyItem mode_items[] = {
{SIPO_MODE_ANIMATION, "FCURVES", 0, "F-Curves", ""},
{SIPO_MODE_DRIVERS, "DRIVERS", 0, "Drivers", ""},
{0, NULL, 0, NULL, NULL}};
srna= RNA_def_struct(brna, "SpaceGraphEditor", "Space");
RNA_def_struct_sdna(srna, "SpaceIpo");
RNA_def_struct_ui_text(srna, "Space Graph Editor", "Graph Editor space data.");
/* mode */
prop= RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mode");
RNA_def_property_enum_items(prop, mode_items);
RNA_def_property_ui_text(prop, "Mode", "Editing context being displayed.");
/* display */
prop= RNA_def_property(srna, "show_seconds", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_DRAWTIME);
RNA_def_property_clear_flag(prop, PROP_EDITABLE); // XXX for now, only set with operator
RNA_def_property_ui_text(prop, "Show Seconds", "Show timing in seconds not frames.");
prop= RNA_def_property(srna, "show_cframe_indicator", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NODRAWCFRANUM);
RNA_def_property_ui_text(prop, "Show Frame Number Indicator", "Show frame number beside the current frame indicator line.");
prop= RNA_def_property(srna, "show_handles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_NOHANDLES);
RNA_def_property_ui_text(prop, "Show Handles", "Show handles of Bezier control points.");
/* editing */
prop= RNA_def_property(srna, "automerge_keyframes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NOTRANSKEYCULL);
RNA_def_property_ui_text(prop, "AutoMerge Keyframes", "Show handles of Bezier control points.");
// TODO... autosnap, dopesheet?
}
static void rna_def_space_nla(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna= RNA_def_struct(brna, "SpaceNLA", "Space");
RNA_def_struct_sdna(srna, "SpaceNla");
RNA_def_struct_ui_text(srna, "Space Nla Editor", "NLA editor space data.");
/* display */
prop= RNA_def_property(srna, "show_seconds", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SNLA_DRAWTIME);
RNA_def_property_clear_flag(prop, PROP_EDITABLE); // XXX for now, only set with operator
RNA_def_property_ui_text(prop, "Show Seconds", "Show timing in seconds not frames.");
prop= RNA_def_property(srna, "show_cframe_indicator", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SNLA_NODRAWCFRANUM);
RNA_def_property_ui_text(prop, "Show Frame Number Indicator", "Show frame number beside the current frame indicator line.");
/* editing */
// TODO... autosnap, dopesheet?
}
static void rna_def_fileselect_params(BlenderRNA *brna)
{
StructRNA *srna;
@ -1009,6 +1120,9 @@ void RNA_def_space(BlenderRNA *brna)
rna_def_background_image(brna);
rna_def_space_3dview(brna);
rna_def_space_buttons(brna);
rna_def_space_dopesheet(brna);
rna_def_space_graph(brna);
rna_def_space_nla(brna);
}
#endif

@ -129,6 +129,7 @@ typedef struct wmNotifier {
#define NC_TEXT (12<<24)
#define NC_WORLD (13<<24)
#define NC_FILE (14<<24)
#define NC_ANIMATION (15<<24)
/* data type, 256 entries is enough, it can overlap */
#define NOTE_DATA 0x00FF0000
@ -188,6 +189,16 @@ typedef struct wmNotifier {
#define ND_PARAMS (60<<16)
#define ND_FILELIST (61<<16)
/* NC_ANIMATION Animato */
#define ND_KEYFRAME_SELECT (70<<16)
#define ND_KEYFRAME_EDIT (71<<16)
#define ND_KEYFRAME_PROP (72<<16)
#define ND_ANIMCHAN_SELECT (73<<16)
#define ND_ANIMCHAN_EDIT (74<<16)
#define ND_NLA_SELECT (75<<16)
#define ND_NLA_EDIT (76<<16)
#define ND_NLA_ACTCHANGE (77<<16)
/* subtype, 256 entries too */
#define NOTE_SUBTYPE 0x0000FF00