Skip to content

Commit

Permalink
Nnnn apply target to source on change
Browse files Browse the repository at this point in the history
This PR reworks how "source to target" binding works.
Previously, any binding marked as "source to target" would run at every frame setting the value to the source, relying on the fact that, after the first frame, it would be setting the same value subsequently and nothing would change.
But that prevents changing the view model source value externally since it would be overwritten immediately.
This PR solves this by keeping track of value changes at the binding level.
It also addresses memory leaks by not creating a new data value on every frame.
And it renames some methods for clarity.

Diffs=
63642c62d4 Nnnn apply target to source on change (#9049)
e417bb4754 add support for state transition duration binding (#9061)

Co-authored-by: hernan <[email protected]>
  • Loading branch information
bodymovin and bodymovin committed Feb 19, 2025
1 parent 778c044 commit 406a997
Show file tree
Hide file tree
Showing 35 changed files with 279 additions and 92 deletions.
2 changes: 1 addition & 1 deletion .rive_head
Original file line number Diff line number Diff line change
@@ -1 +1 @@
98cac08e6a7ae298cf620f3cbc05cdc9233de61c
63642c62d46f41939545609dd151b68d0f4f67fe
3 changes: 2 additions & 1 deletion dev/defs/animation/state_transition.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
"int": 158,
"string": "duration"
},
"description": "Duration of the trasition (mix time) in milliseconds or percentage (0-100) based on flags."
"description": "Duration of the trasition (mix time) in milliseconds or percentage (0-100) based on flags.",
"bindable": true
},
"transitionOrder": {
"type": "FractionalIndex",
Expand Down
48 changes: 40 additions & 8 deletions include/rive/data_bind/context/context_value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,27 @@
#include "rive/viewmodel/viewmodel_instance_value.hpp"
#include "rive/data_bind/converters/data_converter.hpp"
#include "rive/data_bind/data_bind.hpp"
#include "rive/data_bind/data_values/data_value_number.hpp"
#include <stdio.h>
namespace rive
{
class DataBindContextValue
{
protected:
DataBind* m_dataBind;
DataValue* m_dataValue;
DataBind* m_dataBind = nullptr;
DataValue* m_dataValue = nullptr;
bool m_isValid = false;
virtual DataValue* targetValue() { return nullptr; };

public:
DataBindContextValue(DataBind* dataBind);
virtual ~DataBindContextValue(){};
virtual ~DataBindContextValue()
{
if (m_dataValue != nullptr)
{
delete m_dataValue;
}
};
virtual void applyToSource(Core* component,
uint32_t propertyKey,
bool isMainDirection);
Expand All @@ -23,11 +32,12 @@ class DataBindContextValue
bool isMainDirection){};
virtual void update(Core* component){};
virtual void dispose(){};
virtual DataValue* getTargetValue(Core* target, uint32_t propertyKey)
void invalidate() { m_isValid = false; };
virtual bool syncTargetValue(Core* target, uint32_t propertyKey)
{
return nullptr;
return false;
};
void updateSourceValue();
void syncSourceValue();
template <typename T = DataValue, typename U>
U getDataValue(DataValue* input, DataBind* dataBind)
{
Expand Down Expand Up @@ -56,8 +66,30 @@ class DataBindContextValue
template <typename T = DataValue, typename U>
U calculateValue(DataValue* input, bool isMainDirection, DataBind* dataBind)
{
return isMainDirection ? getDataValue<T, U>(input, dataBind)
: getReverseDataValue<T, U>(input, dataBind);
auto value = isMainDirection
? getDataValue<T, U>(input, dataBind)
: getReverseDataValue<T, U>(input, dataBind);
return value;
};
template <typename T = DataValue,
typename U,
typename V = ViewModelInstanceValue>
void calculateValueAndApply(DataValue* input,
bool isMainDirection,
DataBind* dataBind,
Core* component,
uint32_t propertyKey)
{
// Check if target value changed or binding has been invalidated
if (syncTargetValue(component, propertyKey) || !m_isValid)
{
// Calculate new value after converters are applied
auto value = calculateValue<T, U>(input, isMainDirection, dataBind);
// Apply value to source
auto source = dataBind->source();
source->as<V>()->propertyValue(value);
m_isValid = true;
}
};
};
} // namespace rive
Expand Down
11 changes: 9 additions & 2 deletions include/rive/data_bind/context/context_value_boolean.hpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_BOOLEAN_HPP_
#define _RIVE_DATA_BIND_CONTEXT_VALUE_BOOLEAN_HPP_
#include "rive/data_bind/context/context_value.hpp"
#include "rive/data_bind/data_values/data_value_boolean.hpp"
namespace rive
{
class DataBindContextValueBoolean : public DataBindContextValue
{

public:
DataBindContextValueBoolean(DataBind* m_dataBind);
void apply(Core* component,
uint32_t propertyKey,
bool isMainDirection) override;
DataValue* getTargetValue(Core* target, uint32_t propertyKey) override;
bool syncTargetValue(Core* target, uint32_t propertyKey) override;

private:
bool m_previousValue = false;
DataValueBoolean m_targetDataValue;

protected:
DataValue* targetValue() override { return &m_targetDataValue; }
};
} // namespace rive

Expand Down
10 changes: 9 additions & 1 deletion include/rive/data_bind/context/context_value_color.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_COLOR_HPP_
#define _RIVE_DATA_BIND_CONTEXT_VALUE_COLOR_HPP_
#include "rive/data_bind/context/context_value.hpp"
#include "rive/data_bind/data_values/data_value_color.hpp"
namespace rive
{
class DataBindContextValueColor : public DataBindContextValue
Expand All @@ -11,7 +12,14 @@ class DataBindContextValueColor : public DataBindContextValue
void apply(Core* component,
uint32_t propertyKey,
bool isMainDirection) override;
DataValue* getTargetValue(Core* target, uint32_t propertyKey) override;
bool syncTargetValue(Core* target, uint32_t propertyKey) override;

private:
int m_previousValue = 0;
DataValueColor m_targetDataValue;

protected:
DataValue* targetValue() override { return &m_targetDataValue; }
};
} // namespace rive

