Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,81 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "engines/grim/objectstate.h"
#include "engines/grim/grim.h"
#include "engines/grim/debug.h"
#include "engines/grim/set.h"
#include "engines/grim/costume/anim_component.h"
namespace Grim {
AnimComponent::AnimComponent(Component *p, int parentID, const char *filename, tag32 t) :
Component(p, parentID, filename, t) {
_overlay = false;
_created = false;
const char *comma = strchr(filename, ',');
if (comma) {
_name = Common::String(filename, comma);
_overlay = atoi(comma + 1) == 1;
}
}
void AnimComponent::setKey(int val) {
ObjectState *state = g_grim->getCurrSet()->findState(_name);
if (!state) {
Set *set = g_grim->getCurrSet();
state = set->addObjectState(set->getSetup(), (_overlay ? ObjectState::OBJSTATE_OVERLAY : ObjectState::OBJSTATE_UNDERLAY),
_name.c_str(), nullptr, false);
}
_created = true;
if (state) {
state->setActiveImage(val);
return;
}
// Complain that we couldn't find the bitmap. This means we probably
// didn't handle something correctly. Example: Before the tube-switcher
// bitmaps were not loading with the scene. This was because they were requested
// as a different case then they were stored (tu_0_dorcu_door_open versus
// TU_0_DORCU_door_open), which was causing problems in the string comparison.
Debug::warning(Debug::Bitmaps | Debug::Costumes, "Missing scene bitmap: %s", _name.c_str());
/* In case you feel like drawing the missing bitmap anyway...
// Assume that all objects the scene file forgot about are OBJSTATE_STATE class
state = new ObjectState(0, ObjectState::OBJSTATE_STATE, bitmap, NULL, true);
if (!state) {
if (gDebugLevel == DEBUG_BITMAPS || gDebugLevel == DEBUG_WARN || gDebugLevel == DEBUG_ALL)
warning("Couldn't find bitmap %s in current scene", _filename.c_str());
return;
}
g_grim->getCurrSet()->addObjectState(state);
state->setNumber(val);
*/
}
void AnimComponent::reset() {
if (_created) {
setKey(0);
}
}
} // end of namespace Grim

View File

