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

costume.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 COPYRIGHT
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/endian.h"
00024 
00025 #include "engines/grim/debug.h"
00026 #include "engines/grim/colormap.h"
00027 #include "engines/grim/costume.h"
00028 #include "engines/grim/textsplit.h"
00029 #include "engines/grim/resource.h"
00030 #include "engines/grim/model.h"
00031 #include "engines/grim/savegame.h"
00032 #include "engines/grim/emi/modelemi.h"
00033 #include "engines/grim/costume/chore.h"
00034 #include "engines/grim/costume/head.h"
00035 #include "engines/grim/emi/costume/emianim_component.h"
00036 #include "engines/grim/emi/costume/emimesh_component.h"
00037 #include "engines/grim/emi/costume/emiskel_component.h"
00038 #include "engines/grim/costume/main_model_component.h"
00039 #include "engines/grim/costume/colormap_component.h"
00040 #include "engines/grim/costume/keyframe_component.h"
00041 #include "engines/grim/costume/mesh_component.h"
00042 #include "engines/grim/costume/lua_var_component.h"
00043 #include "engines/grim/costume/sound_component.h"
00044 #include "engines/grim/costume/bitmap_component.h"
00045 #include "engines/grim/costume/material_component.h"
00046 #include "engines/grim/costume/sprite_component.h"
00047 #include "engines/grim/costume/anim_component.h"
00048 
00049 namespace Grim {
00050 
00051 // A costume in the Residual/GrimE engine consists of a set of
00052 // components, and a set of chores.  Each component represents an
00053 // on-screen object, or a keyframe animation, or a sound effect; each
00054 // chore gives a set of instructions for how to move and/or activate
00055 // or deactivate each component at certain times.
00056 //
00057 // Each actor contains a stack of costumes, on which a new costume can
00058 // be pushed or from which an old costume can be popped at any time.
00059 // For the most part, these costumes are independent.  The exception
00060 // is the main model component ('MMDL'), for which multiple costumes
00061 // share the same base 3D object (if they refer to the same file).
00062 //
00063 // This is complicated by the fact that multiple keyframe animations
00064 // can have an effect on the positions of the 3D objects.  Each
00065 // keyframe animation has certain nodes internally "tagged", and the
00066 // keyframe components specify precedences for the tagged nodes and
00067 // for the non-tagged nodes.  If the highest precedence for a given
00068 // node is given by multiple keyframe animations, their contributions
00069 // are averaged.
00070 //
00071 // Each component can implement several virtual methods which are
00072 // called by the costume:
00073 //
00074 // init() -- allows the component to initialize itself.  This is
00075 //           separate from the constructor since there are cases where
00076 //           information from child components may be needed before
00077 //           the object can be fully constructed.  This is particularly
00078 //           the case with colormaps, which are needed before even
00079 //           starting to load a 3D model.
00080 // setKey(val) -- notifies the component of a change in the "state"
00081 //                given by a playing chore
00082 // update() -- gives the component a chance to update its internal
00083 //             state once every frame
00084 // draw() -- actually draws the component onto the screen
00085 // reset() -- notifies the component that a chore controlling it
00086 //            has stopped
00087 //
00088 // For the 3D objects, a model's component first initializes internal
00089 // state for the model's nodes in its update() method.  Then the
00090 // keyframes' update() methods work with this data to implement the
00091 // precedence and add up all contributions for the highest precedence.
00092 // Then the model's draw() method does the averaging and draws the
00093 // polygons accordingly.  (Actually, this is a lie -- the top-level
00094 // 3D objects draw themselves and all their children.  This makes it
00095 // easier to move objects Manny is holding when his hands move, for
00096 // example.)
00097 //
00098 // For bitmaps, the actual drawing is handled by the Set class.  The
00099 // bitmaps to be drawn are associated to the needed camera setups
00100 // using NewObjectState; bitmaps marked OBJSTATE_UNDERLAY and
00101 // OBJSTATE_STATE are drawn first, then the 3D objects, then bitmaps
00102 // marked OBJSTATE_OVERLAY.  So the BitmapComponent just needs to pass
00103 // along setKey requests to the actual bitmap object.
00104 
00105 Costume::Costume(const Common::String &fname, Actor *owner, Costume *prevCost) :
00106         Object(), _head(nullptr), _chores(nullptr), _components(nullptr),
00107         _numComponents(0), _numChores(0), _fname(fname), _owner(owner) {
00108     _lookAtRate = 200;
00109     _prevCostume = prevCost;
00110 }
00111 
00112 void Costume::load(Common::SeekableReadStream *data) {
00113     TextSplitter ts(_fname, data);
00114     ts.expectString("costume v0.1");
00115     ts.expectString("section tags");
00116     int numTags;
00117     ts.scanString(" numtags %d", 1, &numTags);
00118     tag32 *tags = new tag32[numTags];
00119     for (int i = 0; i < numTags; i++) {
00120         unsigned char t[4];
00121         int which;
00122 
00123         // Obtain a tag ID from the file
00124         ts.scanString(" %d '%c%c%c%c'", 5, &which, &t[0], &t[1], &t[2], &t[3]);
00125         // Force characters to upper case
00126         for (int j = 0; j < 4; j++)
00127             t[j] = toupper(t[j]);
00128         memcpy(&tags[which], t, sizeof(tag32));
00129         tags[which] = FROM_BE_32(tags[which]);
00130     }
00131 
00132     ts.expectString("section components");
00133     ts.scanString(" numcomponents %d", 1, &_numComponents);
00134     _components = new Component *[_numComponents];
00135     for (int i = 0; i < _numComponents; i++) {
00136         int id, tagID, hash, parentID, namePos;
00137         const char *line = ts.getCurrentLine();
00138         Component *prevComponent = nullptr;
00139 
00140         if (sscanf(line, " %d %d %d %d %n", &id, &tagID, &hash, &parentID, &namePos) < 4)
00141             error("Bad component specification line: `%s'", line);
00142         ts.nextLine();
00143 
00144         // A Parent ID of "-1" indicates that the component should
00145         // use the properties of the previous costume as a base
00146         if (parentID == -1) {
00147             if (_prevCostume) {
00148                 // However, only the first item can actually share the
00149                 // node hierarchy with the previous costume, so flag
00150                 // that component so it knows what to do
00151                 if (i == 0)
00152                     parentID = -2;
00153                 prevComponent = _prevCostume->_components[0];
00154                 // Make sure that the component is valid
00155                 if (!prevComponent->isComponentType('M','M','D','L'))
00156                     prevComponent = nullptr;
00157             } else if (id > 0) {
00158                 // Use the MainModelComponent of this costume as prevComponent,
00159                 // so that the component can use its colormap.
00160                 prevComponent = _components[0];
00161             }
00162         }
00163         // Actually load the appropriate component
00164         _components[id] = loadComponent(tags[tagID], parentID < 0 ? nullptr : _components[parentID], parentID, line + namePos, prevComponent);
00165         _components[id]->setCostume(this);
00166     }
00167 
00168     delete[] tags;
00169 
00170     for (int i = 0; i < _numComponents; i++)
00171         if (_components[i]) {
00172             _components[i]->init();
00173         }
00174 
00175     ts.expectString("section chores");
00176     ts.scanString(" numchores %d", 1, &_numChores);
00177     _chores = new Chore *[_numChores];
00178     for (int i = 0; i < _numChores; i++) {
00179         int id, length, tracks;
00180         char name[32];
00181         ts.scanString(" %d %d %d %32s", 4, &id, &length, &tracks, name);
00182         _chores[id] = new Chore(name, i, this, length, tracks);
00183         Debug::debug(Debug::Chores, "Loaded chore: %s\n", name);
00184     }
00185 
00186     ts.expectString("section keys");
00187     for (int i = 0; i < _numChores; i++) {
00188         int which;
00189         ts.scanString("chore %d", 1, &which);
00190         _chores[which]->load(ts);
00191     }
00192 
00193     _head = new Head();
00194 }
00195 
00196 Costume::~Costume() {
00197     stopChores();
00198     for (int i = _numComponents - 1; i >= 0; i--) {
00199         delete _components[i];
00200     }
00201     delete[] _components;
00202 
00203     for (int i = 0; i < _numChores; ++i) {
00204         delete _chores[i];
00205     }
00206     delete[] _chores;
00207     delete _head;
00208 }
00209 
00210 Component *Costume::loadComponent (tag32 tag, Component *parent, int parentID, const char *name, Component *prevComponent) {
00211     if (tag == MKTAG('M','M','D','L'))
00212         return new MainModelComponent(parent, parentID, name, prevComponent, tag);
00213     else if (tag == MKTAG('M','O','D','L'))
00214         return new ModelComponent(parent, parentID, name, prevComponent, tag);
00215     else if (tag == MKTAG('C','M','A','P'))
00216         return new ColormapComponent(parent, parentID, name, tag);
00217     else if (tag == MKTAG('K','E','Y','F'))
00218         return new KeyframeComponent(parent, parentID, name, tag);
00219     else if (tag == MKTAG('M','E','S','H'))
00220         return new MeshComponent(parent, parentID, name, tag);
00221     else if (tag == MKTAG('L','U','A','V'))
00222         return new LuaVarComponent(parent, parentID, name, tag);
00223     else if (tag == MKTAG('I','M','L','S'))
00224         return new SoundComponent(parent, parentID, name, tag);
00225     else if (tag == MKTAG('B','K','N','D'))
00226         return new BitmapComponent(parent, parentID, name, tag);
00227     else if (tag == MKTAG('M','A','T',' '))
00228         return new MaterialComponent(parent, parentID, name, tag);
00229     else if (tag == MKTAG('S','P','R','T'))
00230         return new SpriteComponent(parent, parentID, name, tag);
00231     else if (tag == MKTAG('A','N','I','M')) //Used  in the demo
00232         return new AnimComponent(parent, parentID, name, tag);
00233 
00234     char t[4];
00235     memcpy(t, &tag, sizeof(tag32));
00236     warning("loadComponent: Unknown tag '%c%c%c%c', name '%s'", t[0], t[1], t[2], t[3], name);
00237     return nullptr;
00238 }
00239 
00240 ModelComponent *Costume::getMainModelComponent() const {
00241     for (int i = 0; i < _numComponents; i++) {
00242         // Needs to handle Main Models (pigeons) and normal Models
00243         // (when Manny climbs the rope)
00244         if (_components[i] && _components[i]->isComponentType('M','M','D','L'))
00245             return static_cast<ModelComponent *>(_components[i]);
00246     }
00247     return nullptr;
00248 }
00249 
00250 ModelNode *Costume::getModelNodes() {
00251     ModelComponent *comp = getMainModelComponent();
00252     if (comp) {
00253         return comp->getHierarchy();
00254     }
00255     return nullptr;
00256 }
00257 
00258 Model *Costume::getModel() {
00259     ModelComponent *comp = getMainModelComponent();
00260     if (comp) {
00261         return comp->getModel();
00262     }
00263     return nullptr;
00264 }
00265 
00266 void Costume::setChoreLastFrame(int num) {
00267     if (num < 0 || num >= _numChores) {
00268         Debug::warning(Debug::Chores, "Requested chore number %d is outside the range of chores (0-%d)", num, _numChores);
00269         return;
00270     }
00271     _chores[num]->setLastFrame();
00272 }
00273 
00274 void Costume::setChoreLooping(int num, bool val) {
00275     if (num < 0 || num >= _numChores) {
00276         Debug::warning(Debug::Chores, "Requested chore number %d is outside the range of chores (0-%d)", num, _numChores);
00277         return;
00278     }
00279     _chores[num]->setLooping(val);
00280 }
00281 
00282 void Costume::playChoreLooping(const char *name, uint msecs) {
00283     for (int i = 0; i < _numChores; ++i) {
00284         if (strcmp(_chores[i]->getName(), name) == 0) {
00285             playChoreLooping(i, msecs);
00286             return;
00287         }
00288     }
00289     warning("Costume::playChoreLooping: Could not find chore: %s", name);
00290     return;
00291 }
00292 
00293 void Costume::playChoreLooping(int num, uint msecs) {
00294     if (num < 0 || num >= _numChores) {
00295         Debug::warning(Debug::Chores, "Requested chore number %d is outside the range of chores (0-%d)", num, _numChores);
00296         return;
00297     }
00298 
00299     _chores[num]->playLooping(msecs);
00300     if (Common::find(_playingChores.begin(), _playingChores.end(), _chores[num]) == _playingChores.end())
00301         _playingChores.push_back(_chores[num]);
00302 }
00303 
00304 Chore *Costume::getChore(const char *name) {
00305     for (int i = 0; i < _numChores; ++i) {
00306         if (strcmp(_chores[i]->getName(), name) == 0) {
00307             return _chores[i];
00308         }
00309     }
00310     return nullptr;
00311 }
00312 
00313 int Costume::getChoreId(const char *name) {
00314     if (name == nullptr) {
00315         return -1;
00316     }
00317     for (int i = 0; i < _numChores; ++i) {
00318         if (strcmp(_chores[i]->getName(), name) == 0) {
00319             return i;
00320         }
00321     }
00322     return -1;
00323 }
00324 
00325 void Costume::playChore(const char *name, uint msecs) {
00326     for (int i = 0; i < _numChores; ++i) {
00327         if (strcmp(_chores[i]->getName(), name) == 0) {
00328             playChore(i, msecs);
00329             return;
00330         }
00331     }
00332     warning("Costume::playChore: Could not find chore: %s", name);
00333     return;
00334 }
00335 
00336 void Costume::playChore(int num, uint msecs) {
00337     if (num < 0 || num >= _numChores) {
00338         Debug::warning(Debug::Chores, "Requested chore number %d is outside the range of chores (0-%d)", num, _numChores);
00339         return;
00340     }
00341     _chores[num]->play(msecs);
00342     if (Common::find(_playingChores.begin(), _playingChores.end(), _chores[num]) == _playingChores.end())
00343         _playingChores.push_back(_chores[num]);
00344 }
00345 
00346 void Costume::stopChore(int num, uint msecs) {
00347     if (num < 0 || num >= _numChores) {
00348         Debug::warning(Debug::Chores, "Requested chore number %d is outside the range of chores (0-%d)", num, _numChores);
00349         return;
00350     }
00351     _chores[num]->stop(msecs);
00352 }
00353 
00354 void Costume::setColormap(const Common::String &map) {
00355     // Sometimes setColormap is called on a null costume,
00356     // see where raoul is gone in hh.set
00357     if (!map.size())
00358         return;
00359     _cmap = g_resourceloader->getColormap(map);
00360     for (int i = 0; i < _numComponents; i++)
00361         if (_components[i])
00362             _components[i]->setColormap(nullptr);
00363 }
00364 
00365 void Costume::stopChores(bool ignoreLoopingChores, int msecs) {
00366     for (int i = 0; i < _numChores; i++) {
00367         if (ignoreLoopingChores && _chores[i]->isLooping()) {
00368             continue;
00369         }
00370         _chores[i]->stop(msecs);
00371     }
00372 }
00373 
00374 void Costume::fadeChoreIn(int chore, uint msecs) {
00375     if (chore < 0 || chore >= _numChores) {
00376         Debug::warning(Debug::Chores, "Requested chore number %d is outside the range of chores (0-%d)", chore, _numChores);
00377         return;
00378     }
00379     _chores[chore]->fadeIn(msecs);
00380     if (Common::find(_playingChores.begin(), _playingChores.end(), _chores[chore]) == _playingChores.end())
00381         _playingChores.push_back(_chores[chore]);
00382 }
00383 
00384 void Costume::fadeChoreOut(int chore, uint msecs) {
00385     if (chore < 0 || chore >= _numChores) {
00386         Debug::warning(Debug::Chores, "Requested chore number %d is outside the range of chores (0-%d)", chore, _numChores);
00387         return;
00388     }
00389     _chores[chore]->fadeOut(msecs);
00390 }
00391 
00392 int Costume::isChoring(const char *name, bool excludeLooping) {
00393     for (int i = 0; i < _numChores; i++) {
00394         if (!strcmp(_chores[i]->getName(), name) && _chores[i]->isPlaying() && !(excludeLooping && _chores[i]->isLooping()))
00395             return i;
00396     }
00397     return -1;
00398 }
00399 
00400 int Costume::isChoring(int num, bool excludeLooping) {
00401     if (num < 0 || num >= _numChores) {
00402         Debug::warning(Debug::Chores, "Requested chore number %d is outside the range of chores (0-%d)", num, _numChores);
00403         return -1;
00404     }
00405     if (_chores[num]->isPlaying() && !(excludeLooping && _chores[num]->isLooping()))
00406         return num;
00407     else
00408         return -1;
00409 }
00410 
00411 int Costume::isChoring(bool excludeLooping) {
00412     for (int i = 0; i < _numChores; i++) {
00413         if (_chores[i]->isPlaying() && !(excludeLooping && _chores[i]->isLooping()))
00414             return i;
00415     }
00416     return -1;
00417 }
00418 
00419 void Costume::draw() {
00420     for (int i = 0; i < _numComponents; i++)
00421         if (_components[i])
00422             _components[i]->draw();
00423 }
00424 
00425 void Costume::getBoundingBox(int *x1, int *y1, int *x2, int *y2) {
00426     for (int i = 0; i < _numComponents; i++) {
00427         if (_components[i] &&(_components[i]->isComponentType('M','M','D','L') ||
00428                               _components[i]->isComponentType('M','O','D','L'))) {
00429             ModelComponent *c = static_cast<ModelComponent *>(_components[i]);
00430             c->getBoundingBox(x1, y1, x2, y2);
00431         }
00432 
00433         if (_components[i] &&(_components[i]->isComponentType('m','e','s','h'))) {
00434             EMIMeshComponent *c = static_cast<EMIMeshComponent *>(_components[i]);
00435             c->getBoundingBox(x1, y1, x2, y2);
00436         }
00437     }
00438 }
00439 
00440 int Costume::update(uint time) {
00441     for (Common::List<Chore*>::iterator i = _playingChores.begin(); i != _playingChores.end(); ++i) {
00442         (*i)->update(time);
00443         if (!(*i)->isPlaying()) {
00444             i = _playingChores.erase(i);
00445             --i;
00446         }
00447     }
00448 
00449     int marker = 0;
00450     for (int i = 0; i < _numComponents; i++) {
00451         if (_components[i]) {
00452             _components[i]->setMatrix(_matrix);
00453             int m = _components[i]->update(time);
00454             if (m > 0) {
00455                 marker = m;
00456             }
00457         }
00458     }
00459 
00460     return marker;
00461 }
00462 
00463 void Costume::animate() {
00464     for (int i = 0; i < _numComponents; i++) {
00465         if (_components[i]) {
00466             _components[i]->animate();
00467         }
00468     }
00469 }
00470 
00471 void Costume::moveHead(bool entering, const Math::Vector3d &lookAt) {
00472     _head->lookAt(entering, lookAt, _lookAtRate, _matrix);
00473 }
00474 
00475 int Costume::getHeadJoint() const {
00476     return static_cast<Head *>(_head)->getJoint3();
00477 }
00478 
00479 void Costume::setHead(int joint1, int joint2, int joint3, float maxRoll, float maxPitch, float maxYaw) {
00480     Head *head = static_cast<Head *>(_head);
00481     head->setJoints(joint1, joint2, joint3);
00482     head->loadJoints(getModelNodes());
00483     head->setMaxAngles(maxPitch, maxYaw, maxRoll);
00484 }
00485 
00486 void Costume::setLookAtRate(float rate) {
00487     _lookAtRate = rate;
00488 }
00489 
00490 float Costume::getLookAtRate() const {
00491     return _lookAtRate;
00492 }
00493 
00494 void Costume::setPosRotate(const Math::Vector3d &pos, const Math::Angle &pitch,
00495                            const Math::Angle &yaw, const Math::Angle &roll) {
00496     _matrix.setPosition(pos);
00497     _matrix.buildFromEuler(yaw, pitch, roll, Math::EO_ZXY);
00498 }
00499 
00500 Math::Matrix4 Costume::getMatrix() const {
00501     return _matrix;
00502 }
00503 
00504 Costume *Costume::getPreviousCostume() const {
00505     return _prevCostume;
00506 }
00507 
00508 void Costume::saveState(SaveGame *state) const {
00509     if (_cmap) {
00510         state->writeBool(true);
00511         state->writeString(_cmap->getFilename());
00512     } else {
00513         state->writeBool(false);
00514     }
00515 
00516     for (int i = 0; i < _numChores; ++i) {
00517         _chores[i]->saveState(state);
00518     }
00519 
00520     for (int i = 0; i < _numComponents; ++i) {
00521         Component *c = _components[i];
00522 
00523         if (c) {
00524             state->writeBool(c->_visible);
00525             c->saveState(state);
00526         }
00527     }
00528 
00529     state->writeLEUint32(_playingChores.size());
00530     for (Common::List<Chore*>::const_iterator i = _playingChores.begin(); i != _playingChores.end(); ++i) {
00531         state->writeLESint32((*i)->getChoreId());
00532     }
00533 
00534     state->writeFloat(_lookAtRate);
00535     _head->saveState(state);
00536 }
00537 
00538 bool Costume::restoreState(SaveGame *state) {
00539     if (state->readBool()) {
00540         Common::String str = state->readString();
00541         setColormap(str);
00542     }
00543 
00544     for (int i = 0; i < _numChores; ++i) {
00545         _chores[i]->restoreState(state);
00546     }
00547 
00548     for (int i = 0; i < _numComponents; ++i) {
00549         Component *c = _components[i];
00550 
00551         if (c) {
00552             c->_visible = state->readBool();
00553             if (state->saveMinorVersion() < 14) {
00554                 // skip the old _matrix vector
00555                 state->readVector3d();
00556             }
00557             c->restoreState(state);
00558         }
00559     }
00560 
00561     int numPlayingChores = state->readLEUint32();
00562     for (int i = 0; i < numPlayingChores; ++i) {
00563         int id = state->readLESint32();
00564         _playingChores.push_back(_chores[id]);
00565     }
00566 
00567     _lookAtRate = state->readFloat();
00568     _head->restoreState(state);
00569     _head->loadJoints(getModelNodes());
00570 
00571     return true;
00572 }
00573 
00574 } // end of namespace Grim


Generated on Sat Mar 23 2019 05:01:25 for ResidualVM by doxygen 1.7.1
curved edge   curved edge