Updating core defs, adding logic for toggle button, bug fix.
diff --git a/dev/defs/animation/event_bool_change.json b/dev/defs/animation/event_bool_change.json index 5bf7a92..7a67cd7 100644 --- a/dev/defs/animation/event_bool_change.json +++ b/dev/defs/animation/event_bool_change.json
@@ -7,8 +7,8 @@ "extends": "animation/event_input_change.json", "properties": { "value": { - "type": "bool", - "initialValue": "true", + "type": "uint", + "initialValue": "1", "key": { "int": 228, "string": "value"
diff --git a/dev/defs/assets/layer_image_asset.json b/dev/defs/assets/layer_image_asset.json new file mode 100644 index 0000000..0c42783 --- /dev/null +++ b/dev/defs/assets/layer_image_asset.json
@@ -0,0 +1,38 @@ +{ + "name": "LayerImageAsset", + "key": { + "int": 120, + "string": "layerimageasset" + }, + "extends": "assets/image_asset.json", + "runtime": false, + "properties": { + "layer": { + "type": "uint", + "initialValue": "-1", + "key": { + "int": 233, + "string": "layer" + }, + "description": "Layer ID as it is analysed by the backend" + }, + "x": { + "type": "double", + "initialValue": "0", + "key": { + "int": 234, + "string": "x" + }, + "description": "x offset for this layer" + }, + "y": { + "type": "double", + "initialValue": "0", + "key": { + "int": 235, + "string": "y" + }, + "description": "y offset for this layer" + } + } +} \ No newline at end of file
diff --git a/dev/defs/assets/layered_asset.json b/dev/defs/assets/layered_asset.json new file mode 100644 index 0000000..042381f --- /dev/null +++ b/dev/defs/assets/layered_asset.json
@@ -0,0 +1,9 @@ +{ + "name": "LayeredAsset", + "key": { + "int": 119, + "string": "layeredasset" + }, + "runtime": false, + "extends": "assets/drawable_asset.json" +} \ No newline at end of file
diff --git a/include/rive/generated/animation/event_bool_change_base.hpp b/include/rive/generated/animation/event_bool_change_base.hpp index 13d95ad..e0914b7 100644 --- a/include/rive/generated/animation/event_bool_change_base.hpp +++ b/include/rive/generated/animation/event_bool_change_base.hpp
@@ -1,7 +1,7 @@ #ifndef _RIVE_EVENT_BOOL_CHANGE_BASE_HPP_ #define _RIVE_EVENT_BOOL_CHANGE_BASE_HPP_ #include "rive/animation/event_input_change.hpp" -#include "rive/core/field_types/core_bool_type.hpp" +#include "rive/core/field_types/core_uint_type.hpp" namespace rive { class EventBoolChangeBase : public EventInputChange { protected: @@ -27,11 +27,11 @@ static const uint16_t valuePropertyKey = 228; private: - bool m_Value = true; + uint32_t m_Value = 1; public: - inline bool value() const { return m_Value; } - void value(bool value) { + inline uint32_t value() const { return m_Value; } + void value(uint32_t value) { if (m_Value == value) { return; } @@ -48,7 +48,7 @@ bool deserialize(uint16_t propertyKey, BinaryReader& reader) override { switch (propertyKey) { case valuePropertyKey: - m_Value = CoreBoolType::deserialize(reader); + m_Value = CoreUintType::deserialize(reader); return true; } return EventInputChange::deserialize(propertyKey, reader);
diff --git a/include/rive/generated/core_registry.hpp b/include/rive/generated/core_registry.hpp index 54f9bc5..918498f 100644 --- a/include/rive/generated/core_registry.hpp +++ b/include/rive/generated/core_registry.hpp
@@ -373,6 +373,9 @@ case TransitionValueConditionBase::opValuePropertyKey: object->as<TransitionValueConditionBase>()->opValue(value); break; + case EventBoolChangeBase::valuePropertyKey: + object->as<EventBoolChangeBase>()->value(value); + break; case StateTransitionBase::stateToIdPropertyKey: object->as<StateTransitionBase>()->stateToId(value); break; @@ -750,9 +753,6 @@ case KeyFrameBoolBase::valuePropertyKey: object->as<KeyFrameBoolBase>()->value(value); break; - case EventBoolChangeBase::valuePropertyKey: - object->as<EventBoolChangeBase>()->value(value); - break; case LinearAnimationBase::enableWorkAreaPropertyKey: object->as<LinearAnimationBase>()->enableWorkArea(value); break; @@ -861,6 +861,8 @@ return object->as<KeyFrameIdBase>()->value(); case TransitionValueConditionBase::opValuePropertyKey: return object->as<TransitionValueConditionBase>()->opValue(); + case EventBoolChangeBase::valuePropertyKey: + return object->as<EventBoolChangeBase>()->value(); case StateTransitionBase::stateToIdPropertyKey: return object->as<StateTransitionBase>()->stateToId(); case StateTransitionBase::flagsPropertyKey: @@ -1117,8 +1119,6 @@ return object->as<NestedSimpleAnimationBase>()->isPlaying(); case KeyFrameBoolBase::valuePropertyKey: return object->as<KeyFrameBoolBase>()->value(); - case EventBoolChangeBase::valuePropertyKey: - return object->as<EventBoolChangeBase>()->value(); case LinearAnimationBase::enableWorkAreaPropertyKey: return object->as<LinearAnimationBase>()->enableWorkArea(); case StateMachineBoolBase::valuePropertyKey: @@ -1183,6 +1183,7 @@ case KeyFrameBase::interpolatorIdPropertyKey: case KeyFrameIdBase::valuePropertyKey: case TransitionValueConditionBase::opValuePropertyKey: + case EventBoolChangeBase::valuePropertyKey: case StateTransitionBase::stateToIdPropertyKey: case StateTransitionBase::flagsPropertyKey: case StateTransitionBase::durationPropertyKey: @@ -1308,7 +1309,6 @@ case IKConstraintBase::invertDirectionPropertyKey: case NestedSimpleAnimationBase::isPlayingPropertyKey: case KeyFrameBoolBase::valuePropertyKey: - case EventBoolChangeBase::valuePropertyKey: case LinearAnimationBase::enableWorkAreaPropertyKey: case StateMachineBoolBase::valuePropertyKey: case ShapePaintBase::isVisiblePropertyKey:
diff --git a/src/animation/event_bool_change.cpp b/src/animation/event_bool_change.cpp index 946f15a..2d81753 100644 --- a/src/animation/event_bool_change.cpp +++ b/src/animation/event_bool_change.cpp
@@ -18,5 +18,15 @@ } // If it's not null, it must be our correct type (why we validate at load time). auto boolInput = reinterpret_cast<SMIBool*>(inputInstance); - boolInput->value(value()); + switch (value()) { + case 0: + boolInput->value(false); + break; + case 1: + boolInput->value(true); + break; + default: + boolInput->value(!boolInput->value()); + break; + } } \ No newline at end of file
diff --git a/src/animation/state_machine_event.cpp b/src/animation/state_machine_event.cpp index 9abce0c..bd17743 100644 --- a/src/animation/state_machine_event.cpp +++ b/src/animation/state_machine_event.cpp
@@ -48,7 +48,7 @@ if (component == target) { auto index = artboard->idOf(shape); if (index != 0) { - m_HitShapesIds.push_back(artboard->idOf(shape)); + m_HitShapesIds.push_back(index); } break; }
diff --git a/src/animation/state_machine_instance.cpp b/src/animation/state_machine_instance.cpp index 0447d10..cf29882 100644 --- a/src/animation/state_machine_instance.cpp +++ b/src/animation/state_machine_instance.cpp
@@ -74,7 +74,7 @@ } } - bool advance(/*Artboard* artboard, */float seconds, Span<SMIInput*> inputs) { + bool advance(/*Artboard* artboard, */ float seconds, Span<SMIInput*> inputs) { m_StateChangedOnAdvance = false; if (m_CurrentState != nullptr) { @@ -134,8 +134,9 @@ return true; } - bool - tryChangeState(StateInstance* stateFromInstance, Span<SMIInput*> inputs, bool ignoreTriggers) { + bool tryChangeState(StateInstance* stateFromInstance, + Span<SMIInput*> inputs, + bool ignoreTriggers) { if (stateFromInstance == nullptr) { return false; } @@ -276,18 +277,12 @@ void StateMachineInstance::pointerMove(Vec2D position) { processEvent(position, EventType::updateHover); } -void StateMachineInstance::pointerDown(Vec2D position) { - processEvent(position, EventType::down); -} -void StateMachineInstance::pointerUp(Vec2D position) { - processEvent(position, EventType::up); -} +void StateMachineInstance::pointerDown(Vec2D position) { processEvent(position, EventType::down); } +void StateMachineInstance::pointerUp(Vec2D position) { processEvent(position, EventType::up); } StateMachineInstance::StateMachineInstance(const StateMachine* machine, - ArtboardInstance* instance) - : Scene(instance) - , m_Machine(machine) -{ + ArtboardInstance* instance) : + Scene(instance), m_Machine(machine) { const auto count = machine->inputCount(); m_InputInstances.resize(count); for (size_t i = 0; i < count; i++) {
diff --git a/src/artboard.cpp b/src/artboard.cpp index 6758548..56f1e6d 100644 --- a/src/artboard.cpp +++ b/src/artboard.cpp
@@ -68,17 +68,25 @@ } } - for (auto object : m_Animations) { - if (!canContinue(code = object->onAddedDirty(this))) { - return code; + // Animations and StateMachines initialize only once on the source/origin + // Artboard. Instances will hold references to the original Animations and StateMachines, so + // running this code for instances will effectively initialize them twice. This can lead to + // unpredictable behaviour. One such example was that resolved objects like event inputs were + // being added to lists twice. + if (!isInstance()) { + for (auto object : m_Animations) { + if (!canContinue(code = object->onAddedDirty(this))) { + return code; + } + } + + for (auto object : m_StateMachines) { + if (!canContinue(code = object->onAddedDirty(this))) { + return code; + } } } - for (auto object : m_StateMachines) { - if (!canContinue(code = object->onAddedDirty(this))) { - return code; - } - } // Store a map of the drawRules to make it easier to lookup the matching // rule for a transform component. std::unordered_map<Core*, DrawRules*> componentDrawRules; @@ -115,15 +123,17 @@ } } - for (auto object : m_Animations) { - if (!canContinue(code = object->onAddedClean(this))) { - return code; + if (!isInstance()) { + for (auto object : m_Animations) { + if (!canContinue(code = object->onAddedClean(this))) { + return code; + } } - } - for (auto object : m_StateMachines) { - if (!canContinue(code = object->onAddedClean(this))) { - return code; + for (auto object : m_StateMachines) { + if (!canContinue(code = object->onAddedClean(this))) { + return code; + } } } @@ -523,6 +533,7 @@ artboardClone->m_Factory = m_Factory; artboardClone->m_FrameOrigin = m_FrameOrigin; + artboardClone->m_IsInstance = true; std::vector<Core*>& cloneObjects = artboardClone->m_Objects; cloneObjects.push_back(artboardClone.get()); @@ -545,8 +556,6 @@ if (artboardClone->initialize() != StatusCode::Ok) { artboardClone = nullptr; - } else { - artboardClone->m_IsInstance = true; } assert(artboardClone->isInstance());
diff --git a/test/assets/light_switch.riv b/test/assets/light_switch.riv new file mode 100644 index 0000000..a779e6b --- /dev/null +++ b/test/assets/light_switch.riv Binary files differ
diff --git a/test/state_machine_event_test.cpp b/test/state_machine_event_test.cpp index ad9e4d3..9bc81cf 100644 --- a/test/state_machine_event_test.cpp +++ b/test/state_machine_event_test.cpp
@@ -81,3 +81,31 @@ REQUIRE(trigger->didFire()); } + +TEST_CASE("hit a toggle boolean event", "[file]") { + auto file = ReadRiveFile("../../test/assets/light_switch.riv"); + + auto artboard = file->artboard()->instance(); + REQUIRE(artboard != nullptr); + REQUIRE(artboard->stateMachineCount() == 1); + + auto stateMachine = artboard->stateMachineAt(0); + REQUIRE(stateMachine != nullptr); + + artboard->advance(0.0f); + stateMachine->advance(0.0f); + + auto switchButton = stateMachine->getBool("On"); + REQUIRE(switchButton != nullptr); + REQUIRE(switchButton->value() == true); + + stateMachine->pointerDown(rive::Vec2D(150.0f, 258.0f)); + stateMachine->pointerUp(rive::Vec2D(150.0f, 258.0f)); + // Got toggled off after pressing + REQUIRE(switchButton->value() == false); + + stateMachine->pointerDown(rive::Vec2D(150.0f, 258.0f)); + stateMachine->pointerUp(rive::Vec2D(150.0f, 258.0f)); + // Got toggled back on after pressing + REQUIRE(switchButton->value() == true); +}