diff --git a/KREngine/KREngine.xcodeproj/project.pbxproj b/KREngine/KREngine.xcodeproj/project.pbxproj index e0d36ab..c7146d1 100644 --- a/KREngine/KREngine.xcodeproj/project.pbxproj +++ b/KREngine/KREngine.xcodeproj/project.pbxproj @@ -17,6 +17,10 @@ E414BAE51435558900A668C4 /* KRInstance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E414BAE41435558800A668C4 /* KRInstance.cpp */; }; E414BAE7143557D200A668C4 /* KRScene.h in Headers */ = {isa = PBXBuildFile; fileRef = E414BAE6143557D200A668C4 /* KRScene.h */; }; E414BAE91435585A00A668C4 /* KRScene.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E414BAE81435585A00A668C4 /* KRScene.cpp */; }; + E416AA9916713749000F6786 /* KRAnimationCurveManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E416AA9816713749000F6786 /* KRAnimationCurveManager.h */; }; + E416AA9A16713749000F6786 /* KRAnimationCurveManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E416AA9816713749000F6786 /* KRAnimationCurveManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + E416AA9C1671375C000F6786 /* KRAnimationCurveManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416AA9B1671375C000F6786 /* KRAnimationCurveManager.cpp */; }; + E416AA9D1671375C000F6786 /* KRAnimationCurveManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E416AA9B1671375C000F6786 /* KRAnimationCurveManager.cpp */; }; E428C2F21669610500A16EDF /* KRAnimationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E428C2F11669610500A16EDF /* KRAnimationManager.h */; }; E428C2F31669610500A16EDF /* KRAnimationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E428C2F11669610500A16EDF /* KRAnimationManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; E428C2F51669611600A16EDF /* KRAnimationManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E428C2F41669611600A16EDF /* KRAnimationManager.cpp */; }; @@ -37,10 +41,6 @@ E428C3171669A24B00A16EDF /* KRAnimationAttribute.h in Headers */ = {isa = PBXBuildFile; fileRef = E428C3151669A24B00A16EDF /* KRAnimationAttribute.h */; settings = {ATTRIBUTES = (Public, ); }; }; E428C3191669A25D00A16EDF /* KRAnimationAttribute.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E428C3181669A25D00A16EDF /* KRAnimationAttribute.cpp */; }; E428C31A1669A25D00A16EDF /* KRAnimationAttribute.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E428C3181669A25D00A16EDF /* KRAnimationAttribute.cpp */; }; - E428C31C1669A77D00A16EDF /* KRAnimationCurveKey.h in Headers */ = {isa = PBXBuildFile; fileRef = E428C31B1669A77D00A16EDF /* KRAnimationCurveKey.h */; }; - E428C31D1669A77D00A16EDF /* KRAnimationCurveKey.h in Headers */ = {isa = PBXBuildFile; fileRef = E428C31B1669A77D00A16EDF /* KRAnimationCurveKey.h */; settings = {ATTRIBUTES = (Public, ); }; }; - E428C31F1669A78D00A16EDF /* KRAnimationCurveKey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E428C31E1669A78C00A16EDF /* KRAnimationCurveKey.cpp */; }; - E428C3201669A78D00A16EDF /* KRAnimationCurveKey.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E428C31E1669A78C00A16EDF /* KRAnimationCurveKey.cpp */; }; E42CB1EC158446940066E0D8 /* KRQuaternion.h in Headers */ = {isa = PBXBuildFile; fileRef = E42CB1EB158446940066E0D8 /* KRQuaternion.h */; }; E42CB1ED158446940066E0D8 /* KRQuaternion.h in Headers */ = {isa = PBXBuildFile; fileRef = E42CB1EB158446940066E0D8 /* KRQuaternion.h */; settings = {ATTRIBUTES = (Public, ); }; }; E42CB1F0158446AB0066E0D8 /* KRQuaternion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E42CB1EF158446AB0066E0D8 /* KRQuaternion.cpp */; }; @@ -236,6 +236,8 @@ E414BAE41435558800A668C4 /* KRInstance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = KRInstance.cpp; path = Classes/KRInstance.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; E414BAE6143557D200A668C4 /* KRScene.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = KRScene.h; path = Classes/KRScene.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; E414BAE81435585A00A668C4 /* KRScene.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = KRScene.cpp; path = Classes/KRScene.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; + E416AA9816713749000F6786 /* KRAnimationCurveManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KRAnimationCurveManager.h; path = Classes/KRAnimationCurveManager.h; sourceTree = ""; }; + E416AA9B1671375C000F6786 /* KRAnimationCurveManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = KRAnimationCurveManager.cpp; path = Classes/KRAnimationCurveManager.cpp; sourceTree = ""; }; E41B841D16260C5600C7A771 /* sky_box.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = sky_box.fsh; path = Shaders/sky_box.fsh; sourceTree = ""; }; E41B842016260C6500C7A771 /* sky_box.vsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = sky_box.vsh; path = Shaders/sky_box.vsh; sourceTree = ""; }; E428C2F11669610500A16EDF /* KRAnimationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KRAnimationManager.h; path = Classes/KRAnimationManager.h; sourceTree = ""; }; @@ -248,8 +250,6 @@ E428C310166971FE00A16EDF /* KRAnimationLayer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = KRAnimationLayer.cpp; path = Classes/KRAnimationLayer.cpp; sourceTree = ""; }; E428C3151669A24B00A16EDF /* KRAnimationAttribute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KRAnimationAttribute.h; path = Classes/KRAnimationAttribute.h; sourceTree = ""; }; E428C3181669A25D00A16EDF /* KRAnimationAttribute.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = KRAnimationAttribute.cpp; path = Classes/KRAnimationAttribute.cpp; sourceTree = ""; }; - E428C31B1669A77D00A16EDF /* KRAnimationCurveKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KRAnimationCurveKey.h; path = Classes/KRAnimationCurveKey.h; sourceTree = ""; }; - E428C31E1669A78C00A16EDF /* KRAnimationCurveKey.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = KRAnimationCurveKey.cpp; path = Classes/KRAnimationCurveKey.cpp; sourceTree = ""; }; E42CB1EB158446940066E0D8 /* KRQuaternion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = KRQuaternion.h; path = Classes/KRQuaternion.h; sourceTree = ""; }; E42CB1EF158446AB0066E0D8 /* KRQuaternion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = KRQuaternion.cpp; path = Classes/KRQuaternion.cpp; sourceTree = ""; }; E430D08015F8882F0010558D /* occlusion_test.fsh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.glsl; name = occlusion_test.fsh; path = Shaders/occlusion_test.fsh; sourceTree = ""; }; @@ -413,6 +413,17 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + E416AA96167136FB000F6786 /* AnimationCurve */ = { + isa = PBXGroup; + children = ( + E428C3031669627900A16EDF /* KRAnimationCurve.h */, + E428C3061669628A00A16EDF /* KRAnimationCurve.cpp */, + E416AA9816713749000F6786 /* KRAnimationCurveManager.h */, + E416AA9B1671375C000F6786 /* KRAnimationCurveManager.cpp */, + ); + name = AnimationCurve; + sourceTree = ""; + }; E428C2EF166960ED00A16EDF /* Animation */ = { isa = PBXGroup; children = ( @@ -422,12 +433,8 @@ E428C2F41669611600A16EDF /* KRAnimationManager.cpp */, E428C2F71669612500A16EDF /* KRAnimation.h */, E428C2FA1669613200A16EDF /* KRAnimation.cpp */, - E428C3031669627900A16EDF /* KRAnimationCurve.h */, - E428C3061669628A00A16EDF /* KRAnimationCurve.cpp */, E428C3151669A24B00A16EDF /* KRAnimationAttribute.h */, E428C3181669A25D00A16EDF /* KRAnimationAttribute.cpp */, - E428C31B1669A77D00A16EDF /* KRAnimationCurveKey.h */, - E428C31E1669A78C00A16EDF /* KRAnimationCurveKey.cpp */, ); name = Animation; sourceTree = ""; @@ -538,6 +545,7 @@ E488399915F92BA300BD66D5 /* Managers */ = { isa = PBXGroup; children = ( + E416AA96167136FB000F6786 /* AnimationCurve */, E428C2EF166960ED00A16EDF /* Animation */, E48839AB15F930E200BD66D5 /* Bundle */, E48839AA15F9309E00BD66D5 /* Material */, @@ -823,7 +831,7 @@ E428C3041669627900A16EDF /* KRAnimationCurve.h in Headers */, E428C311166971FF00A16EDF /* KRAnimationLayer.h in Headers */, E428C3161669A24B00A16EDF /* KRAnimationAttribute.h in Headers */, - E428C31C1669A77D00A16EDF /* KRAnimationCurveKey.h in Headers */, + E416AA9916713749000F6786 /* KRAnimationCurveManager.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -869,9 +877,9 @@ E4AFC6B615F7C46800DDB4C8 /* KRAABB.cpp in Headers */, E428C3171669A24B00A16EDF /* KRAnimationAttribute.h in Headers */, E4AFC6BE15F7C9E600DDB4C8 /* KROctreeNode.h in Headers */, - E428C31D1669A77D00A16EDF /* KRAnimationCurveKey.h in Headers */, E4AFC6BD15F7C9DA00DDB4C8 /* KROctree.h in Headers */, E46A6B701559EF0A000DBD37 /* KRResource+blend.h in Headers */, + E416AA9A16713749000F6786 /* KRAnimationCurveManager.h in Headers */, E42CB1ED158446940066E0D8 /* KRQuaternion.h in Headers */, E4030E4D160A3CF000592648 /* KRStockGeometry.h in Headers */, E4B175AF161F5A1000B8FB80 /* KRTexture.h in Headers */, @@ -1015,7 +1023,7 @@ E428C3071669628A00A16EDF /* KRAnimationCurve.cpp in Sources */, E428C313166971FF00A16EDF /* KRAnimationLayer.cpp in Sources */, E428C3191669A25D00A16EDF /* KRAnimationAttribute.cpp in Sources */, - E428C31F1669A78D00A16EDF /* KRAnimationCurveKey.cpp in Sources */, + E416AA9C1671375C000F6786 /* KRAnimationCurveManager.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1071,7 +1079,7 @@ E428C3081669628A00A16EDF /* KRAnimationCurve.cpp in Sources */, E428C314166971FF00A16EDF /* KRAnimationLayer.cpp in Sources */, E428C31A1669A25D00A16EDF /* KRAnimationAttribute.cpp in Sources */, - E428C3201669A78D00A16EDF /* KRAnimationCurveKey.cpp in Sources */, + E416AA9D1671375C000F6786 /* KRAnimationCurveManager.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/KREngine/KREngine/Classes/KRAnimation.cpp b/KREngine/KREngine/Classes/KRAnimation.cpp index 1d88e8b..ff3215b 100644 --- a/KREngine/KREngine/Classes/KRAnimation.cpp +++ b/KREngine/KREngine/Classes/KRAnimation.cpp @@ -34,7 +34,8 @@ KRAnimation::KRAnimation(KRContext &context, std::string name) : KRResource(context, name) { - + m_auto_play = true; + m_loop = true; } KRAnimation::~KRAnimation() { @@ -56,6 +57,8 @@ bool KRAnimation::save(const std::string& path) { tinyxml2::XMLDocument doc; tinyxml2::XMLElement *animation_node = doc.NewElement( "animation" ); doc.InsertEndChild(animation_node); + animation_node->SetAttribute("loop", m_loop ? "true" : "false"); + animation_node->SetAttribute("auto_play", m_auto_play ? "true" : "false"); for(std::map::iterator itr = m_layers.begin(); itr != m_layers.end(); ++itr){ (*itr).second->saveXML(animation_node); @@ -74,6 +77,14 @@ KRAnimation *KRAnimation::Load(KRContext &context, const std::string &name, KRDa KRAnimation *new_animation = new KRAnimation(context, name); tinyxml2::XMLElement *animation_node = doc.RootElement(); + + if(animation_node->QueryBoolAttribute("loop", &new_animation->m_loop) != tinyxml2::XML_SUCCESS) { + new_animation->m_loop = true; // Default value + } + + if(animation_node->QueryBoolAttribute("auto_play", &new_animation->m_auto_play) != tinyxml2::XML_SUCCESS) { + new_animation->m_auto_play = true; // Default value + } for(tinyxml2::XMLElement *child_element=animation_node->FirstChildElement(); child_element != NULL; child_element = child_element->NextSiblingElement()) { if(strcmp(child_element->Name(), "layer") == 0) { diff --git a/KREngine/KREngine/Classes/KRAnimation.h b/KREngine/KREngine/Classes/KRAnimation.h index 778d154..7462d52 100644 --- a/KREngine/KREngine/Classes/KRAnimation.h +++ b/KREngine/KREngine/Classes/KRAnimation.h @@ -53,10 +53,14 @@ public: void addLayer(KRAnimationLayer *layer); std::map &getLayers(); KRAnimationLayer *getLayer(const char *szName); - + void Start(); + void Stop(); + void Restart(); private: std::map m_layers; + bool m_auto_play; + bool m_loop; }; diff --git a/KREngine/KREngine/Classes/KRAnimationAttribute.cpp b/KREngine/KREngine/Classes/KRAnimationAttribute.cpp index 8a03351..857ee78 100644 --- a/KREngine/KREngine/Classes/KRAnimationAttribute.cpp +++ b/KREngine/KREngine/Classes/KRAnimationAttribute.cpp @@ -34,7 +34,7 @@ KRAnimationAttribute::KRAnimationAttribute(KRContext &context) : KRContextObject(context) { - + m_node_attribute = KRNode::KRENGINE_NODE_ATTRIBUTE_NONE; } KRAnimationAttribute::~KRAnimationAttribute() @@ -49,7 +49,41 @@ tinyxml2::XMLElement *KRAnimationAttribute::saveXML( tinyxml2::XMLNode *parent) tinyxml2::XMLNode *n = parent->InsertEndChild(e); e->SetAttribute("curve", m_curve_name.c_str()); e->SetAttribute("target", m_target_name.c_str()); - e->SetAttribute("attribute", m_target_attribute_name.c_str()); + char *szAttribute = "none"; + switch(m_node_attribute) { + case KRNode::KRENGINE_NODE_ATTRIBUTE_NONE: + szAttribute = "none"; + break; + case KRNode::KRENGINE_NODE_ATTRIBUTE_TRANSLATE_X: + szAttribute = "translate_x"; + break; + case KRNode::KRENGINE_NODE_ATTRIBUTE_TRANSLATE_Y: + szAttribute = "translate_y"; + break; + case KRNode::KRENGINE_NODE_ATTRIBUTE_TRANSLATE_Z: + szAttribute = "translate_z"; + break; + case KRNode::KRENGINE_NODE_ATTRIBUTE_SCALE_X: + szAttribute = "scale_x"; + break; + case KRNode::KRENGINE_NODE_ATTRIBUTE_SCALE_Y: + szAttribute = "scale_y"; + break; + case KRNode::KRENGINE_NODE_ATTRIBUTE_SCALE_Z: + szAttribute = "scale_z"; + break; + case KRNode::KRENGINE_NODE_ATTRIBUTE_ROTATE_X: + szAttribute = "rotate_x"; + break; + case KRNode::KRENGINE_NODE_ATTRIBUTE_ROTATE_Y: + szAttribute = "rotate_y"; + break; + case KRNode::KRENGINE_NODE_ATTRIBUTE_ROTATE_Z: + szAttribute = "rotate_z"; + break; + } + + e->SetAttribute("attribute", szAttribute); return e; } @@ -57,7 +91,32 @@ void KRAnimationAttribute::loadXML(tinyxml2::XMLElement *e) { m_curve_name = e->Attribute("curve"); m_target_name = e->Attribute("target"); - m_target_attribute_name = e->Attribute("attribute"); + m_target_attribute_name = KRNode::KRENGINE_NODE_ATTRIBUTE_NONE; + + const char *szAttribute = e->Attribute("attribute"); + if(strcmp(szAttribute, "none") == 0) { + m_target_attribute_name = KRNode::KRENGINE_NODE_ATTRIBUTE_NONE; + } else if(strcmp(szAttribute, "translate_x") == 0) { + m_target_attribute_name = KRNode::KRENGINE_NODE_ATTRIBUTE_TRANSLATE_X; + } else if(strcmp(szAttribute, "translate_y") == 0) { + m_target_attribute_name = KRNode::KRENGINE_NODE_ATTRIBUTE_TRANSLATE_Y; + } else if(strcmp(szAttribute, "translate_z") == 0) { + m_target_attribute_name = KRNode::KRENGINE_NODE_ATTRIBUTE_TRANSLATE_Z; + } else if(strcmp(szAttribute, "rotate_x") == 0) { + m_target_attribute_name = KRNode::KRENGINE_NODE_ATTRIBUTE_ROTATE_X; + } else if(strcmp(szAttribute, "rotate_y") == 0) { + m_target_attribute_name = KRNode::KRENGINE_NODE_ATTRIBUTE_ROTATE_Y; + } else if(strcmp(szAttribute, "rotate_z") == 0) { + m_target_attribute_name = KRNode::KRENGINE_NODE_ATTRIBUTE_ROTATE_Z; + } else if(strcmp(szAttribute, "scale_x") == 0) { + m_target_attribute_name = KRNode::KRENGINE_NODE_ATTRIBUTE_SCALE_X; + } else if(strcmp(szAttribute, "scale_y") == 0) { + m_target_attribute_name = KRNode::KRENGINE_NODE_ATTRIBUTE_SCALE_Y; + } else if(strcmp(szAttribute, "scale_z") == 0) { + m_target_attribute_name = KRNode::KRENGINE_NODE_ATTRIBUTE_SCALE_Z; + } else { + m_target_attribute_name = KRNode::KRENGINE_NODE_ATTRIBUTE_NONE; + } } std::string KRAnimationAttribute::getTargetName() const diff --git a/KREngine/KREngine/Classes/KRAnimationAttribute.h b/KREngine/KREngine/Classes/KRAnimationAttribute.h index 2eb0f60..e0c9056 100644 --- a/KREngine/KREngine/Classes/KRAnimationAttribute.h +++ b/KREngine/KREngine/Classes/KRAnimationAttribute.h @@ -35,6 +35,7 @@ #import "KRContextObject.h" #import "KREngine-common.h" #import "tinyxml2.h" +#import "KRNode.h" class KRAnimationAttribute : public KRContextObject { public: @@ -56,6 +57,7 @@ public: private: std::string m_target_name; std::string m_curve_name; + KRNode::node_attribute_type m_node_attribute; std::string m_target_attribute_name; }; diff --git a/KREngine/KREngine/Classes/KRAnimationCurve.cpp b/KREngine/KREngine/Classes/KRAnimationCurve.cpp index 0e31df7..4fbda0e 100644 --- a/KREngine/KREngine/Classes/KRAnimationCurve.cpp +++ b/KREngine/KREngine/Classes/KRAnimationCurve.cpp @@ -30,3 +30,112 @@ // #include "KRAnimationCurve.h" + +KRAnimationCurve::KRAnimationCurve(KRContext &context, std::string name) : KRResource(context, name) +{ + m_pData = new KRDataBlock(); + m_pData->expand(sizeof(animation_curve_header)); + animation_curve_header *header = (animation_curve_header *)m_pData->getStart(); + strcpy(header->szTag, "KRCURVE1.0 "); + header->frame_rate = 30.0f; + header->frame_start = 0; + header->frame_count = 0; +} + +KRAnimationCurve::~KRAnimationCurve() +{ + m_pData->unload(); + delete m_pData; +} + +bool KRAnimationCurve::load(KRDataBlock *data) +{ + m_pData->unload(); + delete m_pData; + m_pData = data; + return true; +} + +std::string KRAnimationCurve::getExtension() { + return "kranimationcurve"; +} + +bool KRAnimationCurve::save(const std::string& path) { + return m_pData->save(path); +} + + +KRAnimationCurve *KRAnimationCurve::Load(KRContext &context, const std::string &name, KRDataBlock *data) +{ + KRAnimationCurve *new_animation_curve = new KRAnimationCurve(context, name); + if(new_animation_curve->load(data)) { + return new_animation_curve; + } else { + delete new_animation_curve; + delete data; + return NULL; + } +} + +int KRAnimationCurve::getFrameCount() +{ + return ((animation_curve_header *)m_pData->getStart())->frame_count; +} + +void KRAnimationCurve::setFrameCount(int frame_count) +{ + int prev_frame_count = getFrameCount(); + if(frame_count != prev_frame_count) { + float fill_value = 0.0f; + if(prev_frame_count > 0) { + fill_value = getValue(prev_frame_count - 1); + } + m_pData->expand(sizeof(animation_curve_header) + sizeof(float) * frame_count - m_pData->getSize()); + float *frame_data = (float *)((char *)m_pData->getStart() + sizeof(animation_curve_header)); + for(int frame_number=prev_frame_count; frame_number < frame_count; frame_number++) { + frame_data[frame_number] = fill_value; + } + ((animation_curve_header *)m_pData->getStart())->frame_count = frame_count; + } +} + +float KRAnimationCurve::getFrameRate() +{ + return ((animation_curve_header *)m_pData->getStart())->frame_rate; +} + +void KRAnimationCurve::setFrameRate(float frame_rate) +{ + ((animation_curve_header *)m_pData->getStart())->frame_rate = frame_rate; +} + +int KRAnimationCurve::getFrameStart() +{ + return ((animation_curve_header *)m_pData->getStart())->frame_start; +} + +void KRAnimationCurve::setFrameStart(int frame_number) +{ + ((animation_curve_header *)m_pData->getStart())->frame_start = frame_number; +} + +float KRAnimationCurve::getValue(int frame_number) +{ + int clamped_frame = frame_number; + if(frame_number < 0) { + clamped_frame = frame_number; + } else if(frame_number > getFrameCount()) { + clamped_frame = getFrameCount(); + } + float *frame_data = (float *)((char *)m_pData->getStart() + sizeof(animation_curve_header)); + return frame_data[clamped_frame]; +} + +void KRAnimationCurve::setValue(int frame_number, float value) +{ + if(frame_number >= 0 && frame_number < getFrameCount()) { + float *frame_data = (float *)((char *)m_pData->getStart() + sizeof(animation_curve_header)); + frame_data[frame_number] = value; + } +} + diff --git a/KREngine/KREngine/Classes/KRAnimationCurve.h b/KREngine/KREngine/Classes/KRAnimationCurve.h index 632deb1..b6b6290 100644 --- a/KREngine/KREngine/Classes/KRAnimationCurve.h +++ b/KREngine/KREngine/Classes/KRAnimationCurve.h @@ -32,6 +32,46 @@ #ifndef KRANIMATIONCURVE_H #define KRANIMATIONCURVE_H +#import "KREngine-common.h" +#import "KRContextObject.h" +#import "KRDataBlock.h" +#import "KRResource.h" +#import + +class KRAnimationCurve : public KRResource { + +public: + KRAnimationCurve(KRContext &context, std::string name); + virtual ~KRAnimationCurve(); + + virtual std::string getExtension(); + virtual bool save(const std::string& path); + virtual bool load(KRDataBlock *data); + + float getFrameRate(); + void setFrameRate(float frame_rate); + int getFrameStart(); + void setFrameStart(int frame_number); + int getFrameCount(); + void setFrameCount(int frame_count); + float getValue(int frame_number); + void setValue(int frame_number, float value); + + + static KRAnimationCurve *Load(KRContext &context, const std::string &name, KRDataBlock *data); + + +private: + KRDataBlock *m_pData; + + typedef struct { + char szTag[16]; + float frame_rate; + int32_t frame_start; + int32_t frame_count; + } animation_curve_header; + +}; #endif diff --git a/KREngine/KREngine/Classes/KRAnimationCurveKey.cpp b/KREngine/KREngine/Classes/KRAnimationCurveManager.cpp similarity index 58% rename from KREngine/KREngine/Classes/KRAnimationCurveKey.cpp rename to KREngine/KREngine/Classes/KRAnimationCurveManager.cpp index 46dc44a..73cbbbd 100644 --- a/KREngine/KREngine/Classes/KRAnimationCurveKey.cpp +++ b/KREngine/KREngine/Classes/KRAnimationCurveManager.cpp @@ -1,5 +1,5 @@ // -// KRAnimationCurveKey.cpp +// KRAnimationCurveManager.cpp // KREngine // // Copyright 2012 Kearwood Gilbert. All rights reserved. @@ -29,4 +29,36 @@ // or implied, of Kearwood Gilbert. // -#include "KRAnimationCurveKey.h" +#include "KRAnimationCurveManager.h" +#include "KRAnimationCurve.h" + +KRAnimationCurveManager::KRAnimationCurveManager(KRContext &context) : KRContextObject(context) +{ + +} + +KRAnimationCurveManager::~KRAnimationCurveManager() { + for(map::iterator itr = m_animationCurves.begin(); itr != m_animationCurves.end(); ++itr){ + delete (*itr).second; + } +} + +KRAnimationCurve *KRAnimationCurveManager::loadAnimationCurve(const char *szName, KRDataBlock *data) { + KRAnimationCurve *pAnimationCurve = KRAnimationCurve::Load(*m_pContext, szName, data); + m_animationCurves[szName] = pAnimationCurve; + return pAnimationCurve; +} + +KRAnimationCurve *KRAnimationCurveManager::getAnimationCurve(const char *szName) { + return m_animationCurves[szName]; +} + +std::map &KRAnimationCurveManager::getAnimationCurves() { + return m_animationCurves; +} + +void KRAnimationCurveManager::addAnimationCurve(KRAnimationCurve *new_animation_curve) +{ + m_animationCurves[new_animation_curve->getName()] = new_animation_curve; +} + diff --git a/KREngine/KREngine/Classes/KRAnimationCurveKey.h b/KREngine/KREngine/Classes/KRAnimationCurveManager.h similarity index 67% rename from KREngine/KREngine/Classes/KRAnimationCurveKey.h rename to KREngine/KREngine/Classes/KRAnimationCurveManager.h index 770ccd5..7944722 100644 --- a/KREngine/KREngine/Classes/KRAnimationCurveKey.h +++ b/KREngine/KREngine/Classes/KRAnimationCurveManager.h @@ -1,5 +1,5 @@ // -// KRAnimationCurveKey.h +// KRAnimationCurveManager.h // KREngine // // Copyright 2012 Kearwood Gilbert. All rights reserved. @@ -29,8 +29,33 @@ // or implied, of Kearwood Gilbert. // -#ifndef KRANIMATIONCURVEKEY_H -#define KRANIMATIONCURVEKEY_H +#ifndef KRANIMATIONCURVEMANAGER_H +#define KRANIMATIONCURVEMANAGER_H + +#import "KREngine-common.h" + +#include "KRAnimationCurve.h" +#include "KRContextObject.h" +#include "KRDataBlock.h" + +#include +#import + +using std::map; + +class KRAnimationCurveManager : public KRContextObject { +public: + KRAnimationCurveManager(KRContext &context); + virtual ~KRAnimationCurveManager(); + + KRAnimationCurve *loadAnimationCurve(const char *szName, KRDataBlock *data); + KRAnimationCurve *getAnimationCurve(const char *szName); + void addAnimationCurve(KRAnimationCurve *new_animation_curve); + std::map &getAnimationCurves(); + +private: + map m_animationCurves; +}; diff --git a/KREngine/KREngine/Classes/KRContext.cpp b/KREngine/KREngine/Classes/KRContext.cpp index dd4a1e0..b4228ff 100644 --- a/KREngine/KREngine/Classes/KRContext.cpp +++ b/KREngine/KREngine/Classes/KRContext.cpp @@ -34,6 +34,7 @@ KRContext::KRContext() { m_pModelManager = new KRModelManager(*this); m_pSceneManager = new KRSceneManager(*this); m_pAnimationManager = new KRAnimationManager(*this); + m_pAnimationCurveManager = new KRAnimationCurveManager(*this); m_bDetectedExtensions = false; m_current_frame = 0; m_absolute_time = 0.0f; @@ -71,6 +72,11 @@ KRContext::~KRContext() { m_pAnimationManager = NULL; } + if(m_pAnimationCurveManager) { + delete m_pAnimationCurveManager; + m_pAnimationCurveManager = NULL; + } + // The bundles must be destroyed last, as the other objects may be using mmap'ed data from bundles if(m_pBundleManager) { delete m_pBundleManager; @@ -99,6 +105,9 @@ KRModelManager *KRContext::getModelManager() { KRAnimationManager *KRContext::getAnimationManager() { return m_pAnimationManager; } +KRAnimationCurveManager *KRContext::getAnimationCurveManager() { + return m_pAnimationCurveManager; +} void KRContext::loadResource(const std::string &file_name, KRDataBlock *data) { std::string name = KRResource::GetFileBase(file_name); diff --git a/KREngine/KREngine/Classes/KRContext.h b/KREngine/KREngine/Classes/KRContext.h index a00c23a..4df81e9 100644 --- a/KREngine/KREngine/Classes/KRContext.h +++ b/KREngine/KREngine/Classes/KRContext.h @@ -17,6 +17,7 @@ #import "KRShaderManager.h" #import "KRModelManager.h" #import "KRAnimationManager.h" +#import "KRAnimationCurveManager.h" class KRContext { public: @@ -45,6 +46,7 @@ public: KRShaderManager *getShaderManager(); KRModelManager *getModelManager(); KRAnimationManager *getAnimationManager(); + KRAnimationCurveManager *getAnimationCurveManager(); KRCamera *createCamera(int width, int height); @@ -72,6 +74,7 @@ private: KRShaderManager *m_pShaderManager; KRModelManager *m_pModelManager; KRAnimationManager *m_pAnimationManager; + KRAnimationCurveManager *m_pAnimationCurveManager; void detectExtensions(); bool m_bDetectedExtensions; diff --git a/KREngine/KREngine/Classes/KRDataBlock.h b/KREngine/KREngine/Classes/KRDataBlock.h index fa9248a..0fbcdef 100644 --- a/KREngine/KREngine/Classes/KRDataBlock.h +++ b/KREngine/KREngine/Classes/KRDataBlock.h @@ -49,7 +49,7 @@ public: // Append data to the end of the block, increasing the size of the block and making it read-write. void append(void *data, size_t size); - // Expand the data block, and switch it to read-write mode. Note - this may result in a mmap'ed file being copied to malloc'ed ram and then closed + // Expand or shrink the data block, and switch it to read-write mode. Note - this may result in a mmap'ed file being copied to malloc'ed ram and then closed void expand(size_t size); // Unload a file, releasing any mmap'ed file handles or malloc'ed ram that was in use diff --git a/KREngine/KREngine/Classes/KRNode.cpp b/KREngine/KREngine/Classes/KRNode.cpp index 4830c00..d0bad7a 100644 --- a/KREngine/KREngine/Classes/KRNode.cpp +++ b/KREngine/KREngine/Classes/KRNode.cpp @@ -248,4 +248,37 @@ void KRNode::physicsUpdate(float deltaTime) bool KRNode::hasPhysics() { return false; +} + +void KRNode::SetAttribute(node_attribute_type attrib, float v) +{ + switch(attrib) { + case KRENGINE_NODE_ATTRIBUTE_TRANSLATE_X: + setLocalTranslation(KRVector3(v, m_localTranslation.y, m_localTranslation.z)); + break; + case KRENGINE_NODE_ATTRIBUTE_TRANSLATE_Y: + setLocalTranslation(KRVector3(m_localTranslation.x, v, m_localTranslation.z)); + break; + case KRENGINE_NODE_ATTRIBUTE_TRANSLATE_Z: + setLocalTranslation(KRVector3(m_localTranslation.x, m_localTranslation.y, v)); + break; + case KRENGINE_NODE_ATTRIBUTE_SCALE_X: + setLocalScale(KRVector3(v, m_localScale.y, m_localScale.z)); + break; + case KRENGINE_NODE_ATTRIBUTE_SCALE_Y: + setLocalScale(KRVector3(m_localScale.x, v, m_localScale.z)); + break; + case KRENGINE_NODE_ATTRIBUTE_SCALE_Z: + setLocalScale(KRVector3(m_localScale.x, m_localScale.y, v)); + break; + case KRENGINE_NODE_ATTRIBUTE_ROTATE_X: + setLocalRotation(KRVector3(v, m_localRotation.y, m_localRotation.z)); + break; + case KRENGINE_NODE_ATTRIBUTE_ROTATE_Y: + setLocalRotation(KRVector3(m_localRotation.x, v, m_localRotation.z)); + break; + case KRENGINE_NODE_ATTRIBUTE_ROTATE_Z: + setLocalRotation(KRVector3(m_localRotation.x, m_localRotation.y, v)); + break; + } } \ No newline at end of file diff --git a/KREngine/KREngine/Classes/KRNode.h b/KREngine/KREngine/Classes/KRNode.h index 4c10c41..a8c38ec 100644 --- a/KREngine/KREngine/Classes/KRNode.h +++ b/KREngine/KREngine/Classes/KRNode.h @@ -68,6 +68,21 @@ public: virtual KRAABB getBounds(); const KRMat4 &getModelMatrix(); + enum node_attribute_type { + KRENGINE_NODE_ATTRIBUTE_NONE, + KRENGINE_NODE_ATTRIBUTE_TRANSLATE_X, + KRENGINE_NODE_ATTRIBUTE_TRANSLATE_Y, + KRENGINE_NODE_ATTRIBUTE_TRANSLATE_Z, + KRENGINE_NODE_ATTRIBUTE_SCALE_X, + KRENGINE_NODE_ATTRIBUTE_SCALE_Y, + KRENGINE_NODE_ATTRIBUTE_SCALE_Z, + KRENGINE_NODE_ATTRIBUTE_ROTATE_X, + KRENGINE_NODE_ATTRIBUTE_ROTATE_Y, + KRENGINE_NODE_ATTRIBUTE_ROTATE_Z + }; + + void SetAttribute(node_attribute_type attrib, float v); + KRScene &getScene(); #if TARGET_OS_IPHONE diff --git a/KREngine/KREngine/Classes/KRResource+fbx.cpp b/KREngine/KREngine/Classes/KRResource+fbx.cpp index 0dd5e46..f9fbb6e 100644 --- a/KREngine/KREngine/Classes/KRResource+fbx.cpp +++ b/KREngine/KREngine/Classes/KRResource+fbx.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -41,14 +42,31 @@ void InitializeSdkObjects(KFbxSdkManager*& pSdkManager, KFbxScene*& pScene); void DestroySdkObjects(KFbxSdkManager* pSdkManager); bool LoadScene(KFbxSdkManager* pSdkManager, KFbxDocument* pScene, const char* pFilename); KRAnimation *LoadAnimation(KRContext &context, FbxAnimStack* pAnimStack); +KRAnimationCurve *LoadAnimationCurve(KRContext &context, FbxAnimCurve* pAnimCurve); KRAnimationLayer *LoadAnimationLayer(KRContext &context, FbxAnimLayer *pAnimLayer); void LoadNode(KFbxScene* pFbxScene, KRNode *parent_node, std::vector &resources, FbxGeometryConverter *pGeometryConverter, KFbxNode* pNode); //void BakeNode(KFbxNode* pNode); KRNode *LoadMesh(KRNode *parent_node, std::vector &resources, FbxGeometryConverter *pGeometryConverter, KFbxNode* pNode); KRNode *LoadLight(KRNode *parent_node, std::vector &resources, KFbxNode* pNode); +std::string GetFbxObjectName(FbxObject *obj, char *prefix); const float KRAKEN_FBX_ANIMATION_FRAMERATE = 30.0f; // FINDME - This should be configurable + +std::string GetFbxObjectName(FbxObject *obj, char *prefix) +{ + + std::stringstream st; + st << prefix; + st << obj->GetUniqueID(); + if(strlen(obj->GetName()) != 0) { + st << " ("; + st << obj->GetName(); + st << ")"; + } + return st.str(); +} + std::vector KRResource::LoadFbx(KRContext &context, const std::string& path) { @@ -80,12 +98,20 @@ std::vector KRResource::LoadFbx(KRContext &context, const std::str // ----====---- Import Animation Layers ----====---- - int animation_count = pFbxScene->GetSrcObjectCount(FBX_TYPE(FbxAnimStack)); + int animation_count = pFbxScene->GetSrcObjectCount(); for(int i = 0; i < animation_count; i++) { // FbxAnimStack* pAnimStack = FbxCast(pFbxScene->GetSrcObject(FBX_TYPE(FbxAnimStack), i)); KRAnimation *new_animation = LoadAnimation(context, pFbxScene->GetSrcObject(i)); context.getAnimationManager()->addAnimation(new_animation); - resources.push_back(LoadAnimation(context, pFbxScene->GetSrcObject(i))); + resources.push_back(new_animation); + } + + // ----====---- Import Animation Curves ----====---- + int curve_count = pFbxScene->GetSrcObjectCount(); + for(int i=0; i < curve_count; i++) { + KRAnimationCurve *new_curve = LoadAnimationCurve(context, pFbxScene->GetSrcObject(i)); + context.getAnimationCurveManager()->addAnimationCurve(new_curve); + resources.push_back(new_curve); } // ----====---- Import Scene Graph Nodes ----====---- @@ -101,6 +127,19 @@ std::vector KRResource::LoadFbx(KRContext &context, const std::str DestroySdkObjects(lSdkManager); + + // FINDME - HACK - This logic removes the animations and animation curves from their manager objects so they don't get dealloced twice. In the future, we should keep all objects in their manager objects while importing and just return a KRContext containing all the managers. + for(std::vector::iterator resource_itr=resources.begin(); resource_itr != resources.end(); resource_itr++) { + KRAnimation *animation = dynamic_cast(*resource_itr); + KRAnimationCurve *animation_curve = dynamic_cast(*resource_itr); + if(animation) { + context.getAnimationManager()->getAnimations().erase(animation->getName()); + } + if(animation_curve) { + context.getAnimationCurveManager()->getAnimationCurves().erase(animation_curve->getName()); + } + } + return resources; } @@ -273,8 +312,6 @@ bool LoadScene(KFbxSdkManager* pSdkManager, KFbxDocument* pScene, const char* pF KRAnimation *LoadAnimation(KRContext &context, FbxAnimStack* pAnimStack) { - - printf("Loading animation: \"%s\"\n", pAnimStack->GetName()); KRAnimation *new_animation = new KRAnimation(context, pAnimStack->GetName()); @@ -285,6 +322,38 @@ KRAnimation *LoadAnimation(KRContext &context, FbxAnimStack* pAnimStack) return new_animation; } +KRAnimationCurve *LoadAnimationCurve(KRContext &context, FbxAnimCurve* pAnimCurve) +{ + std::string name = GetFbxObjectName(pAnimCurve, "fbx_curve"); + printf("Loading animation curve: \"%s\"\n", name.c_str()); + FbxTimeSpan time_span; + if(!pAnimCurve->GetTimeInterval(time_span)) { + printf(" ERROR: Failed to get time interval.\n"); + return NULL; + } + + float frame_rate = 30.0f; // FINDME, TODO - This needs to be dynamic + int frame_start = time_span.GetStart().GetSecondDouble() * frame_rate; + int frame_count = (time_span.GetStop().GetSecondDouble() * frame_rate) - frame_start; + + KRAnimationCurve *new_curve = new KRAnimationCurve(context, name); + new_curve->setFrameRate(frame_rate); + new_curve->setFrameStart(frame_start); + new_curve->setFrameCount(frame_count); + + // Resample animation curve + int last_frame = 0; // Used by FBX sdk for faster keyframe searches + for(int frame_number=0; frame_number < frame_count; frame_number++) { + float frame_seconds = (frame_start + frame_number) / frame_rate; + FbxTime frame_time; + frame_time.SetSecondDouble(frame_seconds); + float frame_value = pAnimCurve->Evaluate(frame_time, &last_frame); + //printf(" Frame %i / %i: %.6f\n", frame_number, frame_count, frame_value); + new_curve->setValue(frame_number, frame_value); + } + + return new_curve; +} KRAnimationLayer *LoadAnimationLayer(KRContext &context, FbxAnimLayer *pAnimLayer) { @@ -466,7 +535,7 @@ void LoadNode(KFbxScene* pFbxScene, KRNode *parent_node, std::vectorLclRotation.GetCurve(pFbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_X); if(pAnimCurve) { KRAnimationAttribute *new_attribute = new KRAnimationAttribute(parent_node->getContext()); - new_attribute->setCurveName(pAnimCurve->GetName()); + new_attribute->setCurveName(GetFbxObjectName(pAnimCurve, "fbx_curve")); new_attribute->setTargetName(pNode->GetName()); new_attribute->setTargetAttributeName("rotate_x"); pAnimationLayer->addAttribute(new_attribute); @@ -475,7 +544,7 @@ void LoadNode(KFbxScene* pFbxScene, KRNode *parent_node, std::vectorLclRotation.GetCurve(pFbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y); if(pAnimCurve) { KRAnimationAttribute *new_attribute = new KRAnimationAttribute(parent_node->getContext()); - new_attribute->setCurveName(pAnimCurve->GetName()); + new_attribute->setCurveName(GetFbxObjectName(pAnimCurve, "fbx_curve")); new_attribute->setTargetName(pNode->GetName()); new_attribute->setTargetAttributeName("rotate_y"); pAnimationLayer->addAttribute(new_attribute); @@ -484,7 +553,7 @@ void LoadNode(KFbxScene* pFbxScene, KRNode *parent_node, std::vectorLclRotation.GetCurve(pFbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z); if(pAnimCurve) { KRAnimationAttribute *new_attribute = new KRAnimationAttribute(parent_node->getContext()); - new_attribute->setCurveName(pAnimCurve->GetName()); + new_attribute->setCurveName(GetFbxObjectName(pAnimCurve, "fbx_curve")); new_attribute->setTargetName(pNode->GetName()); new_attribute->setTargetAttributeName("rotate_z"); pAnimationLayer->addAttribute(new_attribute); @@ -493,7 +562,7 @@ void LoadNode(KFbxScene* pFbxScene, KRNode *parent_node, std::vectorLclTranslation.GetCurve(pFbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_X); if(pAnimCurve) { KRAnimationAttribute *new_attribute = new KRAnimationAttribute(parent_node->getContext()); - new_attribute->setCurveName(pAnimCurve->GetName()); + new_attribute->setCurveName(GetFbxObjectName(pAnimCurve, "fbx_curve")); new_attribute->setTargetName(pNode->GetName()); new_attribute->setTargetAttributeName("translate_x"); pAnimationLayer->addAttribute(new_attribute); @@ -502,7 +571,7 @@ void LoadNode(KFbxScene* pFbxScene, KRNode *parent_node, std::vectorLclTranslation.GetCurve(pFbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y); if(pAnimCurve) { KRAnimationAttribute *new_attribute = new KRAnimationAttribute(parent_node->getContext()); - new_attribute->setCurveName(pAnimCurve->GetName()); + new_attribute->setCurveName(GetFbxObjectName(pAnimCurve, "fbx_curve")); new_attribute->setTargetName(pNode->GetName()); new_attribute->setTargetAttributeName("translate_y"); pAnimationLayer->addAttribute(new_attribute); @@ -511,7 +580,7 @@ void LoadNode(KFbxScene* pFbxScene, KRNode *parent_node, std::vectorLclTranslation.GetCurve(pFbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z); if(pAnimCurve) { KRAnimationAttribute *new_attribute = new KRAnimationAttribute(parent_node->getContext()); - new_attribute->setCurveName(pAnimCurve->GetName()); + new_attribute->setCurveName(GetFbxObjectName(pAnimCurve, "fbx_curve")); new_attribute->setTargetName(pNode->GetName()); new_attribute->setTargetAttributeName("translate_z"); pAnimationLayer->addAttribute(new_attribute); @@ -520,7 +589,7 @@ void LoadNode(KFbxScene* pFbxScene, KRNode *parent_node, std::vectorLclScaling.GetCurve(pFbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_X); if(pAnimCurve) { KRAnimationAttribute *new_attribute = new KRAnimationAttribute(parent_node->getContext()); - new_attribute->setCurveName(pAnimCurve->GetName()); + new_attribute->setCurveName(GetFbxObjectName(pAnimCurve, "fbx_curve")); new_attribute->setTargetName(pNode->GetName()); new_attribute->setTargetAttributeName("scale_x"); pAnimationLayer->addAttribute(new_attribute); @@ -529,7 +598,7 @@ void LoadNode(KFbxScene* pFbxScene, KRNode *parent_node, std::vectorLclScaling.GetCurve(pFbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y); if(pAnimCurve) { KRAnimationAttribute *new_attribute = new KRAnimationAttribute(parent_node->getContext()); - new_attribute->setCurveName(pAnimCurve->GetName()); + new_attribute->setCurveName(GetFbxObjectName(pAnimCurve, "fbx_curve")); new_attribute->setTargetName(pNode->GetName()); new_attribute->setTargetAttributeName("scale_y"); pAnimationLayer->addAttribute(new_attribute); @@ -538,7 +607,7 @@ void LoadNode(KFbxScene* pFbxScene, KRNode *parent_node, std::vectorLclScaling.GetCurve(pFbxAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z); if(pAnimCurve) { KRAnimationAttribute *new_attribute = new KRAnimationAttribute(parent_node->getContext()); - new_attribute->setCurveName(pAnimCurve->GetName()); + new_attribute->setCurveName(GetFbxObjectName(pAnimCurve, "fbx_curve")); new_attribute->setTargetName(pNode->GetName()); new_attribute->setTargetAttributeName("scale_z"); pAnimationLayer->addAttribute(new_attribute);