diff --git a/Source/Actor.cpp b/Source/Actor.cpp index d48191e..3b26234 100644 --- a/Source/Actor.cpp +++ b/Source/Actor.cpp @@ -3,6 +3,7 @@ #include "ActorRootBone.hpp" #include "ActorIKTarget.hpp" #include "ActorEvent.hpp" +#include "CustomProperty.hpp" #include "BinaryReader.hpp" #include "BlockReader.hpp" #include "Exceptions/OverflowException.hpp" @@ -277,6 +278,15 @@ void Actor::readComponentsBlock(BlockReader* block) case BlockType::ActorEvent: component = ActorEvent::read(this, componentBlock); break; + case BlockType::CustomIntProperty: + component = CustomIntProperty::read(this, componentBlock); + break; + case BlockType::CustomFloatProperty: + component = CustomFloatProperty::read(this, componentBlock); + break; + case BlockType::CustomStringProperty: + component = CustomStringProperty::read(this, componentBlock); + break; default: // Not handled/expected block. break; diff --git a/Source/Actor.hpp b/Source/Actor.hpp index dcd534d..1e728e6 100644 --- a/Source/Actor.hpp +++ b/Source/Actor.hpp @@ -24,9 +24,12 @@ namespace nima Atlases = 9, Atlas = 10, ActorIKTarget = 11, - ActorEvent = 12 + ActorEvent = 12, + CustomIntProperty = 13, + CustomFloatProperty = 14, + CustomStringProperty = 15 }; - + class Actor { friend class ActorAnimationInstance; diff --git a/Source/ActorComponent.cpp b/Source/ActorComponent.cpp index 4a79b8c..096c3d5 100644 --- a/Source/ActorComponent.cpp +++ b/Source/ActorComponent.cpp @@ -1,5 +1,6 @@ #include "ActorComponent.hpp" #include "ActorNode.hpp" +#include "CustomProperty.hpp" #include "BlockReader.hpp" #include #include @@ -83,4 +84,55 @@ ActorComponent* ActorComponent::read(Actor* actor, BlockReader* reader, ActorCom component->m_ParentIdx = reader->readUnsignedShort(); return component; +} + +void ActorComponent::addCustomIntProperty(CustomIntProperty* property) +{ + m_CustomIntProperties.push_back(property); +} + +void ActorComponent::addCustomFloatProperty(CustomFloatProperty* property) +{ + m_CustomFloatProperties.push_back(property); +} + +void ActorComponent::addCustomStringProperty(CustomStringProperty* property) +{ + m_CustomStringProperties.push_back(property); +} + +CustomIntProperty* ActorComponent::getCustomIntProperty(const std::string& name) +{ + for(CustomIntProperty* prop : m_CustomIntProperties) + { + if(prop->name() == name) + { + return prop; + } + } + return nullptr; +} + +CustomFloatProperty* ActorComponent::getCustomFloatProperty(const std::string& name) +{ + for(CustomFloatProperty* prop : m_CustomFloatProperties) + { + if(prop->name() == name) + { + return prop; + } + } + return nullptr; +} + +CustomStringProperty* ActorComponent::getCustomStringProperty(const std::string& name) +{ + for(CustomStringProperty* prop : m_CustomStringProperties) + { + if(prop->name() == name) + { + return prop; + } + } + return nullptr; } \ No newline at end of file diff --git a/Source/ActorComponent.hpp b/Source/ActorComponent.hpp index 5786995..3e1c361 100644 --- a/Source/ActorComponent.hpp +++ b/Source/ActorComponent.hpp @@ -11,6 +11,9 @@ namespace nima class Actor; class ActorNode; class BlockReader; + class CustomIntProperty; + class CustomFloatProperty; + class CustomStringProperty; enum class ComponentType { @@ -19,7 +22,10 @@ namespace nima ActorRootBone = 4, ActorImage = 5, ActorIKTarget = 11, - ActorEvent = 12 + ActorEvent = 12, + CustomIntProperty = 13, + CustomFloatProperty = 14, + CustomStringProperty = 15 }; @@ -30,6 +36,9 @@ namespace nima std::string m_Name; ActorNode* m_Parent; Actor* m_Actor; + std::vector m_CustomIntProperties; + std::vector m_CustomFloatProperties; + std::vector m_CustomStringProperties; private: unsigned short m_ParentIdx; @@ -54,6 +63,14 @@ namespace nima virtual bool isNode() { return false; } static ActorComponent* read(Actor* actor, BlockReader* reader, ActorComponent* component = NULL); + + void addCustomIntProperty(CustomIntProperty* property); + void addCustomFloatProperty(CustomFloatProperty* property); + void addCustomStringProperty(CustomStringProperty* property); + + CustomIntProperty* getCustomIntProperty(const std::string& name); + CustomFloatProperty* getCustomFloatProperty(const std::string& name); + CustomStringProperty* getCustomStringProperty(const std::string& name); }; } #endif \ No newline at end of file diff --git a/Source/Animation/KeyFrames/KeyFrameCustomProperty.cpp b/Source/Animation/KeyFrames/KeyFrameCustomProperty.cpp new file mode 100644 index 0000000..4f4e8eb --- /dev/null +++ b/Source/Animation/KeyFrames/KeyFrameCustomProperty.cpp @@ -0,0 +1,44 @@ +#include "KeyFrameCustomProperty.hpp" +#include "../../BlockReader.hpp" +#include "../../CustomProperty.hpp" +#include + +using namespace nima; + +void KeyFrameIntProperty::setValue(ActorComponent* component, float value, float mix) +{ + CustomIntProperty* property = reinterpret_cast(component); + property->value((int)round(property->value() * (1.0f - mix) + value * mix)); +} + +void KeyFrameFloatProperty::setValue(ActorComponent* component, float value, float mix) +{ + CustomFloatProperty* property = reinterpret_cast(component); + property->value(property->value() * (1.0f - mix) + value * mix); +} + +bool KeyFrameStringProperty::read(BlockReader* reader, ActorComponent* component) +{ + if(!Base::read(reader, component)) + { + return false; + } + m_Value = reader->readString(); + return true; +} + +void KeyFrameStringProperty::setNext(KeyFrame* frame) +{ + // Intentionally blank, we do not interpolate. +} + +void KeyFrameStringProperty::apply(ActorComponent* component, float mix) +{ + CustomStringProperty* property = reinterpret_cast(component); + property->value(m_Value); +} + +void KeyFrameStringProperty::applyInterpolation(ActorComponent* component, float time, KeyFrame* toFrame, float mix) +{ + apply(component, mix); +} \ No newline at end of file diff --git a/Source/Animation/KeyFrames/KeyFrameCustomProperty.hpp b/Source/Animation/KeyFrames/KeyFrameCustomProperty.hpp new file mode 100644 index 0000000..62b1f0d --- /dev/null +++ b/Source/Animation/KeyFrames/KeyFrameCustomProperty.hpp @@ -0,0 +1,37 @@ +#ifndef _NIMA_KEYFRAMEINTPROPERTY_HPP_ +#define _NIMA_KEYFRAMEINTPROPERTY_HPP_ + +#include "KeyFrameNumeric.hpp" +#include + +namespace nima +{ + class ActorComponent; + + class KeyFrameIntProperty : public KeyFrameInt + { + protected: + void setValue(ActorComponent* component, float value, float mix) override; + }; + + class KeyFrameFloatProperty : public KeyFrameNumeric + { + protected: + void setValue(ActorComponent* component, float value, float mix) override; + }; + + class KeyFrameStringProperty : public KeyFrame + { + typedef KeyFrame Base; + private: + std::string m_Value; + + public: + bool read(BlockReader* reader, ActorComponent* component) override; + void setNext(KeyFrame* frame) override; + void apply(ActorComponent* component, float mix) override; + void applyInterpolation(ActorComponent* component, float time, KeyFrame* toFrame, float mix) override; + }; +} + +#endif \ No newline at end of file diff --git a/Source/Animation/KeyFrames/KeyFrameNumeric.cpp b/Source/Animation/KeyFrames/KeyFrameNumeric.cpp index 4b61513..e02b4e2 100644 --- a/Source/Animation/KeyFrames/KeyFrameNumeric.cpp +++ b/Source/Animation/KeyFrames/KeyFrameNumeric.cpp @@ -64,6 +64,72 @@ void KeyFrameNumeric::applyInterpolation(ActorComponent* component, float time, break; } + default: + // Unhandled interpolation... + break; + } +} + +KeyFrameInt::KeyFrameInt() : + m_Value(0) +{ + +} + +int KeyFrameInt::value() const +{ + return m_Value; +} + +bool KeyFrameInt::read(BlockReader* reader, ActorComponent* component) +{ + if(!Base::read(reader, component)) + { + return false; + } + + m_Value = reader->readInt(); + + return true; +} + +void KeyFrameInt::apply(ActorComponent* component, float mix) +{ + this->setValue(component, m_Value, mix); +} + +void KeyFrameInt::applyInterpolation(ActorComponent* component, float time, KeyFrame* toFrame, float mix) +{ + switch(m_InterpolationType) + { + case InterpolationType::Mirrored: + case InterpolationType::Asymmetric: + case InterpolationType::Disconnected: + { + ValueTimeCurveInterpolator* interpolator = reinterpret_cast(m_Interpolator); + if(interpolator != nullptr) + { + float v = (float)interpolator->get((double)time); + setValue(component, v, mix); + } + break; + } + + case InterpolationType::Hold: + { + setValue(component, m_Value, mix); + break; + } + + case InterpolationType::Linear: + { + KeyFrameInt* to = reinterpret_cast(toFrame); + + float f = (time - m_Time)/(to->m_Time-m_Time); + setValue(component, m_Value * (1.0f-f) + to->m_Value * f, mix); + break; + } + default: // Unhandled interpolation... break; diff --git a/Source/Animation/KeyFrames/KeyFrameNumeric.hpp b/Source/Animation/KeyFrames/KeyFrameNumeric.hpp index ee8d00a..a9f34cc 100644 --- a/Source/Animation/KeyFrames/KeyFrameNumeric.hpp +++ b/Source/Animation/KeyFrames/KeyFrameNumeric.hpp @@ -25,6 +25,24 @@ namespace nima protected: virtual void setValue(ActorComponent* component, float value, float mix) = 0; }; + + class KeyFrameInt : public KeyFrameWithInterpolation + { + typedef KeyFrameWithInterpolation Base; + private: + int m_Value; + + public: + KeyFrameInt(); + int value() const; + + bool read(BlockReader* reader, ActorComponent* component) override; + void apply(ActorComponent* component, float mix) override; + void applyInterpolation(ActorComponent* component, float time, KeyFrame* toFrame, float mix) override; + + protected: + virtual void setValue(ActorComponent* component, float value, float mix) = 0; + }; } #endif \ No newline at end of file diff --git a/Source/Animation/PropertyAnimation.cpp b/Source/Animation/PropertyAnimation.cpp index 36fa085..e91c9bb 100644 --- a/Source/Animation/PropertyAnimation.cpp +++ b/Source/Animation/PropertyAnimation.cpp @@ -12,6 +12,7 @@ #include "KeyFrames/KeyFrameVertexDeform.hpp" #include "KeyFrames/KeyFrameIKStrength.hpp" #include "KeyFrames/KeyFrameTrigger.hpp" +#include "KeyFrames/KeyFrameCustomProperty.hpp" #include using namespace nima; @@ -98,6 +99,15 @@ void PropertyAnimation::read(BlockReader* reader, ActorComponent* component) case PropertyType::Trigger: frame = new KeyFrameTrigger(); break; + case PropertyType::IntProperty: + frame = new KeyFrameIntProperty(); + break; + case PropertyType::FloatProperty: + frame = new KeyFrameFloatProperty(); + break; + case PropertyType::StringProperty: + frame = new KeyFrameStringProperty(); + break; default: // This will only happen if the code isn't handling a property type it should handle. // Check the PropertyType enum and make sure Max is in the right place (and that you're not missing a case). diff --git a/Source/Animation/PropertyAnimation.hpp b/Source/Animation/PropertyAnimation.hpp index 8062544..eb93fbf 100644 --- a/Source/Animation/PropertyAnimation.hpp +++ b/Source/Animation/PropertyAnimation.hpp @@ -22,6 +22,9 @@ namespace nima VertexDeform = 9, IKStrength = 10, Trigger = 11, + IntProperty = 12, + FloatProperty = 13, + StringProperty = 14, Max }; diff --git a/Source/CustomProperty.cpp b/Source/CustomProperty.cpp new file mode 100644 index 0000000..15e4bfe --- /dev/null +++ b/Source/CustomProperty.cpp @@ -0,0 +1,153 @@ +#include "CustomProperty.hpp" +#include "BlockReader.hpp" +using namespace nima; + + +CustomIntProperty::CustomIntProperty() : ActorComponent(ComponentType::CustomIntProperty), m_Value(0) +{ + +} + +ActorComponent* CustomIntProperty::makeInstance(Actor* resetActor) +{ + CustomIntProperty* instanceProp = new CustomIntProperty(); + instanceProp->copy(this, resetActor); + return instanceProp; +} + +void CustomIntProperty::copy(CustomIntProperty* property, Actor* resetActor) +{ + Base::copy(property, resetActor); + m_Value = property->m_Value; +} + +CustomIntProperty* CustomIntProperty::read(Actor* actor, BlockReader* reader, CustomIntProperty* property) +{ + if(property == nullptr) + { + property = new CustomIntProperty(); + } + ActorComponent::read(actor, reader, property); + property->m_Value = reader->readInt(); + return property; +} + +void CustomIntProperty::resolveComponentIndices(ActorComponent** components) +{ + Base::resolveComponentIndices(components); + + ActorComponent* parent = components[parentIdx()]; + if(parent != nullptr) + { + parent->addCustomIntProperty(this); + } +} + +int CustomIntProperty::value() const +{ + return m_Value; +} + +void CustomIntProperty::value(int v) +{ + m_Value = v; +} + +CustomFloatProperty::CustomFloatProperty() : ActorComponent(ComponentType::CustomFloatProperty), m_Value(0.0f) +{ + +} + +ActorComponent* CustomFloatProperty::makeInstance(Actor* resetActor) +{ + CustomFloatProperty* instanceProp = new CustomFloatProperty(); + instanceProp->copy(this, resetActor); + return instanceProp; +} + +void CustomFloatProperty::copy(CustomFloatProperty* property, Actor* resetActor) +{ + Base::copy(property, resetActor); + m_Value = property->m_Value; +} + +CustomFloatProperty* CustomFloatProperty::read(Actor* actor, BlockReader* reader, CustomFloatProperty* property) +{ + if(property == nullptr) + { + property = new CustomFloatProperty(); + } + ActorComponent::read(actor, reader, property); + property->m_Value = reader->readFloat(); + return property; +} + +void CustomFloatProperty::resolveComponentIndices(ActorComponent** components) +{ + Base::resolveComponentIndices(components); + ActorComponent* parent = components[parentIdx()]; + if(parent != nullptr) + { + parent->addCustomFloatProperty(this); + } +} + +float CustomFloatProperty::value() const +{ + return m_Value; +} + +void CustomFloatProperty::value(float v) +{ + m_Value = v; +} + +CustomStringProperty::CustomStringProperty() : ActorComponent(ComponentType::CustomStringProperty) +{ + +} + +ActorComponent* CustomStringProperty::makeInstance(Actor* resetActor) +{ + CustomStringProperty* instanceProp = new CustomStringProperty(); + instanceProp->copy(this, resetActor); + return instanceProp; +} + +void CustomStringProperty::copy(CustomStringProperty* property, Actor* resetActor) +{ + Base::copy(property, resetActor); + m_Value = property->m_Value; +} + +CustomStringProperty* CustomStringProperty::read(Actor* actor, BlockReader* reader, CustomStringProperty* property) +{ + if(property == nullptr) + { + property = new CustomStringProperty(); + } + ActorComponent::read(actor, reader, property); + property->m_Value = reader->readString(); + return property; +} + +void CustomStringProperty::resolveComponentIndices(ActorComponent** components) +{ + Base::resolveComponentIndices(components); + + ActorComponent* parent = components[parentIdx()]; + if(parent != nullptr) + { + parent->addCustomStringProperty(this); + } +} + +const std::string& CustomStringProperty::value() const +{ + return m_Value; +} + +void CustomStringProperty::value(const std::string& v) +{ + m_Value = v; +} \ No newline at end of file diff --git a/Source/CustomProperty.hpp b/Source/CustomProperty.hpp new file mode 100644 index 0000000..8d5c0b5 --- /dev/null +++ b/Source/CustomProperty.hpp @@ -0,0 +1,59 @@ +#ifndef _NIMA_CUSTOMPROPERTY_HPP_ +#define _NIMA_CUSTOMPROPERTY_HPP_ + +#include +#include "ActorComponent.hpp" + +namespace nima +{ + class CustomIntProperty : public ActorComponent + { + typedef ActorComponent Base; + private: + int m_Value; + + public: + CustomIntProperty(); + ActorComponent* makeInstance(Actor* resetActor) override; + void copy(CustomIntProperty* property, Actor* resetActor); + static CustomIntProperty* read(Actor* actor, BlockReader* reader, CustomIntProperty* property = NULL); + + void resolveComponentIndices(ActorComponent** components) override; + int value() const; + void value(int v); + + }; + class CustomFloatProperty : public ActorComponent + { + typedef ActorComponent Base; + private: + float m_Value; + + public: + CustomFloatProperty(); + ActorComponent* makeInstance(Actor* resetActor) override; + void copy(CustomFloatProperty* property, Actor* resetActor); + static CustomFloatProperty* read(Actor* actor, BlockReader* reader, CustomFloatProperty* property = NULL); + + void resolveComponentIndices(ActorComponent** components) override; + float value() const; + void value(float v); + }; + class CustomStringProperty : public ActorComponent + { + typedef ActorComponent Base; + private: + std::string m_Value; + + public: + CustomStringProperty(); + ActorComponent* makeInstance(Actor* resetActor) override; + void copy(CustomStringProperty* property, Actor* resetActor); + static CustomStringProperty* read(Actor* actor, BlockReader* reader, CustomStringProperty* property = NULL); + + void resolveComponentIndices(ActorComponent** components) override; + const std::string& value() const; + void value(const std::string& v); + }; +} +#endif \ No newline at end of file