| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
- // All rights reserved.
- // Code licensed under the BSD License.
- // http://www.anki3d.org/LICENSE
- #include <AnKi/Resource/AnimationResource.h>
- #include <AnKi/Util/Xml.h>
- namespace anki {
- Error AnimationResource::load(const ResourceFilename& filename, [[maybe_unused]] Bool async)
- {
- m_startTime = kMaxSecond;
- Second maxTime = kMinSecond;
- // Document
- ResourceXmlDocument doc;
- ANKI_CHECK(openFileParseXml(filename, doc));
- XmlElement rootel;
- ANKI_CHECK(doc.getChildElement("animation", rootel));
- // Count the number of identity keys. If all of the keys are identities drop a vector
- U identPosCount = 0;
- U identRotCount = 0;
- U identScaleCount = 0;
- // <channels>
- XmlElement channelsEl;
- ANKI_CHECK(rootel.getChildElement("channels", channelsEl));
- XmlElement chEl;
- ANKI_CHECK(channelsEl.getChildElement("channel", chEl));
- U32 channelCount = 0;
- ANKI_CHECK(chEl.getSiblingElementsCount(channelCount));
- ++channelCount;
- if(channelCount == 0)
- {
- ANKI_RESOURCE_LOGE("Didn't found any channels");
- return Error::kUserData;
- }
- m_channels.resize(channelCount);
- // For all channels
- channelCount = 0;
- do
- {
- AnimationChannel& ch = m_channels[channelCount];
- // <name>
- CString strtmp;
- ANKI_CHECK(chEl.getAttributeText("name", strtmp));
- ch.m_name = strtmp;
- XmlElement keysEl, keyEl;
- // <positionKeys>
- ANKI_CHECK(chEl.getChildElementOptional("positionKeys", keysEl));
- if(keysEl)
- {
- ANKI_CHECK(keysEl.getChildElement("key", keyEl));
- U32 count = 0;
- ANKI_CHECK(keyEl.getSiblingElementsCount(count));
- ++count;
- ch.m_positions.resize(count);
- count = 0;
- do
- {
- AnimationKeyframe<Vec3>& key = ch.m_positions[count++];
- // time
- ANKI_CHECK(keyEl.getAttributeNumber("time", key.m_time));
- m_startTime = min(m_startTime, key.m_time);
- maxTime = max(maxTime, key.m_time);
- // value
- ANKI_CHECK(keyEl.getNumbers(key.m_value));
- // Check ident
- if(key.m_value == Vec3(0.0))
- {
- ++identPosCount;
- }
- // Move to next
- ANKI_CHECK(keyEl.getNextSiblingElement("key", keyEl));
- } while(keyEl);
- }
- // <rotationKeys>
- ANKI_CHECK(chEl.getChildElementOptional("rotationKeys", keysEl));
- if(keysEl)
- {
- ANKI_CHECK(keysEl.getChildElement("key", keyEl));
- U32 count = 0;
- ANKI_CHECK(keyEl.getSiblingElementsCount(count));
- ++count;
- ch.m_rotations.resize(count);
- count = 0;
- do
- {
- AnimationKeyframe<Quat>& key = ch.m_rotations[count++];
- // time
- ANKI_CHECK(keyEl.getAttributeNumber("time", key.m_time));
- m_startTime = min(m_startTime, key.m_time);
- maxTime = max(maxTime, key.m_time);
- // value
- ANKI_CHECK(keyEl.getNumbers(key.m_value));
- // Check ident
- if(key.m_value == Quat::getIdentity())
- {
- ++identRotCount;
- }
- // Move to next
- ANKI_CHECK(keyEl.getNextSiblingElement("key", keyEl));
- } while(keyEl);
- }
- // <scalingKeys>
- ANKI_CHECK(chEl.getChildElementOptional("scaleKeys", keysEl));
- if(keysEl)
- {
- ANKI_CHECK(keysEl.getChildElement("key", keyEl));
- U32 count = 0;
- ANKI_CHECK(keyEl.getSiblingElementsCount(count));
- ++count;
- ch.m_scales.resize(count);
- count = 0;
- do
- {
- AnimationKeyframe<F32>& key = ch.m_scales[count++];
- // time
- ANKI_CHECK(keyEl.getAttributeNumber("time", key.m_time));
- m_startTime = std::min(m_startTime, key.m_time);
- maxTime = std::max(maxTime, key.m_time);
- // value
- ANKI_CHECK(keyEl.getNumber(key.m_value));
- // Check ident
- if(isZero(key.m_value - 1.0f))
- {
- ++identScaleCount;
- }
- // Move to next
- ANKI_CHECK(keyEl.getNextSiblingElement("key", keyEl));
- } while(keyEl);
- }
- // Remove identity vectors
- if(identPosCount == ch.m_positions.getSize())
- {
- ch.m_positions.destroy();
- }
- if(identRotCount == ch.m_rotations.getSize())
- {
- ch.m_rotations.destroy();
- }
- if(identScaleCount == ch.m_scales.getSize())
- {
- ch.m_scales.destroy();
- }
- // Move to next channel
- ++channelCount;
- ANKI_CHECK(chEl.getNextSiblingElement("channel", chEl));
- } while(chEl);
- m_duration = maxTime - m_startTime;
- return Error::kNone;
- }
- void AnimationResource::interpolate(U32 channelIndex, Second time, Vec3& pos, Quat& rot, F32& scale) const
- {
- pos = Vec3(0.0f);
- rot = Quat::getIdentity();
- scale = 1.0f;
- if(time < m_startTime) [[unlikely]]
- {
- return;
- }
- // Audjust time
- if(time > m_startTime + m_duration)
- {
- time = mod(time - m_startTime, m_duration) + m_startTime;
- }
- ANKI_ASSERT(time >= m_startTime && time <= m_startTime + m_duration);
- ANKI_ASSERT(channelIndex < m_channels.getSize());
- const AnimationChannel& channel = m_channels[channelIndex];
- // Position
- if(channel.m_positions.getSize() > 1)
- {
- for(U32 i = 0; i < channel.m_positions.getSize() - 1; ++i)
- {
- const AnimationKeyframe<Vec3>& left = channel.m_positions[i];
- const AnimationKeyframe<Vec3>& right = channel.m_positions[i + 1];
- if(time >= left.m_time && time <= right.m_time)
- {
- const Second u = (time - left.m_time) / (right.m_time - left.m_time);
- pos = linearInterpolate(left.m_value, right.m_value, F32(u));
- break;
- }
- }
- }
- // Rotation
- if(channel.m_rotations.getSize() > 1)
- {
- for(U32 i = 0; i < channel.m_rotations.getSize() - 1; ++i)
- {
- const AnimationKeyframe<Quat>& left = channel.m_rotations[i];
- const AnimationKeyframe<Quat>& right = channel.m_rotations[i + 1];
- if(time >= left.m_time && time <= right.m_time)
- {
- const Second u = (time - left.m_time) / (right.m_time - left.m_time);
- rot = left.m_value.slerp(right.m_value, F32(u));
- break;
- }
- }
- }
- // Scale
- if(channel.m_scales.getSize() > 1)
- {
- for(U32 i = 0; i < channel.m_scales.getSize() - 1; ++i)
- {
- const AnimationKeyframe<F32>& left = channel.m_scales[i];
- const AnimationKeyframe<F32>& right = channel.m_scales[i + 1];
- if(time >= left.m_time && time <= right.m_time)
- {
- const Second u = (time - left.m_time) / (right.m_time - left.m_time);
- scale = linearInterpolate(left.m_value, right.m_value, F32(u));
- break;
- }
- }
- }
- }
- } // end namespace anki
|