2011-02-23 10:52:22 +00:00
|
|
|
/*
|
2008-12-27 11:44:00 +00:00
|
|
|
* ***** 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,
|
2010-02-12 13:34:04 +00:00
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2008-12-27 11:44:00 +00:00
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
*
|
|
|
|
* Contributor(s): Joshua Leung
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
2011-02-27 20:29:51 +00:00
|
|
|
/** \file blender/editors/space_action/action_edit.c
|
|
|
|
* \ingroup spaction
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2008-12-27 11:44:00 +00:00
|
|
|
#include <math.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <float.h>
|
|
|
|
|
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
2009-11-10 20:43:45 +00:00
|
|
|
#include "BLI_math.h"
|
2011-01-07 18:36:47 +00:00
|
|
|
#include "BLI_utildefines.h"
|
2008-12-27 11:44:00 +00:00
|
|
|
|
2.5: Blender "Animato" - New Animation System
Finally, here is the basic (functional) prototype of the new animation system which will allow for the infamous "everything is animatable", and which also addresses several of the more serious shortcomings of the old system. Unfortunately, this will break old animation files (especially right now, as I haven't written the version patching code yet), however, this is for the future.
Highlights of the new system:
* Scrapped IPO-Curves/IPO/(Action+Constraint-Channels)/Action system, and replaced it with F-Curve/Action.
- F-Curves (animators from other packages will feel at home with this name) replace IPO-Curves.
- The 'new' Actions, act as the containers for F-Curves, so that they can be reused. They are therefore more akin to the old 'IPO' blocks, except they do not have the blocktype restriction, so you can store materials/texture/geometry F-Curves in the same Action as Object transforms, etc.
* F-Curves use RNA-paths for Data Access, hence allowing "every" (where sensible/editable that is) user-accessible setting from RNA to be animated.
* Drivers are no longer mixed with Animation Data, so rigs will not be that easily broken and several dependency problems can be eliminated. (NOTE: drivers haven't been hooked up yet, but the code is in place)
* F-Curve modifier system allows useful 'large-scale' manipulation of F-Curve values, including (I've only included implemented ones here): envelope deform (similar to lattices to allow broad-scale reshaping of curves), curve generator (polynomial or py-expression), cycles (replacing the old cyclic extrapolation modes, giving more control over this). (NOTE: currently this cannot be tested, as there's not access to them, but the code is all in place)
* NLA system with 'tracks' (i.e. layers), and multiple strips per track. (NOTE: NLA system is not yet functional, as it's only partially coded still)
There are more nice things that I will be preparing some nice docs for soon, but for now, check for more details:
http://lists.blender.org/pipermail/bf-taskforce25/2009-January/000260.html
So, what currently works:
* I've implemented two basic operators for the 3D-view only to Insert and Delete Keyframes. These are tempolary ones only that will be replaced in due course with 'proper' code.
* Object Loc/Rot/Scale can be keyframed. Also, the colour of the 'active' material (Note: this should really be for nth material instead, but that doesn't work yet in RNA) can also be keyframed into the same datablock.
* Standard animation refresh (i.e. animation resulting from NLA and Action evaluation) is now done completely separate from drivers before anything else is done after a frame change. Drivers are handled after this in a separate pass, as dictated by depsgraph flags, etc.
Notes:
* Drivers haven't been hooked up yet
* Only objects and data directly linked to objects can be animated.
* Depsgraph will need further tweaks. Currently, I've only made sure that it will update some things in the most basic cases (i.e. frame change).
* Animation Editors are currently broken (in terms of editing stuff). This will be my next target (priority to get Dopesheet working first, then F-Curve editor - i.e. old IPO Editor)
* I've had to put in large chunks of XXX sandboxing for old animation system code all around the place. This will be cleaned up in due course, as some places need special review.
In particular, the particles and sequencer code have far too many manual calls to calculate + flush animation info, which is really bad (this is a 'please explain yourselves' call to Physics coders!).
2009-01-17 03:12:50 +00:00
|
|
|
#include "DNA_anim_types.h"
|
2011-01-10 22:10:28 +00:00
|
|
|
#include "DNA_gpencil_types.h"
|
2008-12-27 11:44:00 +00:00
|
|
|
#include "DNA_object_types.h"
|
|
|
|
#include "DNA_scene_types.h"
|
2012-06-08 14:31:38 +00:00
|
|
|
#include "DNA_mask_types.h"
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
#include "RNA_access.h"
|
|
|
|
#include "RNA_define.h"
|
2009-05-08 10:50:32 +00:00
|
|
|
#include "RNA_enum_types.h"
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
#include "BKE_action.h"
|
2.5: Blender "Animato" - New Animation System
Finally, here is the basic (functional) prototype of the new animation system which will allow for the infamous "everything is animatable", and which also addresses several of the more serious shortcomings of the old system. Unfortunately, this will break old animation files (especially right now, as I haven't written the version patching code yet), however, this is for the future.
Highlights of the new system:
* Scrapped IPO-Curves/IPO/(Action+Constraint-Channels)/Action system, and replaced it with F-Curve/Action.
- F-Curves (animators from other packages will feel at home with this name) replace IPO-Curves.
- The 'new' Actions, act as the containers for F-Curves, so that they can be reused. They are therefore more akin to the old 'IPO' blocks, except they do not have the blocktype restriction, so you can store materials/texture/geometry F-Curves in the same Action as Object transforms, etc.
* F-Curves use RNA-paths for Data Access, hence allowing "every" (where sensible/editable that is) user-accessible setting from RNA to be animated.
* Drivers are no longer mixed with Animation Data, so rigs will not be that easily broken and several dependency problems can be eliminated. (NOTE: drivers haven't been hooked up yet, but the code is in place)
* F-Curve modifier system allows useful 'large-scale' manipulation of F-Curve values, including (I've only included implemented ones here): envelope deform (similar to lattices to allow broad-scale reshaping of curves), curve generator (polynomial or py-expression), cycles (replacing the old cyclic extrapolation modes, giving more control over this). (NOTE: currently this cannot be tested, as there's not access to them, but the code is all in place)
* NLA system with 'tracks' (i.e. layers), and multiple strips per track. (NOTE: NLA system is not yet functional, as it's only partially coded still)
There are more nice things that I will be preparing some nice docs for soon, but for now, check for more details:
http://lists.blender.org/pipermail/bf-taskforce25/2009-January/000260.html
So, what currently works:
* I've implemented two basic operators for the 3D-view only to Insert and Delete Keyframes. These are tempolary ones only that will be replaced in due course with 'proper' code.
* Object Loc/Rot/Scale can be keyframed. Also, the colour of the 'active' material (Note: this should really be for nth material instead, but that doesn't work yet in RNA) can also be keyframed into the same datablock.
* Standard animation refresh (i.e. animation resulting from NLA and Action evaluation) is now done completely separate from drivers before anything else is done after a frame change. Drivers are handled after this in a separate pass, as dictated by depsgraph flags, etc.
Notes:
* Drivers haven't been hooked up yet
* Only objects and data directly linked to objects can be animated.
* Depsgraph will need further tweaks. Currently, I've only made sure that it will update some things in the most basic cases (i.e. frame change).
* Animation Editors are currently broken (in terms of editing stuff). This will be my next target (priority to get Dopesheet working first, then F-Curve editor - i.e. old IPO Editor)
* I've had to put in large chunks of XXX sandboxing for old animation system code all around the place. This will be cleaned up in due course, as some places need special review.
In particular, the particles and sequencer code have far too many manual calls to calculate + flush animation info, which is really bad (this is a 'please explain yourselves' call to Physics coders!).
2009-01-17 03:12:50 +00:00
|
|
|
#include "BKE_fcurve.h"
|
2009-06-23 13:25:31 +00:00
|
|
|
#include "BKE_nla.h"
|
2008-12-27 11:44:00 +00:00
|
|
|
#include "BKE_context.h"
|
2009-02-24 11:23:04 +00:00
|
|
|
#include "BKE_report.h"
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
#include "UI_view2d.h"
|
|
|
|
|
|
|
|
#include "ED_anim_api.h"
|
2011-01-10 22:10:28 +00:00
|
|
|
#include "ED_gpencil.h"
|
2008-12-27 11:44:00 +00:00
|
|
|
#include "ED_keyframing.h"
|
|
|
|
#include "ED_keyframes_edit.h"
|
|
|
|
#include "ED_screen.h"
|
2009-07-08 16:17:47 +00:00
|
|
|
#include "ED_transform.h"
|
2011-01-06 04:35:57 +00:00
|
|
|
#include "ED_markers.h"
|
2012-06-08 14:31:38 +00:00
|
|
|
#include "ED_mask.h"
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
#include "WM_api.h"
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
2009-10-01 23:32:57 +00:00
|
|
|
#include "UI_interface.h"
|
|
|
|
|
2008-12-27 11:44:00 +00:00
|
|
|
#include "action_intern.h"
|
|
|
|
|
2.5 - Assorted Animation UI/Editing Tweaks
Main Feature:
* It is now possible to choose which AnimData block is the 'active' one for editing, and/or select them too. AnimData blocks are generally the dark blue and lighter-blue expanders (i.e. Scene, Object, Camera, Lamp, Curve, Armature, etc.)
* Objects are no longer selected/deselected when AKEY is used to toggle selection of channels. This was getting a bit annoying.
* Following on from selection of AnimData blocks, it is now possible to select/make active an AnimData block in the animation editors, and change the active action for that block via the 'Animation Data' panel in NLA Editor's properties region.
--> Be aware that user-counts are not totally handled correctly there yet, so some funky behaviour might be seen...
--> It is possible to assign a new action, or to assign an existing one, allowing to switch between actions as in the past with Actions/IPO Editors...
Other tweaks:
* Some code tweaks towards making the 'Euler Filter' feature for Graph Editor working sometime soon
* Added some backend code for snapping the values of keyframes to a single value. Still need to work out some UI for it though.
* Shuffled the code for ACT_OT_new() around, and removed the poll() callback so that it worked in NLA too.
* Fixed some more notifier bugs with deleting bones and a few other editmode operations for Armatures.
2009-09-27 04:22:04 +00:00
|
|
|
/* ************************************************************************** */
|
|
|
|
/* ACTION MANAGEMENT */
|
|
|
|
|
|
|
|
/* ******************** New Action Operator *********************** */
|
|
|
|
|
2010-10-15 01:36:14 +00:00
|
|
|
static int act_new_exec(bContext *C, wmOperator *UNUSED(op))
|
2.5 - Assorted Animation UI/Editing Tweaks
Main Feature:
* It is now possible to choose which AnimData block is the 'active' one for editing, and/or select them too. AnimData blocks are generally the dark blue and lighter-blue expanders (i.e. Scene, Object, Camera, Lamp, Curve, Armature, etc.)
* Objects are no longer selected/deselected when AKEY is used to toggle selection of channels. This was getting a bit annoying.
* Following on from selection of AnimData blocks, it is now possible to select/make active an AnimData block in the animation editors, and change the active action for that block via the 'Animation Data' panel in NLA Editor's properties region.
--> Be aware that user-counts are not totally handled correctly there yet, so some funky behaviour might be seen...
--> It is possible to assign a new action, or to assign an existing one, allowing to switch between actions as in the past with Actions/IPO Editors...
Other tweaks:
* Some code tweaks towards making the 'Euler Filter' feature for Graph Editor working sometime soon
* Added some backend code for snapping the values of keyframes to a single value. Still need to work out some UI for it though.
* Shuffled the code for ACT_OT_new() around, and removed the poll() callback so that it worked in NLA too.
* Fixed some more notifier bugs with deleting bones and a few other editmode operations for Armatures.
2009-09-27 04:22:04 +00:00
|
|
|
{
|
2009-10-01 23:32:57 +00:00
|
|
|
PointerRNA ptr, idptr;
|
|
|
|
PropertyRNA *prop;
|
2.5 - Assorted Animation UI/Editing Tweaks
Main Feature:
* It is now possible to choose which AnimData block is the 'active' one for editing, and/or select them too. AnimData blocks are generally the dark blue and lighter-blue expanders (i.e. Scene, Object, Camera, Lamp, Curve, Armature, etc.)
* Objects are no longer selected/deselected when AKEY is used to toggle selection of channels. This was getting a bit annoying.
* Following on from selection of AnimData blocks, it is now possible to select/make active an AnimData block in the animation editors, and change the active action for that block via the 'Animation Data' panel in NLA Editor's properties region.
--> Be aware that user-counts are not totally handled correctly there yet, so some funky behaviour might be seen...
--> It is possible to assign a new action, or to assign an existing one, allowing to switch between actions as in the past with Actions/IPO Editors...
Other tweaks:
* Some code tweaks towards making the 'Euler Filter' feature for Graph Editor working sometime soon
* Added some backend code for snapping the values of keyframes to a single value. Still need to work out some UI for it though.
* Shuffled the code for ACT_OT_new() around, and removed the poll() callback so that it worked in NLA too.
* Fixed some more notifier bugs with deleting bones and a few other editmode operations for Armatures.
2009-09-27 04:22:04 +00:00
|
|
|
|
2009-10-01 23:32:57 +00:00
|
|
|
/* hook into UI */
|
|
|
|
uiIDContextProperty(C, &ptr, &prop);
|
2011-01-11 00:39:59 +00:00
|
|
|
|
|
|
|
if (prop) {
|
2012-05-08 16:02:13 +00:00
|
|
|
bAction *action = NULL, *oldact = NULL;
|
2011-01-11 00:39:59 +00:00
|
|
|
PointerRNA oldptr;
|
|
|
|
|
|
|
|
/* create action - the way to do this depends on whether we've got an
|
|
|
|
* existing one there already, in which case we make a copy of it
|
|
|
|
* (which is useful for "versioning" actions within the same file)
|
|
|
|
*/
|
|
|
|
oldptr = RNA_property_pointer_get(&ptr, prop);
|
|
|
|
oldact = (bAction *)oldptr.id.data;
|
|
|
|
|
2012-05-08 16:02:13 +00:00
|
|
|
if (oldact && GS(oldact->id.name) == ID_AC) {
|
2011-01-11 00:39:59 +00:00
|
|
|
/* make a copy of the existing action */
|
2012-05-08 16:02:13 +00:00
|
|
|
action = BKE_action_copy(oldact);
|
2011-01-11 00:39:59 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* just make a new (empty) action */
|
2012-05-08 16:02:13 +00:00
|
|
|
action = add_empty_action("Action");
|
2011-01-11 00:39:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* when creating new ID blocks, use is already 1 (fake user),
|
|
|
|
* but RNA pointer use also increases user, so this compensates it
|
|
|
|
*/
|
2009-10-01 23:32:57 +00:00
|
|
|
action->id.us--;
|
2011-01-11 00:39:59 +00:00
|
|
|
|
2009-10-01 23:32:57 +00:00
|
|
|
RNA_id_pointer_create(&action->id, &idptr);
|
|
|
|
RNA_property_pointer_set(&ptr, prop, idptr);
|
|
|
|
RNA_property_update(C, &ptr, prop);
|
|
|
|
}
|
2011-01-11 00:39:59 +00:00
|
|
|
|
2.5 - Assorted Animation UI/Editing Tweaks
Main Feature:
* It is now possible to choose which AnimData block is the 'active' one for editing, and/or select them too. AnimData blocks are generally the dark blue and lighter-blue expanders (i.e. Scene, Object, Camera, Lamp, Curve, Armature, etc.)
* Objects are no longer selected/deselected when AKEY is used to toggle selection of channels. This was getting a bit annoying.
* Following on from selection of AnimData blocks, it is now possible to select/make active an AnimData block in the animation editors, and change the active action for that block via the 'Animation Data' panel in NLA Editor's properties region.
--> Be aware that user-counts are not totally handled correctly there yet, so some funky behaviour might be seen...
--> It is possible to assign a new action, or to assign an existing one, allowing to switch between actions as in the past with Actions/IPO Editors...
Other tweaks:
* Some code tweaks towards making the 'Euler Filter' feature for Graph Editor working sometime soon
* Added some backend code for snapping the values of keyframes to a single value. Still need to work out some UI for it though.
* Shuffled the code for ACT_OT_new() around, and removed the poll() callback so that it worked in NLA too.
* Fixed some more notifier bugs with deleting bones and a few other editmode operations for Armatures.
2009-09-27 04:22:04 +00:00
|
|
|
/* set notifier that keyframes have changed */
|
2012-05-08 16:02:13 +00:00
|
|
|
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
|
2.5 - Assorted Animation UI/Editing Tweaks
Main Feature:
* It is now possible to choose which AnimData block is the 'active' one for editing, and/or select them too. AnimData blocks are generally the dark blue and lighter-blue expanders (i.e. Scene, Object, Camera, Lamp, Curve, Armature, etc.)
* Objects are no longer selected/deselected when AKEY is used to toggle selection of channels. This was getting a bit annoying.
* Following on from selection of AnimData blocks, it is now possible to select/make active an AnimData block in the animation editors, and change the active action for that block via the 'Animation Data' panel in NLA Editor's properties region.
--> Be aware that user-counts are not totally handled correctly there yet, so some funky behaviour might be seen...
--> It is possible to assign a new action, or to assign an existing one, allowing to switch between actions as in the past with Actions/IPO Editors...
Other tweaks:
* Some code tweaks towards making the 'Euler Filter' feature for Graph Editor working sometime soon
* Added some backend code for snapping the values of keyframes to a single value. Still need to work out some UI for it though.
* Shuffled the code for ACT_OT_new() around, and removed the poll() callback so that it worked in NLA too.
* Fixed some more notifier bugs with deleting bones and a few other editmode operations for Armatures.
2009-09-27 04:22:04 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
void ACTION_OT_new(wmOperatorType *ot)
|
2.5 - Assorted Animation UI/Editing Tweaks
Main Feature:
* It is now possible to choose which AnimData block is the 'active' one for editing, and/or select them too. AnimData blocks are generally the dark blue and lighter-blue expanders (i.e. Scene, Object, Camera, Lamp, Curve, Armature, etc.)
* Objects are no longer selected/deselected when AKEY is used to toggle selection of channels. This was getting a bit annoying.
* Following on from selection of AnimData blocks, it is now possible to select/make active an AnimData block in the animation editors, and change the active action for that block via the 'Animation Data' panel in NLA Editor's properties region.
--> Be aware that user-counts are not totally handled correctly there yet, so some funky behaviour might be seen...
--> It is possible to assign a new action, or to assign an existing one, allowing to switch between actions as in the past with Actions/IPO Editors...
Other tweaks:
* Some code tweaks towards making the 'Euler Filter' feature for Graph Editor working sometime soon
* Added some backend code for snapping the values of keyframes to a single value. Still need to work out some UI for it though.
* Shuffled the code for ACT_OT_new() around, and removed the poll() callback so that it worked in NLA too.
* Fixed some more notifier bugs with deleting bones and a few other editmode operations for Armatures.
2009-09-27 04:22:04 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "New Action";
|
|
|
|
ot->idname = "ACTION_OT_new";
|
|
|
|
ot->description = "Create new action";
|
2.5 - Assorted Animation UI/Editing Tweaks
Main Feature:
* It is now possible to choose which AnimData block is the 'active' one for editing, and/or select them too. AnimData blocks are generally the dark blue and lighter-blue expanders (i.e. Scene, Object, Camera, Lamp, Curve, Armature, etc.)
* Objects are no longer selected/deselected when AKEY is used to toggle selection of channels. This was getting a bit annoying.
* Following on from selection of AnimData blocks, it is now possible to select/make active an AnimData block in the animation editors, and change the active action for that block via the 'Animation Data' panel in NLA Editor's properties region.
--> Be aware that user-counts are not totally handled correctly there yet, so some funky behaviour might be seen...
--> It is possible to assign a new action, or to assign an existing one, allowing to switch between actions as in the past with Actions/IPO Editors...
Other tweaks:
* Some code tweaks towards making the 'Euler Filter' feature for Graph Editor working sometime soon
* Added some backend code for snapping the values of keyframes to a single value. Still need to work out some UI for it though.
* Shuffled the code for ACT_OT_new() around, and removed the poll() callback so that it worked in NLA too.
* Fixed some more notifier bugs with deleting bones and a few other editmode operations for Armatures.
2009-09-27 04:22:04 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = act_new_exec;
|
2012-10-20 20:20:02 +00:00
|
|
|
/* NOTE: this is used in the NLA too... */
|
2012-03-22 07:26:09 +00:00
|
|
|
//ot->poll = ED_operator_action_active;
|
2.5 - Assorted Animation UI/Editing Tweaks
Main Feature:
* It is now possible to choose which AnimData block is the 'active' one for editing, and/or select them too. AnimData blocks are generally the dark blue and lighter-blue expanders (i.e. Scene, Object, Camera, Lamp, Curve, Armature, etc.)
* Objects are no longer selected/deselected when AKEY is used to toggle selection of channels. This was getting a bit annoying.
* Following on from selection of AnimData blocks, it is now possible to select/make active an AnimData block in the animation editors, and change the active action for that block via the 'Animation Data' panel in NLA Editor's properties region.
--> Be aware that user-counts are not totally handled correctly there yet, so some funky behaviour might be seen...
--> It is possible to assign a new action, or to assign an existing one, allowing to switch between actions as in the past with Actions/IPO Editors...
Other tweaks:
* Some code tweaks towards making the 'Euler Filter' feature for Graph Editor working sometime soon
* Added some backend code for snapping the values of keyframes to a single value. Still need to work out some UI for it though.
* Shuffled the code for ACT_OT_new() around, and removed the poll() callback so that it worked in NLA too.
* Fixed some more notifier bugs with deleting bones and a few other editmode operations for Armatures.
2009-09-27 04:22:04 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-08 16:02:13 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2.5 - Assorted Animation UI/Editing Tweaks
Main Feature:
* It is now possible to choose which AnimData block is the 'active' one for editing, and/or select them too. AnimData blocks are generally the dark blue and lighter-blue expanders (i.e. Scene, Object, Camera, Lamp, Curve, Armature, etc.)
* Objects are no longer selected/deselected when AKEY is used to toggle selection of channels. This was getting a bit annoying.
* Following on from selection of AnimData blocks, it is now possible to select/make active an AnimData block in the animation editors, and change the active action for that block via the 'Animation Data' panel in NLA Editor's properties region.
--> Be aware that user-counts are not totally handled correctly there yet, so some funky behaviour might be seen...
--> It is possible to assign a new action, or to assign an existing one, allowing to switch between actions as in the past with Actions/IPO Editors...
Other tweaks:
* Some code tweaks towards making the 'Euler Filter' feature for Graph Editor working sometime soon
* Added some backend code for snapping the values of keyframes to a single value. Still need to work out some UI for it though.
* Shuffled the code for ACT_OT_new() around, and removed the poll() callback so that it worked in NLA too.
* Fixed some more notifier bugs with deleting bones and a few other editmode operations for Armatures.
2009-09-27 04:22:04 +00:00
|
|
|
}
|
|
|
|
|
2011-02-26 06:28:24 +00:00
|
|
|
/* ************************************************************************** */
|
|
|
|
/* POSE MARKERS STUFF */
|
|
|
|
|
|
|
|
/* *************************** Localise Markers ***************************** */
|
|
|
|
|
|
|
|
/* ensure that there is:
|
2012-05-08 16:02:13 +00:00
|
|
|
* 1) an active action editor
|
|
|
|
* 2) that the mode will have an active action available
|
|
|
|
* 3) that the set of markers being shown are the scene markers, not the list we're merging
|
2011-02-26 06:28:24 +00:00
|
|
|
* 4) that there are some selected markers
|
|
|
|
*/
|
|
|
|
static int act_markers_make_local_poll(bContext *C)
|
|
|
|
{
|
|
|
|
SpaceAction *sact = CTX_wm_space_action(C);
|
|
|
|
|
|
|
|
/* 1) */
|
|
|
|
if (sact == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* 2) */
|
|
|
|
if (ELEM(sact->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY) == 0)
|
|
|
|
return 0;
|
|
|
|
if (sact->action == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* 3) */
|
|
|
|
if (sact->flag & SACTION_POSEMARKERS_SHOW)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* 4) */
|
|
|
|
return ED_markers_get_first_selected(ED_context_get_markers(C)) != NULL;
|
|
|
|
}
|
|
|
|
|
2012-05-08 16:02:13 +00:00
|
|
|
static int act_markers_make_local_exec(bContext *C, wmOperator *UNUSED(op))
|
2011-02-26 06:28:24 +00:00
|
|
|
{
|
|
|
|
ListBase *markers = ED_context_get_markers(C);
|
|
|
|
|
|
|
|
SpaceAction *sact = CTX_wm_space_action(C);
|
2012-05-08 16:02:13 +00:00
|
|
|
bAction *act = (sact) ? sact->action : NULL;
|
2011-02-26 06:28:24 +00:00
|
|
|
|
2012-05-08 16:02:13 +00:00
|
|
|
TimeMarker *marker, *markern = NULL;
|
2011-02-26 06:28:24 +00:00
|
|
|
|
|
|
|
/* sanity checks */
|
|
|
|
if (ELEM(NULL, markers, act))
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
/* migrate markers */
|
|
|
|
for (marker = markers->first; marker; marker = markern) {
|
|
|
|
markern = marker->next;
|
|
|
|
|
|
|
|
/* move if marker is selected */
|
|
|
|
if (marker->flag & SELECT) {
|
|
|
|
BLI_remlink(markers, marker);
|
|
|
|
BLI_addtail(&act->markers, marker);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now enable the "show posemarkers only" setting, so that we can see that something did happen */
|
|
|
|
sact->flag |= SACTION_POSEMARKERS_SHOW;
|
|
|
|
|
|
|
|
/* notifiers - both sets, as this change affects both */
|
2012-05-08 16:02:13 +00:00
|
|
|
WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
|
|
|
|
WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
|
2011-02-26 06:28:24 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
void ACTION_OT_markers_make_local(wmOperatorType *ot)
|
2011-02-26 06:28:24 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Make Markers Local";
|
|
|
|
ot->idname = "ACTION_OT_markers_make_local";
|
|
|
|
ot->description = "Move selected scene markers to the active Action as local 'pose' markers";
|
2011-02-26 06:28:24 +00:00
|
|
|
|
|
|
|
/* callbacks */
|
|
|
|
ot->exec = act_markers_make_local_exec;
|
|
|
|
ot->poll = act_markers_make_local_poll;
|
|
|
|
|
|
|
|
/* flags */
|
2012-05-08 16:02:13 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2011-02-26 06:28:24 +00:00
|
|
|
}
|
|
|
|
|
2009-01-01 01:47:36 +00:00
|
|
|
/* ************************************************************************** */
|
|
|
|
/* KEYFRAME-RANGE STUFF */
|
|
|
|
|
|
|
|
/* *************************** Calculate Range ************************** */
|
|
|
|
|
|
|
|
/* Get the min/max keyframes*/
|
2012-05-08 16:02:13 +00:00
|
|
|
static void get_keyframe_extents(bAnimContext *ac, float *min, float *max, const short onlySel)
|
2009-01-01 01:47:36 +00:00
|
|
|
{
|
|
|
|
ListBase anim_data = {NULL, NULL};
|
|
|
|
bAnimListElem *ale;
|
|
|
|
int filter;
|
|
|
|
|
|
|
|
/* get data to filter, from Action or Dopesheet */
|
2012-10-20 20:20:02 +00:00
|
|
|
/* XXX: what is sel doing here?!
|
|
|
|
* Commented it, was breaking things (eg. the "auto preview range" tool). */
|
2012-05-08 16:02:13 +00:00
|
|
|
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_SEL *//*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
|
2009-01-26 04:13:38 +00:00
|
|
|
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
|
2009-01-01 01:47:36 +00:00
|
|
|
|
|
|
|
/* set large values to try to override */
|
2012-05-08 16:02:13 +00:00
|
|
|
*min = 999999999.0f;
|
|
|
|
*max = -999999999.0f;
|
2009-01-01 01:47:36 +00:00
|
|
|
|
|
|
|
/* check if any channels to set range with */
|
|
|
|
if (anim_data.first) {
|
2009-01-03 06:01:11 +00:00
|
|
|
/* go through channels, finding max extents */
|
2012-05-08 16:02:13 +00:00
|
|
|
for (ale = anim_data.first; ale; ale = ale->next) {
|
|
|
|
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
|
2011-10-13 03:35:08 +00:00
|
|
|
if (ale->datatype == ALE_GPFRAME) {
|
2012-05-08 16:02:13 +00:00
|
|
|
bGPDlayer *gpl = ale->data;
|
2011-10-13 03:35:08 +00:00
|
|
|
bGPDframe *gpf;
|
|
|
|
|
|
|
|
/* find gp-frame which is less than or equal to cframe */
|
2012-05-08 16:02:13 +00:00
|
|
|
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
|
2012-10-27 11:18:54 +00:00
|
|
|
const float framenum = (float)gpf->framenum;
|
|
|
|
*min = min_ff(*min, framenum);
|
|
|
|
*max = max_ff(*max, framenum);
|
2011-10-13 03:35:08 +00:00
|
|
|
}
|
|
|
|
}
|
2012-06-08 14:31:38 +00:00
|
|
|
else if (ale->datatype == ALE_MASKLAY) {
|
|
|
|
MaskLayer *masklay = ale->data;
|
|
|
|
MaskLayerShape *masklay_shape;
|
|
|
|
|
|
|
|
/* find mask layer which is less than or equal to cframe */
|
|
|
|
for (masklay_shape = masklay->splines_shapes.first;
|
|
|
|
masklay_shape;
|
|
|
|
masklay_shape = masklay_shape->next)
|
|
|
|
{
|
2012-10-27 11:18:54 +00:00
|
|
|
const float framenum = (float)masklay_shape->frame;
|
|
|
|
*min = min_ff(*min, framenum);
|
|
|
|
*max = max_ff(*max, framenum);
|
2012-06-08 14:31:38 +00:00
|
|
|
}
|
|
|
|
}
|
2011-10-13 03:35:08 +00:00
|
|
|
else {
|
2012-05-08 16:02:13 +00:00
|
|
|
FCurve *fcu = (FCurve *)ale->key_data;
|
2011-10-13 03:35:08 +00:00
|
|
|
float tmin, tmax;
|
|
|
|
|
|
|
|
/* get range and apply necessary scaling before processing */
|
2011-10-23 17:52:20 +00:00
|
|
|
calc_fcurve_range(fcu, &tmin, &tmax, onlySel, TRUE);
|
2011-10-13 03:35:08 +00:00
|
|
|
|
|
|
|
if (adt) {
|
2012-05-08 16:02:13 +00:00
|
|
|
tmin = BKE_nla_tweakedit_remap(adt, tmin, NLATIME_CONVERT_MAP);
|
|
|
|
tmax = BKE_nla_tweakedit_remap(adt, tmax, NLATIME_CONVERT_MAP);
|
2011-10-13 03:35:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* try to set cur using these values, if they're more extreme than previously set values */
|
2012-10-27 11:18:54 +00:00
|
|
|
*min = min_ff(*min, tmin);
|
|
|
|
*max = max_ff(*max, tmax);
|
2009-01-01 01:47:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* free memory */
|
|
|
|
BLI_freelistN(&anim_data);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* set default range */
|
|
|
|
if (ac->scene) {
|
2012-05-08 16:02:13 +00:00
|
|
|
*min = (float)ac->scene->r.sfra;
|
|
|
|
*max = (float)ac->scene->r.efra;
|
2009-01-01 01:47:36 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-05-08 16:02:13 +00:00
|
|
|
*min = -5;
|
|
|
|
*max = 100;
|
2009-01-01 01:47:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ****************** Automatic Preview-Range Operator ****************** */
|
|
|
|
|
2010-10-15 01:36:14 +00:00
|
|
|
static int actkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op))
|
2009-01-01 01:47:36 +00:00
|
|
|
{
|
|
|
|
bAnimContext ac;
|
|
|
|
Scene *scene;
|
|
|
|
float min, max;
|
|
|
|
|
|
|
|
/* get editor data */
|
|
|
|
if (ANIM_animdata_get_context(C, &ac) == 0)
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
if (ac.scene == NULL)
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
else
|
2012-05-08 16:02:13 +00:00
|
|
|
scene = ac.scene;
|
2009-01-01 01:47:36 +00:00
|
|
|
|
|
|
|
/* set the range directly */
|
2011-03-17 10:02:37 +00:00
|
|
|
get_keyframe_extents(&ac, &min, &max, FALSE);
|
2010-01-19 20:30:04 +00:00
|
|
|
scene->r.flag |= SCER_PRV_RANGE;
|
2012-05-08 16:02:13 +00:00
|
|
|
scene->r.psfra = (int)floor(min + 0.5f);
|
|
|
|
scene->r.pefra = (int)floor(max + 0.5f);
|
2009-01-01 01:47:36 +00:00
|
|
|
|
2009-01-05 09:54:39 +00:00
|
|
|
/* set notifier that things have changed */
|
|
|
|
// XXX err... there's nothing for frame ranges yet, but this should do fine too
|
2012-05-08 16:02:13 +00:00
|
|
|
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, ac.scene);
|
2009-01-01 01:47:36 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
void ACTION_OT_previewrange_set(wmOperatorType *ot)
|
2009-01-01 01:47:36 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Auto-Set Preview Range";
|
|
|
|
ot->idname = "ACTION_OT_previewrange_set";
|
|
|
|
ot->description = "Set Preview Range based on extents of selected Keyframes";
|
2009-01-01 01:47:36 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = actkeys_previewrange_exec;
|
|
|
|
ot->poll = ED_operator_action_active;
|
2009-01-01 01:47:36 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-08 16:02:13 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2009-01-01 01:47:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ****************** View-All Operator ****************** */
|
|
|
|
|
2011-03-17 10:02:37 +00:00
|
|
|
static int actkeys_viewall(bContext *C, const short onlySel)
|
2009-01-01 01:47:36 +00:00
|
|
|
{
|
|
|
|
bAnimContext ac;
|
|
|
|
View2D *v2d;
|
|
|
|
float extra;
|
|
|
|
|
|
|
|
/* get editor data */
|
|
|
|
if (ANIM_animdata_get_context(C, &ac) == 0)
|
|
|
|
return OPERATOR_CANCELLED;
|
2012-05-08 16:02:13 +00:00
|
|
|
v2d = &ac.ar->v2d;
|
2009-01-01 01:47:36 +00:00
|
|
|
|
|
|
|
/* set the horizontal range, with an extra offset so that the extreme keys will be in view */
|
2011-03-17 10:02:37 +00:00
|
|
|
get_keyframe_extents(&ac, &v2d->cur.xmin, &v2d->cur.xmax, onlySel);
|
2009-01-01 01:47:36 +00:00
|
|
|
|
2012-09-15 11:48:20 +00:00
|
|
|
extra = 0.1f * BLI_rctf_size_x(&v2d->cur);
|
2009-01-01 01:47:36 +00:00
|
|
|
v2d->cur.xmin -= extra;
|
|
|
|
v2d->cur.xmax += extra;
|
|
|
|
|
|
|
|
/* set vertical range */
|
2012-03-24 02:51:46 +00:00
|
|
|
v2d->cur.ymax = 0.0f;
|
2012-09-15 11:48:20 +00:00
|
|
|
v2d->cur.ymin = (float)-BLI_rcti_size_y(&v2d->mask);
|
2009-01-01 01:47:36 +00:00
|
|
|
|
|
|
|
/* do View2D syncing */
|
|
|
|
UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
|
|
|
|
|
2009-07-10 10:48:25 +00:00
|
|
|
/* just redraw this view */
|
2009-01-05 09:54:39 +00:00
|
|
|
ED_area_tag_redraw(CTX_wm_area(C));
|
2009-01-01 01:47:36 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
2011-03-17 10:02:37 +00:00
|
|
|
|
|
|
|
/* ......... */
|
|
|
|
|
|
|
|
static int actkeys_viewall_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
{
|
|
|
|
/* whole range */
|
|
|
|
return actkeys_viewall(C, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int actkeys_viewsel_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
{
|
|
|
|
/* only selected */
|
|
|
|
return actkeys_viewall(C, TRUE);
|
|
|
|
}
|
2009-01-01 01:47:36 +00:00
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
void ACTION_OT_view_all(wmOperatorType *ot)
|
2009-01-01 01:47:36 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "View All";
|
|
|
|
ot->idname = "ACTION_OT_view_all";
|
|
|
|
ot->description = "Reset viewable area to show full keyframe range";
|
2009-01-01 01:47:36 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = actkeys_viewall_exec;
|
|
|
|
ot->poll = ED_operator_action_active;
|
2009-01-01 01:47:36 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-08 16:02:13 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2009-01-01 01:47:36 +00:00
|
|
|
}
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
void ACTION_OT_view_selected(wmOperatorType *ot)
|
2011-03-17 10:02:37 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "View Selected";
|
|
|
|
ot->idname = "ACTION_OT_view_selected";
|
|
|
|
ot->description = "Reset viewable area to show selected keyframes range";
|
2011-03-17 10:02:37 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = actkeys_viewsel_exec;
|
|
|
|
ot->poll = ED_operator_action_active;
|
2011-03-17 10:02:37 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-08 16:02:13 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2011-03-17 10:02:37 +00:00
|
|
|
}
|
|
|
|
|
2008-12-27 11:44:00 +00:00
|
|
|
/* ************************************************************************** */
|
|
|
|
/* GENERAL STUFF */
|
|
|
|
|
2008-12-29 11:04:55 +00:00
|
|
|
/* ******************** Copy/Paste Keyframes Operator ************************* */
|
2009-02-24 11:18:24 +00:00
|
|
|
/* NOTE: the backend code for this is shared with the graph editor */
|
2008-12-29 11:04:55 +00:00
|
|
|
|
2012-05-08 16:02:13 +00:00
|
|
|
static short copy_action_keys(bAnimContext *ac)
|
2009-01-22 10:53:22 +00:00
|
|
|
{
|
2008-12-29 11:04:55 +00:00
|
|
|
ListBase anim_data = {NULL, NULL};
|
2012-05-08 16:02:13 +00:00
|
|
|
int filter, ok = 0;
|
2008-12-29 11:04:55 +00:00
|
|
|
|
|
|
|
/* clear buffer first */
|
2009-02-24 11:18:24 +00:00
|
|
|
free_anim_copybuf();
|
2008-12-29 11:04:55 +00:00
|
|
|
|
|
|
|
/* filter data */
|
2012-05-08 16:02:13 +00:00
|
|
|
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
|
2009-01-26 04:13:38 +00:00
|
|
|
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
|
2008-12-29 11:04:55 +00:00
|
|
|
|
2009-02-24 11:18:24 +00:00
|
|
|
/* copy keyframes */
|
2012-05-08 16:02:13 +00:00
|
|
|
ok = copy_animedit_keys(ac, &anim_data);
|
2008-12-29 11:04:55 +00:00
|
|
|
|
2009-02-24 11:18:24 +00:00
|
|
|
/* clean up */
|
2008-12-29 11:04:55 +00:00
|
|
|
BLI_freelistN(&anim_data);
|
2009-02-24 16:51:55 +00:00
|
|
|
|
|
|
|
return ok;
|
2008-12-29 11:04:55 +00:00
|
|
|
}
|
|
|
|
|
2009-02-24 11:18:24 +00:00
|
|
|
|
2012-05-08 16:02:13 +00:00
|
|
|
static short paste_action_keys(bAnimContext *ac,
|
|
|
|
const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode)
|
2009-02-24 11:18:24 +00:00
|
|
|
{
|
2008-12-29 11:04:55 +00:00
|
|
|
ListBase anim_data = {NULL, NULL};
|
2012-05-08 16:02:13 +00:00
|
|
|
int filter, ok = 0;
|
2008-12-29 11:04:55 +00:00
|
|
|
|
Tweaks for Pasting Keyframes in DopeSheet/Graph Editors
In response to [#31670], I've reviewed the way that the Paste Keyframes tool for
the DopeSheet and Graph Editors works. Previously, it required you to always
select the F-Curves to paste the keyframes into before allowing you to paste
keyframes. This was because it is quite difficult to infer which ID-block's set
of curves is intended if more than one ID-block has similar curves (e.g. a scene
with two materials, and both have their diffuse color animated). The underlying
assumption and intention of the feature here was that the copy+paste were only
being used by animators to copy animation between similar curves, to transfer
and offset animation across block boundaries.
However, it turns out that many people were by far more familiar with the
simpler copy/paste paradigm from everywhere else (i.e. instead of trying to use
duplicate to copy keyframes around within their respective F-Curves).
Furthermore, in most cases there is only going to be a single character being
animated at a time (vs multiple), which means that most of the time the matching
problem is much simpler.
Hence, the Paste now works as follows:
- If there are selected F-Curves, we limit the paste-matching to only consider
those in the selected F-Curves. This makes it possible to still explicitly
specify where to paste.
- In the more general case (no prior selections), pasting will try to match
anything relevant it finds.
TODO:
- Check on whether the strictest matching level needs adjustments to limit the
number of false positives
- Testing and feedback of the new behaviour needed <--- ANIMATORS! PLEASE TEST
2012-06-01 15:00:28 +00:00
|
|
|
/* filter data
|
|
|
|
* - First time we try to filter more strictly, allowing only selected channels
|
|
|
|
* to allow copying animation between channels
|
|
|
|
* - Second time, we loosen things up if nothing was found the first time, allowing
|
|
|
|
* users to just paste keyframes back into the original curve again [#31670]
|
|
|
|
*/
|
|
|
|
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
|
|
|
|
|
|
|
|
if (ANIM_animdata_filter(ac, &anim_data, filter | ANIMFILTER_SEL, ac->data, ac->datatype) == 0)
|
|
|
|
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
|
2008-12-29 11:04:55 +00:00
|
|
|
|
2009-02-24 11:18:24 +00:00
|
|
|
/* paste keyframes */
|
2012-05-08 16:02:13 +00:00
|
|
|
ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode);
|
2008-12-29 11:04:55 +00:00
|
|
|
|
2009-02-24 11:18:24 +00:00
|
|
|
/* clean up */
|
2008-12-29 11:04:55 +00:00
|
|
|
BLI_freelistN(&anim_data);
|
2009-02-24 16:51:55 +00:00
|
|
|
|
|
|
|
return ok;
|
2008-12-29 11:04:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------- */
|
|
|
|
|
|
|
|
static int actkeys_copy_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
bAnimContext ac;
|
|
|
|
|
|
|
|
/* get editor data */
|
|
|
|
if (ANIM_animdata_get_context(C, &ac) == 0)
|
|
|
|
return OPERATOR_CANCELLED;
|
2012-07-06 23:56:59 +00:00
|
|
|
|
2008-12-29 11:04:55 +00:00
|
|
|
/* copy keyframes */
|
2012-12-03 08:37:43 +00:00
|
|
|
if (ac.datatype == ANIMCONT_GPENCIL) {
|
2012-07-06 23:56:59 +00:00
|
|
|
/* FIXME... */
|
2012-10-26 17:32:50 +00:00
|
|
|
BKE_report(op->reports, RPT_ERROR, "Keyframe pasting is not available for grease pencil mode");
|
2011-10-01 00:56:36 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2008-12-29 11:04:55 +00:00
|
|
|
}
|
2012-06-08 14:31:38 +00:00
|
|
|
else if (ac.datatype == ANIMCONT_MASK) {
|
2012-07-06 23:56:59 +00:00
|
|
|
/* FIXME... */
|
2012-06-08 14:31:38 +00:00
|
|
|
BKE_report(op->reports, RPT_ERROR, "Keyframe pasting is not available for mask mode");
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
2008-12-29 11:04:55 +00:00
|
|
|
else {
|
2012-10-21 05:46:41 +00:00
|
|
|
if (copy_action_keys(&ac)) {
|
2009-02-24 11:23:04 +00:00
|
|
|
BKE_report(op->reports, RPT_ERROR, "No keyframes copied to keyframes copy/paste buffer");
|
|
|
|
return OPERATOR_CANCELLED;
|
2008-12-29 11:04:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
void ACTION_OT_copy(wmOperatorType *ot)
|
2008-12-29 11:04:55 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Copy Keyframes";
|
|
|
|
ot->idname = "ACTION_OT_copy";
|
|
|
|
ot->description = "Copy selected keyframes to the copy/paste buffer";
|
2008-12-29 11:04:55 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = actkeys_copy_exec;
|
|
|
|
ot->poll = ED_operator_action_active;
|
2011-01-10 17:48:38 +00:00
|
|
|
|
2008-12-29 11:04:55 +00:00
|
|
|
/* flags */
|
2012-05-08 16:02:13 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2008-12-29 11:04:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int actkeys_paste_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
bAnimContext ac;
|
2010-12-14 15:14:16 +00:00
|
|
|
|
2012-05-08 16:02:13 +00:00
|
|
|
const eKeyPasteOffset offset_mode = RNA_enum_get(op->ptr, "offset");
|
|
|
|
const eKeyMergeMode merge_mode = RNA_enum_get(op->ptr, "merge");
|
2008-12-29 11:04:55 +00:00
|
|
|
|
|
|
|
/* get editor data */
|
|
|
|
if (ANIM_animdata_get_context(C, &ac) == 0)
|
|
|
|
return OPERATOR_CANCELLED;
|
2011-10-27 01:55:10 +00:00
|
|
|
|
|
|
|
/* ac.reports by default will be the global reports list, which won't show warnings */
|
2012-05-08 16:02:13 +00:00
|
|
|
ac.reports = op->reports;
|
2010-12-09 11:49:38 +00:00
|
|
|
|
2008-12-29 11:04:55 +00:00
|
|
|
/* paste keyframes */
|
2012-06-08 14:31:38 +00:00
|
|
|
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
|
2012-10-20 20:20:02 +00:00
|
|
|
/* FIXME... */
|
2012-10-26 17:32:50 +00:00
|
|
|
BKE_report(op->reports, RPT_ERROR, "Keyframe pasting is not available for grease pencil or mask mode");
|
2011-10-01 00:56:36 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2008-12-29 11:04:55 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-10-27 01:55:10 +00:00
|
|
|
/* non-zero return means an error occurred while trying to paste */
|
2010-12-14 15:14:16 +00:00
|
|
|
if (paste_action_keys(&ac, offset_mode, merge_mode)) {
|
2009-02-24 11:23:04 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
2008-12-29 11:04:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* validate keyframes after editing */
|
|
|
|
ANIM_editkeyframes_refresh(&ac);
|
|
|
|
|
2009-07-10 10:48:25 +00:00
|
|
|
/* set notifier that keyframes have changed */
|
2012-05-08 16:02:13 +00:00
|
|
|
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
|
2008-12-29 11:04:55 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
void ACTION_OT_paste(wmOperatorType *ot)
|
2008-12-29 11:04:55 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Paste Keyframes";
|
|
|
|
ot->idname = "ACTION_OT_paste";
|
|
|
|
ot->description = "Paste keyframes from copy/paste buffer for the selected channels, starting on the current frame";
|
2008-12-29 11:04:55 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
// ot->invoke = WM_operator_props_popup; // better wait for action redo panel
|
|
|
|
ot->exec = actkeys_paste_exec;
|
|
|
|
ot->poll = ED_operator_action_active;
|
2008-12-29 11:04:55 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-08 16:02:13 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2011-10-27 01:55:10 +00:00
|
|
|
|
|
|
|
/* props */
|
2011-01-10 17:48:38 +00:00
|
|
|
RNA_def_enum(ot->srna, "offset", keyframe_paste_offset_items, KEYFRAME_PASTE_OFFSET_CFRA_START, "Offset", "Paste time offset of keys");
|
2011-09-17 09:15:30 +00:00
|
|
|
RNA_def_enum(ot->srna, "merge", keyframe_paste_merge_items, KEYFRAME_PASTE_MERGE_MIX, "Type", "Method of merging pasted keys and existing");
|
2008-12-29 11:04:55 +00:00
|
|
|
}
|
2008-12-28 11:51:41 +00:00
|
|
|
|
2009-02-21 05:04:12 +00:00
|
|
|
/* ******************** Insert Keyframes Operator ************************* */
|
|
|
|
|
|
|
|
/* defines for insert keyframes tool */
|
2011-02-14 17:55:27 +00:00
|
|
|
static EnumPropertyItem prop_actkeys_insertkey_types[] = {
|
2009-06-16 00:52:21 +00:00
|
|
|
{1, "ALL", 0, "All Channels", ""},
|
|
|
|
{2, "SEL", 0, "Only Selected Channels", ""},
|
2012-10-20 20:20:02 +00:00
|
|
|
{3, "GROUP", 0, "In Active Group", ""}, /* XXX not in all cases */
|
2009-06-16 00:52:21 +00:00
|
|
|
{0, NULL, 0, NULL, NULL}
|
2009-02-21 05:04:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* this function is responsible for snapping keyframes to frame-times */
|
|
|
|
static void insert_action_keys(bAnimContext *ac, short mode)
|
|
|
|
{
|
|
|
|
ListBase anim_data = {NULL, NULL};
|
|
|
|
bAnimListElem *ale;
|
|
|
|
int filter;
|
|
|
|
|
2010-11-17 12:02:36 +00:00
|
|
|
ReportList *reports = ac->reports;
|
2012-05-08 16:02:13 +00:00
|
|
|
Scene *scene = ac->scene;
|
2009-02-21 05:04:12 +00:00
|
|
|
short flag = 0;
|
|
|
|
|
|
|
|
/* filter data */
|
2012-05-08 16:02:13 +00:00
|
|
|
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
|
|
|
|
if (mode == 2) filter |= ANIMFILTER_SEL;
|
|
|
|
else if (mode == 3) filter |= ANIMFILTER_ACTGROUPED;
|
2009-02-21 05:04:12 +00:00
|
|
|
|
|
|
|
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
|
|
|
|
|
|
|
|
/* init keyframing flag */
|
2009-12-14 12:09:20 +00:00
|
|
|
flag = ANIM_get_keyframing_flags(scene, 1);
|
2009-02-21 05:04:12 +00:00
|
|
|
|
|
|
|
/* insert keyframes */
|
2012-05-08 16:02:13 +00:00
|
|
|
for (ale = anim_data.first; ale; ale = ale->next) {
|
|
|
|
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
|
|
|
|
FCurve *fcu = (FCurve *)ale->key_data;
|
2011-01-12 03:41:12 +00:00
|
|
|
float cfra;
|
2011-06-22 13:30:59 +00:00
|
|
|
|
2009-02-21 05:04:12 +00:00
|
|
|
/* adjust current frame for NLA-scaling */
|
2009-06-23 13:25:31 +00:00
|
|
|
if (adt)
|
2012-05-08 16:02:13 +00:00
|
|
|
cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
|
2009-06-23 13:25:31 +00:00
|
|
|
else
|
2012-05-08 16:02:13 +00:00
|
|
|
cfra = (float)CFRA;
|
2009-02-21 05:04:12 +00:00
|
|
|
|
|
|
|
/* if there's an id */
|
|
|
|
if (ale->id)
|
2012-05-08 16:02:13 +00:00
|
|
|
insert_keyframe(reports, ale->id, NULL, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
|
2009-02-21 05:04:12 +00:00
|
|
|
else
|
|
|
|
insert_vert_fcurve(fcu, cfra, fcu->curval, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_freelistN(&anim_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------- */
|
|
|
|
|
|
|
|
static int actkeys_insertkey_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
bAnimContext ac;
|
|
|
|
short mode;
|
|
|
|
|
|
|
|
/* get editor data */
|
|
|
|
if (ANIM_animdata_get_context(C, &ac) == 0)
|
|
|
|
return OPERATOR_CANCELLED;
|
2012-06-08 14:31:38 +00:00
|
|
|
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
2009-02-21 05:04:12 +00:00
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
2009-06-29 03:02:41 +00:00
|
|
|
/* what channels to affect? */
|
2012-05-08 16:02:13 +00:00
|
|
|
mode = RNA_enum_get(op->ptr, "type");
|
2009-02-21 05:04:12 +00:00
|
|
|
|
2009-06-29 03:02:41 +00:00
|
|
|
/* insert keyframes */
|
2009-02-21 05:04:12 +00:00
|
|
|
insert_action_keys(&ac, mode);
|
|
|
|
|
|
|
|
/* validate keyframes after editing */
|
|
|
|
ANIM_editkeyframes_refresh(&ac);
|
|
|
|
|
2009-07-10 10:48:25 +00:00
|
|
|
/* set notifier that keyframes have changed */
|
2012-05-08 16:02:13 +00:00
|
|
|
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
|
2009-02-21 05:04:12 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
void ACTION_OT_keyframe_insert(wmOperatorType *ot)
|
2009-02-21 05:04:12 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Insert Keyframes";
|
|
|
|
ot->idname = "ACTION_OT_keyframe_insert";
|
|
|
|
ot->description = "Insert keyframes for the specified channels";
|
2009-02-21 05:04:12 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = WM_menu_invoke;
|
|
|
|
ot->exec = actkeys_insertkey_exec;
|
|
|
|
ot->poll = ED_operator_action_active;
|
2009-02-21 05:04:12 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-08 16:02:13 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2009-02-21 05:04:12 +00:00
|
|
|
|
|
|
|
/* id-props */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_insertkey_types, 0, "Type", "");
|
2009-02-21 05:04:12 +00:00
|
|
|
}
|
|
|
|
|
2009-02-20 11:17:33 +00:00
|
|
|
/* ******************** Duplicate Keyframes Operator ************************* */
|
|
|
|
|
2012-05-08 16:02:13 +00:00
|
|
|
static void duplicate_action_keys(bAnimContext *ac)
|
2009-02-20 11:17:33 +00:00
|
|
|
{
|
|
|
|
ListBase anim_data = {NULL, NULL};
|
|
|
|
bAnimListElem *ale;
|
|
|
|
int filter;
|
|
|
|
|
|
|
|
/* filter data */
|
2012-06-08 14:31:38 +00:00
|
|
|
if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
2012-05-08 16:02:13 +00:00
|
|
|
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
|
2009-02-20 11:17:33 +00:00
|
|
|
else
|
2012-05-08 16:02:13 +00:00
|
|
|
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
|
2009-02-20 11:17:33 +00:00
|
|
|
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
|
|
|
|
|
|
|
|
/* loop through filtered data and delete selected keys */
|
2012-05-08 16:02:13 +00:00
|
|
|
for (ale = anim_data.first; ale; ale = ale->next) {
|
2011-01-10 22:10:28 +00:00
|
|
|
if (ale->type == ANIMTYPE_FCURVE)
|
2009-02-20 11:17:33 +00:00
|
|
|
duplicate_fcurve_keys((FCurve *)ale->key_data);
|
2012-06-08 14:31:38 +00:00
|
|
|
else if (ale->type == ANIMTYPE_GPLAYER)
|
2012-06-08 21:48:04 +00:00
|
|
|
ED_gplayer_frames_duplicate((bGPDlayer *)ale->data);
|
2012-06-08 14:31:38 +00:00
|
|
|
else if (ale->type == ANIMTYPE_MASKLAYER)
|
2012-06-08 21:48:04 +00:00
|
|
|
ED_masklayer_frames_duplicate((MaskLayer *)ale->data);
|
2012-06-08 14:31:38 +00:00
|
|
|
else
|
|
|
|
BLI_assert(0);
|
2009-02-20 11:17:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* free filtered list */
|
|
|
|
BLI_freelistN(&anim_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------- */
|
|
|
|
|
2010-10-15 01:36:14 +00:00
|
|
|
static int actkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
|
2009-02-20 11:17:33 +00:00
|
|
|
{
|
|
|
|
bAnimContext ac;
|
|
|
|
|
|
|
|
/* get editor data */
|
|
|
|
if (ANIM_animdata_get_context(C, &ac) == 0)
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
/* duplicate keyframes */
|
|
|
|
duplicate_action_keys(&ac);
|
|
|
|
|
|
|
|
/* validate keyframes after editing */
|
2012-06-08 14:31:38 +00:00
|
|
|
if (!ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
2011-10-01 00:56:36 +00:00
|
|
|
ANIM_editkeyframes_refresh(&ac);
|
2009-02-20 11:17:33 +00:00
|
|
|
|
2009-07-10 10:48:25 +00:00
|
|
|
/* set notifier that keyframes have changed */
|
2012-05-08 16:02:13 +00:00
|
|
|
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
|
2009-02-20 11:17:33 +00:00
|
|
|
|
2011-10-01 00:56:36 +00:00
|
|
|
return OPERATOR_FINISHED;
|
2009-02-20 11:17:33 +00:00
|
|
|
}
|
|
|
|
|
2010-10-15 01:36:14 +00:00
|
|
|
static int actkeys_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
|
2009-02-20 11:17:33 +00:00
|
|
|
{
|
|
|
|
actkeys_duplicate_exec(C, op);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
void ACTION_OT_duplicate(wmOperatorType *ot)
|
2009-02-20 11:17:33 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Duplicate Keyframes";
|
|
|
|
ot->idname = "ACTION_OT_duplicate";
|
|
|
|
ot->description = "Make a copy of all selected keyframes";
|
2009-02-20 11:17:33 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = actkeys_duplicate_invoke;
|
|
|
|
ot->exec = actkeys_duplicate_exec;
|
|
|
|
ot->poll = ED_operator_action_active;
|
2009-02-20 11:17:33 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-08 16:02:13 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2009-02-20 11:17:33 +00:00
|
|
|
}
|
|
|
|
|
2008-12-29 01:19:25 +00:00
|
|
|
/* ******************** Delete Keyframes Operator ************************* */
|
|
|
|
|
2012-05-08 16:02:13 +00:00
|
|
|
static void delete_action_keys(bAnimContext *ac)
|
2008-12-29 01:19:25 +00:00
|
|
|
{
|
|
|
|
ListBase anim_data = {NULL, NULL};
|
|
|
|
bAnimListElem *ale;
|
|
|
|
int filter;
|
|
|
|
|
|
|
|
/* filter data */
|
2012-06-08 14:31:38 +00:00
|
|
|
if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
2012-05-08 16:02:13 +00:00
|
|
|
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
|
2008-12-29 01:19:25 +00:00
|
|
|
else
|
2012-05-08 16:02:13 +00:00
|
|
|
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
|
2009-01-26 04:13:38 +00:00
|
|
|
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
|
2008-12-29 01:19:25 +00:00
|
|
|
|
|
|
|
/* loop through filtered data and delete selected keys */
|
2012-05-08 16:02:13 +00:00
|
|
|
for (ale = anim_data.first; ale; ale = ale->next) {
|
2012-06-08 14:31:38 +00:00
|
|
|
if (ale->type == ANIMTYPE_GPLAYER) {
|
2012-06-08 21:48:04 +00:00
|
|
|
ED_gplayer_frames_delete((bGPDlayer *)ale->data);
|
2012-06-08 14:31:38 +00:00
|
|
|
}
|
|
|
|
else if (ale->type == ANIMTYPE_MASKLAYER) {
|
2012-06-08 21:48:04 +00:00
|
|
|
ED_masklayer_frames_delete((MaskLayer *)ale->data);
|
2012-06-08 14:31:38 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-05-08 16:02:13 +00:00
|
|
|
FCurve *fcu = (FCurve *)ale->key_data;
|
|
|
|
AnimData *adt = ale->adt;
|
2009-12-04 03:51:52 +00:00
|
|
|
|
|
|
|
/* delete selected keyframes only */
|
|
|
|
delete_fcurve_keys(fcu);
|
|
|
|
|
|
|
|
/* Only delete curve too if it won't be doing anything anymore */
|
|
|
|
if ((fcu->totvert == 0) && (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0))
|
2009-12-06 09:37:31 +00:00
|
|
|
ANIM_fcurve_delete_from_animdata(ac, adt, fcu);
|
2009-12-04 03:51:52 +00:00
|
|
|
}
|
2008-12-29 01:19:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* free filtered list */
|
|
|
|
BLI_freelistN(&anim_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------- */
|
|
|
|
|
2010-10-15 01:36:14 +00:00
|
|
|
static int actkeys_delete_exec(bContext *C, wmOperator *UNUSED(op))
|
2008-12-29 01:19:25 +00:00
|
|
|
{
|
|
|
|
bAnimContext ac;
|
|
|
|
|
|
|
|
/* get editor data */
|
|
|
|
if (ANIM_animdata_get_context(C, &ac) == 0)
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
|
|
|
/* delete keyframes */
|
|
|
|
delete_action_keys(&ac);
|
|
|
|
|
|
|
|
/* validate keyframes after editing */
|
2012-06-08 14:31:38 +00:00
|
|
|
if (!ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
2011-10-01 00:56:36 +00:00
|
|
|
ANIM_editkeyframes_refresh(&ac);
|
2008-12-29 01:19:25 +00:00
|
|
|
|
2009-07-10 10:48:25 +00:00
|
|
|
/* set notifier that keyframes have changed */
|
2012-05-08 16:02:13 +00:00
|
|
|
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
|
2008-12-29 01:19:25 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
void ACTION_OT_delete(wmOperatorType *ot)
|
2008-12-29 01:19:25 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Delete Keyframes";
|
|
|
|
ot->idname = "ACTION_OT_delete";
|
|
|
|
ot->description = "Remove all selected keyframes";
|
2008-12-29 01:19:25 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = WM_operator_confirm;
|
|
|
|
ot->exec = actkeys_delete_exec;
|
|
|
|
ot->poll = ED_operator_action_active;
|
2008-12-29 01:19:25 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-08 16:02:13 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2008-12-29 01:19:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ******************** Clean Keyframes Operator ************************* */
|
|
|
|
|
2012-05-08 16:02:13 +00:00
|
|
|
static void clean_action_keys(bAnimContext *ac, float thresh)
|
2008-12-29 01:19:25 +00:00
|
|
|
{
|
|
|
|
ListBase anim_data = {NULL, NULL};
|
|
|
|
bAnimListElem *ale;
|
|
|
|
int filter;
|
|
|
|
|
|
|
|
/* filter data */
|
2012-05-08 16:02:13 +00:00
|
|
|
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_SEL /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
|
2009-01-26 04:13:38 +00:00
|
|
|
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
|
2008-12-29 01:19:25 +00:00
|
|
|
|
|
|
|
/* loop through filtered data and clean curves */
|
2012-05-08 16:02:13 +00:00
|
|
|
for (ale = anim_data.first; ale; ale = ale->next)
|
2.5: Blender "Animato" - New Animation System
Finally, here is the basic (functional) prototype of the new animation system which will allow for the infamous "everything is animatable", and which also addresses several of the more serious shortcomings of the old system. Unfortunately, this will break old animation files (especially right now, as I haven't written the version patching code yet), however, this is for the future.
Highlights of the new system:
* Scrapped IPO-Curves/IPO/(Action+Constraint-Channels)/Action system, and replaced it with F-Curve/Action.
- F-Curves (animators from other packages will feel at home with this name) replace IPO-Curves.
- The 'new' Actions, act as the containers for F-Curves, so that they can be reused. They are therefore more akin to the old 'IPO' blocks, except they do not have the blocktype restriction, so you can store materials/texture/geometry F-Curves in the same Action as Object transforms, etc.
* F-Curves use RNA-paths for Data Access, hence allowing "every" (where sensible/editable that is) user-accessible setting from RNA to be animated.
* Drivers are no longer mixed with Animation Data, so rigs will not be that easily broken and several dependency problems can be eliminated. (NOTE: drivers haven't been hooked up yet, but the code is in place)
* F-Curve modifier system allows useful 'large-scale' manipulation of F-Curve values, including (I've only included implemented ones here): envelope deform (similar to lattices to allow broad-scale reshaping of curves), curve generator (polynomial or py-expression), cycles (replacing the old cyclic extrapolation modes, giving more control over this). (NOTE: currently this cannot be tested, as there's not access to them, but the code is all in place)
* NLA system with 'tracks' (i.e. layers), and multiple strips per track. (NOTE: NLA system is not yet functional, as it's only partially coded still)
There are more nice things that I will be preparing some nice docs for soon, but for now, check for more details:
http://lists.blender.org/pipermail/bf-taskforce25/2009-January/000260.html
So, what currently works:
* I've implemented two basic operators for the 3D-view only to Insert and Delete Keyframes. These are tempolary ones only that will be replaced in due course with 'proper' code.
* Object Loc/Rot/Scale can be keyframed. Also, the colour of the 'active' material (Note: this should really be for nth material instead, but that doesn't work yet in RNA) can also be keyframed into the same datablock.
* Standard animation refresh (i.e. animation resulting from NLA and Action evaluation) is now done completely separate from drivers before anything else is done after a frame change. Drivers are handled after this in a separate pass, as dictated by depsgraph flags, etc.
Notes:
* Drivers haven't been hooked up yet
* Only objects and data directly linked to objects can be animated.
* Depsgraph will need further tweaks. Currently, I've only made sure that it will update some things in the most basic cases (i.e. frame change).
* Animation Editors are currently broken (in terms of editing stuff). This will be my next target (priority to get Dopesheet working first, then F-Curve editor - i.e. old IPO Editor)
* I've had to put in large chunks of XXX sandboxing for old animation system code all around the place. This will be cleaned up in due course, as some places need special review.
In particular, the particles and sequencer code have far too many manual calls to calculate + flush animation info, which is really bad (this is a 'please explain yourselves' call to Physics coders!).
2009-01-17 03:12:50 +00:00
|
|
|
clean_fcurve((FCurve *)ale->key_data, thresh);
|
2008-12-29 01:19:25 +00:00
|
|
|
|
|
|
|
/* free temp data */
|
|
|
|
BLI_freelistN(&anim_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------- */
|
|
|
|
|
|
|
|
static int actkeys_clean_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
bAnimContext ac;
|
|
|
|
float thresh;
|
|
|
|
|
|
|
|
/* get editor data */
|
|
|
|
if (ANIM_animdata_get_context(C, &ac) == 0)
|
|
|
|
return OPERATOR_CANCELLED;
|
2012-06-08 14:31:38 +00:00
|
|
|
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
2008-12-29 01:19:25 +00:00
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
|
|
|
|
/* get cleaning threshold */
|
2012-05-08 16:02:13 +00:00
|
|
|
thresh = RNA_float_get(op->ptr, "threshold");
|
2008-12-29 01:19:25 +00:00
|
|
|
|
|
|
|
/* clean keyframes */
|
|
|
|
clean_action_keys(&ac, thresh);
|
|
|
|
|
|
|
|
/* validate keyframes after editing */
|
|
|
|
ANIM_editkeyframes_refresh(&ac);
|
|
|
|
|
2009-07-10 10:48:25 +00:00
|
|
|
/* set notifier that keyframes have changed */
|
2012-05-08 16:02:13 +00:00
|
|
|
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
|
2008-12-29 01:19:25 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
void ACTION_OT_clean(wmOperatorType *ot)
|
2008-12-29 01:19:25 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Clean Keyframes";
|
|
|
|
ot->idname = "ACTION_OT_clean";
|
|
|
|
ot->description = "Simplify F-Curves by removing closely spaced keyframes";
|
2008-12-29 01:19:25 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
//ot->invoke = // XXX we need that number popup for this!
|
|
|
|
ot->exec = actkeys_clean_exec;
|
|
|
|
ot->poll = ED_operator_action_active;
|
2008-12-29 01:19:25 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-08 16:02:13 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2008-12-29 01:19:25 +00:00
|
|
|
|
|
|
|
/* properties */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->prop = RNA_def_float(ot->srna, "threshold", 0.001f, 0.0f, FLT_MAX, "Threshold", "", 0.0f, 1000.0f);
|
2008-12-29 01:19:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ******************** Sample Keyframes Operator *********************** */
|
|
|
|
|
|
|
|
/* Evaluates the curves between each selected keyframe on each frame, and keys the value */
|
2012-05-08 16:02:13 +00:00
|
|
|
static void sample_action_keys(bAnimContext *ac)
|
2008-12-29 01:19:25 +00:00
|
|
|
{
|
|
|
|
ListBase anim_data = {NULL, NULL};
|
|
|
|
bAnimListElem *ale;
|
|
|
|
int filter;
|
|
|
|
|
|
|
|
/* filter data */
|
2012-05-08 16:02:13 +00:00
|
|
|
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
|
2009-01-26 04:13:38 +00:00
|
|
|
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
|
2008-12-29 01:19:25 +00:00
|
|
|
|
|
|
|
/* loop through filtered data and add keys between selected keyframes on every frame */
|
2012-05-08 16:02:13 +00:00
|
|
|
for (ale = anim_data.first; ale; ale = ale->next)
|
2009-09-04 04:27:06 +00:00
|
|
|
sample_fcurve((FCurve *)ale->key_data);
|
2008-12-29 01:19:25 +00:00
|
|
|
|
|
|
|
/* admin and redraws */
|
|
|
|
BLI_freelistN(&anim_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------- */
|
|
|
|
|
2010-10-15 01:36:14 +00:00
|
|
|
static int actkeys_sample_exec(bContext *C, wmOperator *UNUSED(op))
|
2008-12-29 01:19:25 +00:00
|
|
|
{
|
|
|
|
bAnimContext ac;
|
|
|
|
|
|
|
|
/* get editor data */
|
|
|
|
if (ANIM_animdata_get_context(C, &ac) == 0)
|
|
|
|
return OPERATOR_CANCELLED;
|
2012-06-08 14:31:38 +00:00
|
|
|
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
2008-12-29 01:19:25 +00:00
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
|
|
|
|
/* sample keyframes */
|
|
|
|
sample_action_keys(&ac);
|
|
|
|
|
|
|
|
/* validate keyframes after editing */
|
|
|
|
ANIM_editkeyframes_refresh(&ac);
|
|
|
|
|
2009-07-10 10:48:25 +00:00
|
|
|
/* set notifier that keyframes have changed */
|
2012-05-08 16:02:13 +00:00
|
|
|
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
|
2008-12-29 01:19:25 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
void ACTION_OT_sample(wmOperatorType *ot)
|
2008-12-29 01:19:25 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Sample Keyframes";
|
|
|
|
ot->idname = "ACTION_OT_sample";
|
|
|
|
ot->description = "Add keyframes on every frame between the selected keyframes";
|
2008-12-29 01:19:25 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = actkeys_sample_exec;
|
|
|
|
ot->poll = ED_operator_action_active;
|
2008-12-29 01:19:25 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-08 16:02:13 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2008-12-29 01:19:25 +00:00
|
|
|
}
|
|
|
|
|
2008-12-27 11:44:00 +00:00
|
|
|
/* ************************************************************************** */
|
|
|
|
/* SETTINGS STUFF */
|
|
|
|
|
2008-12-28 11:51:41 +00:00
|
|
|
/* ******************** Set Extrapolation-Type Operator *********************** */
|
|
|
|
|
2011-07-07 13:59:28 +00:00
|
|
|
/* defines for make/clear cyclic extrapolation tools */
|
2012-05-08 16:02:13 +00:00
|
|
|
#define MAKE_CYCLIC_EXPO -1
|
|
|
|
#define CLEAR_CYCLIC_EXPO -2
|
2011-07-07 13:59:28 +00:00
|
|
|
|
2009-01-02 11:06:27 +00:00
|
|
|
/* defines for set extrapolation-type for selected keyframes tool */
|
2011-02-14 17:55:27 +00:00
|
|
|
static EnumPropertyItem prop_actkeys_expo_types[] = {
|
2012-10-15 04:17:29 +00:00
|
|
|
{FCURVE_EXTRAPOLATE_CONSTANT, "CONSTANT", 0, "Constant Extrapolation", "Values on endpoint keyframes are held"},
|
|
|
|
{FCURVE_EXTRAPOLATE_LINEAR, "LINEAR", 0, "Linear Extrapolation", "Straight-line slope of end segments are extended past the endpoint keyframes"},
|
2011-07-07 13:59:28 +00:00
|
|
|
|
|
|
|
{MAKE_CYCLIC_EXPO, "MAKE_CYCLIC", 0, "Make Cyclic (F-Modifier)", "Add Cycles F-Modifier if one doesn't exist already"},
|
|
|
|
{CLEAR_CYCLIC_EXPO, "CLEAR_CYCLIC", 0, "Clear Cyclic (F-Modifier)", "Remove Cycles F-Modifier if not needed anymore"},
|
2009-06-16 00:52:21 +00:00
|
|
|
{0, NULL, 0, NULL, NULL}
|
2008-12-28 11:51:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* this function is responsible for setting extrapolation mode for keyframes */
|
|
|
|
static void setexpo_action_keys(bAnimContext *ac, short mode)
|
|
|
|
{
|
|
|
|
ListBase anim_data = {NULL, NULL};
|
|
|
|
bAnimListElem *ale;
|
|
|
|
int filter;
|
|
|
|
|
|
|
|
/* filter data */
|
2012-05-08 16:02:13 +00:00
|
|
|
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_SEL /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
|
2009-01-26 04:13:38 +00:00
|
|
|
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
|
2008-12-28 11:51:41 +00:00
|
|
|
|
2009-01-20 11:07:42 +00:00
|
|
|
/* loop through setting mode per F-Curve */
|
2012-05-08 16:02:13 +00:00
|
|
|
for (ale = anim_data.first; ale; ale = ale->next) {
|
|
|
|
FCurve *fcu = (FCurve *)ale->data;
|
2011-07-07 13:59:28 +00:00
|
|
|
|
|
|
|
if (mode >= 0) {
|
|
|
|
/* just set mode setting */
|
2012-05-08 16:02:13 +00:00
|
|
|
fcu->extend = mode;
|
2011-07-07 13:59:28 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* shortcuts for managing Cycles F-Modifiers to make it easier to toggle cyclic animation
|
|
|
|
* without having to go through FModifier UI in Graph Editor to do so
|
|
|
|
*/
|
|
|
|
if (mode == MAKE_CYCLIC_EXPO) {
|
|
|
|
/* only add if one doesn't exist */
|
|
|
|
if (list_has_suitable_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES, -1) == 0) {
|
2012-10-20 20:20:02 +00:00
|
|
|
/* TODO: add some more preset versions which set different extrapolation options? */
|
2011-07-07 13:59:28 +00:00
|
|
|
add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_CYCLES);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (mode == CLEAR_CYCLIC_EXPO) {
|
|
|
|
/* remove all the modifiers fitting this description */
|
2012-05-08 16:02:13 +00:00
|
|
|
FModifier *fcm, *fcn = NULL;
|
2011-07-07 13:59:28 +00:00
|
|
|
|
|
|
|
for (fcm = fcu->modifiers.first; fcm; fcm = fcn) {
|
|
|
|
fcn = fcm->next;
|
|
|
|
|
|
|
|
if (fcm->type == FMODIFIER_TYPE_CYCLES)
|
|
|
|
remove_fmodifier(&fcu->modifiers, fcm);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-01-20 11:07:42 +00:00
|
|
|
}
|
2008-12-28 11:51:41 +00:00
|
|
|
|
|
|
|
/* cleanup */
|
|
|
|
BLI_freelistN(&anim_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------- */
|
|
|
|
|
|
|
|
static int actkeys_expo_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
bAnimContext ac;
|
|
|
|
short mode;
|
|
|
|
|
|
|
|
/* get editor data */
|
|
|
|
if (ANIM_animdata_get_context(C, &ac) == 0)
|
|
|
|
return OPERATOR_CANCELLED;
|
2012-06-08 14:31:38 +00:00
|
|
|
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
2008-12-28 11:51:41 +00:00
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
|
|
|
|
/* get handle setting mode */
|
2012-05-08 16:02:13 +00:00
|
|
|
mode = RNA_enum_get(op->ptr, "type");
|
2008-12-28 11:51:41 +00:00
|
|
|
|
|
|
|
/* set handle type */
|
|
|
|
setexpo_action_keys(&ac, mode);
|
|
|
|
|
|
|
|
/* validate keyframes after editing */
|
|
|
|
ANIM_editkeyframes_refresh(&ac);
|
|
|
|
|
2009-07-10 10:48:25 +00:00
|
|
|
/* set notifier that keyframe properties have changed */
|
2012-05-08 16:02:13 +00:00
|
|
|
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
|
2008-12-28 11:51:41 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
void ACTION_OT_extrapolation_type(wmOperatorType *ot)
|
2008-12-28 11:51:41 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Set Keyframe Extrapolation";
|
|
|
|
ot->idname = "ACTION_OT_extrapolation_type";
|
|
|
|
ot->description = "Set extrapolation mode for selected F-Curves";
|
2008-12-28 11:51:41 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = WM_menu_invoke;
|
|
|
|
ot->exec = actkeys_expo_exec;
|
|
|
|
ot->poll = ED_operator_action_active;
|
2008-12-28 11:51:41 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-08 16:02:13 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2008-12-28 11:51:41 +00:00
|
|
|
|
|
|
|
/* id-props */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_expo_types, 0, "Type", "");
|
2008-12-28 11:51:41 +00:00
|
|
|
}
|
|
|
|
|
2008-12-28 08:15:29 +00:00
|
|
|
/* ******************** Set Interpolation-Type Operator *********************** */
|
|
|
|
|
|
|
|
/* this function is responsible for setting interpolation mode for keyframes */
|
|
|
|
static void setipo_action_keys(bAnimContext *ac, short mode)
|
|
|
|
{
|
|
|
|
ListBase anim_data = {NULL, NULL};
|
|
|
|
bAnimListElem *ale;
|
|
|
|
int filter;
|
2012-05-08 16:02:13 +00:00
|
|
|
KeyframeEditFunc set_cb = ANIM_editkeyframes_ipo(mode);
|
2008-12-28 08:15:29 +00:00
|
|
|
|
|
|
|
/* filter data */
|
2012-05-08 16:02:13 +00:00
|
|
|
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
|
2009-01-26 04:13:38 +00:00
|
|
|
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
|
2008-12-28 08:15:29 +00:00
|
|
|
|
2008-12-28 11:51:41 +00:00
|
|
|
/* loop through setting BezTriple interpolation
|
2010-04-02 12:02:39 +00:00
|
|
|
* Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here...
|
2008-12-28 08:15:29 +00:00
|
|
|
*/
|
2012-05-08 16:02:13 +00:00
|
|
|
for (ale = anim_data.first; ale; ale = ale->next)
|
2010-04-02 12:02:39 +00:00
|
|
|
ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
|
2008-12-28 08:15:29 +00:00
|
|
|
|
|
|
|
/* cleanup */
|
|
|
|
BLI_freelistN(&anim_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------- */
|
|
|
|
|
|
|
|
static int actkeys_ipo_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
bAnimContext ac;
|
|
|
|
short mode;
|
|
|
|
|
|
|
|
/* get editor data */
|
|
|
|
if (ANIM_animdata_get_context(C, &ac) == 0)
|
|
|
|
return OPERATOR_CANCELLED;
|
2012-06-08 14:31:38 +00:00
|
|
|
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
2008-12-28 08:15:29 +00:00
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
|
|
|
|
/* get handle setting mode */
|
2012-05-08 16:02:13 +00:00
|
|
|
mode = RNA_enum_get(op->ptr, "type");
|
2008-12-28 08:15:29 +00:00
|
|
|
|
|
|
|
/* set handle type */
|
|
|
|
setipo_action_keys(&ac, mode);
|
|
|
|
|
|
|
|
/* validate keyframes after editing */
|
|
|
|
ANIM_editkeyframes_refresh(&ac);
|
|
|
|
|
2009-07-10 10:48:25 +00:00
|
|
|
/* set notifier that keyframe properties have changed */
|
2012-05-08 16:02:13 +00:00
|
|
|
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
|
2008-12-28 08:15:29 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
void ACTION_OT_interpolation_type(wmOperatorType *ot)
|
2008-12-28 08:15:29 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Set Keyframe Interpolation";
|
|
|
|
ot->idname = "ACTION_OT_interpolation_type";
|
|
|
|
ot->description = "Set interpolation mode for the F-Curve segments starting from the selected keyframes";
|
2008-12-28 08:15:29 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = WM_menu_invoke;
|
|
|
|
ot->exec = actkeys_ipo_exec;
|
|
|
|
ot->poll = ED_operator_action_active;
|
2008-12-28 08:15:29 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-08 16:02:13 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2008-12-28 08:15:29 +00:00
|
|
|
|
|
|
|
/* id-props */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->prop = RNA_def_enum(ot->srna, "type", beztriple_interpolation_mode_items, 0, "Type", "");
|
2008-12-28 08:15:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ******************** Set Handle-Type Operator *********************** */
|
|
|
|
|
|
|
|
/* this function is responsible for setting handle-type of selected keyframes */
|
|
|
|
static void sethandles_action_keys(bAnimContext *ac, short mode)
|
|
|
|
{
|
|
|
|
ListBase anim_data = {NULL, NULL};
|
|
|
|
bAnimListElem *ale;
|
|
|
|
int filter;
|
2010-02-02 21:16:28 +00:00
|
|
|
|
2012-05-08 16:02:13 +00:00
|
|
|
KeyframeEditFunc edit_cb = ANIM_editkeyframes_handles(mode);
|
|
|
|
KeyframeEditFunc sel_cb = ANIM_editkeyframes_ok(BEZT_OK_SELECTED);
|
2008-12-28 08:15:29 +00:00
|
|
|
|
|
|
|
/* filter data */
|
2012-05-08 16:02:13 +00:00
|
|
|
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
|
2009-01-26 04:13:38 +00:00
|
|
|
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
|
2008-12-28 08:15:29 +00:00
|
|
|
|
|
|
|
/* loop through setting flags for handles
|
2010-04-02 12:02:39 +00:00
|
|
|
* Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here...
|
2008-12-28 08:15:29 +00:00
|
|
|
*/
|
2012-05-08 16:02:13 +00:00
|
|
|
for (ale = anim_data.first; ale; ale = ale->next) {
|
|
|
|
FCurve *fcu = (FCurve *)ale->key_data;
|
2010-02-01 11:45:24 +00:00
|
|
|
|
2010-02-02 21:16:28 +00:00
|
|
|
/* any selected keyframes for editing? */
|
2010-04-02 12:02:39 +00:00
|
|
|
if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL)) {
|
2010-02-02 21:16:28 +00:00
|
|
|
/* change type of selected handles */
|
2010-04-02 12:02:39 +00:00
|
|
|
ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, edit_cb, calchandles_fcurve);
|
2010-02-02 21:16:28 +00:00
|
|
|
}
|
2008-12-28 08:15:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* cleanup */
|
|
|
|
BLI_freelistN(&anim_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------- */
|
|
|
|
|
|
|
|
static int actkeys_handletype_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
bAnimContext ac;
|
|
|
|
short mode;
|
|
|
|
|
|
|
|
/* get editor data */
|
|
|
|
if (ANIM_animdata_get_context(C, &ac) == 0)
|
|
|
|
return OPERATOR_CANCELLED;
|
2012-06-08 14:31:38 +00:00
|
|
|
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
2008-12-28 08:15:29 +00:00
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
|
|
|
|
/* get handle setting mode */
|
2012-05-08 16:02:13 +00:00
|
|
|
mode = RNA_enum_get(op->ptr, "type");
|
2008-12-28 08:15:29 +00:00
|
|
|
|
|
|
|
/* set handle type */
|
2010-02-02 21:16:28 +00:00
|
|
|
sethandles_action_keys(&ac, mode);
|
2008-12-28 08:15:29 +00:00
|
|
|
|
|
|
|
/* validate keyframes after editing */
|
|
|
|
ANIM_editkeyframes_refresh(&ac);
|
|
|
|
|
2009-07-10 10:48:25 +00:00
|
|
|
/* set notifier that keyframe properties have changed */
|
2012-05-08 16:02:13 +00:00
|
|
|
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
|
2008-12-28 08:15:29 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
void ACTION_OT_handle_type(wmOperatorType *ot)
|
2008-12-28 08:15:29 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Set Keyframe Handle Type";
|
|
|
|
ot->idname = "ACTION_OT_handle_type";
|
|
|
|
ot->description = "Set type of handle for selected keyframes";
|
2008-12-28 08:15:29 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = WM_menu_invoke;
|
|
|
|
ot->exec = actkeys_handletype_exec;
|
|
|
|
ot->poll = ED_operator_action_active;
|
2008-12-28 08:15:29 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-08 16:02:13 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2008-12-28 08:15:29 +00:00
|
|
|
|
|
|
|
/* id-props */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->prop = RNA_def_enum(ot->srna, "type", keyframe_handle_type_items, 0, "Type", "");
|
2008-12-28 08:15:29 +00:00
|
|
|
}
|
|
|
|
|
2009-09-04 02:44:56 +00:00
|
|
|
/* ******************** Set Keyframe-Type Operator *********************** */
|
|
|
|
|
|
|
|
/* this function is responsible for setting interpolation mode for keyframes */
|
|
|
|
static void setkeytype_action_keys(bAnimContext *ac, short mode)
|
|
|
|
{
|
|
|
|
ListBase anim_data = {NULL, NULL};
|
|
|
|
bAnimListElem *ale;
|
|
|
|
int filter;
|
2012-05-08 16:02:13 +00:00
|
|
|
KeyframeEditFunc set_cb = ANIM_editkeyframes_keytype(mode);
|
2009-09-04 02:44:56 +00:00
|
|
|
|
|
|
|
/* filter data */
|
2012-05-08 16:02:13 +00:00
|
|
|
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
|
2009-09-04 02:44:56 +00:00
|
|
|
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
|
|
|
|
|
|
|
|
/* loop through setting BezTriple interpolation
|
2010-04-02 12:02:39 +00:00
|
|
|
* Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here...
|
2009-09-04 02:44:56 +00:00
|
|
|
*/
|
2012-05-08 16:02:13 +00:00
|
|
|
for (ale = anim_data.first; ale; ale = ale->next)
|
2010-04-02 12:02:39 +00:00
|
|
|
ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, NULL);
|
2009-09-04 02:44:56 +00:00
|
|
|
|
|
|
|
/* cleanup */
|
|
|
|
BLI_freelistN(&anim_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------- */
|
|
|
|
|
|
|
|
static int actkeys_keytype_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
bAnimContext ac;
|
|
|
|
short mode;
|
|
|
|
|
|
|
|
/* get editor data */
|
|
|
|
if (ANIM_animdata_get_context(C, &ac) == 0)
|
|
|
|
return OPERATOR_CANCELLED;
|
2012-06-08 14:31:38 +00:00
|
|
|
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
2009-09-04 02:44:56 +00:00
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
|
|
|
|
/* get handle setting mode */
|
2012-05-08 16:02:13 +00:00
|
|
|
mode = RNA_enum_get(op->ptr, "type");
|
2009-09-04 02:44:56 +00:00
|
|
|
|
|
|
|
/* set handle type */
|
|
|
|
setkeytype_action_keys(&ac, mode);
|
|
|
|
|
|
|
|
/* validate keyframes after editing */
|
|
|
|
ANIM_editkeyframes_refresh(&ac);
|
|
|
|
|
|
|
|
/* set notifier that keyframe properties have changed */
|
2012-05-08 16:02:13 +00:00
|
|
|
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
|
2009-09-04 02:44:56 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
void ACTION_OT_keyframe_type(wmOperatorType *ot)
|
2009-09-04 02:44:56 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Set Keyframe Type";
|
|
|
|
ot->idname = "ACTION_OT_keyframe_type";
|
|
|
|
ot->description = "Set type of keyframe for the selected keyframes";
|
2009-09-04 02:44:56 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = WM_menu_invoke;
|
|
|
|
ot->exec = actkeys_keytype_exec;
|
|
|
|
ot->poll = ED_operator_action_active;
|
2009-09-04 02:44:56 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-08 16:02:13 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2009-09-04 02:44:56 +00:00
|
|
|
|
|
|
|
/* id-props */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->prop = RNA_def_enum(ot->srna, "type", beztriple_keyframe_type_items, 0, "Type", "");
|
2009-09-04 02:44:56 +00:00
|
|
|
}
|
|
|
|
|
2008-12-27 11:44:00 +00:00
|
|
|
/* ************************************************************************** */
|
|
|
|
/* TRANSFORM STUFF */
|
|
|
|
|
2009-06-22 03:26:36 +00:00
|
|
|
/* ***************** Jump to Selected Frames Operator *********************** */
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
/* snap current-frame indicator to 'average time' of selected keyframe */
|
2010-10-15 01:36:14 +00:00
|
|
|
static int actkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
|
2008-12-27 11:44:00 +00:00
|
|
|
{
|
|
|
|
bAnimContext ac;
|
2012-05-08 16:02:13 +00:00
|
|
|
ListBase anim_data = {NULL, NULL};
|
2008-12-28 04:13:18 +00:00
|
|
|
bAnimListElem *ale;
|
|
|
|
int filter;
|
2012-05-08 16:02:13 +00:00
|
|
|
KeyframeEditData ked = {{NULL}};
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
/* get editor data */
|
|
|
|
if (ANIM_animdata_get_context(C, &ac) == 0)
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
2012-10-21 05:46:41 +00:00
|
|
|
/* init edit data */
|
2008-12-28 04:13:18 +00:00
|
|
|
/* loop over action data, averaging values */
|
2012-05-08 16:02:13 +00:00
|
|
|
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ | ANIMFILTER_NODUPLIS);
|
2009-01-26 04:13:38 +00:00
|
|
|
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
|
2008-12-28 04:13:18 +00:00
|
|
|
|
2012-05-08 16:02:13 +00:00
|
|
|
for (ale = anim_data.first; ale; ale = ale->next) {
|
|
|
|
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
|
2009-06-23 13:25:31 +00:00
|
|
|
if (adt) {
|
2010-01-15 10:34:39 +00:00
|
|
|
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
|
2010-04-02 12:02:39 +00:00
|
|
|
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL);
|
2010-01-15 10:34:39 +00:00
|
|
|
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
|
2009-06-23 13:25:31 +00:00
|
|
|
}
|
|
|
|
else
|
2010-04-02 12:02:39 +00:00
|
|
|
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL);
|
2009-06-23 13:25:31 +00:00
|
|
|
}
|
2008-12-28 04:13:18 +00:00
|
|
|
|
|
|
|
BLI_freelistN(&anim_data);
|
|
|
|
|
|
|
|
/* set the new current frame value, based on the average time */
|
2010-04-02 12:02:39 +00:00
|
|
|
if (ked.i1) {
|
2012-05-08 16:02:13 +00:00
|
|
|
Scene *scene = ac.scene;
|
|
|
|
CFRA = (int)floor((ked.f1 / ked.i1) + 0.5f);
|
|
|
|
SUBFRA = 0.f;
|
2008-12-28 04:13:18 +00:00
|
|
|
}
|
2008-12-27 11:44:00 +00:00
|
|
|
|
2009-04-10 03:34:20 +00:00
|
|
|
/* set notifier that things have changed */
|
2012-05-08 16:02:13 +00:00
|
|
|
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, ac.scene);
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
void ACTION_OT_frame_jump(wmOperatorType *ot)
|
2008-12-27 11:44:00 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-10-15 03:52:27 +00:00
|
|
|
ot->name = "Jump to Keyframes";
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->idname = "ACTION_OT_frame_jump";
|
2012-10-15 03:52:27 +00:00
|
|
|
ot->description = "Set the current frame to the average frame value of selected keyframes";
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->exec = actkeys_framejump_exec;
|
|
|
|
ot->poll = ED_operator_action_active;
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-08 16:02:13 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2008-12-27 11:44:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ******************** Snap Keyframes Operator *********************** */
|
|
|
|
|
|
|
|
/* defines for snap keyframes tool */
|
2011-02-14 17:55:27 +00:00
|
|
|
static EnumPropertyItem prop_actkeys_snap_types[] = {
|
2012-10-21 05:46:41 +00:00
|
|
|
{ACTKEYS_SNAP_CFRA, "CFRA", 0, "Current frame",
|
2012-10-08 05:57:52 +00:00
|
|
|
"Snap selected keyframes to the current frame"},
|
2012-10-21 05:46:41 +00:00
|
|
|
{ACTKEYS_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Nearest Frame",
|
2012-10-08 21:03:35 +00:00
|
|
|
"Snap selected keyframes to the nearest (whole) frame (use to fix accidental sub-frame offsets)"},
|
2012-10-21 05:46:41 +00:00
|
|
|
{ACTKEYS_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Nearest Second",
|
2012-10-08 05:57:52 +00:00
|
|
|
"Snap selected keyframes to the nearest second"},
|
2012-10-21 05:46:41 +00:00
|
|
|
{ACTKEYS_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Nearest Marker",
|
2012-10-08 05:57:52 +00:00
|
|
|
"Snap selected keyframes to the nearest marker"},
|
2009-06-16 00:52:21 +00:00
|
|
|
{0, NULL, 0, NULL, NULL}
|
2008-12-27 11:44:00 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* this function is responsible for snapping keyframes to frame-times */
|
|
|
|
static void snap_action_keys(bAnimContext *ac, short mode)
|
|
|
|
{
|
|
|
|
ListBase anim_data = {NULL, NULL};
|
|
|
|
bAnimListElem *ale;
|
|
|
|
int filter;
|
|
|
|
|
2012-05-08 16:02:13 +00:00
|
|
|
KeyframeEditData ked = {{NULL}};
|
2010-04-02 12:02:39 +00:00
|
|
|
KeyframeEditFunc edit_cb;
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
/* filter data */
|
2012-06-08 14:31:38 +00:00
|
|
|
if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
2012-05-08 16:02:13 +00:00
|
|
|
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
|
2008-12-27 11:44:00 +00:00
|
|
|
else
|
2012-05-08 16:02:13 +00:00
|
|
|
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
|
2009-01-26 04:13:38 +00:00
|
|
|
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
/* get beztriple editing callbacks */
|
2012-05-08 16:02:13 +00:00
|
|
|
edit_cb = ANIM_editkeyframes_snap(mode);
|
2010-10-31 15:39:37 +00:00
|
|
|
|
2012-05-08 16:02:13 +00:00
|
|
|
ked.scene = ac->scene;
|
2009-05-09 02:37:12 +00:00
|
|
|
if (mode == ACTKEYS_SNAP_NEAREST_MARKER) {
|
2012-05-08 16:02:13 +00:00
|
|
|
ked.list.first = (ac->markers) ? ac->markers->first : NULL;
|
|
|
|
ked.list.last = (ac->markers) ? ac->markers->last : NULL;
|
2009-05-09 02:37:12 +00:00
|
|
|
}
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
/* snap keyframes */
|
2012-05-08 16:02:13 +00:00
|
|
|
for (ale = anim_data.first; ale; ale = ale->next) {
|
|
|
|
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
|
2008-12-27 11:44:00 +00:00
|
|
|
|
2009-06-23 13:25:31 +00:00
|
|
|
if (adt) {
|
2010-01-15 10:34:39 +00:00
|
|
|
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
|
2010-04-02 12:02:39 +00:00
|
|
|
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
|
2010-01-15 10:34:39 +00:00
|
|
|
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
|
2008-12-27 11:44:00 +00:00
|
|
|
}
|
|
|
|
//else if (ale->type == ACTTYPE_GPLAYER)
|
|
|
|
// snap_gplayer_frames(ale->data, mode);
|
|
|
|
else
|
2010-04-02 12:02:39 +00:00
|
|
|
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
|
2008-12-27 11:44:00 +00:00
|
|
|
}
|
2010-01-26 03:16:14 +00:00
|
|
|
|
2008-12-27 11:44:00 +00:00
|
|
|
BLI_freelistN(&anim_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------- */
|
|
|
|
|
|
|
|
static int actkeys_snap_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
bAnimContext ac;
|
|
|
|
short mode;
|
|
|
|
|
|
|
|
/* get editor data */
|
|
|
|
if (ANIM_animdata_get_context(C, &ac) == 0)
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* XXX... */
|
2012-06-08 14:31:38 +00:00
|
|
|
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
2011-10-01 00:56:36 +00:00
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
|
2008-12-27 11:44:00 +00:00
|
|
|
/* get snapping mode */
|
2012-05-08 16:02:13 +00:00
|
|
|
mode = RNA_enum_get(op->ptr, "type");
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
/* snap keyframes */
|
|
|
|
snap_action_keys(&ac, mode);
|
|
|
|
|
|
|
|
/* validate keyframes after editing */
|
|
|
|
ANIM_editkeyframes_refresh(&ac);
|
|
|
|
|
2009-07-10 10:48:25 +00:00
|
|
|
/* set notifier that keyframes have changed */
|
2012-05-08 16:02:13 +00:00
|
|
|
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
void ACTION_OT_snap(wmOperatorType *ot)
|
2008-12-27 11:44:00 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Snap Keys";
|
|
|
|
ot->idname = "ACTION_OT_snap";
|
|
|
|
ot->description = "Snap selected keyframes to the times specified";
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = WM_menu_invoke;
|
|
|
|
ot->exec = actkeys_snap_exec;
|
|
|
|
ot->poll = ED_operator_action_active;
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-08 16:02:13 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
/* id-props */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_snap_types, 0, "Type", "");
|
2008-12-27 11:44:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ******************** Mirror Keyframes Operator *********************** */
|
|
|
|
|
2008-12-28 08:15:29 +00:00
|
|
|
/* defines for mirror keyframes tool */
|
2011-02-14 17:55:27 +00:00
|
|
|
static EnumPropertyItem prop_actkeys_mirror_types[] = {
|
2012-10-21 05:46:41 +00:00
|
|
|
{ACTKEYS_MIRROR_CFRA, "CFRA", 0, "By Times over Current frame",
|
2012-10-08 05:57:52 +00:00
|
|
|
"Flip times of selected keyframes using the current frame as the mirror line"},
|
2012-10-21 05:46:41 +00:00
|
|
|
{ACTKEYS_MIRROR_XAXIS, "XAXIS", 0, "By Values over Value=0",
|
2012-10-08 20:25:07 +00:00
|
|
|
"Flip values of selected keyframes (i.e. negative values become positive, and vice versa)"},
|
2012-10-21 05:46:41 +00:00
|
|
|
{ACTKEYS_MIRROR_MARKER, "MARKER", 0, "By Times over First Selected Marker",
|
2012-10-08 05:57:52 +00:00
|
|
|
"Flip times of selected keyframes using the first selected marker as the reference point"},
|
2009-06-16 00:52:21 +00:00
|
|
|
{0, NULL, 0, NULL, NULL}
|
2008-12-27 11:44:00 +00:00
|
|
|
};
|
|
|
|
|
2008-12-28 08:15:29 +00:00
|
|
|
/* this function is responsible for mirroring keyframes */
|
2008-12-27 11:44:00 +00:00
|
|
|
static void mirror_action_keys(bAnimContext *ac, short mode)
|
|
|
|
{
|
|
|
|
ListBase anim_data = {NULL, NULL};
|
|
|
|
bAnimListElem *ale;
|
|
|
|
int filter;
|
|
|
|
|
2012-05-08 16:02:13 +00:00
|
|
|
KeyframeEditData ked = {{NULL}};
|
2010-04-02 12:02:39 +00:00
|
|
|
KeyframeEditFunc edit_cb;
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
/* get beztriple editing callbacks */
|
2012-05-08 16:02:13 +00:00
|
|
|
edit_cb = ANIM_editkeyframes_mirror(mode);
|
2010-10-31 15:39:37 +00:00
|
|
|
|
2012-05-08 16:02:13 +00:00
|
|
|
ked.scene = ac->scene;
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
/* for 'first selected marker' mode, need to find first selected marker first! */
|
2012-10-20 20:20:02 +00:00
|
|
|
/* XXX should this be made into a helper func in the API? */
|
2008-12-27 11:44:00 +00:00
|
|
|
if (mode == ACTKEYS_MIRROR_MARKER) {
|
2012-10-08 05:57:52 +00:00
|
|
|
TimeMarker *marker = ED_markers_get_first_selected(ac->markers);
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
if (marker)
|
2012-05-08 16:02:13 +00:00
|
|
|
ked.f1 = (float)marker->frame;
|
2008-12-27 11:44:00 +00:00
|
|
|
else
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* filter data */
|
2012-06-08 14:31:38 +00:00
|
|
|
if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
2012-05-08 16:02:13 +00:00
|
|
|
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
|
2008-12-27 11:44:00 +00:00
|
|
|
else
|
2012-05-08 16:02:13 +00:00
|
|
|
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
|
2009-01-26 04:13:38 +00:00
|
|
|
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
/* mirror keyframes */
|
2012-05-08 16:02:13 +00:00
|
|
|
for (ale = anim_data.first; ale; ale = ale->next) {
|
|
|
|
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
|
2008-12-27 11:44:00 +00:00
|
|
|
|
2009-06-23 13:25:31 +00:00
|
|
|
if (adt) {
|
2010-01-15 10:34:39 +00:00
|
|
|
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
|
2010-04-02 12:02:39 +00:00
|
|
|
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
|
2010-01-15 10:34:39 +00:00
|
|
|
ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
|
2008-12-27 11:44:00 +00:00
|
|
|
}
|
|
|
|
//else if (ale->type == ACTTYPE_GPLAYER)
|
|
|
|
// snap_gplayer_frames(ale->data, mode);
|
|
|
|
else
|
2010-04-02 12:02:39 +00:00
|
|
|
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
|
2008-12-27 11:44:00 +00:00
|
|
|
}
|
2010-01-26 03:16:14 +00:00
|
|
|
|
2008-12-27 11:44:00 +00:00
|
|
|
BLI_freelistN(&anim_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------- */
|
|
|
|
|
|
|
|
static int actkeys_mirror_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
bAnimContext ac;
|
|
|
|
short mode;
|
|
|
|
|
|
|
|
/* get editor data */
|
|
|
|
if (ANIM_animdata_get_context(C, &ac) == 0)
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
2012-10-20 20:20:02 +00:00
|
|
|
/* XXX... */
|
2012-06-08 14:31:38 +00:00
|
|
|
if (ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
|
2011-10-01 00:56:36 +00:00
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
|
2008-12-28 08:15:29 +00:00
|
|
|
/* get mirroring mode */
|
2012-05-08 16:02:13 +00:00
|
|
|
mode = RNA_enum_get(op->ptr, "type");
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
/* mirror keyframes */
|
|
|
|
mirror_action_keys(&ac, mode);
|
|
|
|
|
|
|
|
/* validate keyframes after editing */
|
|
|
|
ANIM_editkeyframes_refresh(&ac);
|
|
|
|
|
2009-07-10 10:48:25 +00:00
|
|
|
/* set notifier that keyframes have changed */
|
2012-05-08 16:02:13 +00:00
|
|
|
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2012-04-29 17:11:40 +00:00
|
|
|
void ACTION_OT_mirror(wmOperatorType *ot)
|
2008-12-27 11:44:00 +00:00
|
|
|
{
|
|
|
|
/* identifiers */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->name = "Mirror Keys";
|
|
|
|
ot->idname = "ACTION_OT_mirror";
|
|
|
|
ot->description = "Flip selected keyframes over the selected mirror line";
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
/* api callbacks */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->invoke = WM_menu_invoke;
|
|
|
|
ot->exec = actkeys_mirror_exec;
|
|
|
|
ot->poll = ED_operator_action_active;
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
/* flags */
|
2012-05-08 16:02:13 +00:00
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
2008-12-27 11:44:00 +00:00
|
|
|
|
|
|
|
/* id-props */
|
2012-03-22 07:26:09 +00:00
|
|
|
ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_mirror_types, 0, "Type", "");
|
2008-12-27 11:44:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ************************************************************************** */
|