Expand Down
10 changes: 9 additions & 1 deletion include/rive/data_bind/context/context_value_enum.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_ENUM_HPP_
#define _RIVE_DATA_BIND_CONTEXT_VALUE_ENUM_HPP_
#include "rive/data_bind/context/context_value.hpp"
#include "rive/data_bind/data_values/data_value_enum.hpp"
namespace rive
{
class DataBindContextValueEnum : public DataBindContextValue
Expand All @@ -11,7 +12,14 @@ class DataBindContextValueEnum : public DataBindContextValue
void apply(Core* component,
uint32_t propertyKey,
bool isMainDirection) override;
DataValue* getTargetValue(Core* target, uint32_t propertyKey) override;
bool syncTargetValue(Core* target, uint32_t propertyKey) override;

private:
uint32_t m_previousValue = 0;
DataValueEnum m_targetDataValue;

protected:
DataValue* targetValue() override { return &m_targetDataValue; }
};
} // namespace rive

Expand Down
10 changes: 9 additions & 1 deletion include/rive/data_bind/context/context_value_number.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_NUMBER_HPP_
#define _RIVE_DATA_BIND_CONTEXT_VALUE_NUMBER_HPP_
#include "rive/data_bind/context/context_value.hpp"
#include "rive/data_bind/data_values/data_value_number.hpp"
namespace rive
{
class DataBindContextValueNumber : public DataBindContextValue
Expand All @@ -11,7 +12,14 @@ class DataBindContextValueNumber : public DataBindContextValue
void apply(Core* component,
uint32_t propertyKey,
bool isMainDirection) override;
DataValue* getTargetValue(Core* target, uint32_t propertyKey) override;
bool syncTargetValue(Core* target, uint32_t propertyKey) override;

private:
float m_previousValue = 0;
DataValueNumber m_targetDataValue;

protected:
DataValue* targetValue() override { return &m_targetDataValue; }
};
} // namespace rive

Expand Down
10 changes: 9 additions & 1 deletion include/rive/data_bind/context/context_value_string.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_STRING_HPP_
#define _RIVE_DATA_BIND_CONTEXT_VALUE_STRING_HPP_
#include "rive/data_bind/context/context_value.hpp"
#include "rive/data_bind/data_values/data_value_string.hpp"
namespace rive
{
class DataBindContextValueString : public DataBindContextValue
Expand All @@ -11,7 +12,14 @@ class DataBindContextValueString : public DataBindContextValue
void apply(Core* component,
uint32_t propertyKey,
bool isMainDirection) override;
DataValue* getTargetValue(Core* target, uint32_t propertyKey) override;
bool syncTargetValue(Core* target, uint32_t propertyKey) override;

private:
std::string m_previousValue = "";
DataValueString m_targetDataValue;

protected:
DataValue* targetValue() override { return &m_targetDataValue; }
};
} // namespace rive