@@ -0,0 +1,43 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRIM_ANIM_COMPONENT_H
#define GRIM_ANIM_COMPONENT_H
#include "engines/grim/costume/component.h"
namespace Grim {
// This is used in Grim demo only
class AnimComponent : public Component {
public:
AnimComponent(Component *parent, int parentID, const char *filename, tag32 tag);
void setKey(int val) override;
void reset() override;
private:
bool _created;
bool _overlay;
};
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,61 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "engines/grim/objectstate.h"
#include "engines/grim/grim.h"
#include "engines/grim/debug.h"
#include "engines/grim/set.h"
#include "engines/grim/costume/bitmap_component.h"
namespace Grim {
BitmapComponent::BitmapComponent(Component *p, int parentID, const char *filename, tag32 t) :
Component(p, parentID, filename, t) {
}
void BitmapComponent::setKey(int val) {
ObjectState *state = g_grim->getCurrSet()->findState(_name);
if (state) {
state->setActiveImage(val);
return;
}
// Complain that we couldn't find the bitmap. This means we probably
// didn't handle something correctly. Example: Before the tube-switcher
// bitmaps were not loading with the scene. This was because they were requested
// as a different case then they were stored (tu_0_dorcu_door_open versus
// TU_0_DORCU_door_open), which was causing problems in the string comparison.
Debug::warning(Debug::Bitmaps | Debug::Costumes, "Missing scene bitmap: %s", _name.c_str());
/* In case you feel like drawing the missing bitmap anyway...
// Assume that all objects the scene file forgot about are OBJSTATE_STATE class
state = new ObjectState(0, ObjectState::OBJSTATE_STATE, bitmap, NULL, true);
if (!state) {
if (gDebugLevel == DEBUG_BITMAPS || gDebugLevel == DEBUG_WARN || gDebugLevel == DEBUG_ALL)
warning("Couldn't find bitmap %s in current scene", _filename.c_str());
return;
}
g_grim->getCurrSet()->addObjectState(state);
state->setNumber(val);
*/
}
} // end of namespace Grim

View File

@@ -0,0 +1,37 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRIM_BITMAP_COMPONENT_H
#define GRIM_BITMAP_COMPONENT_H
#include "engines/grim/costume/component.h"
namespace Grim {
class BitmapComponent : public Component {
public:
BitmapComponent(Component *parent, int parentID, const char *filename, tag32 tag);
void setKey(int val) override;
};
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,246 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "engines/grim/costume.h"
#include "engines/grim/savegame.h"
#include "engines/grim/textsplit.h"
#include "engines/grim/costume/chore.h"
#include "engines/grim/costume/component.h"
#include "engines/grim/costume/keyframe_component.h"
namespace Grim {
// Should initialize the status variables so the chore can't play unexpectedly
Chore::Chore(char name[32], int id, Costume *owner, int length, int numTracks) :
_hasPlayed(false), _playing(false), _looping(false), _paused(false), _currTime(-1),
_numTracks(numTracks), _length(length), _choreId(id), _owner(owner) {
memcpy(_name, name, 32);
_tracks = new ChoreTrack[_numTracks];
}
Chore::~Chore() {
if (_tracks) {
for (int i = 0; i < _numTracks; i++)
delete[] _tracks[i].keys;
delete[] _tracks;
_tracks = nullptr;
}
}
void Chore::load(TextSplitter &ts) {
_hasPlayed = _playing = false;
for (int i = 0; i < _numTracks; i++) {
int compID, numKeys;
ts.scanString(" %d %d", 2, &compID, &numKeys);
_tracks[i].compID = compID;
_tracks[i].numKeys = numKeys;
_tracks[i].keys = new TrackKey[numKeys];
for (int j = 0; j < numKeys; j++) {
ts.scanString(" %d %d", 2, &_tracks[i].keys[j].time, &_tracks[i].keys[j].value);
}
}
}
void Chore::play(uint msecs) {
_playing = true;
_paused = false;
_hasPlayed = true;
_looping = false;
_currTime = -1;
if (msecs > 0)
fade(Animation::FadeIn, msecs);
else
fade(Animation::None, 0);
}
void Chore::playLooping(uint msecs) {
_playing = true;
_paused = false;
_hasPlayed = true;
_looping = true;
_currTime = -1;
if (msecs > 0)
fade(Animation::FadeIn, msecs);
else
fade(Animation::None, 0);
}
Component *Chore::getComponentForTrack(int i) const {
if (_tracks[i].compID == -1)
return _tracks[i].component;
else
return _owner->_components[_tracks[i].compID];
}
void Chore::stop(uint msecs) {
if (msecs > 0)
fade(Animation::FadeOut, msecs);
_playing = false;
_hasPlayed = false;
for (int i = 0; i < _numTracks; i++) {
Component *comp = getComponentForTrack(i);
if (comp)
comp->reset();
}
}
void Chore::setKeys(int startTime, int stopTime) {
for (int i = 0; i < _numTracks; i++) {
Component *comp = getComponentForTrack(i);
if (!comp)
continue;
for (int j = 0; j < _tracks[i].numKeys; j++) {
if (_tracks[i].keys[j].time > stopTime && stopTime != -1)
break;
if (_tracks[i].keys[j].time > startTime)
comp->setKey(_tracks[i].keys[j].value);
}
}
}
void Chore::setLastFrame() {
// If the chore has already played then don't set it to the end
// Example: This executing would result in Glottis being
// choppy when he hands Manny the work order
// if (_hasPlayed)
// return;
// This comment above is perfectly right, but unfortunately doing that
// breaks glottis movements when he answers to "i'm calavera, manny calavera".
// Moreover, the choppy behaviour stated above happens with grim original too,
// meaning the bug is not in Residual but in the scripts or in GrimE design.
_currTime = -1;
_playing = false;
_paused = false;
_hasPlayed = true;
_looping = false;
// In the demo, the chore 4 (stop_talk) of ms.cos, has length 67, and 4 keys,
// the last two of which are at time 133 and 200. We use -1 as stopTime here
// as a special value, instead of _length, to ensure all the keys are run.
// (failing to do so will result in manny's mouth not closing when he stops talking)
setKeys(-1, -1);
}
void Chore::update(uint time) {
if (!_playing || _paused)
return;
int newTime;
if (_currTime < 0)
newTime = 0; // For first time through
else
newTime = _currTime + time;
setKeys(_currTime, newTime);
if (newTime > _length) {
if (!_looping) {
_playing = false;
} else {
do {
newTime -= _length;
setKeys(-1, newTime);
} while (newTime > _length);
}
}
_currTime = newTime;
}
void Chore::fade(Animation::FadeMode mode, uint msecs) {
if (mode == Animation::FadeIn) {
if (!_playing) {
_playing = true;
_hasPlayed = true;
_currTime = -1;
}
} else if (mode == Animation::FadeOut) {
// Stop the chore, but do not alter the components state.
_playing = false;
}
for (int i = 0; i < _numTracks; i++) {
Component *comp = getComponentForTrack(i);
if (comp) {
comp->fade(mode, msecs);
}
}
}
void Chore::fadeIn(uint msecs) {
fade(Animation::FadeIn, msecs);
}
void Chore::fadeOut(uint msecs) {
// Note: It doesn't matter whether the chore is playing or not. The keyframe
// components should fade out in either case.
fade(Animation::FadeOut, msecs);
}
void Chore::setPaused(bool paused) {
_paused = paused;
for (int i = 0; i < _numTracks; i++) {
Component *comp = getComponentForTrack(i);
if (comp) {
comp->setPaused(paused);
}
}
}
void Chore::advance(uint msecs) {
setKeys(_currTime, _currTime + msecs);
for (int i = 0; i < _numTracks; i++) {
Component *comp = getComponentForTrack(i);
if (comp) {
comp->advance(msecs);
}
}
_currTime += msecs;
}
void Chore::saveState(SaveGame *state) const {
state->writeBool(_hasPlayed);
state->writeBool(_playing);
state->writeBool(_looping);
state->writeLESint32(_currTime);
state->writeBool(_paused);
}
void Chore::restoreState(SaveGame *state) {
_hasPlayed = state->readBool();
_playing = state->readBool();
_looping = state->readBool();
_currTime = state->readLESint32();
if (state->saveMinorVersion() >= 10)
_paused = state->readBool();
}
} // end of namespace Grim

View File

@@ -0,0 +1,96 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRIM_CHORE_H
#define GRIM_CHORE_H
#include "engines/grim/animation.h"
namespace Grim {
class Costume;
class Animation;
class Component;
class TextSplitter;
struct TrackKey {
int time, value;
};
struct ChoreTrack {
int compID;
int numKeys;
TrackKey *keys;
Component *component;
};
class Chore {
public:
Chore(char name[32], int id, Costume *owner, int length, int numTracks);
virtual ~Chore();
void load(TextSplitter &ts);
virtual void play(uint msecs);
virtual void playLooping(uint msecs);
void setLooping(bool val) { _looping = val; }
virtual void stop(uint msecs);
virtual void update(uint time);
void setLastFrame();
void fadeIn(uint msecs);
void fadeOut(uint msecs);
void setPaused(bool paused);
bool isPlaying() { return _playing; }
bool isPaused() { return _paused; }
bool isLooping() { return _looping; }
void advance(uint msecs);
const char *getName() const { return _name; }
int getChoreId() { return _choreId; }
Costume *getOwner() { return _owner; }
virtual void saveState(SaveGame *state) const;
virtual void restoreState(SaveGame *state);
protected:
void setKeys(int startTime, int stopTime);
virtual void fade(Animation::FadeMode, uint msecs);
Component *getComponentForTrack(int i) const;
Costume *_owner;
int _choreId;
int _length;
int _numTracks;
ChoreTrack *_tracks;
char _name[32];
bool _hasPlayed, _playing, _looping, _paused;
int _currTime;
friend class EMICostume;
};
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,44 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "engines/grim/costume.h"
#include "engines/grim/resource.h"
#include "engines/grim/colormap.h"
#include "engines/grim/costume/colormap_component.h"
namespace Grim {
ColormapComponent::ColormapComponent(Component *p, int parentID, const char *filename, tag32 t) :
Component(p, parentID, filename, t) {
_cmap = g_resourceloader->getColormap(_name);
// Set the colormap here in the ctor and not in init()!
if (p)
p->setColormap(_cmap);
}
void ColormapComponent::init() {
if (!_parent)
warning("No parent to apply colormap object on. CMap: %s, Costume: %s",
_cmap->getFilename().c_str(), _cost->getFilename().c_str());
}
} // end of namespace Grim

View File

@@ -0,0 +1,39 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRIM_COLORMAP_COMPONENT_H
#define GRIM_COLORMAP_COMPONENT_H
#include "engines/grim/costume/component.h"
namespace Grim {
class ColormapComponent : public Component {
public:
ColormapComponent(Component *parent, int parentID, const char *filename, tag32 tag);
ColormapComponent *copy(Component *newParent);
void init() override;
};
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,100 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "engines/grim/costume/component.h"
#include "engines/grim/colormap.h"
#include "engines/grim/costume.h"
namespace Grim {
Component::Component(Component *p, int parentID, const char *name, tag32 t) :
_visible(true), _tag(t), _parentID(parentID), _name(name),
_previousCmap(nullptr), _cmap(nullptr), _cost(nullptr) {
setParent(p);
}
Component::~Component() {
if (_parent)
_parent->removeChild(this);
Component *child = _child;
while (child) {
child->_parent = nullptr;
child = child->_sibling;
}
}
void Component::setColormap(CMap *c) {
if (c)
_cmap = c;
if (getCMap()) {
resetHierCMap();
}
}
bool Component::isVisible() {
if (_visible && _parent)
return _parent->isVisible();
return _visible;
}
CMap *Component::getCMap() {
if (!_cmap && _previousCmap)
return _previousCmap;
else if (!_cmap && _parent)
return _parent->getCMap();
else if (!_cmap && !_parent && _cost)
return _cost->getCMap();
else
return _cmap;
}
void Component::setParent(Component *newParent) {
_parent = newParent;
_child = nullptr;
_sibling = nullptr;
if (_parent) {
_sibling = _parent->_child;
_parent->_child = this;
}
}
void Component::removeChild(Component *child) {
Component **childPos = &_child;
while (*childPos && *childPos != child)
childPos = &(*childPos)->_sibling;
if (*childPos) {
*childPos = child->_sibling;
child->_parent = nullptr;
}
}
void Component::resetHierCMap() {
resetColormap();
Component *child = _child;
while (child) {
child->resetHierCMap();
child = child->_sibling;
}
}
} // end of namespace Grim

View File

@@ -0,0 +1,84 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRIM_COMPONENT_H
#define GRIM_COMPONENT_H
#include "math/matrix4.h"
#include "engines/grim/object.h"
#include "engines/grim/animation.h"
namespace Grim {
typedef uint32 tag32;
class Costume;
class CMap;
class SaveGame;
class Component {
public:
Component(Component *parent, int parentID, const char *name, tag32 tag);
CMap *getCMap();
virtual void setColormap(CMap *c);
bool isVisible();
Component *getParent() { return _parent; }
virtual void setMatrix(const Math::Matrix4 &) { };
virtual void init() { }
virtual void setKey(int) { }
virtual void setMapName(char *) { }
virtual int update(uint time) { return 0; }
virtual void animate() { }
virtual void draw() { }
virtual void reset() { }
virtual void fade(Animation::FadeMode, int) { }
virtual void advance(uint msecs) { }
virtual void setPaused(bool paused) { }
virtual void resetColormap() { }
virtual void saveState(SaveGame *) { }
virtual void restoreState(SaveGame *) { }
virtual ~Component();
bool isComponentType(char a0, char a1, char a2, char a3) { return _tag == MKTAG(a0, a1, a2, a3); }
protected:
ObjectPtr<CMap> _cmap, _previousCmap;
tag32 _tag;
int _parentID;
bool _visible;
Component *_parent, *_child, *_sibling;
Costume *_cost;
Common::String _name;
void setCostume(Costume *cost) { _cost = cost; }
void setParent(Component *newParent);
void removeChild(Component *child);
void resetHierCMap();
friend class Costume;
friend class EMICostume;
};
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,249 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "engines/grim/model.h"
#include "engines/grim/grim.h"
#include "engines/grim/savegame.h"
#include "engines/grim/costume/head.h"
namespace Grim {
Head::Joint::Joint() :
_node(nullptr), _pitch(0.f), _yaw(0.f), _roll(0.f) {
}
void Head::Joint::init(ModelNode *node) {
_node = node;
}
void Head::Joint::orientTowards(bool entering, const Math::Vector3d &point, float rate, const Math::Matrix4 &matrix,
float maxPitch, float maxYaw, float maxRoll, float constrain) {
float step = g_grim->getPerSecond(rate);
float yawStep = step;
float pitchStep = step / 3.0f;
float rollStep = step / 3.0f;
if (!_node)
return;
// Make sure we have up-to-date world transform matrices computed for the joint nodes of this character.
_node->_needsUpdate = true;
ModelNode *p = _node;
while (p->_parent) {
p = p->_parent;
p->_needsUpdate = true;
}
p->setMatrix(matrix);
p->update();
Math::Vector3d modelFront; // the modeling convention for the forward direction.
Math::Vector3d modelUp; // the modeling convention for the upward direction.
Math::Vector3d frontDir; // Character front facing direction vector in world space (global scene coordinate space)
// the character head coordinate frame is: +Y forward, +Z up, +X right.
frontDir = Math::Vector3d(_node->_matrix(0, 1), _node->_matrix(1, 1), _node->_matrix(2, 1)); // Look straight ahead. (+Y)
modelFront = Math::Vector3d(0, 1, 0);
modelUp = Math::Vector3d(0, 0, 1);
// v is the world space direction vector this character should be looking towards.
Math::Vector3d targetDir = point - _node->_pivotMatrix.getPosition();
if (!entering)
targetDir = frontDir;
if (targetDir.isZero())
return;
targetDir.normalize();
// The vector v is in world space, so generate the world space lookat matrix for the desired head facing
// orientation.
Math::Matrix4 lookAtTM;
lookAtTM.setToIdentity();
const Math::Vector3d worldUp(0, 0, 1); // The Residual scene convention: +Z is world space up.
if (Math::Vector3d::dotProduct(targetDir, worldUp) >= 0.98f) // Avoid singularity if trying to look straight up.
lookAtTM.buildFromTargetDir(modelFront, targetDir, modelUp, -frontDir); // Instead of orienting head towards scene up, orient head towards character "back",
// i.e. when you look straight up, your head up vector tilts/arches to point straight backwards.
else if (Math::Vector3d::dotProduct(targetDir, worldUp) <= -0.98f) // Avoid singularity if trying to look straight down.
lookAtTM.buildFromTargetDir(modelFront, targetDir, modelUp, frontDir); // Instead of orienting head towards scene down, orient head towards character "front",
// i.e. when you look straight down, your head up vector tilts/arches to point straight forwards.
else
lookAtTM.buildFromTargetDir(modelFront, targetDir, modelUp, worldUp);
// The above specifies the world space orientation of this bone, but we need to output
// the orientation in parent space (as yaw/pitch/roll).
// Get the coordinate frame in which we need to produce the character head yaw/pitch/roll values.
Math::Matrix4 parentWorldTM;
if (_node->_parent)
parentWorldTM = _node->_parent->_matrix;
// While we could compute the desired lookat direction directly in the above coordinate frame,
// it is preferrable to compute the lookat direction with respect to the head orientation in
// the keyframe animation. This is because the LUA scripts specify the maximum head yaw, pitch and
// roll values with respect to those keyframe animations. If the lookat was simply computed
// directly in the space of the parent, we couldn't apply the head maxYaw/Pitch/Roll constraints
// properly. So, compute the coordinate frame of this bone in the keyframe animation.
Math::Matrix4 animFrame = _node->_localMatrix;
parentWorldTM = parentWorldTM * animFrame;
parentWorldTM.invertAffineOrthonormal();
// Convert lookAtTM orientation from world space to parent-with-keyframe-animation space.
lookAtTM = parentWorldTM * lookAtTM;
// Decompose to yaw-pitch-roll (+Z, +X, +Y).
// In this space, Yaw is +Z. Pitch is +X. Roll is +Y.
Math::Angle y, pt, r;
lookAtTM.getEuler(&y, &pt, &r, Math::EO_ZXY);
y = y * constrain;
pt = pt * constrain;
r = r * constrain;
// Constrain the maximum head movement, as desired by the game LUA scripts.
y.clampDegrees(maxYaw);
pt.clampDegrees(maxPitch);
r.clampDegrees(maxRoll);
// Also limit yaw, pitch and roll to make at most a movement as large as the given max step size during this frame.
// This will produce a slow head-turning animation instead of immediately snapping to the
// target lookat orientation.
if (y - _yaw > yawStep)
y = _yaw + yawStep;
if (_yaw - y > yawStep)
y = _yaw - yawStep;
if (pt - _pitch > pitchStep)
pt = _pitch + pitchStep;
if (_pitch - pt > pitchStep)
pt = _pitch - pitchStep;
if (r - _roll > rollStep)
r = _roll + rollStep;
if (_roll - r > rollStep)
r = _roll - rollStep;
// Remember how far we animated the head this frame, and we'll continue from here the next frame.
_pitch = pt;
_yaw = y;
_roll = r;
// Assemble ypr to a quaternion.
// This is the head orientation with respect to parent-with-keyframe-animation space.
Math::Quaternion lookAtQuat = Math::Quaternion::fromEuler(y, pt, r, Math::EO_ZXY);
_node->_animRot = _node->_animRot * lookAtQuat;
}
void Head::Joint::saveState(SaveGame *state) const {
state->writeFloat(_pitch.getDegrees());
state->writeFloat(_yaw.getDegrees());
state->writeFloat(_roll.getDegrees());
}
void Head::Joint::restoreState(SaveGame *state) {
_pitch = state->readFloat();
_yaw = state->readFloat();
_roll = state->readFloat();
}
Head::Head() :
_maxPitch(0), _maxYaw(0), _maxRoll(0),
_joint1Node(-1), _joint2Node(-1), _joint3Node(-1) {
}
void Head::setJoints(int joint1, int joint2, int joint3) {
_joint1Node = joint1;
_joint2Node = joint2;
_joint3Node = joint3;
}
void Head::loadJoints(ModelNode *nodes) {
if (_joint1Node >= 0 && _joint2Node >= 0 && _joint3Node >= 0 && nodes) {
_joint1.init(nodes + _joint1Node);
_joint2.init(nodes + _joint2Node);
_joint3.init(nodes + _joint3Node);
}
}
void Head::setMaxAngles(float maxPitch, float maxYaw, float maxRoll) {
_maxRoll = maxRoll;
_maxPitch = maxPitch;
_maxYaw = maxYaw;
}
void Head::lookAt(bool entering, const Math::Vector3d &point, float rate, const Math::Matrix4 &matrix) {
if (_joint1Node != -1) {
// NOTE: By default, the _head.maxRoll for Manny's head is constrained to 165 degrees, which
// comes in from the original Lua data scripts. (also, maxYaw == 80, maxPitch == 28).
// The very small maxPitch angle, and a very large maxRoll angle causes problems when Manny
// is trying to look straight up to an object, in which case the euler roll angles vary
// wildly compared to the pitch angles, which get clamped to a much smaller interval. Therefore,
// restrict the maximum roll angle to a smaller value than 165 degrees to avoid this behavior.
// If you want to change this, good places to test are:
// A) Year 1, outside the Department of Death, run/walk up & down the stairs, there's a sign
// right above the stairs, and Manny looks dead up.
// B) Year 3, when Manny and Meche are imprisoned in the vault. Walk inside the room where Meche
// is in, to look straight up to the sprinklers.
if (_joint1Node == _joint2Node && _joint1Node == _joint3Node) {
// Most characters only have one head joint instead of three, so we can orient the head
// with a single call.
_joint3.orientTowards(entering, point, rate, matrix, _maxPitch, _maxYaw, 30.f, 1.0f);
} else {
// For characters like Manny, we'll have to orient each of the three head joints.
_joint1.orientTowards(entering, point, rate / 3, matrix, _maxPitch / 3, _maxYaw / 3, 10.f, 0.333f);
_joint2.orientTowards(entering, point, rate / 3, matrix, _maxPitch / 3, _maxYaw / 3, 10.f, 0.666f);
_joint3.orientTowards(entering, point, rate / 3, matrix, _maxPitch / 3, _maxYaw / 3, 10.f, 1.000f);
}
}
}
void Head::saveState(SaveGame *state) const {
state->writeLESint32(_joint1Node);
state->writeLESint32(_joint2Node);
state->writeLESint32(_joint3Node);
state->writeFloat(_maxPitch);
state->writeFloat(_maxYaw);
state->writeFloat(_maxRoll);
_joint1.saveState(state);
_joint2.saveState(state);
_joint3.saveState(state);
}
void Head::restoreState(SaveGame *state) {
_joint1Node = state->readLESint32();
_joint2Node = state->readLESint32();
_joint3Node = state->readLESint32();
_maxPitch = state->readFloat();
_maxYaw = state->readFloat();
_maxRoll = state->readFloat();
if (state->saveMinorVersion() < 2) {
state->readFloat();
state->readFloat();
} else {
_joint1.restoreState(state);
_joint2.restoreState(state);
_joint3.restoreState(state);
}
}
} // end of namespace Grim

View File

@@ -0,0 +1,98 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRIM_HEAD_H
#define GRIM_HEAD_H
#include "math/matrix4.h"
namespace Grim {
class ModelNode;
class SaveGame;
class BaseHead {
public:
virtual ~BaseHead() {}
virtual void lookAt(bool entering, const Math::Vector3d &point, float rate, const Math::Matrix4 &matrix) = 0;
virtual void saveState(SaveGame *state) const = 0;
virtual void restoreState(SaveGame *state) = 0;
virtual void loadJoints(ModelNode *nodes) = 0;
};
class Head : public BaseHead {
public:
class Joint {
public:
Joint();
void init(ModelNode *node);
void orientTowards(bool entering, const Math::Vector3d &point, float rate, const Math::Matrix4 &matrix,
float maxPitch, float maxYaw, float maxRoll, float constrain);
void saveState(SaveGame *state) const;
void restoreState(SaveGame *state);
private:
ModelNode *_node;
Math::Angle _pitch;
Math::Angle _yaw;
Math::Angle _roll;
};
Head();
void setJoints(int joint1, int joint2, int joint3);
void loadJoints(ModelNode *nodes);
void setMaxAngles(float maxPitch, float maxYaw, float maxRoll);
void lookAt(bool entering, const Math::Vector3d &point, float rate, const Math::Matrix4 &matrix);
void saveState(SaveGame *state) const;
void restoreState(SaveGame *state);
int getJoint1() const { return _joint1Node; }
int getJoint2() const { return _joint2Node; }
int getJoint3() const { return _joint3Node; }
private:
int _joint1Node;
int _joint2Node;
int _joint3Node;
float _maxRoll;
float _maxPitch;
float _maxYaw;
// Specifies the three head joint bones of this character.
// These joint bones are animated by the moveHead function to make
// the characters face different directions.
// Note that for some characters, these variables may all be equal.
Joint _joint1;
Joint _joint2;
Joint _joint3;
};
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,133 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "engines/grim/debug.h"
#include "engines/grim/costume/keyframe_component.h"
#include "engines/grim/costume/model_component.h"
namespace Grim {
KeyframeComponent::KeyframeComponent(Component *p, int parentID, const char *filename, tag32 t) :
Component(p, parentID, filename, t), _priority1(1), _priority2(5), _anim(nullptr) {
const char *comma = strchr(filename, ',');
if (comma) {
_name = Common::String(filename, comma);
sscanf(comma + 1, "%d,%d", &_priority1, &_priority2);
}
}
KeyframeComponent::~KeyframeComponent() {
delete _anim;
}
void KeyframeComponent::fade(Animation::FadeMode fadeMode, int fadeLength) {
_anim->fade(fadeMode, fadeLength);
}
void KeyframeComponent::setKey(int val) {
switch (val) {
case 0: // "Play Once"
_anim->play(Animation::Once);
break;
case 1: // "Play Looping"
_anim->play(Animation::Looping);
break;
case 2: // "Play and Endpause"
_anim->play(Animation::PauseAtEnd);
break;
case 3: // "Play and Endfade"
_anim->play(Animation::FadeAtEnd);
break;
case 4: // "Stop"
reset();
break;
case 5: // "Pause"
_anim->pause(true);
break;
case 6: // "Unpause"
_anim->pause(false);
break;
case 7: // "1.0 Fade in"
fade(Animation::FadeIn, 1000);
_anim->activate();
break;
case 8: // "0.5 Fade in"
fade(Animation::FadeIn, 500);
_anim->activate();
break;
case 9: // "0.25 Fade in"
fade(Animation::FadeIn, 250);
_anim->activate();
break;
case 10: // "0.125 Fade in"
fade(Animation::FadeIn, 125);
_anim->activate();
break;
case 11: // "1.0 Fade out"
fade(Animation::FadeOut, 1000);
break;
case 12: // "0.5 Fade out
fade(Animation::FadeOut, 500);
break;
case 13: // "0.25 Fade out"
fade(Animation::FadeOut, 250);
break;
case 14: // "0.125 Fade out"
fade(Animation::FadeOut, 125);
break;
default:
Debug::warning(Debug::Costumes, "Unknown key %d for component %s", val, _name.c_str());
}
}
void KeyframeComponent::reset() {
if (_anim->getFadeMode() != Animation::FadeOut) {
_anim->stop();
}
}
int KeyframeComponent::update(uint time) {
if (!_anim->getIsActive())
return 0;
return _anim->update((int)time);
}
void KeyframeComponent::init() {
if (_parent->isComponentType('M','M','D','L') ||
_parent->isComponentType('M','O','D','L')) {
ModelComponent *mc = static_cast<ModelComponent *>(_parent);
_anim = new Animation(_name, mc->getAnimManager(), _priority1, _priority2);
} else {
Debug::warning(Debug::Costumes, "Parent of %s was not a model", _name.c_str());
_anim = nullptr;
}
}
void KeyframeComponent::saveState(SaveGame *state) {
_anim->saveState(state);
}
void KeyframeComponent::restoreState(SaveGame *state) {
_anim->restoreState(state);
}
} // end of namespace Grim

View File

@@ -0,0 +1,51 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRIM_KEYFRAME_COMPONENT_H
#define GRIM_KEYFRAME_COMPONENT_H
#include "engines/grim/costume/component.h"
#include "engines/grim/animation.h"
namespace Grim {
class Animation;
class KeyframeComponent : public Component {
public:
KeyframeComponent(Component *parent, int parentID, const char *filename, tag32 tag);
~KeyframeComponent();
void init() override;
void fade(Animation::FadeMode, int fadeLength) override;
void setKey(int val) override;
int update(uint time) override;
void reset() override;
void saveState(SaveGame *state) override;
void restoreState(SaveGame *state) override;
private:
Animation *_anim;
int _priority1, _priority2;
};
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,36 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "engines/grim/costume/lua_var_component.h"
#include "engines/grim/lua/lua.h"
namespace Grim {
LuaVarComponent::LuaVarComponent(Component *p, int parentID, const char *name, tag32 t) :
Component(p, parentID, name, t) {
}
void LuaVarComponent::setKey(int val) {
lua_pushnumber(val);
lua_setglobal(_name.c_str());
}
} // end of namespace Grim

View File

@@ -0,0 +1,37 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRIM_LUA_VAR_COMPONENT_H
#define GRIM_LUA_VAR_COMPONENT_H
#include "engines/grim/costume/component.h"
namespace Grim {
class LuaVarComponent : public Component {
public:
LuaVarComponent(Component *parent, int parentID, const char *name, tag32 tag);
void setKey(int val) override;
};
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,83 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "engines/grim/model.h"
#include "engines/grim/costume/model_component.h"
#include "engines/grim/costume/main_model_component.h"
namespace Grim {
MainModelComponent::MainModelComponent(Component *p, int parentID, const char *filename, Component *prevComponent, tag32 t) :
ModelComponent(p, parentID, filename, prevComponent, t), _hierShared(false), _parentModel(nullptr) {
if (parentID == -2 && prevComponent && prevComponent->isComponentType('M','M','D','L')) {
MainModelComponent *mmc = static_cast<MainModelComponent *>(prevComponent);
if (mmc->_name == _name) {
_animation = mmc->_animation;
_obj = mmc->_obj;
_hier = mmc->_hier;
_hierShared = true;
mmc->_children.push_back(this);
_parentModel = mmc;
}
}
}
MainModelComponent::~MainModelComponent() {
if (_hierShared) {
_obj = nullptr; // Keep ~ModelComp from deleting it
_animation = nullptr;
}
for (MainModelComponent *child : _children) {
child->_obj = nullptr;
child->_hier = nullptr;
child->_parentModel = nullptr;
}
if (_parentModel) {
_parentModel->_children.remove(this);
}
}
void MainModelComponent::init() {
ModelComponent::init();
_visible = true;
_hier->_hierVisible = _visible;
}
void MainModelComponent::setColormap(CMap *cmap) {
Component::setColormap(cmap);
if (_parentModel) {
_parentModel->setColormap(cmap);
}
}
void MainModelComponent::reset() {
_visible = true;
// Can be NULL if this was attached to another costume which
// was deleted.
if (_hier) {
_hier->_hierVisible = _visible;
}
}
} // end of namespace Grim

View File

@@ -0,0 +1,47 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRIM_MAIN_MODEL_COMPONENT_H
#define GRIM_MAIN_MODEL_COMPONENT_H
#include "engines/grim/costume/model_component.h"
namespace Grim {
class CMap;
class MainModelComponent : public ModelComponent {
public:
MainModelComponent(Component *parent, int parentID, const char *filename, Component *prevComponent, tag32 tag);
~MainModelComponent();
void init();
void setColormap(CMap *cmap);
void reset();
private:
bool _hierShared;
Common::List<MainModelComponent*> _children;
MainModelComponent *_parentModel;
};
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,78 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "common/textconsole.h"
#include "engines/grim/costume.h"
#include "engines/grim/debug.h"
#include "engines/grim/model.h"
#include "engines/grim/material.h"
#include "engines/grim/savegame.h"
#include "engines/grim/costume/material_component.h"
#include "engines/grim/costume/model_component.h"
namespace Grim {
MaterialComponent::MaterialComponent(Component *p, int parentID, const char *filename, tag32 t) :
Component(p, parentID, filename, t) {
Debug::debug(Debug::Costumes, "Constructing MaterialComponent %s", filename);
}
void MaterialComponent::init() {
_mat = nullptr;
if (_parent->isComponentType('M','M','D','L') ||
_parent->isComponentType('M','O','D','L')) {
ModelComponent *p = static_cast<ModelComponent *>(_parent);
Model *model = p->getModel();
if (model) {
for (int i = 0; i < model->_numMaterials; ++i) {
if (_name.compareToIgnoreCase(model->_materials[i]->getFilename()) == 0) {
_mat = model->_materials[i];
return;
}
}
}
} else {
warning("Parent of a MaterialComponent not a ModelComponent. %s %s", _name.c_str(), _cost->getFilename().c_str());
}
}
void MaterialComponent::setKey(int val) {
_mat->setActiveTexture(val);
}
void MaterialComponent::reset() {
_mat->setActiveTexture(0);
}
void MaterialComponent::resetColormap() {
init();
}
void MaterialComponent::saveState(SaveGame *state) {
state->writeLESint32(_mat->getActiveTexture());
}
void MaterialComponent::restoreState(SaveGame *state) {
_mat->setActiveTexture(state->readLESint32());
}
} // end of namespace Grim

View File

@@ -0,0 +1,47 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRIM_MATERIAL_COMPONENT_H
#define GRIM_MATERIAL_COMPONENT_H
#include "engines/grim/costume/component.h"
namespace Grim {
class Material;
class MaterialComponent : public Component {
public:
MaterialComponent(Component *parent, int parentID, const char *filename, tag32 tag);
void init() override;
void setKey(int val) override;
void reset() override;
void resetColormap() override;
void saveState(SaveGame *state) override;
void restoreState(SaveGame *state) override;
private:
Material *_mat;
};
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,92 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "common/textconsole.h"
#include "engines/grim/debug.h"
#include "engines/grim/model.h"
#include "engines/grim/savegame.h"
#include "engines/grim/costume/mesh_component.h"
#include "engines/grim/costume/model_component.h"
namespace Grim {
MeshComponent::MeshComponent(Component *p, int parentID, const char *name, tag32 t) :
Component(p, parentID, name, t), _node(nullptr) {
if (sscanf(name, "mesh %d", &_num) < 1)
error("Couldn't parse mesh name %s", name);
}
void MeshComponent::init() {
if (_parent->isComponentType('M','M','D','L') ||
_parent->isComponentType('M','O','D','L')) {
ModelComponent *mc = static_cast<ModelComponent *>(_parent);
_node = mc->getHierarchy() + _num;
_model = mc->getModel();
} else {
Debug::warning(Debug::Costumes, "Parent of mesh %d was not a model", _num);
_node = nullptr;
_model = nullptr;
}
}
CMap *MeshComponent::cmap() {
if (_parent->isComponentType('M','M','D','L') ||
_parent->isComponentType('M','O','D','L')) {
ModelComponent *mc = static_cast<ModelComponent *>(_parent);
return mc->getCMap();
}
return nullptr;
}
void MeshComponent::setKey(int val) {
_node->_meshVisible = (val != 0);
}
void MeshComponent::reset() {
// NOTE: Setting the visibility to true here causes a bug with the thunderboy costume:
// closing the inventory causes the hat to appear, while it shouldn't.
// This could however introduce regressions somewhere else, so if there is something
// disappearing or not behaving properly in a costume the cause might be here.
//_node->_meshVisible = true;
}
int MeshComponent::update(uint /*time*/) {
_node->setMatrix(_matrix);
return 0;
}
void MeshComponent::saveState(SaveGame *state) {
state->writeBool(_node->_meshVisible);
state->writeVector3d(_matrix.getPosition());
}
void MeshComponent::restoreState(SaveGame *state) {
_node->_meshVisible = state->readBool();
if (state->saveMinorVersion() >= 14) {
_matrix.setPosition(state->readVector3d());
_node->setMatrix(_matrix);
}
}
} // end of namespace Grim

View File

@@ -0,0 +1,58 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRIM_MESH_COMPONENT_H
#define GRIM_MESH_COMPONENT_H
#include "engines/grim/costume/component.h"
namespace Grim {
class CMap;
class Model;
class ModelNode;
class MeshComponent : public Component {
public:
MeshComponent(Component *parent, int parentID, const char *name, tag32 tag);
void init() override;
CMap *cmap();
void setKey(int val) override;
int update(uint time) override;
void reset() override;
void saveState(SaveGame *state) override;
void restoreState(SaveGame *state) override;
void setMatrix(const Math::Matrix4 &matrix) override { _matrix = matrix; };
ModelNode *getNode() { return _node; }
Model *getModel() { return _model; }
private:
int _num;
Model *_model;
ModelNode *_node;
Math::Matrix4 _matrix;
};
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,210 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "engines/grim/debug.h"
#include "engines/grim/model.h"
#include "engines/grim/resource.h"
#include "engines/grim/grim.h"
#include "engines/grim/set.h"
#include "engines/grim/gfx_base.h"
#include "engines/grim/colormap.h"
#include "engines/grim/animation.h"
#include "engines/grim/costume/model_component.h"
#include "engines/grim/costume/main_model_component.h"
#include "engines/grim/costume/mesh_component.h"
namespace Grim {
#define DEFAULT_COLORMAP "item.cmp"
ModelComponent::ModelComponent(Component *p, int parentID, const char *filename, Component *prevComponent, tag32 t) :
Component(p, parentID, filename, t),
_obj(nullptr), _hier(nullptr), _animation(nullptr), _animated(false) {
const char *comma = strchr(filename, ',');
// Can be called with a comma and a numeric parameter afterward, but
// the use for this parameter is currently unknown
// Example: At the "scrimshaw parlor" in Rubacava the object
// "manny_cafe.3do,1" is requested
if (comma) {
_name = Common::String(filename, comma);
warning("Comma in model components not supported: %s", filename);
}
_prevComp = prevComponent;
}
ModelComponent::~ModelComponent() {
if (_hier && _hier->_parent) {
_hier->_parent->removeChild(_hier);
}
delete _obj;
delete _animation;
}
void ModelComponent::init() {
if (_prevComp && _prevComp->isComponentType('M','M','D','L')) {
_previousCmap = _prevComp->getCMap();
}
// Skip loading if it was initialized
// by the sharing MainModelComponent
// constructor before
if (!_obj) {
CMapPtr cm = getCMap();
// Get the default colormap if we haven't found
// a valid colormap
if (!cm && g_grim->getCurrSet())
cm = g_grim->getCurrSet()->getCMap();
if (!cm) {
Debug::warning(Debug::Costumes, "No colormap specified for %s, using %s", _name.c_str(), DEFAULT_COLORMAP);
cm = g_resourceloader->getColormap(DEFAULT_COLORMAP);
}
// If we're the child of a mesh component, put our nodes in the
// parent object's tree.
if (_parent) {
MeshComponent *mc = static_cast<MeshComponent *>(_parent);
_obj = g_resourceloader->loadModel(_name, cm, mc->getModel());
_hier = _obj->getHierarchy();
mc->getNode()->addChild(_hier);
} else {
_obj = g_resourceloader->loadModel(_name, cm);
_hier = _obj->getHierarchy();
Debug::warning(Debug::Costumes, "Parent of model %s wasn't a mesh", _name.c_str());
}
// Use parent availability to decide whether to default the
// component to being visible
if (_parent)
setKey(0);
else
setKey(1);
}
if (!_animation) {
_animation = new AnimManager();
}
}
void ModelComponent::setKey(int val) {
_visible = (val != 0);
_hier->_hierVisible = _visible;
}
void ModelComponent::reset() {
_visible = false;
_hier->_hierVisible = _visible;
}
AnimManager *ModelComponent::getAnimManager() const {
return _animation;
}
int ModelComponent::update(uint time) {
// First reset the current animation.
for (int i = 0; i < getNumNodes(); i++) {
_hier[i]._animPos = _hier[i]._pos;
_hier[i]._animRot = _hier[i]._rot;
}
_animated = false;
return 0;
}
void ModelComponent::animate() {
if (_animated) {
return;
}
_animation->animate(_hier, getNumNodes());
_animated = true;
}
void ModelComponent::resetColormap() {
CMap *cm;
cm = getCMap();
if (_obj && cm)
_obj->reload(cm);
}
void ModelComponent::restoreState(SaveGame *state) {
_hier->_hierVisible = _visible;
}
int ModelComponent::getNumNodes() {
return _obj->getNumNodes();
}
void ModelComponent::translateObject(ModelNode *node, bool reset) {
if (node->_parent)
translateObject(node->_parent, reset);
if (reset) {
node->translateViewpointFinish();
} else {
node->translateViewpointStart();
node->translateViewpoint();
}
}
void ModelComponent::translateObject(bool res) {
ModelNode *node = _hier->_parent;
if (node) {
translateObject(node, res);
}
}
void ModelComponent::draw() {
// If the object was drawn by being a component
// of it's parent then don't draw it
if (_parent && _parent->isVisible())
return;
// Need to translate object to be in accordance
// with the setup of the parent
translateObject(false);
_hier->draw();
// Need to un-translate when done
translateObject(true);
}
void ModelComponent::getBoundingBox(int *x1, int *y1, int *x2, int *y2) {
// If the object was drawn by being a component
// of it's parent then don't draw it
if (_parent && _parent->isVisible())
return;
// Need to translate object to be in accordance
// with the setup of the parent
translateObject(false);
_hier->getBoundingBox(x1, y1, x2, y2);
// Need to un-translate when done
translateObject(true);
}
} // end of namespace Grim

View File

@@ -0,0 +1,64 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRIM_MODEL_COMPONENT_H
#define GRIM_MODEL_COMPONENT_H
#include "engines/grim/costume/component.h"
namespace Grim {
class Model;
class AnimManager;
class ModelComponent : public Component {
public:
ModelComponent(Component *parent, int parentID, const char *filename, Component *prevComponent, tag32 tag);
~ModelComponent();
void init();
void setKey(int val);
int update(uint time);
void animate();
void reset();
void resetColormap();
void restoreState(SaveGame *state);
void translateObject(bool reset);
static void translateObject(ModelNode *node, bool reset);
AnimManager *getAnimManager() const;
ModelNode *getHierarchy() { return _hier; }
int getNumNodes();
Model *getModel() { return _obj; }
void draw();
void getBoundingBox(int *x1, int *y1, int *x2, int *y2);
protected:
Model *_obj;
ModelNode *_hier;
AnimManager *_animation;
Component *_prevComp;
bool _animated;
};
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,72 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "engines/grim/grim.h"
#include "engines/grim/set.h"
#include "engines/grim/debug.h"
#include "engines/grim/costume.h"
#include "engines/grim/costume/sound_component.h"
#include "engines/grim/imuse/imuse.h"
namespace Grim {
SoundComponent::SoundComponent(Component *p, int parentID, const char *filename, tag32 t) :
Component(p, parentID, filename, t) {
const char *comma = strchr(filename, ',');
if (comma) {
_name = Common::String(filename, comma);
}
}
SoundComponent::~SoundComponent() {
// Stop the sound if it's in progress
reset();
}
void SoundComponent::setKey(int val) {
switch (val) {
case 0: // "Play"
// No longer a need to check the sound status, if it's already playing
// then it will just use the existing handle
g_imuse->startSfx(_name.c_str());
if (g_grim->getCurrSet()) {
Math::Vector3d pos = _cost->getMatrix().getPosition();
g_grim->getCurrSet()->setSoundPosition(_name.c_str(), pos);
}
break;
case 1: // "Stop"
g_imuse->stopSound(_name.c_str());
break;
case 2: // "Stop Looping"
g_imuse->setHookId(_name.c_str(), 0x80);
break;
default:
Debug::warning(Debug::Costumes, "Unknown key %d for sound %s", val, _name.c_str());
}
}
void SoundComponent::reset() {
// A lot of the sound components this gets called against aren't actually running
if (g_imuse && g_imuse->getSoundStatus(_name.c_str()))
g_imuse->stopSound(_name.c_str());
}
} // end of namespace Grim

View File

@@ -0,0 +1,40 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRIM_SOUND_COMPONENT_H
#define GRIM_SOUND_COMPONENT_H
#include "engines/grim/costume/component.h"
namespace Grim {
class SoundComponent : public Component {
public:
SoundComponent(Component *parent, int parentID, const char *name, tag32 tag);
~SoundComponent();
void setKey(int val) override;
void reset() override;
};
} // end of namespace Grim
#endif

View File

@@ -0,0 +1,111 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "engines/grim/debug.h"
#include "engines/grim/savegame.h"
#include "engines/grim/model.h"
#include "engines/grim/sprite.h"
#include "engines/grim/material.h"
#include "engines/grim/resource.h"
#include "engines/grim/costume/mesh_component.h"
#include "engines/grim/costume/model_component.h"
#include "engines/grim/costume/sprite_component.h"
namespace Grim {
SpriteComponent::SpriteComponent(Component *p, int parentID, const char *filename, tag32 t) :
Component(p, parentID, filename, t), _sprite(nullptr) {
}
SpriteComponent::~SpriteComponent() {
if (_sprite) {
if (_parent) {
MeshComponent *mc = static_cast<MeshComponent *>(_parent);
if (mc) {
if (mc->getParent()->isComponentType('M','M','D','L') ||
mc->getParent()->isComponentType('M','O','D','L')) {
ModelComponent *mdlc = static_cast<ModelComponent *>(mc->getParent());
if (mdlc->getHierarchy())
mc->getNode()->removeSprite(_sprite);
}
}
}
delete _sprite->_material;
delete _sprite;
}
}
void SpriteComponent::init() {
const char *comma = strchr(_name.c_str(), ',');
Common::String name(_name.c_str(), comma);
if (_sprite) {
if (_parent) {
MeshComponent *mc = static_cast<MeshComponent *>(_parent);
mc->getNode()->removeSprite(_sprite);
}
delete _sprite;
_sprite = nullptr;
}
if (comma) {
_sprite = new Sprite();
_sprite->loadGrim(name, comma, getCMap());
if (_parent) {
if (_parent->isComponentType('M','E','S','H')) {
MeshComponent *mc = static_cast<MeshComponent *>(_parent);
mc->getNode()->addSprite(_sprite);
} else
Debug::warning(Debug::Costumes, "Parent of sprite %s wasn't a mesh", _name.c_str());
}
}
}
void SpriteComponent::setKey(int val) {
if (!_sprite)
return;
if (val == 0) {
_sprite->_visible = false;
} else {
_sprite->_visible = true;
_sprite->_material->setActiveTexture(val - 1);
}
}
void SpriteComponent::reset() {
if (_sprite)
_sprite->_visible = false;
}
void SpriteComponent::saveState(SaveGame *state) {
state->writeBool(_sprite->_visible);
state->writeLESint32(_sprite->_material->getActiveTexture());
}
void SpriteComponent::restoreState(SaveGame *state) {
_sprite->_visible = state->readBool();
_sprite->_material->setActiveTexture(state->readLESint32());
}
} // end of namespace Grim

View File

@@ -0,0 +1,48 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef GRIM_SPRITE_COMPONENT_H
#define GRIM_SPRITE_COMPONENT_H
#include "engines/grim/costume/component.h"
namespace Grim {
class Sprite;
class SpriteComponent : public Component {
public:
SpriteComponent(Component *parent, int parentID, const char *filename, tag32 tag);
~SpriteComponent();
void init() override;
void setKey(int val) override;
void reset() override;
void saveState(SaveGame *state) override;
void restoreState(SaveGame *state) override;
private:
Sprite *_sprite;
};
} // end of namespace Grim
#endif