/* Object Viewer Qt Copyright (C) 2010 Dzmitry Kamiahin This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "stdpch.h" #include "entity.h" #include // NeL includes #include #include #include #include #include #include #include #include #include #include // Project includes #include "modules.h" using namespace NLMISC; using namespace NL3D; namespace NLQT { CSlotInfo::CSlotInfo() : Animation("empty"), Skeleton("empty"), Offset(0), StartTime(0), EndTime(0), StartBlend(1), EndBlend (1), Smoothness(1), SpeedFactor(1), ClampMode(0), SkeletonInverted(false), Enable(true) { } CSlotInfo &CSlotInfo::operator=(const CSlotInfo &slotInfo) { if ( this != &slotInfo) { Animation = slotInfo.Animation; ClampMode = slotInfo.ClampMode; Enable = slotInfo.Enable; EndBlend = slotInfo.EndBlend; EndTime = slotInfo.EndTime; Offset = slotInfo.Offset; Skeleton = slotInfo.Skeleton; SkeletonInverted = slotInfo.SkeletonInverted; Smoothness = slotInfo.Smoothness; SpeedFactor = slotInfo.SpeedFactor; StartBlend = slotInfo.StartBlend; StartTime = slotInfo.StartTime; } return *this; } CEntity::CEntity(void) : _Name(""), _FileNameShape(""), _FileNameSkeleton(""), _inPlace(false), _incPos(false), _Instance(NULL), _Skeleton(NULL), _PlayList(NULL), _AnimationSet(NULL) { _CharacterScalePos = 1; } CEntity::~CEntity(void) { if (_PlayList != NULL) { _PlayList->resetAllChannels(); Modules::objView().getPlayListManager()->deletePlayList (_PlayList); _PlayList = NULL; } if (_AnimationSet != NULL) { Modules::objView().getDriver()->deleteAnimationSet(_AnimationSet); _AnimationSet = NULL; } if (!_Skeleton.empty()) { _Skeleton.detachSkeletonSon(_Instance); Modules::objView().getScene()->deleteSkeleton(_Skeleton); _Skeleton = NULL; } if (!_Instance.empty()) { Modules::objView().getScene()->deleteInstance(_Instance); _Instance = NULL; } } void CEntity::loadAnimation(std::string &fileName) { uint id = _AnimationSet->addAnimation(fileName.c_str(),CFile::getFilenameWithoutExtension(fileName).c_str()); _AnimationList.push_back(_AnimationSet->getAnimationName(id)); _AnimationSet->build(); if (!_Skeleton.empty()) _PlayList->registerTransform(_Skeleton); else _PlayList->registerTransform(_Instance); } void CEntity::loadSWT(std::string &fileName) { uint id = _AnimationSet->addSkeletonWeight(fileName.c_str(),CFile::getFilenameWithoutExtension(fileName).c_str()); _SWTList.push_back(_AnimationSet->getSkeletonWeightName(id)); } void CEntity::addAnimToPlayList(std::string &name) { _PlayListAnimation.push_back(name); _AnimationStatus.EndAnim = this->getPlayListLength(); _Instance.start(); } void CEntity::removeAnimToPlayList(uint row) { if (row < _PlayListAnimation.size()) _PlayListAnimation.erase(_PlayListAnimation.begin() + row); _AnimationStatus.EndAnim = this->getPlayListLength(); } void CEntity::swapAnimToPlayList(uint row1, uint row2) { if ((row1 < _PlayListAnimation.size()) && (row2 < _PlayListAnimation.size())) std::swap(_PlayListAnimation[row1], _PlayListAnimation[row2]); } void CEntity::playbackAnim(bool play) { _AnimationStatus.PlayAnim = play; if (play) _Instance.start(); else _Instance.freezeHRC(); } void CEntity::reset() { _PlayListAnimation.clear(); _AnimationList.clear(); _SWTList.clear(); _PlayList->resetAllChannels(); } float CEntity::getPlayListLength() { // Accumul all the time float time = 0; for(size_t i = 0; i < _PlayListAnimation.size(); ++i) time += getAnimLength(_PlayListAnimation[i]); return time; } float CEntity::getAnimLength(std::string name) { uint id = _AnimationSet->getAnimationIdByName(name.c_str()); NL3D::UAnimation *anim = _AnimationSet->getAnimation(id); return anim->getEndTime() - anim->getBeginTime(); } void CEntity::update(NL3D::TAnimationTime time) { this->resetChannel(); switch (_AnimationStatus.Mode) { case Mode::PlayList: animatePlayList(time); break; case Mode::Mixer: animateChannelMixer(); break; } } void CEntity::resetChannel() { for(uint i = 0; i < NL3D::CChannelMixer::NumAnimationSlot; ++i) _PlayList->setAnimation(i, UPlayList::empty); } void CEntity::addTransformation (CMatrix ¤t, UAnimation *anim, float begin, float end, UTrack *posTrack, UTrack *rotquatTrack, UTrack *nextPosTrack, UTrack *nextRotquatTrack, bool removeLast) { // In place ? if (_inPlace) { // Just identity current.identity(); } else { // Remove the start of the animation CQuat rotEnd (0,0,0,1); CVector posEnd (0,0,0); if (rotquatTrack) { // Interpolate the rotation rotquatTrack->interpolate (end, rotEnd); } if (posTrack) { // Interpolate the position posTrack->interpolate (end, posEnd); } // Add the final rotation and position CMatrix tmp; tmp.identity (); tmp.setRot (rotEnd); tmp.setPos (posEnd); // Incremental ? if (_incPos) current *= tmp; else current = tmp; if (removeLast) { CQuat rotStart (0,0,0,1); CVector posStart (0,0,0); if (nextRotquatTrack) { // Interpolate the rotation nextRotquatTrack->interpolate (begin, rotStart); } if (nextPosTrack) { // Interpolate the position nextPosTrack->interpolate (begin, posStart); } // Remove the init rotation and position of the next animation tmp.identity (); tmp.setRot (rotStart); tmp.setPos (posStart); tmp.invert (); current *= tmp; // Normalize the mt CVector I = current.getI (); CVector J = current.getJ (); I.z = 0; J.z = 0; J.normalize (); CVector K = I^J; K.normalize (); I = J^K; I.normalize (); tmp.setRot (I, J, K); tmp.setPos (current.getPos ()); current = tmp; } } } void CEntity::animatePlayList(NL3D::TAnimationTime time) { if (!_PlayListAnimation.empty()) { // Animation index uint id = _AnimationSet->getAnimationIdByName(_PlayListAnimation[0].c_str()); // Try channel AnimationSet NL3D::UAnimation *anim = _AnimationSet->getAnimation(id); bool there = false; UTrack *posTrack = NULL; UTrack *rotQuatTrack = NULL; // Current matrix CMatrix current; current.identity(); // read an animation for init matrix rotQuatTrack = anim->getTrackByName("rotquat"); posTrack = anim->getTrackByName("pos"); there = posTrack || rotQuatTrack; // Accumul time float startTime = 0; float endTime = anim->getEndTime() - anim->getBeginTime(); uint index = 0; while (time >= endTime) { index++; if (index < _PlayListAnimation.size()) { id = _AnimationSet->getAnimationIdByName(_PlayListAnimation[index].c_str()); NL3D::UAnimation *newAnim = _AnimationSet->getAnimation(id); UTrack *newPosTrack = newAnim->getTrackByName ("pos"); UTrack *newRotquatTrack = newAnim->getTrackByName ("rotquat"); // Add the transformation addTransformation (current, anim, newAnim->getBeginTime(), anim->getEndTime(), posTrack, rotQuatTrack, newPosTrack, newRotquatTrack, true); anim = newAnim; posTrack = newPosTrack; rotQuatTrack = newRotquatTrack; // Add start time startTime = endTime; endTime = startTime + (anim->getEndTime() - anim->getBeginTime()); } else { // Add the transformation addTransformation (current, anim, 0, anim->getEndTime(), posTrack, rotQuatTrack, NULL, NULL, false); break; } } // Time cropped ? if (index >= _PlayListAnimation.size()) { // Yes index--; id = _AnimationSet->getAnimationIdByName(_PlayListAnimation[index].c_str()); anim = _AnimationSet->getAnimation(id); // End time for last anim startTime = anim->getEndTime() - time; } else { // No // Add the transformation addTransformation (current, anim, 0, anim->getBeginTime() + time - startTime, posTrack, rotQuatTrack, NULL, NULL, false); id = _AnimationSet->getAnimationIdByName(_PlayListAnimation[index].c_str()); anim = _AnimationSet->getAnimation(id); // Final time startTime -= anim->getBeginTime(); } // Set the slot _PlayList->setAnimation(0, id); _PlayList->setTimeOrigin(0, startTime); _PlayList->setSpeedFactor(0, 1.0f); _PlayList->setWeightSmoothness(0, 1.0f); _PlayList->setStartWeight(0, 1, 0); _PlayList->setEndWeight(0, 1, 1); _PlayList->setWrapMode(0, UPlayList::Clamp); // Setup the pos and rot for this shape if (there) { CVector pos = current.getPos(); // If a skeleton model if(!_Skeleton.empty()) { // scale animated pos value with the CFG scale pos *= _CharacterScalePos; _Skeleton.setPos(pos); _Skeleton.setRotQuat(current.getRot()); } else { _Instance.setPos(pos); _Instance.setRotQuat(current.getRot()); } } } } void CEntity::animateChannelMixer() { for (uint i = 0; i < NL3D::CChannelMixer::NumAnimationSlot; ++i) { if (_SlotInfo[i].Enable) { // Set the animation uint animId = _AnimationSet->getAnimationIdByName(_SlotInfo[i].Animation); if (animId == UAnimationSet::NotFound) _PlayList->setAnimation(i, UPlayList::empty); else _PlayList->setAnimation(i, animId); // Set the skeleton weight uint skelId = _AnimationSet->getSkeletonWeightIdByName(_SlotInfo[i].Skeleton); if (skelId == UAnimationSet::NotFound) _PlayList->setSkeletonWeight(i, UPlayList::empty, false); else _PlayList->setSkeletonWeight(i, skelId, _SlotInfo[i].SkeletonInverted); // Set others values _PlayList->setTimeOrigin(i, _SlotInfo[i].Offset); _PlayList->setSpeedFactor(i, _SlotInfo[i].SpeedFactor); _PlayList->setStartWeight(i, _SlotInfo[i].StartBlend, _SlotInfo[i].StartTime); _PlayList->setEndWeight(i, _SlotInfo[i].EndBlend, _SlotInfo[i].EndTime); _PlayList->setWeightSmoothness(i, _SlotInfo[i].Smoothness); // Switch between wrap modes switch (_SlotInfo[i].ClampMode) { case 0: _PlayList->setWrapMode (i, UPlayList::Clamp); break; case 1: _PlayList->setWrapMode (i, UPlayList::Repeat); break; case 2: _PlayList->setWrapMode (i, UPlayList::Disable); break; } } } } } /* namespace NLQT */