Expand Down
10 changes: 9 additions & 1 deletion include/rive/data_bind/context/context_value_trigger.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef _RIVE_DATA_BIND_CONTEXT_VALUE_TRIGGER_HPP_
#define _RIVE_DATA_BIND_CONTEXT_VALUE_TRIGGER_HPP_
#include "rive/data_bind/context/context_value.hpp"
#include "rive/data_bind/data_values/data_value_trigger.hpp"
namespace rive
{
class DataBindContextValueTrigger : public DataBindContextValue
Expand All @@ -11,7 +12,14 @@ class DataBindContextValueTrigger : public DataBindContextValue
void apply(Core* component,
uint32_t propertyKey,
bool isMainDirection) override;
DataValue* getTargetValue(Core* target, uint32_t propertyKey) override;
bool syncTargetValue(Core* target, uint32_t propertyKey) override;

private:
uint32_t m_previousValue = 0;
DataValueTrigger m_targetDataValue;

protected:
DataValue* targetValue() override { return &m_targetDataValue; }
};
} // namespace rive

Expand Down
2 changes: 1 addition & 1 deletion include/rive/data_bind/converters/data_converter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class DataConverter : public DataConverterBase
StatusCode import(ImportStack& importStack) override;
void addDataBind(DataBind* dataBind);
std::vector<DataBind*> dataBinds() const { return m_dataBinds; }
void addDirt(ComponentDirt dirt);
void markConverterDirty();
virtual void update();
void copy(const DataConverter& object);
virtual bool advance(float elapsedTime);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class DataConverterInterpolator : public DataConverterInterpolatorBase
DataValue* reverseConvert(DataValue* value, DataBind* dataBind) override;
bool advance(float elapsedTime) override;
void copy(const DataConverterInterpolatorBase& object);
void durationChanged() override;

private:
DataValueNumber m_output;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class DataConverterOperationValue : public DataConverterOperationValueBase
public:
DataValue* convert(DataValue* value, DataBind* dataBind) override;
DataValue* reverseConvert(DataValue* value, DataBind* dataBind) override;
void operationValueChanged() override;
};
} // namespace rive

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ class DataConverterRangeMapper : public DataConverterRangeMapperBase
DataValue* convert(DataValue* value, DataBind* dataBind) override;
DataValue* reverseConvert(DataValue* value, DataBind* dataBind) override;
void copy(const DataConverterRangeMapperBase& object);
void minInputChanged() override;
void maxInputChanged() override;
void minOutputChanged() override;
void maxOutputChanged() override;

private:
DataValueNumber m_output;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ class DataConverterStringPad : public DataConverterStringPadBase
public:
DataValue* convert(DataValue* value, DataBind* dataBind) override;
DataType outputType() override { return DataType::string; };
void lengthChanged() override;
void padTypeChanged() override;
void textChanged() override;

private:
DataValueString m_output;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class DataConverterStringTrim : public DataConverterStringTrimBase
DataValue* convert(DataValue* value, DataBind* dataBind) override;
DataType outputType() override { return DataType::string; };
TrimType trimValue() { return (TrimType)trimType(); }
void trimTypeChanged() override;

private:
DataValueString m_output;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ class DataConverterToString : public DataConverterToStringBase
public:
DataValue* convert(DataValue* value, DataBind* dataBind) override;
DataType outputType() override { return DataType::string; };
void decimalsChanged() override;
void colorFormatChanged() override;

private:
DataValue* convertNumber(DataValueNumber* value);
Expand Down
2 changes: 1 addition & 1 deletion include/rive/data_bind/data_bind.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class DataBind : public DataBindBase
~DataBind();
StatusCode onAddedDirty(CoreContext* context) override;
StatusCode import(ImportStack& importStack) override;
virtual void updateSourceBinding();
virtual void updateSourceBinding(bool invalidate = false);
virtual void update(ComponentDirt value);
Core* target() const { return m_target; };
void target(Core* value) { m_target = value; };
Expand Down
1 change: 1 addition & 0 deletions include/rive/data_bind/data_values/data_value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace rive
class DataValue
{
public:
virtual ~DataValue(){};
virtual bool isTypeOf(DataType dataType) const { return false; }
template <typename T> inline bool is() const
{
Expand Down
2 changes: 1 addition & 1 deletion src/animation/listener_viewmodel_change.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,5 @@ void ListenerViewModelChange::perform(
stateMachineInstance->bindableDataBindToSource(bindableInstance);
// Apply the change that will assign the value of the bindable property to
// the view model property instance
dataBind->updateSourceBinding();
dataBind->updateSourceBinding(true);
}
4 changes: 4 additions & 0 deletions src/animation/state_machine_instance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1340,6 +1340,10 @@ StateMachineInstance::StateMachineInstance(const StateMachine* machine,
dataBindClone;
}
}
else
{
dataBindClone->target(dataBind->target());
}
}

// Initialize listeners. Store a lookup table of shape id to hit shape
Expand Down
Loading

0 comments on commit 406a997

Please sign in to comment.