2011-02-23 10:52:22 +00:00
|
|
|
/*
|
2009-07-02 04:47:36 +00:00
|
|
|
* 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
|
2018-06-01 18:19:39 +02:00
|
|
|
* of the License, or (at your option) any later version.
|
2009-07-02 04:47:36 +00:00
|
|
|
*
|
|
|
|
|
* 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.
|
2009-07-02 04:47:36 +00:00
|
|
|
*
|
|
|
|
|
* The Original Code is Copyright (C) 2009 Blender Foundation.
|
|
|
|
|
* All rights reserved.
|
|
|
|
|
*/
|
|
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
|
* \ingroup edanimation
|
2011-02-27 20:29:51 +00:00
|
|
|
*/
|
|
|
|
|
|
2020-10-29 17:37:44 -05:00
|
|
|
/**
|
|
|
|
|
* User Interface for F-Modifiers
|
2010-03-18 13:04:46 +00:00
|
|
|
*
|
2020-10-29 17:37:44 -05:00
|
|
|
* This file defines templates and some editing callbacks needed by the interface for
|
|
|
|
|
* F-Modifiers, as used by F-Curves in the Graph Editor and NLA-Strips in the NLA Editor.
|
2009-07-02 04:47:36 +00:00
|
|
|
*/
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-07-02 04:47:36 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include "DNA_anim_types.h"
|
|
|
|
|
#include "DNA_scene_types.h"
|
2021-02-19 10:11:35 -06:00
|
|
|
#include "DNA_space_types.h"
|
2009-07-02 04:47:36 +00:00
|
|
|
|
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
2015-08-16 17:32:01 +10:00
|
|
|
#include "BLT_translation.h"
|
2012-03-03 21:42:21 +00:00
|
|
|
|
More F-Modifier Tweaks:
This commit started out aiming to make the "Stepped" F-Modifier (committed last night) even more useful, but ended up fixing a few other finer-points of how F-Modifiers work.
Firstly, the new stuff:
I've addded options to the Stepped F-Modifier to not affect frames before and/or after specified values, and renamed the 'start offset' to 'offset' for clarity.
The main objective of this is to allow Stepped F-Modifiers to only affect certain time ranges, so that by layering/using multiple instances of the F-Modifier, it can be possible to have multiple stepping-sizes.
This allows for effects like:
http://www.pasteall.org/blend/2230
or in words, it provides a convenient mechanism for animators to specify whether sections of the animation is shown "on twos", "fours", or even "forty-second-ths plus a smidgen", as can be easily done with 2D.
Assorted changes to support this:
* Properly fixed up how F-Modifiers that work with time, evaluate the time to evaluate the curve at. Now layered time effects like this should be possible in a much nicer way.
* Added proper value range validation/clamping to many properties. There are still a lot more that need checking, but at least more properties now do "the right thing".
2010-03-19 03:38:14 +00:00
|
|
|
#include "BLI_blenlib.h"
|
2011-01-07 18:36:47 +00:00
|
|
|
#include "BLI_utildefines.h"
|
More F-Modifier Tweaks:
This commit started out aiming to make the "Stepped" F-Modifier (committed last night) even more useful, but ended up fixing a few other finer-points of how F-Modifiers work.
Firstly, the new stuff:
I've addded options to the Stepped F-Modifier to not affect frames before and/or after specified values, and renamed the 'start offset' to 'offset' for clarity.
The main objective of this is to allow Stepped F-Modifiers to only affect certain time ranges, so that by layering/using multiple instances of the F-Modifier, it can be possible to have multiple stepping-sizes.
This allows for effects like:
http://www.pasteall.org/blend/2230
or in words, it provides a convenient mechanism for animators to specify whether sections of the animation is shown "on twos", "fours", or even "forty-second-ths plus a smidgen", as can be easily done with 2D.
Assorted changes to support this:
* Properly fixed up how F-Modifiers that work with time, evaluate the time to evaluate the curve at. Now layered time effects like this should be possible in a much nicer way.
* Added proper value range validation/clamping to many properties. There are still a lot more that need checking, but at least more properties now do "the right thing".
2010-03-19 03:38:14 +00:00
|
|
|
|
2009-07-02 04:47:36 +00:00
|
|
|
#include "BKE_context.h"
|
|
|
|
|
#include "BKE_fcurve.h"
|
2021-02-19 10:11:35 -06:00
|
|
|
#include "BKE_screen.h"
|
2009-07-02 04:47:36 +00:00
|
|
|
|
|
|
|
|
#include "WM_api.h"
|
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
|
|
|
|
|
#include "RNA_access.h"
|
|
|
|
|
|
|
|
|
|
#include "UI_interface.h"
|
|
|
|
|
#include "UI_resources.h"
|
|
|
|
|
|
2011-02-14 17:55:27 +00:00
|
|
|
#include "ED_anim_api.h"
|
2018-04-02 15:02:08 +02:00
|
|
|
#include "ED_undo.h"
|
2011-02-14 17:55:27 +00:00
|
|
|
|
2019-01-10 15:56:02 +01:00
|
|
|
#include "DEG_depsgraph.h"
|
|
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
typedef void (*PanelDrawFn)(const bContext *, struct Panel *);
|
|
|
|
|
static void fmodifier_panel_header(const bContext *C, Panel *panel);
|
2010-03-18 13:04:46 +00:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Panel Registering and Panel Callbacks
|
|
|
|
|
* \{ */
|
2009-07-02 04:47:36 +00:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
/**
|
|
|
|
|
* Get the list of FModifiers from the context (either the NLA or graph editor).
|
|
|
|
|
*/
|
|
|
|
|
static ListBase *fmodifier_list_space_specific(const bContext *C)
|
|
|
|
|
{
|
|
|
|
|
ScrArea *area = CTX_wm_area(C);
|
2009-07-02 04:47:36 +00:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
if (area->spacetype == SPACE_GRAPH) {
|
|
|
|
|
FCurve *fcu = ANIM_graph_context_fcurve(C);
|
|
|
|
|
return &fcu->modifiers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (area->spacetype == SPACE_NLA) {
|
|
|
|
|
NlaStrip *strip = ANIM_nla_context_strip(C);
|
|
|
|
|
return &strip->modifiers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This should not be called in any other space. */
|
|
|
|
|
BLI_assert(false);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get a pointer to the panel's FModifier, and also its owner ID if \a r_owner_id is not NULL.
|
|
|
|
|
* Also in the graph editor, gray out the panel if the FModifier's FCurve has modifiers turned off.
|
|
|
|
|
*/
|
|
|
|
|
static PointerRNA *fmodifier_get_pointers(const bContext *C, const Panel *panel, ID **r_owner_id)
|
2019-06-20 17:46:57 +02:00
|
|
|
{
|
2021-02-19 10:11:35 -06:00
|
|
|
PointerRNA *ptr = UI_panel_custom_data_get(panel);
|
|
|
|
|
|
|
|
|
|
if (r_owner_id != NULL) {
|
|
|
|
|
*r_owner_id = ptr->owner_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (C != NULL && CTX_wm_space_graph(C)) {
|
|
|
|
|
FCurve *fcu = ANIM_graph_context_fcurve(C);
|
|
|
|
|
uiLayoutSetActive(panel->layout, !(fcu->flag & FCURVE_MOD_OFF));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ptr;
|
2019-06-20 17:46:57 +02:00
|
|
|
}
|
|
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
/**
|
|
|
|
|
* Move an FModifier to the index it's moved to after a drag and drop.
|
|
|
|
|
*/
|
|
|
|
|
static void fmodifier_reorder(bContext *C, Panel *panel, int new_index)
|
2009-07-02 04:47:36 +00:00
|
|
|
{
|
2021-02-19 10:11:35 -06:00
|
|
|
ID *owner_id;
|
|
|
|
|
PointerRNA *ptr = fmodifier_get_pointers(NULL, panel, &owner_id);
|
|
|
|
|
FModifier *fcm = ptr->data;
|
|
|
|
|
const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(fcm->type);
|
|
|
|
|
|
|
|
|
|
/* Cycles modifier has to be the first, so make sure it's kept that way. */
|
|
|
|
|
if (fmi->requires & FMI_REQUIRES_ORIGINAL_DATA) {
|
|
|
|
|
WM_report(RPT_ERROR, "Modifier requires original data");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ListBase *modifiers = fmodifier_list_space_specific(C);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
/* Again, make sure we don't move a modifier before a cycles modifier. */
|
|
|
|
|
FModifier *fcm_first = modifiers->first;
|
|
|
|
|
const FModifierTypeInfo *fmi_first = get_fmodifier_typeinfo(fcm_first->type);
|
|
|
|
|
if (fmi_first->requires & FMI_REQUIRES_ORIGINAL_DATA && new_index == 0) {
|
|
|
|
|
WM_report(RPT_ERROR, "Modifier requires original data");
|
|
|
|
|
return;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2021-02-19 10:11:35 -06:00
|
|
|
|
|
|
|
|
int current_index = BLI_findindex(modifiers, fcm);
|
|
|
|
|
BLI_assert(current_index >= 0);
|
|
|
|
|
BLI_assert(new_index >= 0);
|
|
|
|
|
|
|
|
|
|
/* Don't do anything if the drag didn't change the index. */
|
|
|
|
|
if (current_index == new_index) {
|
|
|
|
|
return;
|
2019-06-20 17:46:57 +02:00
|
|
|
}
|
2021-02-19 10:11:35 -06:00
|
|
|
|
|
|
|
|
/* Move the FModifier in the list. */
|
|
|
|
|
BLI_listbase_link_move(modifiers, fcm, new_index - current_index);
|
|
|
|
|
|
|
|
|
|
ED_undo_push(C, "Reorder F-Curve Modifier");
|
|
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
|
|
|
|
|
DEG_id_tag_update(owner_id, ID_RECALC_ANIMATION);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static short get_fmodifier_expand_flag(const bContext *UNUSED(C), Panel *panel)
|
|
|
|
|
{
|
|
|
|
|
PointerRNA *ptr = fmodifier_get_pointers(NULL, panel, NULL);
|
|
|
|
|
FModifier *fcm = (FModifier *)ptr->data;
|
|
|
|
|
|
|
|
|
|
return fcm->ui_expand_flag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void set_fmodifier_expand_flag(const bContext *UNUSED(C), Panel *panel, short expand_flag)
|
|
|
|
|
{
|
|
|
|
|
PointerRNA *ptr = fmodifier_get_pointers(NULL, panel, NULL);
|
|
|
|
|
FModifier *fcm = (FModifier *)ptr->data;
|
|
|
|
|
|
|
|
|
|
fcm->ui_expand_flag = expand_flag;
|
2009-07-02 04:47:36 +00:00
|
|
|
}
|
|
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
static PanelType *fmodifier_panel_register(ARegionType *region_type,
|
|
|
|
|
eFModifier_Types type,
|
|
|
|
|
PanelDrawFn draw,
|
|
|
|
|
PanelTypePollFn poll,
|
|
|
|
|
const char *id_prefix)
|
|
|
|
|
{
|
2021-03-09 13:31:51 -05:00
|
|
|
PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
|
2021-02-19 10:11:35 -06:00
|
|
|
|
|
|
|
|
/* Intentionally leave the label field blank. The header is filled with buttons. */
|
2021-03-09 13:31:51 -05:00
|
|
|
const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type);
|
|
|
|
|
BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_PT_%s", id_prefix, fmi->name);
|
2021-02-19 10:11:35 -06:00
|
|
|
BLI_strncpy(panel_type->category, "Modifiers", BKE_ST_MAXNAME);
|
|
|
|
|
BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME);
|
|
|
|
|
|
|
|
|
|
panel_type->draw_header = fmodifier_panel_header;
|
|
|
|
|
panel_type->draw = draw;
|
|
|
|
|
panel_type->poll = poll;
|
|
|
|
|
|
|
|
|
|
/* Give the panel the special flag that says it was built here and corresponds to a
|
2021-02-20 15:38:14 +11:00
|
|
|
* modifier rather than a #PanelType. */
|
UI: Visual style update to panels
Back in Blender 2.30, the GUI project brought panels into Blender among other important visual updates.
For the first time it was possible to move the wall of buttons around. Providing a clear separation
between sections (it even allowed the grouping of panels in tabs!)
During the 2.5 redesign, the separation between panels became a line on top of each panel, and panels received
theme settings for background and header colors. The default theme used the same color for both.
In 2.8 the background color of panels was different from headers in the default theme, so the separator
line was removed. While the separator line wasn't elegant (only on top, non-themeable, hard-coded emboss effect),
it provided a sort of separation between panels.
This patch solves the panels-separation by simply adding a margin space around them (not visible in default theme yet).
Even though the margin reduces the width of the working area slightly, it makes room for the upcoming always-visible scrollbars.
Other adjustments:
* Use arrow icon instead of triangle to collapse/expand
* Use rounded corners to match the rest of the UI (editor corners, nodes, etc).
{F10953929, size=full}
Margin on panels makes use of the `style->panelouter` property that hasn't been
used in a while. Also slight tweaks to `boxspace` and `templatespace` style properties so they
are multiples of 2 and operations on them round better.
There is technically no need to update the themes for them to work, so no theme changes are included in this patch.
{F10953931, size=full}
{F10953933, size=full}
{F10953934, size=full}
{F10954003, size=full}
----
A new theme setting under Style controls the roundness of all panels (added it to Style instead of ThemeSpace because I think controlling the panel roundness per editor is a bit overkill):
{F11091561, size=full, autoplay, loop}
Reviewed By: HooglyBoogly
Differential Revision: https://developer.blender.org/D12814
2021-10-17 18:22:53 +02:00
|
|
|
panel_type->flag = PANEL_TYPE_HEADER_EXPAND | PANEL_TYPE_INSTANCED;
|
2021-02-19 10:11:35 -06:00
|
|
|
panel_type->reorder = fmodifier_reorder;
|
|
|
|
|
panel_type->get_list_data_expand_flag = get_fmodifier_expand_flag;
|
|
|
|
|
panel_type->set_list_data_expand_flag = set_fmodifier_expand_flag;
|
|
|
|
|
|
|
|
|
|
BLI_addtail(®ion_type->paneltypes, panel_type);
|
|
|
|
|
|
|
|
|
|
return panel_type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add a child panel to the parent.
|
|
|
|
|
*
|
|
|
|
|
* \note To create the panel type's idname, it appends the \a name argument to the \a parent's
|
|
|
|
|
* idname.
|
|
|
|
|
*/
|
|
|
|
|
static PanelType *fmodifier_subpanel_register(ARegionType *region_type,
|
|
|
|
|
const char *name,
|
|
|
|
|
const char *label,
|
|
|
|
|
PanelDrawFn draw_header,
|
|
|
|
|
PanelDrawFn draw,
|
|
|
|
|
PanelTypePollFn poll,
|
|
|
|
|
PanelType *parent)
|
|
|
|
|
{
|
2021-03-09 13:31:51 -05:00
|
|
|
PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__);
|
2021-02-19 10:11:35 -06:00
|
|
|
|
2021-03-09 13:31:51 -05:00
|
|
|
BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name);
|
2021-02-19 10:11:35 -06:00
|
|
|
BLI_strncpy(panel_type->label, label, BKE_ST_MAXNAME);
|
|
|
|
|
BLI_strncpy(panel_type->category, "Modifiers", BKE_ST_MAXNAME);
|
|
|
|
|
BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME);
|
|
|
|
|
|
|
|
|
|
panel_type->draw_header = draw_header;
|
|
|
|
|
panel_type->draw = draw;
|
|
|
|
|
panel_type->poll = poll;
|
UI: Visual style update to panels
Back in Blender 2.30, the GUI project brought panels into Blender among other important visual updates.
For the first time it was possible to move the wall of buttons around. Providing a clear separation
between sections (it even allowed the grouping of panels in tabs!)
During the 2.5 redesign, the separation between panels became a line on top of each panel, and panels received
theme settings for background and header colors. The default theme used the same color for both.
In 2.8 the background color of panels was different from headers in the default theme, so the separator
line was removed. While the separator line wasn't elegant (only on top, non-themeable, hard-coded emboss effect),
it provided a sort of separation between panels.
This patch solves the panels-separation by simply adding a margin space around them (not visible in default theme yet).
Even though the margin reduces the width of the working area slightly, it makes room for the upcoming always-visible scrollbars.
Other adjustments:
* Use arrow icon instead of triangle to collapse/expand
* Use rounded corners to match the rest of the UI (editor corners, nodes, etc).
{F10953929, size=full}
Margin on panels makes use of the `style->panelouter` property that hasn't been
used in a while. Also slight tweaks to `boxspace` and `templatespace` style properties so they
are multiples of 2 and operations on them round better.
There is technically no need to update the themes for them to work, so no theme changes are included in this patch.
{F10953931, size=full}
{F10953933, size=full}
{F10953934, size=full}
{F10954003, size=full}
----
A new theme setting under Style controls the roundness of all panels (added it to Style instead of ThemeSpace because I think controlling the panel roundness per editor is a bit overkill):
{F11091561, size=full, autoplay, loop}
Reviewed By: HooglyBoogly
Differential Revision: https://developer.blender.org/D12814
2021-10-17 18:22:53 +02:00
|
|
|
panel_type->flag = PANEL_TYPE_DEFAULT_CLOSED ;
|
2021-02-19 10:11:35 -06:00
|
|
|
|
|
|
|
|
BLI_assert(parent != NULL);
|
|
|
|
|
BLI_strncpy(panel_type->parent_id, parent->idname, BKE_ST_MAXNAME);
|
|
|
|
|
panel_type->parent = parent;
|
|
|
|
|
BLI_addtail(&parent->children, BLI_genericNodeN(panel_type));
|
|
|
|
|
BLI_addtail(®ion_type->paneltypes, panel_type);
|
|
|
|
|
|
|
|
|
|
return panel_type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name General UI Callbacks and Drawing
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
/* XXX! -------------------------------- */
|
|
|
|
|
/* Temporary definition for limits of float number buttons
|
|
|
|
|
* (FLT_MAX tends to infinity with old system). */
|
|
|
|
|
#define UI_FLT_MAX 10000.0f
|
|
|
|
|
|
|
|
|
|
#define B_REDR 1
|
|
|
|
|
#define B_FMODIFIER_REDRAW 20
|
|
|
|
|
|
2021-06-24 15:56:58 +10:00
|
|
|
/* Callback to remove the given modifier. */
|
2019-01-10 15:56:02 +01:00
|
|
|
typedef struct FModifierDeleteContext {
|
2021-02-19 10:11:35 -06:00
|
|
|
ID *owner_id;
|
2019-01-10 15:56:02 +01:00
|
|
|
ListBase *modifiers;
|
|
|
|
|
} FModifierDeleteContext;
|
2021-02-19 10:11:35 -06:00
|
|
|
|
2019-01-10 15:56:02 +01:00
|
|
|
static void delete_fmodifier_cb(bContext *C, void *ctx_v, void *fcm_v)
|
2009-07-02 04:47:36 +00:00
|
|
|
{
|
2019-01-10 15:56:02 +01:00
|
|
|
FModifierDeleteContext *ctx = (FModifierDeleteContext *)ctx_v;
|
|
|
|
|
ListBase *modifiers = ctx->modifiers;
|
2012-05-08 11:48:19 +00:00
|
|
|
FModifier *fcm = (FModifier *)fcm_v;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2009-07-02 05:25:14 +00:00
|
|
|
/* remove the given F-Modifier from the active modifier-stack */
|
|
|
|
|
remove_fmodifier(modifiers, fcm);
|
2011-04-06 01:13:01 +00:00
|
|
|
|
|
|
|
|
ED_undo_push(C, "Delete F-Curve Modifier");
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
|
|
|
|
|
DEG_id_tag_update(ctx->owner_id, ID_RECALC_ANIMATION);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void fmodifier_influence_draw(uiLayout *layout, PointerRNA *ptr)
|
|
|
|
|
{
|
|
|
|
|
FModifier *fcm = (FModifier *)ptr->data;
|
|
|
|
|
uiItemS(layout);
|
|
|
|
|
|
|
|
|
|
uiLayout *row = uiLayoutRowWithHeading(layout, true, IFACE_("Influence"));
|
|
|
|
|
uiItemR(row, ptr, "use_influence", 0, "", ICON_NONE);
|
|
|
|
|
uiLayout *sub = uiLayoutRow(row, true);
|
|
|
|
|
|
|
|
|
|
uiLayoutSetActive(sub, fcm->flag & FMODIFIER_FLAG_USEINFLUENCE);
|
|
|
|
|
uiItemR(sub, ptr, "influence", 0, "", ICON_NONE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void fmodifier_frame_range_header_draw(const bContext *C, Panel *panel)
|
|
|
|
|
{
|
|
|
|
|
uiLayout *layout = panel->layout;
|
|
|
|
|
|
|
|
|
|
PointerRNA *ptr = fmodifier_get_pointers(C, panel, NULL);
|
|
|
|
|
|
|
|
|
|
uiItemR(layout, ptr, "use_restricted_range", 0, NULL, ICON_NONE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void fmodifier_frame_range_draw(const bContext *C, Panel *panel)
|
|
|
|
|
{
|
|
|
|
|
uiLayout *col;
|
|
|
|
|
uiLayout *layout = panel->layout;
|
|
|
|
|
|
|
|
|
|
PointerRNA *ptr = fmodifier_get_pointers(C, panel, NULL);
|
|
|
|
|
|
|
|
|
|
uiLayoutSetPropSep(layout, true);
|
2021-03-03 16:32:55 -06:00
|
|
|
uiLayoutSetPropDecorate(layout, false);
|
2021-02-19 10:11:35 -06:00
|
|
|
|
|
|
|
|
FModifier *fcm = (FModifier *)ptr->data;
|
|
|
|
|
uiLayoutSetActive(layout, fcm->flag & FMODIFIER_FLAG_RANGERESTRICT);
|
|
|
|
|
|
|
|
|
|
col = uiLayoutColumn(layout, true);
|
|
|
|
|
uiItemR(col, ptr, "frame_start", 0, IFACE_("Start"), ICON_NONE);
|
|
|
|
|
uiItemR(col, ptr, "frame_end", 0, IFACE_("End"), ICON_NONE);
|
|
|
|
|
|
|
|
|
|
col = uiLayoutColumn(layout, true);
|
|
|
|
|
uiItemR(col, ptr, "blend_in", 0, IFACE_("Blend In"), ICON_NONE);
|
|
|
|
|
uiItemR(col, ptr, "blend_out", 0, IFACE_("Out"), ICON_NONE);
|
2009-07-02 04:47:36 +00:00
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
static void fmodifier_panel_header(const bContext *C, Panel *panel)
|
2009-07-02 04:47:36 +00:00
|
|
|
{
|
2021-02-19 10:11:35 -06:00
|
|
|
uiLayout *layout = panel->layout;
|
|
|
|
|
|
|
|
|
|
ID *owner_id;
|
|
|
|
|
PointerRNA *ptr = fmodifier_get_pointers(C, panel, &owner_id);
|
|
|
|
|
FModifier *fcm = (FModifier *)ptr->data;
|
|
|
|
|
const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm);
|
|
|
|
|
|
|
|
|
|
uiBlock *block = uiLayoutGetBlock(layout);
|
|
|
|
|
|
|
|
|
|
uiLayout *sub = uiLayoutRow(layout, true);
|
|
|
|
|
uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_LEFT);
|
|
|
|
|
uiLayoutSetEmboss(sub, UI_EMBOSS_NONE);
|
|
|
|
|
|
|
|
|
|
/* Checkbox for 'active' status (for now). */
|
|
|
|
|
uiItemR(sub, ptr, "active", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
|
|
|
|
|
|
|
|
|
|
/* Name. */
|
|
|
|
|
if (fmi) {
|
|
|
|
|
uiItemL(sub, IFACE_(fmi->name), ICON_NONE);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
uiItemL(sub, IFACE_("<Unknown Modifier>"), ICON_NONE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Right align. */
|
|
|
|
|
sub = uiLayoutRow(layout, true);
|
|
|
|
|
uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT);
|
|
|
|
|
uiLayoutSetEmboss(sub, UI_EMBOSS_NONE);
|
|
|
|
|
|
|
|
|
|
/* 'Mute' button. */
|
|
|
|
|
uiItemR(sub, ptr, "mute", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
|
|
|
|
|
|
|
|
|
|
/* Delete button. */
|
|
|
|
|
uiBut *but = uiDefIconBut(block,
|
|
|
|
|
UI_BTYPE_BUT,
|
|
|
|
|
B_REDR,
|
|
|
|
|
ICON_X,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
UI_UNIT_X,
|
|
|
|
|
UI_UNIT_Y,
|
|
|
|
|
NULL,
|
|
|
|
|
0.0,
|
|
|
|
|
0.0,
|
|
|
|
|
0.0,
|
|
|
|
|
0.0,
|
|
|
|
|
TIP_("Delete Modifier"));
|
|
|
|
|
FModifierDeleteContext *ctx = MEM_mallocN(sizeof(FModifierDeleteContext), __func__);
|
|
|
|
|
ctx->owner_id = owner_id;
|
|
|
|
|
ctx->modifiers = fmodifier_list_space_specific(C);
|
|
|
|
|
BLI_assert(ctx->modifiers != NULL);
|
|
|
|
|
|
|
|
|
|
UI_but_funcN_set(but, delete_fmodifier_cb, ctx, fcm);
|
|
|
|
|
|
|
|
|
|
uiItemS(layout);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Generator Modifier
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
static void generator_panel_draw(const bContext *C, Panel *panel)
|
|
|
|
|
{
|
|
|
|
|
uiLayout *layout = panel->layout;
|
|
|
|
|
|
|
|
|
|
ID *owner_id;
|
|
|
|
|
PointerRNA *ptr = fmodifier_get_pointers(C, panel, &owner_id);
|
|
|
|
|
FModifier *fcm = (FModifier *)ptr->data;
|
2012-05-08 11:48:19 +00:00
|
|
|
FMod_Generator *data = (FMod_Generator *)fcm->data;
|
2021-02-19 10:11:35 -06:00
|
|
|
|
|
|
|
|
uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
|
|
|
|
|
|
|
|
|
|
uiLayoutSetPropSep(layout, true);
|
|
|
|
|
uiLayoutSetPropDecorate(layout, false);
|
|
|
|
|
|
|
|
|
|
uiItemR(layout, ptr, "use_additive", 0, NULL, ICON_NONE);
|
|
|
|
|
|
|
|
|
|
uiItemR(layout, ptr, "poly_order", 0, IFACE_("Order"), ICON_NONE);
|
|
|
|
|
|
|
|
|
|
PropertyRNA *prop = RNA_struct_find_property(ptr, "coefficients");
|
|
|
|
|
uiLayout *col = uiLayoutColumn(layout, true);
|
2009-07-02 04:47:36 +00:00
|
|
|
switch (data->mode) {
|
2021-02-19 10:11:35 -06:00
|
|
|
case FCM_GENERATOR_POLYNOMIAL: /* Polynomial expression. */
|
2009-07-02 04:47:36 +00:00
|
|
|
{
|
2021-02-19 10:11:35 -06:00
|
|
|
|
2009-07-02 04:47:36 +00:00
|
|
|
char xval[32];
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
/* The first value gets a "Coefficient" label. */
|
|
|
|
|
BLI_strncpy(xval, "Coefficient", sizeof(xval));
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < data->arraysize; i++) {
|
|
|
|
|
uiItemFullR(col, ptr, prop, i, 0, 0, N_(xval), ICON_NONE);
|
|
|
|
|
BLI_snprintf(xval, sizeof(xval), "x^%d", i + 1);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
break;
|
2009-07-02 04:47:36 +00:00
|
|
|
}
|
|
|
|
|
case FCM_GENERATOR_POLYNOMIAL_FACTORISED: /* Factorized polynomial expression */
|
2019-04-17 06:17:24 +02:00
|
|
|
{
|
2021-02-19 10:11:35 -06:00
|
|
|
{
|
|
|
|
|
/* Add column labels above the buttons to prevent confusion.
|
|
|
|
|
* Fake the property split layout, otherwise the labels use the full row. */
|
|
|
|
|
uiLayout *split = uiLayoutSplit(col, 0.4f, false);
|
|
|
|
|
uiLayoutColumn(split, false);
|
|
|
|
|
uiLayout *title_col = uiLayoutColumn(split, false);
|
|
|
|
|
uiLayout *title_row = uiLayoutRow(title_col, true);
|
|
|
|
|
uiItemL(title_row, N_("A"), ICON_NONE);
|
|
|
|
|
uiItemL(title_row, N_("B"), ICON_NONE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uiLayout *first_row = uiLayoutRow(col, true);
|
|
|
|
|
uiItemFullR(first_row, ptr, prop, 0, 0, 0, N_("y = (Ax + B)"), ICON_NONE);
|
|
|
|
|
uiItemFullR(first_row, ptr, prop, 1, 0, 0, "", ICON_NONE);
|
|
|
|
|
for (int i = 2; i < data->arraysize - 1; i++) {
|
|
|
|
|
/* \u2715 is the multiplication symbol. */
|
|
|
|
|
uiLayout *row = uiLayoutRow(col, true);
|
|
|
|
|
uiItemFullR(row, ptr, prop, i, 0, 0, N_("\u2715 (Ax + B)"), ICON_NONE);
|
|
|
|
|
uiItemFullR(row, ptr, prop, i + 1, 0, 0, "", ICON_NONE);
|
2009-07-02 04:47:36 +00:00
|
|
|
}
|
2013-07-19 15:23:42 +00:00
|
|
|
break;
|
2009-07-02 04:47:36 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2021-02-19 10:11:35 -06:00
|
|
|
|
|
|
|
|
fmodifier_influence_draw(layout, ptr);
|
2009-07-02 04:47:36 +00:00
|
|
|
}
|
|
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
static void panel_register_generator(ARegionType *region_type,
|
|
|
|
|
const char *id_prefix,
|
|
|
|
|
PanelTypePollFn poll_fn)
|
|
|
|
|
{
|
|
|
|
|
PanelType *panel_type = fmodifier_panel_register(
|
|
|
|
|
region_type, FMODIFIER_TYPE_GENERATOR, generator_panel_draw, poll_fn, id_prefix);
|
|
|
|
|
fmodifier_subpanel_register(region_type,
|
|
|
|
|
"frame_range",
|
|
|
|
|
"",
|
|
|
|
|
fmodifier_frame_range_header_draw,
|
|
|
|
|
fmodifier_frame_range_draw,
|
|
|
|
|
poll_fn,
|
|
|
|
|
panel_type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
2009-07-02 04:47:36 +00:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Function Generator Modifier
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
static void fn_generator_panel_draw(const bContext *C, Panel *panel)
|
2009-07-02 04:47:36 +00:00
|
|
|
{
|
2009-07-03 01:10:46 +00:00
|
|
|
uiLayout *col;
|
2021-02-19 10:11:35 -06:00
|
|
|
uiLayout *layout = panel->layout;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
PointerRNA *ptr = fmodifier_get_pointers(C, panel, NULL);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
uiItemR(layout, ptr, "function_type", 0, "", ICON_NONE);
|
|
|
|
|
|
|
|
|
|
uiLayoutSetPropSep(layout, true);
|
2021-03-03 16:32:55 -06:00
|
|
|
uiLayoutSetPropDecorate(layout, false);
|
2021-02-19 10:11:35 -06:00
|
|
|
|
|
|
|
|
col = uiLayoutColumn(layout, false);
|
|
|
|
|
uiItemR(col, ptr, "use_additive", 0, NULL, ICON_NONE);
|
|
|
|
|
|
|
|
|
|
col = uiLayoutColumn(layout, false);
|
|
|
|
|
uiItemR(col, ptr, "amplitude", 0, NULL, ICON_NONE);
|
|
|
|
|
uiItemR(col, ptr, "phase_multiplier", 0, NULL, ICON_NONE);
|
|
|
|
|
uiItemR(col, ptr, "phase_offset", 0, NULL, ICON_NONE);
|
|
|
|
|
uiItemR(col, ptr, "value_offset", 0, NULL, ICON_NONE);
|
|
|
|
|
|
|
|
|
|
fmodifier_influence_draw(layout, ptr);
|
2009-07-02 04:47:36 +00:00
|
|
|
}
|
|
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
static void panel_register_fn_generator(ARegionType *region_type,
|
|
|
|
|
const char *id_prefix,
|
|
|
|
|
PanelTypePollFn poll_fn)
|
|
|
|
|
{
|
|
|
|
|
PanelType *panel_type = fmodifier_panel_register(
|
|
|
|
|
region_type, FMODIFIER_TYPE_FN_GENERATOR, fn_generator_panel_draw, poll_fn, id_prefix);
|
|
|
|
|
fmodifier_subpanel_register(region_type,
|
|
|
|
|
"frame_range",
|
|
|
|
|
"",
|
|
|
|
|
fmodifier_frame_range_header_draw,
|
|
|
|
|
fmodifier_frame_range_draw,
|
|
|
|
|
poll_fn,
|
|
|
|
|
panel_type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Cycles Modifier
|
|
|
|
|
* \{ */
|
2009-07-02 04:47:36 +00:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
static void cycles_panel_draw(const bContext *C, Panel *panel)
|
2009-07-02 04:47:36 +00:00
|
|
|
{
|
2021-02-19 10:11:35 -06:00
|
|
|
uiLayout *col;
|
|
|
|
|
uiLayout *layout = panel->layout;
|
|
|
|
|
|
|
|
|
|
PointerRNA *ptr = fmodifier_get_pointers(C, panel, NULL);
|
|
|
|
|
|
|
|
|
|
uiLayoutSetPropSep(layout, true);
|
|
|
|
|
uiLayoutSetPropDecorate(layout, false);
|
|
|
|
|
|
|
|
|
|
/* Before. */
|
|
|
|
|
col = uiLayoutColumn(layout, false);
|
|
|
|
|
uiItemR(col, ptr, "mode_before", 0, NULL, ICON_NONE);
|
|
|
|
|
uiItemR(col, ptr, "cycles_before", 0, IFACE_("Count"), ICON_NONE);
|
|
|
|
|
|
|
|
|
|
/* After. */
|
|
|
|
|
col = uiLayoutColumn(layout, false);
|
|
|
|
|
uiItemR(col, ptr, "mode_after", 0, NULL, ICON_NONE);
|
|
|
|
|
uiItemR(col, ptr, "cycles_after", 0, IFACE_("Count"), ICON_NONE);
|
|
|
|
|
|
|
|
|
|
fmodifier_influence_draw(layout, ptr);
|
2009-07-02 04:47:36 +00:00
|
|
|
}
|
|
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
static void panel_register_cycles(ARegionType *region_type,
|
|
|
|
|
const char *id_prefix,
|
|
|
|
|
PanelTypePollFn poll_fn)
|
|
|
|
|
{
|
|
|
|
|
PanelType *panel_type = fmodifier_panel_register(
|
|
|
|
|
region_type, FMODIFIER_TYPE_CYCLES, cycles_panel_draw, poll_fn, id_prefix);
|
|
|
|
|
fmodifier_subpanel_register(region_type,
|
|
|
|
|
"frame_range",
|
|
|
|
|
"",
|
|
|
|
|
fmodifier_frame_range_header_draw,
|
|
|
|
|
fmodifier_frame_range_draw,
|
|
|
|
|
poll_fn,
|
|
|
|
|
panel_type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
2009-07-02 04:47:36 +00:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Noise Modifier
|
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
|
|
static void noise_panel_draw(const bContext *C, Panel *panel)
|
2009-07-02 04:47:36 +00:00
|
|
|
{
|
2021-02-19 10:11:35 -06:00
|
|
|
uiLayout *col;
|
|
|
|
|
uiLayout *layout = panel->layout;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
PointerRNA *ptr = fmodifier_get_pointers(C, panel, NULL);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
uiLayoutSetPropSep(layout, true);
|
|
|
|
|
uiLayoutSetPropDecorate(layout, false);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
uiItemR(layout, ptr, "blend_type", 0, NULL, ICON_NONE);
|
|
|
|
|
|
|
|
|
|
col = uiLayoutColumn(layout, false);
|
|
|
|
|
uiItemR(col, ptr, "scale", 0, NULL, ICON_NONE);
|
|
|
|
|
uiItemR(col, ptr, "strength", 0, NULL, ICON_NONE);
|
|
|
|
|
uiItemR(col, ptr, "offset", 0, NULL, ICON_NONE);
|
|
|
|
|
uiItemR(col, ptr, "phase", 0, NULL, ICON_NONE);
|
|
|
|
|
uiItemR(col, ptr, "depth", 0, NULL, ICON_NONE);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
fmodifier_influence_draw(layout, ptr);
|
|
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
static void panel_register_noise(ARegionType *region_type,
|
|
|
|
|
const char *id_prefix,
|
|
|
|
|
PanelTypePollFn poll_fn)
|
|
|
|
|
{
|
|
|
|
|
PanelType *panel_type = fmodifier_panel_register(
|
|
|
|
|
region_type, FMODIFIER_TYPE_NOISE, noise_panel_draw, poll_fn, id_prefix);
|
|
|
|
|
fmodifier_subpanel_register(region_type,
|
|
|
|
|
"frame_range",
|
|
|
|
|
"",
|
|
|
|
|
fmodifier_frame_range_header_draw,
|
|
|
|
|
fmodifier_frame_range_draw,
|
|
|
|
|
poll_fn,
|
|
|
|
|
panel_type);
|
2009-07-02 04:47:36 +00:00
|
|
|
}
|
|
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
2021-02-20 15:38:14 +11:00
|
|
|
/** \name Envelope Modifier
|
2021-02-19 10:11:35 -06:00
|
|
|
* \{ */
|
|
|
|
|
|
2012-05-08 11:48:19 +00:00
|
|
|
static void fmod_envelope_addpoint_cb(bContext *C, void *fcm_dv, void *UNUSED(arg))
|
2009-07-02 04:47:36 +00:00
|
|
|
{
|
2012-05-08 11:48:19 +00:00
|
|
|
Scene *scene = CTX_data_scene(C);
|
|
|
|
|
FMod_Envelope *env = (FMod_Envelope *)fcm_dv;
|
2009-07-02 04:47:36 +00:00
|
|
|
FCM_EnvelopeData *fedn;
|
|
|
|
|
FCM_EnvelopeData fed;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-07-02 04:47:36 +00:00
|
|
|
/* init template data */
|
2012-05-08 11:48:19 +00:00
|
|
|
fed.min = -1.0f;
|
|
|
|
|
fed.max = 1.0f;
|
|
|
|
|
fed.time = (float)scene->r.cfra; /* XXX make this int for ease of use? */
|
|
|
|
|
fed.f1 = fed.f2 = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-07-02 04:47:36 +00:00
|
|
|
/* check that no data exists for the current frame... */
|
|
|
|
|
if (env->data) {
|
2013-03-17 19:13:04 +00:00
|
|
|
bool exists;
|
2013-01-31 08:19:11 +00:00
|
|
|
int i = BKE_fcm_envelope_find_index(env->data, (float)(scene->r.cfra), env->totvert, &exists);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-01-15 23:24:20 +11:00
|
|
|
/* binarysearch_...() will set exists by default to 0,
|
|
|
|
|
* so if it is non-zero, that means that the point exists already */
|
|
|
|
|
if (exists) {
|
2009-07-02 04:47:36 +00:00
|
|
|
return;
|
2019-01-15 23:24:20 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-07-02 04:47:36 +00:00
|
|
|
/* add new */
|
2012-05-08 11:48:19 +00:00
|
|
|
fedn = MEM_callocN((env->totvert + 1) * sizeof(FCM_EnvelopeData), "FCM_EnvelopeData");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-07-02 04:47:36 +00:00
|
|
|
/* add the points that should occur before the point to be pasted */
|
2019-04-22 09:19:45 +10:00
|
|
|
if (i > 0) {
|
2012-05-08 11:48:19 +00:00
|
|
|
memcpy(fedn, env->data, i * sizeof(FCM_EnvelopeData));
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-07-02 04:47:36 +00:00
|
|
|
/* add point to paste at index i */
|
2012-05-08 11:48:19 +00:00
|
|
|
*(fedn + i) = fed;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-07-02 04:47:36 +00:00
|
|
|
/* add the points that occur after the point to be pasted */
|
2019-04-22 09:19:45 +10:00
|
|
|
if (i < env->totvert) {
|
2012-05-08 11:48:19 +00:00
|
|
|
memcpy(fedn + i + 1, env->data + i, (env->totvert - i) * sizeof(FCM_EnvelopeData));
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-07-02 04:47:36 +00:00
|
|
|
/* replace (+ free) old with new */
|
|
|
|
|
MEM_freeN(env->data);
|
2012-05-08 11:48:19 +00:00
|
|
|
env->data = fedn;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-07-02 04:47:36 +00:00
|
|
|
env->totvert++;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2012-05-08 11:48:19 +00:00
|
|
|
env->data = MEM_callocN(sizeof(FCM_EnvelopeData), "FCM_EnvelopeData");
|
|
|
|
|
*(env->data) = fed;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-08 11:48:19 +00:00
|
|
|
env->totvert = 1;
|
2009-07-02 04:47:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* callback to remove envelope data point */
|
|
|
|
|
/* TODO: should we have a separate file for things like this? */
|
2012-05-08 11:48:19 +00:00
|
|
|
static void fmod_envelope_deletepoint_cb(bContext *UNUSED(C), void *fcm_dv, void *ind_v)
|
2009-07-02 04:47:36 +00:00
|
|
|
{
|
2012-05-08 11:48:19 +00:00
|
|
|
FMod_Envelope *env = (FMod_Envelope *)fcm_dv;
|
2009-07-02 04:47:36 +00:00
|
|
|
FCM_EnvelopeData *fedn;
|
2018-09-19 12:05:58 +10:00
|
|
|
int index = POINTER_AS_INT(ind_v);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-07-02 04:47:36 +00:00
|
|
|
/* check that no data exists for the current frame... */
|
|
|
|
|
if (env->totvert > 1) {
|
|
|
|
|
/* allocate a new smaller array */
|
2012-05-08 11:48:19 +00:00
|
|
|
fedn = MEM_callocN(sizeof(FCM_EnvelopeData) * (env->totvert - 1), "FCM_EnvelopeData");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-08 11:48:19 +00:00
|
|
|
memcpy(fedn, env->data, sizeof(FCM_EnvelopeData) * (index));
|
|
|
|
|
memcpy(fedn + index,
|
|
|
|
|
env->data + (index + 1),
|
|
|
|
|
sizeof(FCM_EnvelopeData) * ((env->totvert - index) - 1));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2009-07-02 04:47:36 +00:00
|
|
|
/* free old array, and set the new */
|
|
|
|
|
MEM_freeN(env->data);
|
2012-05-08 11:48:19 +00:00
|
|
|
env->data = fedn;
|
2009-07-02 04:47:36 +00:00
|
|
|
env->totvert--;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* just free array, since the only vert was deleted */
|
2021-08-06 13:59:38 +10:00
|
|
|
MEM_SAFE_FREE(env->data);
|
2012-05-08 11:48:19 +00:00
|
|
|
env->totvert = 0;
|
2009-07-02 04:47:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* draw settings for envelope modifier */
|
2021-02-19 10:11:35 -06:00
|
|
|
static void envelope_panel_draw(const bContext *C, Panel *panel)
|
2009-07-02 04:47:36 +00:00
|
|
|
{
|
2021-02-19 10:11:35 -06:00
|
|
|
uiLayout *row, *col;
|
|
|
|
|
uiLayout *layout = panel->layout;
|
|
|
|
|
|
|
|
|
|
ID *owner_id;
|
|
|
|
|
PointerRNA *ptr = fmodifier_get_pointers(C, panel, &owner_id);
|
|
|
|
|
FModifier *fcm = (FModifier *)ptr->data;
|
2012-05-08 11:48:19 +00:00
|
|
|
FMod_Envelope *env = (FMod_Envelope *)fcm->data;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
uiLayoutSetPropSep(layout, true);
|
2021-03-03 16:32:55 -06:00
|
|
|
uiLayoutSetPropDecorate(layout, false);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
/* General settings. */
|
2014-04-01 11:34:00 +11:00
|
|
|
col = uiLayoutColumn(layout, true);
|
2021-02-19 10:11:35 -06:00
|
|
|
uiItemR(col, ptr, "reference_value", 0, IFACE_("Reference"), ICON_NONE);
|
|
|
|
|
uiItemR(col, ptr, "default_min", 0, IFACE_("Min"), ICON_NONE);
|
|
|
|
|
uiItemR(col, ptr, "default_max", 0, IFACE_("Max"), ICON_NONE);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
/* Control points list. */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-05-08 11:48:19 +00:00
|
|
|
row = uiLayoutRow(layout, false);
|
2021-02-19 10:11:35 -06:00
|
|
|
uiBlock *block = uiLayoutGetBlock(row);
|
|
|
|
|
|
|
|
|
|
uiBut *but = uiDefBut(block,
|
|
|
|
|
UI_BTYPE_BUT,
|
|
|
|
|
B_FMODIFIER_REDRAW,
|
|
|
|
|
IFACE_("Add Control Point"),
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
7.5 * UI_UNIT_X,
|
|
|
|
|
UI_UNIT_Y,
|
|
|
|
|
NULL,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
TIP_("Add a new control-point to the envelope on the current frame"));
|
2014-11-09 21:20:40 +01:00
|
|
|
UI_but_func_set(but, fmod_envelope_addpoint_cb, env, NULL);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
col = uiLayoutColumn(layout, false);
|
|
|
|
|
uiLayoutSetPropSep(col, false);
|
|
|
|
|
|
|
|
|
|
FCM_EnvelopeData *fed = env->data;
|
|
|
|
|
for (int i = 0; i < env->totvert; i++, fed++) {
|
2020-05-14 13:59:19 +02:00
|
|
|
PointerRNA ctrl_ptr;
|
2021-02-19 10:11:35 -06:00
|
|
|
RNA_pointer_create(owner_id, &RNA_FModifierEnvelopeControlPoint, fed, &ctrl_ptr);
|
2020-05-14 13:59:19 +02:00
|
|
|
|
2009-07-02 23:27:11 +00:00
|
|
|
/* get a new row to operate on */
|
2021-02-19 10:11:35 -06:00
|
|
|
row = uiLayoutRow(col, true);
|
2012-05-08 11:48:19 +00:00
|
|
|
block = uiLayoutGetBlock(row);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
uiItemR(row, &ctrl_ptr, "frame", 0, NULL, ICON_NONE);
|
|
|
|
|
uiItemR(row, &ctrl_ptr, "min", 0, IFACE_("Min"), ICON_NONE);
|
|
|
|
|
uiItemR(row, &ctrl_ptr, "max", 0, IFACE_("Max"), ICON_NONE);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-11-09 21:20:40 +01:00
|
|
|
but = uiDefIconBut(block,
|
|
|
|
|
UI_BTYPE_BUT,
|
|
|
|
|
B_FMODIFIER_REDRAW,
|
|
|
|
|
ICON_X,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0.9 * UI_UNIT_X,
|
|
|
|
|
UI_UNIT_Y,
|
2012-05-08 11:48:19 +00:00
|
|
|
NULL,
|
|
|
|
|
0.0,
|
|
|
|
|
0.0,
|
|
|
|
|
0.0,
|
|
|
|
|
0.0,
|
|
|
|
|
TIP_("Delete envelope control point"));
|
2018-09-19 12:05:58 +10:00
|
|
|
UI_but_func_set(but, fmod_envelope_deletepoint_cb, env, POINTER_FROM_INT(i));
|
2014-11-09 21:20:40 +01:00
|
|
|
UI_block_align_begin(block);
|
2009-07-02 04:47:36 +00:00
|
|
|
}
|
|
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
fmodifier_influence_draw(layout, ptr);
|
|
|
|
|
}
|
2009-07-02 04:47:36 +00:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
static void panel_register_envelope(ARegionType *region_type,
|
|
|
|
|
const char *id_prefix,
|
|
|
|
|
PanelTypePollFn poll_fn)
|
2009-07-02 04:47:36 +00:00
|
|
|
{
|
2021-02-19 10:11:35 -06:00
|
|
|
PanelType *panel_type = fmodifier_panel_register(
|
|
|
|
|
region_type, FMODIFIER_TYPE_ENVELOPE, envelope_panel_draw, poll_fn, id_prefix);
|
|
|
|
|
fmodifier_subpanel_register(region_type,
|
|
|
|
|
"frame_range",
|
|
|
|
|
"",
|
|
|
|
|
fmodifier_frame_range_header_draw,
|
|
|
|
|
fmodifier_frame_range_draw,
|
|
|
|
|
poll_fn,
|
|
|
|
|
panel_type);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
/** \} */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Limits Modifier
|
|
|
|
|
* \{ */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
static void limits_panel_draw(const bContext *C, Panel *panel)
|
|
|
|
|
{
|
|
|
|
|
uiLayout *col, *row, *sub;
|
|
|
|
|
uiLayout *layout = panel->layout;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
PointerRNA *ptr = fmodifier_get_pointers(C, panel, NULL);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
uiLayoutSetPropSep(layout, true);
|
2021-03-03 16:32:55 -06:00
|
|
|
uiLayoutSetPropDecorate(layout, false);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
/* Minimums. */
|
|
|
|
|
col = uiLayoutColumn(layout, false);
|
2021-02-22 15:48:54 +01:00
|
|
|
row = uiLayoutRowWithHeading(col, true, IFACE_("Minimum X"));
|
2021-02-19 10:11:35 -06:00
|
|
|
uiItemR(row, ptr, "use_min_x", 0, "", ICON_NONE);
|
|
|
|
|
sub = uiLayoutColumn(row, true);
|
|
|
|
|
uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min_x"));
|
|
|
|
|
uiItemR(sub, ptr, "min_x", 0, "", ICON_NONE);
|
|
|
|
|
|
|
|
|
|
row = uiLayoutRowWithHeading(col, true, IFACE_("Y"));
|
|
|
|
|
uiItemR(row, ptr, "use_min_y", 0, "", ICON_NONE);
|
|
|
|
|
sub = uiLayoutColumn(row, true);
|
|
|
|
|
uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min_y"));
|
|
|
|
|
uiItemR(sub, ptr, "min_y", 0, "", ICON_NONE);
|
|
|
|
|
|
|
|
|
|
/* Maximums. */
|
|
|
|
|
col = uiLayoutColumn(layout, false);
|
|
|
|
|
row = uiLayoutRowWithHeading(col, true, IFACE_("Maximum X"));
|
|
|
|
|
uiItemR(row, ptr, "use_max_x", 0, "", ICON_NONE);
|
|
|
|
|
sub = uiLayoutColumn(row, true);
|
|
|
|
|
uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max_x"));
|
|
|
|
|
uiItemR(sub, ptr, "max_x", 0, "", ICON_NONE);
|
|
|
|
|
|
|
|
|
|
row = uiLayoutRowWithHeading(col, true, IFACE_("Y"));
|
|
|
|
|
uiItemR(row, ptr, "use_max_y", 0, "", ICON_NONE);
|
|
|
|
|
sub = uiLayoutColumn(row, true);
|
|
|
|
|
uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max_y"));
|
|
|
|
|
uiItemR(sub, ptr, "max_y", 0, "", ICON_NONE);
|
|
|
|
|
|
|
|
|
|
fmodifier_influence_draw(layout, ptr);
|
2009-07-02 04:47:36 +00:00
|
|
|
}
|
|
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
static void panel_register_limits(ARegionType *region_type,
|
|
|
|
|
const char *id_prefix,
|
|
|
|
|
PanelTypePollFn poll_fn)
|
2010-03-18 13:04:46 +00:00
|
|
|
{
|
2021-02-19 10:11:35 -06:00
|
|
|
PanelType *panel_type = fmodifier_panel_register(
|
|
|
|
|
region_type, FMODIFIER_TYPE_LIMITS, limits_panel_draw, poll_fn, id_prefix);
|
|
|
|
|
fmodifier_subpanel_register(region_type,
|
|
|
|
|
"frame_range",
|
|
|
|
|
"",
|
|
|
|
|
fmodifier_frame_range_header_draw,
|
|
|
|
|
fmodifier_frame_range_draw,
|
|
|
|
|
poll_fn,
|
|
|
|
|
panel_type);
|
|
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
/** \} */
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Stepped Interpolation Modifier
|
|
|
|
|
* \{ */
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
static void stepped_panel_draw(const bContext *C, Panel *panel)
|
|
|
|
|
{
|
|
|
|
|
uiLayout *col, *sub, *row;
|
|
|
|
|
uiLayout *layout = panel->layout;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
PointerRNA *ptr = fmodifier_get_pointers(C, panel, NULL);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
uiLayoutSetPropSep(layout, true);
|
2021-03-03 16:32:55 -06:00
|
|
|
uiLayoutSetPropDecorate(layout, false);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
/* Stepping Settings. */
|
|
|
|
|
col = uiLayoutColumn(layout, false);
|
|
|
|
|
uiItemR(col, ptr, "frame_step", 0, NULL, ICON_NONE);
|
|
|
|
|
uiItemR(col, ptr, "frame_offset", 0, NULL, ICON_NONE);
|
|
|
|
|
|
|
|
|
|
/* Start range settings. */
|
|
|
|
|
row = uiLayoutRowWithHeading(layout, true, IFACE_("Start Frame"));
|
|
|
|
|
uiItemR(row, ptr, "use_frame_start", 0, "", ICON_NONE);
|
|
|
|
|
sub = uiLayoutColumn(row, true);
|
|
|
|
|
uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_frame_start"));
|
|
|
|
|
uiItemR(sub, ptr, "frame_start", 0, "", ICON_NONE);
|
|
|
|
|
|
|
|
|
|
/* End range settings. */
|
|
|
|
|
row = uiLayoutRowWithHeading(layout, true, IFACE_("End Frame"));
|
|
|
|
|
uiItemR(row, ptr, "use_frame_end", 0, "", ICON_NONE);
|
|
|
|
|
sub = uiLayoutColumn(row, true);
|
|
|
|
|
uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_frame_end"));
|
|
|
|
|
uiItemR(sub, ptr, "frame_end", 0, "", ICON_NONE);
|
|
|
|
|
|
|
|
|
|
fmodifier_influence_draw(layout, ptr);
|
2010-03-18 13:04:46 +00:00
|
|
|
}
|
|
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
static void panel_register_stepped(ARegionType *region_type,
|
|
|
|
|
const char *id_prefix,
|
|
|
|
|
PanelTypePollFn poll_fn)
|
2009-07-02 04:47:36 +00:00
|
|
|
{
|
2021-02-19 10:11:35 -06:00
|
|
|
PanelType *panel_type = fmodifier_panel_register(
|
|
|
|
|
region_type, FMODIFIER_TYPE_STEPPED, stepped_panel_draw, poll_fn, id_prefix);
|
|
|
|
|
fmodifier_subpanel_register(region_type,
|
|
|
|
|
"frame_range",
|
|
|
|
|
"",
|
|
|
|
|
fmodifier_frame_range_header_draw,
|
|
|
|
|
fmodifier_frame_range_draw,
|
|
|
|
|
poll_fn,
|
|
|
|
|
panel_type);
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
/** \} */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Panel Creation
|
|
|
|
|
* \{ */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
/**
|
2021-02-20 15:38:14 +11:00
|
|
|
* Checks if the panels match the active strip / curve, rebuilds them if they don't.
|
2021-02-19 10:11:35 -06:00
|
|
|
*/
|
|
|
|
|
void ANIM_fmodifier_panels(const bContext *C,
|
|
|
|
|
ID *owner_id,
|
|
|
|
|
ListBase *fmodifiers,
|
|
|
|
|
uiListPanelIDFromDataFunc panel_id_fn)
|
|
|
|
|
{
|
|
|
|
|
ARegion *region = CTX_wm_region(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
bool panels_match = UI_panel_list_matches_data(region, fmodifiers, panel_id_fn);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
if (!panels_match) {
|
|
|
|
|
UI_panels_free_instanced(C, region);
|
|
|
|
|
FModifier *fcm = fmodifiers->first;
|
|
|
|
|
for (int i = 0; fcm; i++, fcm = fcm->next) {
|
|
|
|
|
char panel_idname[MAX_NAME];
|
|
|
|
|
panel_id_fn(fcm, panel_idname);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
PointerRNA *fcm_ptr = MEM_mallocN(sizeof(PointerRNA), "panel customdata");
|
|
|
|
|
RNA_pointer_create(owner_id, &RNA_FModifier, fcm, fcm_ptr);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
UI_panel_add_instanced(C, region, ®ion->panels, panel_idname, fcm_ptr);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2009-07-02 04:47:36 +00:00
|
|
|
}
|
2021-02-19 10:11:35 -06:00
|
|
|
else {
|
|
|
|
|
/* Assuming there's only one group of instanced panels, update the custom data pointers. */
|
|
|
|
|
Panel *panel = region->panels.first;
|
|
|
|
|
LISTBASE_FOREACH (FModifier *, fcm, fmodifiers) {
|
|
|
|
|
|
|
|
|
|
/* Move to the next instanced panel corresponding to the next modifier. */
|
|
|
|
|
while ((panel->type == NULL) || !(panel->type->flag & PANEL_TYPE_INSTANCED)) {
|
|
|
|
|
panel = panel->next;
|
|
|
|
|
BLI_assert(panel != NULL); /* There shouldn't be fewer panels than modifiers with UIs. */
|
2011-06-04 06:22:01 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
PointerRNA *fcm_ptr = MEM_mallocN(sizeof(PointerRNA), "panel customdata");
|
|
|
|
|
RNA_pointer_create(owner_id, &RNA_FModifier, fcm, fcm_ptr);
|
|
|
|
|
UI_panel_custom_data_set(panel, fcm_ptr);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
panel = panel->next;
|
2011-06-03 13:34:02 +00:00
|
|
|
}
|
2009-07-02 04:47:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-19 10:11:35 -06:00
|
|
|
void ANIM_modifier_panels_register_graph_and_NLA(ARegionType *region_type,
|
|
|
|
|
const char *modifier_panel_prefix,
|
|
|
|
|
PanelTypePollFn poll_function)
|
|
|
|
|
{
|
|
|
|
|
panel_register_generator(region_type, modifier_panel_prefix, poll_function);
|
|
|
|
|
panel_register_fn_generator(region_type, modifier_panel_prefix, poll_function);
|
|
|
|
|
panel_register_noise(region_type, modifier_panel_prefix, poll_function);
|
|
|
|
|
panel_register_envelope(region_type, modifier_panel_prefix, poll_function);
|
|
|
|
|
panel_register_limits(region_type, modifier_panel_prefix, poll_function);
|
|
|
|
|
panel_register_stepped(region_type, modifier_panel_prefix, poll_function);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ANIM_modifier_panels_register_graph_only(ARegionType *region_type,
|
|
|
|
|
const char *modifier_panel_prefix,
|
|
|
|
|
PanelTypePollFn poll_function)
|
|
|
|
|
{
|
|
|
|
|
panel_register_cycles(region_type, modifier_panel_prefix, poll_function);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
2020-10-29 17:37:44 -05:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Copy / Paste Buffer Code
|
|
|
|
|
*
|
|
|
|
|
* For now, this is also defined in this file so that it can be shared between the graph editor
|
|
|
|
|
* and the NLA editor.
|
|
|
|
|
* \{ */
|
2010-03-18 13:04:46 +00:00
|
|
|
|
|
|
|
|
/* Copy/Paste Buffer itself (list of FModifier 's) */
|
|
|
|
|
static ListBase fmodifier_copypaste_buf = {NULL, NULL};
|
|
|
|
|
|
|
|
|
|
/* ---------- */
|
|
|
|
|
|
|
|
|
|
/* free the copy/paste buffer */
|
2016-04-03 01:18:23 +13:00
|
|
|
void ANIM_fmodifiers_copybuf_free(void)
|
2010-03-18 13:04:46 +00:00
|
|
|
{
|
|
|
|
|
/* just free the whole buffer */
|
|
|
|
|
free_fmodifiers(&fmodifier_copypaste_buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* copy the given F-Modifiers to the buffer, returning whether anything was copied or not
|
2016-04-03 01:18:23 +13:00
|
|
|
* assuming that the buffer has been cleared already with ANIM_fmodifiers_copybuf_free()
|
2018-11-14 12:53:15 +11:00
|
|
|
* - active: only copy the active modifier
|
2010-03-18 13:04:46 +00:00
|
|
|
*/
|
2014-04-11 11:25:41 +10:00
|
|
|
bool ANIM_fmodifiers_copy_to_buf(ListBase *modifiers, bool active)
|
2010-03-18 13:04:46 +00:00
|
|
|
{
|
2014-04-11 11:25:41 +10:00
|
|
|
bool ok = true;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-03-18 13:04:46 +00:00
|
|
|
/* sanity checks */
|
2019-04-22 09:19:45 +10:00
|
|
|
if (ELEM(NULL, modifiers, modifiers->first)) {
|
2010-03-18 13:04:46 +00:00
|
|
|
return 0;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-03-18 13:04:46 +00:00
|
|
|
/* copy the whole list, or just the active one? */
|
|
|
|
|
if (active) {
|
|
|
|
|
FModifier *fcm = find_active_fmodifier(modifiers);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-03-18 13:04:46 +00:00
|
|
|
if (fcm) {
|
|
|
|
|
FModifier *fcmN = copy_fmodifier(fcm);
|
|
|
|
|
BLI_addtail(&fmodifier_copypaste_buf, fcmN);
|
|
|
|
|
}
|
2019-04-22 09:19:45 +10:00
|
|
|
else {
|
2010-03-18 13:04:46 +00:00
|
|
|
ok = 0;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2010-03-18 13:04:46 +00:00
|
|
|
}
|
2019-04-22 09:19:45 +10:00
|
|
|
else {
|
2010-03-18 13:04:46 +00:00
|
|
|
copy_fmodifiers(&fmodifier_copypaste_buf, modifiers);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2010-03-18 13:04:46 +00:00
|
|
|
/* did we succeed? */
|
|
|
|
|
return ok;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-04 09:31:30 +02:00
|
|
|
/* 'Paste' the F-Modifier(s) from the buffer to the specified list
|
2018-11-14 12:53:15 +11:00
|
|
|
* - replace: free all the existing modifiers to leave only the pasted ones
|
2010-03-18 13:04:46 +00:00
|
|
|
*/
|
2017-10-17 19:39:10 +03:00
|
|
|
bool ANIM_fmodifiers_paste_from_buf(ListBase *modifiers, bool replace, FCurve *curve)
|
2010-03-18 13:04:46 +00:00
|
|
|
{
|
|
|
|
|
FModifier *fcm;
|
2014-04-11 11:25:41 +10:00
|
|
|
bool ok = false;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2010-03-18 13:04:46 +00:00
|
|
|
/* sanity checks */
|
2019-04-22 09:19:45 +10:00
|
|
|
if (modifiers == NULL) {
|
2010-03-18 13:04:46 +00:00
|
|
|
return 0;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2017-10-17 19:39:10 +03:00
|
|
|
bool was_cyclic = curve && BKE_fcurve_is_cyclic(curve);
|
|
|
|
|
|
2010-03-18 13:04:46 +00:00
|
|
|
/* if replacing the list, free the existing modifiers */
|
2019-04-22 09:19:45 +10:00
|
|
|
if (replace) {
|
2010-03-18 13:04:46 +00:00
|
|
|
free_fmodifiers(modifiers);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2010-03-18 13:04:46 +00:00
|
|
|
/* now copy over all the modifiers in the buffer to the end of the list */
|
2012-05-08 11:48:19 +00:00
|
|
|
for (fcm = fmodifier_copypaste_buf.first; fcm; fcm = fcm->next) {
|
2010-03-18 13:04:46 +00:00
|
|
|
/* make a copy of it */
|
|
|
|
|
FModifier *fcmN = copy_fmodifier(fcm);
|
2017-10-17 19:39:10 +03:00
|
|
|
|
|
|
|
|
fcmN->curve = curve;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2010-03-18 13:04:46 +00:00
|
|
|
/* make sure the new one isn't active, otherwise the list may get several actives */
|
|
|
|
|
fcmN->flag &= ~FMODIFIER_FLAG_ACTIVE;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2010-03-18 13:04:46 +00:00
|
|
|
/* now add it to the end of the list */
|
|
|
|
|
BLI_addtail(modifiers, fcmN);
|
|
|
|
|
ok = 1;
|
|
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2017-10-17 19:39:10 +03:00
|
|
|
/* adding or removing the Cycles modifier requires an update to handles */
|
2019-04-22 09:19:45 +10:00
|
|
|
if (curve && BKE_fcurve_is_cyclic(curve) != was_cyclic) {
|
2017-10-17 19:39:10 +03:00
|
|
|
calchandles_fcurve(curve);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2017-10-17 19:39:10 +03:00
|
|
|
|
2010-03-18 13:04:46 +00:00
|
|
|
/* did we succeed? */
|
|
|
|
|
return ok;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-29 17:37:44 -05:00
|
|
|
/** \} */
|