ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

anim.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "common/debug.h"
00024 
00025 #include "engines/stark/debug.h"
00026 #include "engines/stark/formats/biffmesh.h"
00027 #include "engines/stark/formats/tm.h"
00028 #include "engines/stark/formats/xrc.h"
00029 
00030 #include "engines/stark/gfx/driver.h"
00031 #include "engines/stark/resources/anim.h"
00032 #include "engines/stark/resources/animscript.h"
00033 #include "engines/stark/resources/bonesmesh.h"
00034 #include "engines/stark/resources/direction.h"
00035 #include "engines/stark/resources/image.h"
00036 #include "engines/stark/resources/item.h"
00037 #include "engines/stark/resources/location.h"
00038 #include "engines/stark/resources/textureset.h"
00039 
00040 #include "engines/stark/services/archiveloader.h"
00041 #include "engines/stark/services/global.h"
00042 #include "engines/stark/services/services.h"
00043 #include "engines/stark/services/settings.h"
00044 #include "engines/stark/services/stateprovider.h"
00045 
00046 #include "engines/stark/model/animhandler.h"
00047 #include "engines/stark/model/skeleton_anim.h"
00048 #include "engines/stark/visual/actor.h"
00049 #include "engines/stark/visual/prop.h"
00050 #include "engines/stark/visual/smacker.h"
00051 
00052 namespace Stark {
00053 namespace Resources {
00054 
00055 Object *Anim::construct(Object *parent, byte subType, uint16 index, const Common::String &name) {
00056     switch (subType) {
00057     case kAnimImages:
00058         return new AnimImages(parent, subType, index, name);
00059     case kAnimProp:
00060         return new AnimProp(parent, subType, index, name);
00061     case kAnimVideo:
00062         return new AnimVideo(parent, subType, index, name);
00063     case kAnimSkeleton:
00064         return new AnimSkeleton(parent, subType, index, name);
00065     default:
00066         error("Unknown anim subtype %d", subType);
00067     }
00068 }
00069 
00070 Anim::~Anim() {
00071 }
00072 
00073 Anim::Anim(Object *parent, byte subType, uint16 index, const Common::String &name) :
00074         Object(parent, subType, index, name),
00075         _activity(0),
00076         _currentFrame(0),
00077         _numFrames(0),
00078         _refCount(0) {
00079     _type = TYPE;
00080 }
00081 
00082 void Anim::readData(Formats::XRCReadStream *stream) {
00083     _activity = stream->readUint32LE();
00084     _numFrames = stream->readUint32LE();
00085 }
00086 
00087 void Anim::selectFrame(uint32 frameIndex) {
00088 }
00089 
00090 uint32 Anim::getActivity() const {
00091     return _activity;
00092 }
00093 
00094 void Anim::applyToItem(Item *item) {
00095     _refCount++;
00096 }
00097 void Anim::removeFromItem(Item *item) {
00098     _refCount--;
00099 }
00100 
00101 bool Anim::isInUse() const {
00102     return _refCount > 0;
00103 }
00104 
00105 int Anim::getPointHotspotIndex(const Common::Point &point) const {
00106     // Most anim types only have one hotspot
00107     return 0;
00108 }
00109 
00110 void Anim::playAsAction(ItemVisual *item) {
00111     AnimScript *animScript = findChild<AnimScript>();
00112     animScript->goToScriptItem(0);
00113 }
00114 
00115 bool Anim::isAtTime(uint32 time) const {
00116     warning("Anim::isAtTime is not implemented");
00117     return true;
00118 }
00119 
00120 void Anim::shouldResetItem(bool resetItem) {
00121     // Script animations don't keep track of the item
00122 }
00123 
00124 void Anim::resetItem() {
00125     // Script animations don't keep track of the item
00126 }
00127 
00128 bool Anim::isDone() const {
00129     AnimScript *animScript = findChild<AnimScript>();
00130     return animScript->isDone();
00131 }
00132 
00133 uint32 Anim::getMovementSpeed() const {
00134     return 100;
00135 }
00136 
00137 uint32 Anim::getIdleActionFrequency() const {
00138     return 1;
00139 }
00140 
00141 void Anim::printData() {
00142     debug("activity: %d", _activity);
00143     debug("numFrames: %d", _numFrames);
00144 }
00145 
00146 AnimImages::~AnimImages() {
00147 }
00148 
00149 AnimImages::AnimImages(Object *parent, byte subType, uint16 index, const Common::String &name) :
00150         Anim(parent, subType, index, name),
00151         _field_3C(0),
00152         _currentDirection(0),
00153         _currentFrameImage(nullptr) {
00154 }
00155 
00156 void AnimImages::readData(Formats::XRCReadStream *stream) {
00157     Anim::readData(stream);
00158 
00159     _field_3C = stream->readFloatLE();
00160 }
00161 
00162 void AnimImages::onAllLoaded() {
00163     Anim::onAllLoaded();
00164 
00165     _directions = listChildren<Direction>();
00166 }
00167 
00168 void AnimImages::selectFrame(uint32 frameIndex) {
00169     if (frameIndex > _numFrames) {
00170         // The original silently ignores this as well
00171         warning("Request for frame %d for anim '%s' has been ignored, it is above max frame %d", frameIndex, getName().c_str(), _numFrames);
00172         _currentFrame = 0;
00173     }
00174 
00175     _currentFrame = frameIndex;
00176 }
00177 
00178 Visual *AnimImages::getVisual() {
00179     Direction *direction = _directions[_currentDirection];
00180     _currentFrameImage = direction->findChildWithIndex<Image>(_currentFrame);
00181     return _currentFrameImage->getVisual();
00182 }
00183 
00184 void AnimImages::printData() {
00185     Anim::printData();
00186 
00187     debug("field_3C: %f", _field_3C);
00188 }
00189 
00190 int AnimImages::getPointHotspotIndex(const Common::Point &point) const {
00191     if (_currentFrameImage) {
00192         return _currentFrameImage->indexForPoint(point);
00193     }
00194     return -1;
00195 }
00196 
00197 Common::Point AnimImages::getHotspotPosition(uint index) const {
00198     if (_currentFrameImage) {
00199         return _currentFrameImage->getHotspotPosition(index);
00200     }
00201     return Common::Point(-1, -1);
00202 }
00203 
00204 void AnimImages::saveLoad(ResourceSerializer *serializer) {
00205     Anim::saveLoad(serializer);
00206 
00207     serializer->syncAsUint32LE(_currentFrame);
00208 
00209     if (serializer->isLoading()) {
00210         selectFrame(_currentFrame);
00211     }
00212 }
00213 
00214 AnimProp::~AnimProp() {
00215     delete _visual;
00216 }
00217 
00218 AnimProp::AnimProp(Object *parent, byte subType, uint16 index, const Common::String &name) :
00219         Anim(parent, subType, index, name),
00220         _movementSpeed(100) {
00221     _visual = StarkGfx->createPropRenderer();
00222 }
00223 
00224 Visual *AnimProp::getVisual() {
00225     return _visual;
00226 }
00227 
00228 uint32 AnimProp::getMovementSpeed() const {
00229     return _movementSpeed;
00230 }
00231 
00232 void AnimProp::readData(Formats::XRCReadStream *stream) {
00233     Anim::readData(stream);
00234 
00235     _field_3C = stream->readString();
00236 
00237     uint32 meshCount = stream->readUint32LE();
00238     for (uint i = 0; i < meshCount; i++) {
00239         _meshFilenames.push_back(stream->readString());
00240     }
00241 
00242     _textureFilename = stream->readString();
00243     _movementSpeed = stream->readUint32LE();
00244     _archiveName = stream->getArchiveName();
00245 }
00246 
00247 void AnimProp::onPostRead() {
00248     if (_meshFilenames.size() != 1) {
00249         error("Unexpected mesh count in prop anim: '%d'", _meshFilenames.size());
00250     }
00251 
00252     ArchiveReadStream *stream = StarkArchiveLoader->getFile(_meshFilenames[0], _archiveName);
00253     _visual->setModel(Formats::BiffMeshReader::read(stream));
00254     delete stream;
00255 
00256     stream = StarkArchiveLoader->getFile(_textureFilename, _archiveName);
00257     _visual->setTexture(Formats::TextureSetReader::read(stream));
00258     delete stream;
00259 }
00260 
00261 void AnimProp::printData() {
00262     Anim::printData();
00263 
00264     debug("field_3C: %s", _field_3C.c_str());
00265 
00266     Common::String description;
00267     for (uint32 i = 0; i < _meshFilenames.size(); i++) {
00268         debug("meshFilename[%d]: %s", i, _meshFilenames[i].c_str());
00269     }
00270     debug("textureFilename: %s", _textureFilename.c_str());
00271     debug("movementSpeed: %d", _movementSpeed);
00272 }
00273 
00274 AnimVideo::~AnimVideo() {
00275     delete _smacker;
00276 }
00277 
00278 AnimVideo::AnimVideo(Object *parent, byte subType, uint16 index, const Common::String &name) :
00279         Anim(parent, subType, index, name),
00280         _width(0),
00281         _height(0),
00282         _smacker(nullptr),
00283         _frameRateOverride(-1),
00284         _preload(false),
00285         _loop(false),
00286         _actionItem(nullptr),
00287         _shouldResetItem(true),
00288         _done(false) {
00289 }
00290 
00291 void AnimVideo::readData(Formats::XRCReadStream *stream) {
00292     Anim::readData(stream);
00293     _smackerFile = stream->readString();
00294     _width = stream->readUint32LE();
00295     _height = stream->readUint32LE();
00296 
00297     _positions.clear();
00298     _sizes.clear();
00299 
00300     uint32 size = stream->readUint32LE();
00301     for (uint i = 0; i < size; i++) {
00302         _positions.push_back(stream->readPoint());
00303         _sizes.push_back(stream->readRect());
00304     }
00305 
00306     _loop = stream->readBool();
00307     _frameRateOverride = stream->readUint32LE();
00308 
00309     if (stream->isDataLeft()) {
00310         _preload = stream->readBool();
00311     }
00312 
00313     _archiveName = stream->getArchiveName();
00314 
00315     // WORKAROUND: Fix the position of various items being incorrect in the game datafiles
00316     Location *location = findParent<Location>();
00317     if (_name == "Mountain comes down" && location && location->getName() == "Below Floating Mountain") {
00318         for (uint i = 0; i < _sizes.size(); i++) {
00319             _positions[i].x = 352;
00320         }
00321     }
00322 }
00323 
00324 void AnimVideo::onAllLoaded() {
00325     if (!_smacker) {
00326 
00327         _smacker = new VisualSmacker(StarkGfx);
00328 
00329         Common::SeekableReadStream *overrideStreamBink = nullptr;
00330         Common::SeekableReadStream *overrideStreamSmacker = nullptr;
00331         if (StarkSettings->isAssetsModEnabled()) {
00332             overrideStreamBink = openOverrideFile(".bik");
00333             if (!overrideStreamBink) {
00334                 overrideStreamSmacker = openOverrideFile(".smk");
00335             }
00336         }
00337 
00338         Common::SeekableReadStream *stream = StarkArchiveLoader->getExternalFile(_smackerFile, _archiveName);
00339         if (overrideStreamBink) {
00340             _smacker->loadBink(overrideStreamBink);
00341             _smacker->readOriginalSize(stream);
00342         } else if (overrideStreamSmacker) {
00343             _smacker->loadSmacker(overrideStreamSmacker);
00344             _smacker->readOriginalSize(stream);
00345         } else {
00346             _smacker->loadSmacker(stream);
00347         }
00348 
00349         _smacker->overrideFrameRate(_frameRateOverride);
00350 
00351         updateSmackerPosition();
00352     }
00353 }
00354 
00355 Common::SeekableReadStream *AnimVideo::openOverrideFile(const Common::String &extension) const {
00356     if (!_smackerFile.hasSuffixIgnoreCase(".sss")) {
00357         return nullptr;
00358     }
00359 
00360     Common::String filename = Common::String(_smackerFile.c_str(), _smackerFile.size() - 4) + extension;
00361     Common::String filePath = StarkArchiveLoader->getExternalFilePath(filename, _archiveName);
00362 
00363     debugC(kDebugModding, "Attempting to load %s", filePath.c_str());
00364 
00365     Common::SeekableReadStream *smkStream = SearchMan.createReadStreamForMember(filePath);
00366     if (!smkStream) {
00367         return nullptr;
00368     }
00369 
00370     debugC(kDebugModding, "Loaded %s", filePath.c_str());
00371 
00372     return smkStream;
00373 }
00374 
00375 void AnimVideo::onGameLoop() {
00376     if (!_smacker || !isInUse()) {
00377         return; // Animation not in use, no need to update the movie
00378     }
00379 
00380     if (_smacker->isDone()) {
00381         // The last frame has been reached
00382         _done = true;
00383 
00384         if (_shouldResetItem) {
00385             resetItem();
00386         }
00387 
00388         if (_loop) {
00389             _smacker->rewind();
00390         }
00391     }
00392 
00393     if (!_smacker->isDone()) {
00394         _smacker->update();
00395         updateSmackerPosition();
00396     }
00397 }
00398 
00399 void AnimVideo::resetItem() {
00400     if (!_loop && _actionItem) {
00401         // Reset our item if needed
00402         if (_actionItem->getActionAnim() == this) {
00403             _actionItem->resetActionAnim();
00404         }
00405         _actionItem = nullptr;
00406     }
00407 }
00408 
00409 void AnimVideo::onEnginePause(bool pause) {
00410     Object::onEnginePause(pause);
00411 
00412     if (_smacker && isInUse()) {
00413         _smacker->pause(pause);
00414     }
00415 }
00416 
00417 Visual *AnimVideo::getVisual() {
00418     return _smacker;
00419 }
00420 
00421 void AnimVideo::updateSmackerPosition() {
00422     int frame = _smacker->getFrameNumber();
00423     if (frame == -1) {
00424         return;
00425     }
00426 
00427     if (frame < (int) _positions.size()) {
00428         _smacker->setPosition(_positions[frame]);
00429     }
00430 }
00431 
00432 void AnimVideo::shouldResetItem(bool resetItem) {
00433     _shouldResetItem = resetItem;
00434 }
00435 
00436 void AnimVideo::playAsAction(ItemVisual *item) {
00437     _actionItem = item;
00438     _shouldResetItem = true;
00439     _done = false;
00440 
00441     if (!_loop) {
00442         _smacker->rewind();
00443     }
00444 
00445     // Update here so we have something up to date to show when rendering this frame
00446     _smacker->update();
00447 }
00448 
00449 bool AnimVideo::isAtTime(uint32 time) const {
00450     uint32 currentTime = _smacker->getCurrentTime();
00451     return currentTime >= time;
00452 }
00453 
00454 void AnimVideo::saveLoadCurrent(ResourceSerializer *serializer) {
00455     Anim::saveLoadCurrent(serializer);
00456 
00457     int32 frameNumber = _smacker->getFrameNumber();
00458     serializer->syncAsSint32LE(frameNumber);
00459     serializer->syncAsSint32LE(_refCount);
00460 
00461     // TODO: Seek to the saved frame number when loading
00462 }
00463 
00464 void AnimVideo::printData() {
00465     Anim::printData();
00466 
00467     debug("smackerFile: %s", _smackerFile.c_str());
00468     debug("size: x %d, y %d", _width, _height);
00469 
00470     Common::String description;
00471     for (uint32 i = 0; i < _positions.size(); i++) {
00472         description += Common::String::format("(x %d, y %d) ", _positions[i].x, _positions[i].y);
00473     }
00474     debug("positions: %s", description.c_str());
00475 
00476     description.clear();
00477     for (uint32 i = 0; i < _sizes.size(); i++) {
00478         description += Common::String::format("(l %d, t %d, r %d, b %d) ",
00479                 _sizes[i].left, _sizes[i].top, _sizes[i].right, _sizes[i].bottom);
00480     }
00481     debug("sizes: %s", description.c_str());
00482 
00483     debug("frameRateOverride: %d", _frameRateOverride);
00484     debug("preload: %d", _preload);
00485     debug("loop: %d", _loop);
00486 }
00487 
00488 AnimSkeleton::~AnimSkeleton() {
00489     delete _visual;
00490     delete _skeletonAnim;
00491 }
00492 
00493 AnimSkeleton::AnimSkeleton(Object *parent, byte subType, uint16 index, const Common::String &name) :
00494         Anim(parent, subType, index, name),
00495         _castsShadow(true),
00496         _loop(false),
00497         _movementSpeed(100),
00498         _idleActionFrequency(1),
00499         _skeletonAnim(nullptr),
00500         _currentTime(0),
00501         _totalTime(0),
00502         _done(false),
00503         _actionItem(nullptr),
00504         _shouldResetItem(true) {
00505     _visual = StarkGfx->createActorRenderer();
00506 }
00507 
00508 void AnimSkeleton::applyToItem(Item *item) {
00509     Anim::applyToItem(item);
00510 
00511     if (!_loop) {
00512         _currentTime = 0;
00513     }
00514 
00515     if (_currentTime > _totalTime) {
00516         _currentTime = 0;
00517     }
00518 
00519     debugC(kDebugAnimation, "%s: add %s", item->getName().c_str(), getName().c_str());
00520 
00521     ModelItem *modelItem = Object::cast<ModelItem>(item);
00522 
00523     BonesMesh *mesh = modelItem->findBonesMesh();
00524     TextureSet *texture = modelItem->findTextureSet(TextureSet::kTextureNormal);
00525 
00526     AnimHandler *animHandler = modelItem->getAnimHandler();
00527     animHandler->setModel(mesh->getModel());
00528     animHandler->setAnim(_skeletonAnim);
00529 
00530     _visual->setModel(mesh->getModel());
00531     _visual->setAnimHandler(animHandler);
00532     _visual->setTexture(texture->getTexture());
00533     _visual->setTextureFacial(nullptr);
00534     _visual->setTime(_currentTime);
00535     _visual->setCastShadow(_castsShadow);
00536 }
00537 
00538 void AnimSkeleton::removeFromItem(Item *item) {
00539     Anim::removeFromItem(item);
00540 
00541     debugC(kDebugAnimation, "%s: remove %s", item->getName().c_str(), getName().c_str());
00542 
00543     _actionItem = nullptr;
00544 }
00545 
00546 Visual *AnimSkeleton::getVisual() {
00547     return _visual;
00548 }
00549 
00550 void AnimSkeleton::readData(Formats::XRCReadStream *stream) {
00551     Anim::readData(stream);
00552 
00553     _animFilename = stream->readString();
00554     stream->readString(); // Skipped in the original
00555     stream->readString(); // Skipped in the original
00556     stream->readString(); // Skipped in the original
00557 
00558     _loop = stream->readBool();
00559     _movementSpeed = stream->readUint32LE();
00560 
00561     if (_movementSpeed < 1) {
00562         _movementSpeed = 100;
00563     }
00564 
00565     if (stream->isDataLeft()) {
00566         _castsShadow = stream->readBool();
00567     } else {
00568         _castsShadow = true;
00569     }
00570 
00571     if (stream->isDataLeft()) {
00572         _idleActionFrequency = stream->readUint32LE();
00573     } else {
00574         _idleActionFrequency = 1;
00575     }
00576 
00577     _archiveName = stream->getArchiveName();
00578 }
00579 
00580 void AnimSkeleton::onPostRead() {
00581     ArchiveReadStream *stream = StarkArchiveLoader->getFile(_animFilename, _archiveName);
00582 
00583     _skeletonAnim = new SkeletonAnim();
00584     _skeletonAnim->createFromStream(stream);
00585 
00586     delete stream;
00587 }
00588 
00589 void AnimSkeleton::onAllLoaded() {
00590     Anim::onAllLoaded();
00591 
00592     _totalTime = _skeletonAnim->getLength();
00593     _currentTime = 0;
00594 }
00595 
00596 void AnimSkeleton::onGameLoop() {
00597     Anim::onGameLoop();
00598 
00599     if (isInUse() && _totalTime) {
00600         uint32 newTime = _currentTime + StarkGlobal->getMillisecondsPerGameloop();
00601 
00602         if (!_loop && newTime >= _totalTime) {
00603             _done = true;
00604 
00605             if (_shouldResetItem) {
00606                 resetItem();
00607             }
00608         } else {
00609             _currentTime = newTime % _totalTime;
00610             _visual->setTime(_currentTime);
00611         }
00612     }
00613 }
00614 
00615 void AnimSkeleton::resetItem() {
00616     if (_actionItem) {
00617         if (_actionItem->getActionAnim() == this) {
00618             _actionItem->resetActionAnim();
00619         }
00620         _actionItem = nullptr;
00621     }
00622 }
00623 
00624 void AnimSkeleton::onPreDestroy() {
00625     resetItem();
00626 
00627     Anim::onPreDestroy();
00628 }
00629 
00630 uint32 AnimSkeleton::getMovementSpeed() const {
00631     return _movementSpeed;
00632 }
00633 
00634 uint32 AnimSkeleton::getCurrentTime() const {
00635     return _currentTime;
00636 }
00637 
00638 uint32 AnimSkeleton::getRemainingTime() const {
00639     int32 remainingTime = _totalTime - _currentTime;
00640     return CLIP<int32>(remainingTime, 0, _totalTime);
00641 }
00642 
00643 void AnimSkeleton::shouldResetItem(bool resetItem) {
00644     _shouldResetItem = resetItem;
00645 }
00646 
00647 void AnimSkeleton::playAsAction(ItemVisual *item) {
00648     _actionItem = item;
00649     _done = false;
00650     _shouldResetItem = true;
00651 
00652     if (!_loop) {
00653         _currentTime = 0;
00654     }
00655 }
00656 
00657 bool AnimSkeleton::isAtTime(uint32 time) const {
00658     return _currentTime >= time;
00659 }
00660 
00661 uint32 AnimSkeleton::getIdleActionFrequency() const {
00662     return _idleActionFrequency;
00663 }
00664 
00665 void AnimSkeleton::printData() {
00666     Anim::printData();
00667 
00668     debug("filename: %s", _animFilename.c_str());
00669     debug("castsShadow: %d", _castsShadow);
00670     debug("loop: %d", _loop);
00671     debug("movementSpeed: %d", _movementSpeed);
00672     debug("idleActionFrequency: %d", _idleActionFrequency);
00673 }
00674 
00675 } // End of namespace Resources
00676 } // End of namespace Stark


Generated on Sat May 18 2019 05:00:55 for ResidualVM by doxygen 1.7.1
curved edge   curved edge