Initial commit
This commit is contained in:
7
engines/grim/POTFILES
Normal file
7
engines/grim/POTFILES
Normal file
@@ -0,0 +1,7 @@
|
||||
engines/grim/grim.cpp
|
||||
engines/grim/inputdialog.cpp
|
||||
engines/grim/md5check.cpp
|
||||
engines/grim/md5checkdialog.cpp
|
||||
engines/grim/metaengine.cpp
|
||||
engines/grim/resource.cpp
|
||||
engines/grim/emi/sound/emisound.cpp
|
||||
2638
engines/grim/actor.cpp
Normal file
2638
engines/grim/actor.cpp
Normal file
File diff suppressed because it is too large
Load Diff
738
engines/grim/actor.h
Normal file
738
engines/grim/actor.h
Normal file
@@ -0,0 +1,738 @@
|
||||
/* 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_ACTOR_H
|
||||
#define GRIM_ACTOR_H
|
||||
|
||||
#include "engines/grim/pool.h"
|
||||
#include "engines/grim/object.h"
|
||||
#include "engines/grim/color.h"
|
||||
|
||||
#include "math/vector3d.h"
|
||||
#include "math/angle.h"
|
||||
#include "math/quat.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class TextObject;
|
||||
class Sector;
|
||||
class Costume;
|
||||
class LipSync;
|
||||
class Font;
|
||||
class Set;
|
||||
class Material;
|
||||
struct SetShadow;
|
||||
struct Joint;
|
||||
class EMIModel;
|
||||
|
||||
struct Plane {
|
||||
Common::String setName;
|
||||
Sector *sector;
|
||||
};
|
||||
|
||||
typedef Common::List<Plane> SectorListType;
|
||||
|
||||
#define MAX_SHADOWS 8
|
||||
|
||||
struct Shadow {
|
||||
Shadow();
|
||||
|
||||
Common::String name;
|
||||
Math::Vector3d pos;
|
||||
SectorListType planeList;
|
||||
bool active;
|
||||
bool dontNegate;
|
||||
Color color;
|
||||
void *userData;
|
||||
};
|
||||
|
||||
/**
|
||||
* @class Actor
|
||||
*
|
||||
* @short Actor represents a 3D character on screen.
|
||||
*/
|
||||
class Actor : public PoolObject<Actor> {
|
||||
public:
|
||||
enum CollisionMode {
|
||||
CollisionOff = 0,
|
||||
CollisionBox = 1,
|
||||
CollisionSphere = 2
|
||||
};
|
||||
|
||||
enum AlphaMode {
|
||||
AlphaOff = -1,
|
||||
AlphaReplace = 2,
|
||||
AlphaModulate = 3 // Seems to be unused
|
||||
};
|
||||
|
||||
enum LightMode {
|
||||
LightStatic = 0,
|
||||
LightFastDyn = 1,
|
||||
LightNormDyn = 2,
|
||||
LightNone = 3
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds an actor setting up only the minimal variables.
|
||||
*/
|
||||
Actor();
|
||||
/**
|
||||
* Destroys the actor.
|
||||
* The actor is automatically removed from the GrimEngine instance.
|
||||
*/
|
||||
~Actor();
|
||||
|
||||
static int32 getStaticTag() { return MKTAG('A', 'C', 'T', 'R'); }
|
||||
|
||||
/**
|
||||
* Saves the actor state.
|
||||
*
|
||||
* @param savedState The save state to which save the actor's state.
|
||||
*/
|
||||
void saveState(SaveGame *savedState) const;
|
||||
/**
|
||||
* Restores the actor state.
|
||||
*
|
||||
* @param savedState The saved state from which the actor will be restored.
|
||||
*/
|
||||
bool restoreState(SaveGame *savedState);
|
||||
|
||||
/**
|
||||
* Returns the name of the actor.
|
||||
*/
|
||||
const Common::String &getName() const { return _name; }
|
||||
|
||||
/**
|
||||
* Sets the name of the actor.
|
||||
*
|
||||
* @param name The name.
|
||||
*/
|
||||
void setName(const Common::String &name) { _name = name; }
|
||||
|
||||
/**
|
||||
* Sets the color of the subtitles of the actor.
|
||||
*
|
||||
* @param color The color.
|
||||
* @see getTalkColor
|
||||
*/
|
||||
void setTalkColor(const Color &color) { _talkColor = color; }
|
||||
/**
|
||||
* Returns the color of the subtitles of the actor.
|
||||
*
|
||||
* @see setTalkColor
|
||||
*/
|
||||
Color getTalkColor() const { return _talkColor; }
|
||||
|
||||
/**
|
||||
* Sets the position of the actor on the 3D scene.
|
||||
*
|
||||
* @param position The position.
|
||||
* @see getPos
|
||||
*/
|
||||
void setPos(const Math::Vector3d &position);
|
||||
/**
|
||||
* Returns the position of the actor on the 3D scene.
|
||||
*
|
||||
* @see setPos
|
||||
*/
|
||||
Math::Vector3d getPos() const { return _pos; }
|
||||
inline Math::Vector3d getDestPos() const { return _destPos; }
|
||||
|
||||
/**
|
||||
* Tells the actor to go to the wanted position.
|
||||
* If the actor follows the walkboxes it will find the best
|
||||
* route to go there, otherwise it will walk on a straight line.
|
||||
*
|
||||
* @param position The destination position.
|
||||
* @see stopWalking
|
||||
* @see isWalking
|
||||
*/
|
||||
void walkTo(const Math::Vector3d &position);
|
||||
/**
|
||||
* Stops immediately the actor's walk.
|
||||
*
|
||||
* @see walkTo
|
||||
* @see isWalking
|
||||
*/
|
||||
void stopWalking() { _walking = false; }
|
||||
/**
|
||||
* Returns true if the actor is walking to a position.
|
||||
*
|
||||
* @see walkTo
|
||||
* @see stopWalking
|
||||
*/
|
||||
bool isWalking() const;
|
||||
|
||||
/**
|
||||
* Sets the rotation of thes actor in the 3D scene.
|
||||
* The effect is not immediate, the actor will slowly rotate
|
||||
* to the destination orientation.
|
||||
*
|
||||
* @param pitch The rotation of the x axis
|
||||
* @param yaw The rotation of the z axis
|
||||
* @param roll The rotation of the y axis
|
||||
* @param snap If true tells the actor to increate its turn speed.
|
||||
* @see getPitch
|
||||
* @see getYaw
|
||||
* @see getRoll
|
||||
* @see setRot
|
||||
* @see turn
|
||||
* @see isTurning
|
||||
*/
|
||||
void turnTo(const Math::Angle &pitch, const Math::Angle &yaw, const Math::Angle &roll, bool snap = false);
|
||||
/**
|
||||
* Turn the actor towards a point in space.
|
||||
* The effect is not immediate, the actor will slowly rotate
|
||||
* to the destination orientation.
|
||||
*
|
||||
* @param pos The position the actor should turn to.
|
||||
* @param snap If true tells the actor to increate its turn speed.
|
||||
* @see turnTo
|
||||
* @see setRot
|
||||
*/
|
||||
void turnTo(const Math::Vector3d &pos, bool snap = false);
|
||||
/**
|
||||
* Turn the actor towards a point in space, by an amount defined by the turn rate.
|
||||
* This function does not make an actor point at the given position, but it makes
|
||||
* it rotate towards that.
|
||||
*
|
||||
* @param pos The position the actor should turn to.
|
||||
* @return true if the actor has reached the desired orientation
|
||||
* @see turnTo
|
||||
* @see setRot
|
||||
*/
|
||||
bool singleTurnTo(const Math::Vector3d &pos);
|
||||
/**
|
||||
* Returns true if the actor is turning.
|
||||
*
|
||||
* @see turnTo
|
||||
*/
|
||||
bool isTurning() const;
|
||||
/**
|
||||
* Stops the actor from turning
|
||||
*/
|
||||
void stopTurning();
|
||||
/**
|
||||
* Sets the rotation of the actor in the 3D scene.
|
||||
* The effect is immediate.
|
||||
*
|
||||
* @param pitch The rotation of the x axis
|
||||
* @param yaw The rotation of the z axis
|
||||
* @param roll The rotation of the y axis
|
||||
* @see getPitch
|
||||
* @see getYaw
|
||||
* @see getRoll
|
||||
* @see turnTo
|
||||
* @see turn
|
||||
* @see isTurning
|
||||
*/
|
||||
void setRot(const Math::Angle &pitch, const Math::Angle &yaw, const Math::Angle &roll);
|
||||
/**
|
||||
* Turn the actor towards a point in space.
|
||||
* The effect is immediate.
|
||||
*
|
||||
* @param pos The position the actor should turn to.
|
||||
* @see turnTo
|
||||
* @see setRot
|
||||
*/
|
||||
void setRot(const Math::Vector3d &pos);
|
||||
/**
|
||||
* Turns the actor by the given parameter on the z axis.
|
||||
* The actual movement depends also on the turn rate.
|
||||
*
|
||||
* @param dir The quantity of the movement.
|
||||
* @see getPitch
|
||||
* @see getYaw
|
||||
* @see getRoll
|
||||
* @see setRot
|
||||
* @see turnTo
|
||||
* @see isTurning
|
||||
*/
|
||||
void turn(int dir);
|
||||
/**
|
||||
* Returns the pitch of the actor, which is the rotation
|
||||
* on the x axis.
|
||||
*
|
||||
* @see getYaw
|
||||
* @see getRoll
|
||||
* @see setRot
|
||||
* @see turnTo
|
||||
* @see isTurning
|
||||
*/
|
||||
Math::Angle getPitch() const { return _pitch; }
|
||||
/**
|
||||
* Returns the yaw of the actor, which is the rotation
|
||||
* on the z axis.
|
||||
*
|
||||
* @see getPitch
|
||||
* @see getRoll
|
||||
* @see setRot
|
||||
* @see turnTo
|
||||
* @see isTurning
|
||||
*/
|
||||
Math::Angle getYaw() const { return _yaw; }
|
||||
/**
|
||||
* Returns the roll of the actor, which is the rotation
|
||||
* on the y axis.
|
||||
*
|
||||
* @see getPitch
|
||||
* @see getYaw
|
||||
* @see setRot
|
||||
* @see turnTo
|
||||
* @see isTurning
|
||||
*/
|
||||
Math::Angle getRoll() const { return _roll; }
|
||||
|
||||
/**
|
||||
* Calculates and returns the angle between the direction the
|
||||
* actor is facing and the direction towards another actor.
|
||||
*
|
||||
* @param actor The actor to look at.
|
||||
*/
|
||||
Math::Angle getYawTo(const Actor *actor) const;
|
||||
/**
|
||||
* Calculates and returns the angle between the direction the
|
||||
* actor is facing and the direction towards a point.
|
||||
*
|
||||
* @param actor The point to look at.
|
||||
*/
|
||||
Math::Angle getYawTo(const Math::Vector3d &p) const;
|
||||
|
||||
/**
|
||||
* Sets the actor visibility.
|
||||
*
|
||||
* @param val The value: true if visible, false otherwise.
|
||||
* @see isVisible
|
||||
*/
|
||||
void setVisibility(bool val) { _visible = val; }
|
||||
/**
|
||||
* Returns true if the actor is visible.
|
||||
*
|
||||
* @see setVisibility
|
||||
*/
|
||||
bool isVisible() const { return _visible; }
|
||||
|
||||
/**
|
||||
* Sets the scale of the actor.
|
||||
* A value of 1 is the natural size.
|
||||
*
|
||||
* @param scale The scale of the actor.
|
||||
*/
|
||||
void setScale(float scale) { _scale = scale; }
|
||||
float getScale() const { return _scale; }
|
||||
|
||||
/**
|
||||
* Sets the time scale of the actor, used to calculate the
|
||||
* speed of its animations.
|
||||
* A value of 1 is the normal speed.
|
||||
*
|
||||
* @param scale The time scale.
|
||||
* @see getTimeScale
|
||||
*/
|
||||
void setTimeScale(float scale) { _timeScale = scale; }
|
||||
/**
|
||||
* Returns the time scale of the actor.
|
||||
*
|
||||
* @see setTimeScale
|
||||
*/
|
||||
float getTimeScale() const { return _timeScale; }
|
||||
|
||||
/**
|
||||
* Puts the actor in a set.
|
||||
*
|
||||
* @param setName The name of the set.
|
||||
*/
|
||||
void putInSet(const Common::String &setName);
|
||||
/**
|
||||
* Returns true if the actor is in the given set.
|
||||
* For engine internal use only, do not expose via lua API.
|
||||
*
|
||||
* @param setName The name of the set.
|
||||
*/
|
||||
bool isDrawableInSet(const Common::String &setName) const;
|
||||
/**
|
||||
* Returns true if the actor is in the given set.
|
||||
* Can be exposed via lua API.
|
||||
*
|
||||
* @param setName The name of the set.
|
||||
*/
|
||||
bool isInSet(const Common::String &setName) const;
|
||||
|
||||
/**
|
||||
* Sets the rate of the turning.
|
||||
*
|
||||
* @param rat The wanted rate.
|
||||
* @see getTurnRate
|
||||
*/
|
||||
void setTurnRate(float rate) { _turnRate = rate; }
|
||||
/**
|
||||
* Returns the turn rate.
|
||||
*
|
||||
* @see setTurnRate
|
||||
*/
|
||||
float getTurnRate() const { return _turnRate; }
|
||||
/**
|
||||
* Sets the rate of the walk movement.
|
||||
*
|
||||
* @param rate The wanted rate.
|
||||
* @see getWalkRate
|
||||
*/
|
||||
void setWalkRate(float rate) { _walkRate = rate; }
|
||||
/**
|
||||
* Returns the walk rate of the actor.
|
||||
*
|
||||
* @see setWalkRate
|
||||
*/
|
||||
float getWalkRate() const { return _walkRate; }
|
||||
|
||||
void setLooking(bool lookingMode) { _lookingMode = lookingMode; }
|
||||
|
||||
/**
|
||||
* Makes the actor move forward, the length of the movement based
|
||||
* on the walk rate.
|
||||
* If it is following boxes it will not go into not walkable areas.
|
||||
*
|
||||
* @see walkTo
|
||||
*/
|
||||
void walkForward();
|
||||
void moveTo(const Math::Vector3d &pos);
|
||||
/**
|
||||
* Used to tell the actor if it is running or not.
|
||||
*
|
||||
* @param running The value: true if it is running.
|
||||
*/
|
||||
void setRunning(bool running) { _running = running; }
|
||||
void setReflection(float angle) { _reflectionAngle = angle; }
|
||||
/**
|
||||
* Returns a vector representing the direction the actor
|
||||
* is facing.
|
||||
*/
|
||||
Math::Vector3d getPuckVector() const;
|
||||
|
||||
void setPuckOrient(bool orient);
|
||||
|
||||
/**
|
||||
* Makes the actor say the given line.
|
||||
* It will show a subtitle and/or play the voice, depending
|
||||
* on the speech mode set in the GrimEngine instance.
|
||||
*
|
||||
* @param msgId The id of the message to say.
|
||||
* @param background ?? actual meaning unknown yet.
|
||||
* @see isTalking
|
||||
* @see shutUp
|
||||
*/
|
||||
void sayLine(const char *msgId, bool background, float x, float y);
|
||||
// When we clean all text objects we don't want the actors to clean their
|
||||
// objects again since they're already freed
|
||||
void lineCleanup();
|
||||
/**
|
||||
* Makes the actor discard any subtitle and voice.
|
||||
*
|
||||
* @see sayLine
|
||||
* @see isTalking
|
||||
*/
|
||||
void shutUp();
|
||||
/**
|
||||
* Returns true if the actor is saying something.
|
||||
*
|
||||
* @see sayLine
|
||||
* @see shutUp
|
||||
*/
|
||||
bool isTalking();
|
||||
|
||||
void setRestChore(int choreNumber, Costume *cost);
|
||||
int getRestChore() const;
|
||||
void setWalkChore(int choreNumber, Costume *cost);
|
||||
void setTurnChores(int left_chore, int right_chore, Costume *cost);
|
||||
void setTalkChore(int index, int choreNumber, Costume *cost);
|
||||
int getTalkChore(int index) const;
|
||||
Costume *getTalkCostume(int index) const;
|
||||
void setMumbleChore(int choreNumber, Costume *cost);
|
||||
void stopAllChores(bool ignoreLoopingChores = false);
|
||||
void setColormap(const char *map);
|
||||
void pushCostume(const char *name);
|
||||
void setCostume(const char *name);
|
||||
void popCostume();
|
||||
void clearCostumes();
|
||||
Costume *getCurrentCostume() const;
|
||||
void setLocalAlphaMode(unsigned int vertex, AlphaMode alphamode);
|
||||
void setLocalAlpha(unsigned int vertex, float alpha);
|
||||
bool hasLocalAlpha() const;
|
||||
float getLocalAlpha(unsigned int vertex) const;
|
||||
Costume *findCostume(const Common::String &name);
|
||||
int getCostumeStackDepth() const {
|
||||
return _costumeStack.size();
|
||||
}
|
||||
const Common::List<Costume *> &getCostumes() const { return _costumeStack; }
|
||||
|
||||
void setActiveShadow(int shadowId);
|
||||
void setShadowPoint(const Math::Vector3d &pos);
|
||||
void setShadowColor(const Color &color);
|
||||
void setShadowPlane(const char *name);
|
||||
void addShadowPlane(const char *name);
|
||||
void clearShadowPlanes();
|
||||
void clearShadowPlane(int i);
|
||||
void setShadowValid(int);
|
||||
void setActivateShadow(int, bool);
|
||||
|
||||
void setFollowBoxes(bool follow);
|
||||
bool hasFollowBoxes() const { return _followBoxes; }
|
||||
bool hasFollowedBoxes() const { return _hasFollowedBoxes; }
|
||||
void update(uint frameTime);
|
||||
/**
|
||||
* Check if the actor is still talking. If it is returns true, otherwise false.
|
||||
*/
|
||||
bool updateTalk(uint frameTime);
|
||||
void draw();
|
||||
|
||||
bool isLookAtVectorZero() {
|
||||
return _lookAtVector.isZero();
|
||||
}
|
||||
void setLookAtVectorZero() {
|
||||
_lookAtVector.set(0.f, 0.f, 0.f);
|
||||
_lookAtActor = 0;
|
||||
}
|
||||
void setLookAtVector(const Math::Vector3d &vector) {
|
||||
_lookAtVector = vector;
|
||||
_lookAtActor = 0;
|
||||
}
|
||||
Math::Vector3d getLookAtVector() {
|
||||
return _lookAtVector;
|
||||
}
|
||||
void setLookAtActor(Actor *other) { _lookAtActor = other->getId(); }
|
||||
void setLookAtRate(float rate);
|
||||
float getLookAtRate() const;
|
||||
void setHead(int joint1, int joint2, int joint3, float maxRoll, float maxPitch, float maxYaw);
|
||||
void setHead(const char *joint, const Math::Vector3d &offset);
|
||||
void setHeadLimits(float yawRange, float maxPitch, float minPitch);
|
||||
|
||||
void setCollisionMode(CollisionMode mode);
|
||||
void setCollisionScale(float scale);
|
||||
|
||||
bool handleCollisionWith(Actor *actor, CollisionMode mode, Math::Vector3d *vec) const;
|
||||
|
||||
static void saveStaticState(SaveGame *state);
|
||||
static void restoreStaticState(SaveGame *state);
|
||||
|
||||
bool isAttached() const { return _attachedActor != 0; }
|
||||
Math::Vector3d getWorldPos() const;
|
||||
void attachToActor(Actor *other, const char *joint);
|
||||
void detach();
|
||||
Math::Quaternion getRotationQuat() const;
|
||||
const Math::Matrix4 getFinalMatrix() const;
|
||||
Math::Vector3d getHeadPos() const;
|
||||
|
||||
void setInOverworld(bool inOverworld) { _inOverworld = inOverworld; }
|
||||
bool isInOverworld() const { return _inOverworld; }
|
||||
|
||||
float getGlobalAlpha() const { return _globalAlpha; }
|
||||
AlphaMode getAlphaMode() const { return _alphaMode; }
|
||||
float getEffectiveAlpha() const { return _alphaMode != AlphaOff ? _globalAlpha : 1.f; }
|
||||
void setGlobalAlpha(float alpha, const Common::String &mesh);
|
||||
void setAlphaMode(AlphaMode mode, const Common::String &mesh);
|
||||
|
||||
int getSortOrder() const;
|
||||
void setSortOrder(const int order);
|
||||
int getEffectiveSortOrder() const;
|
||||
|
||||
void activateShadow(bool active, const char *shadowName);
|
||||
void activateShadow(bool active, SetShadow *shadow);
|
||||
|
||||
void drawToCleanBuffer();
|
||||
|
||||
bool isTalkingForeground() const;
|
||||
|
||||
LightMode getLightMode() const { return _lightMode; }
|
||||
void setLightMode(LightMode lightMode) { _lightMode = lightMode; }
|
||||
|
||||
ObjectPtr<Material> loadMaterial(const Common::String &name, bool clamp);
|
||||
ObjectPtr<Material> findMaterial(const Common::String &name);
|
||||
|
||||
void getBBoxInfo(Math::Vector3d &bboxPos, Math::Vector3d &bboxSize) const;
|
||||
|
||||
private:
|
||||
void costumeMarkerCallback(int marker);
|
||||
void collisionHandlerCallback(Actor *other) const;
|
||||
void updateWalk();
|
||||
void addShadowPlane(const char *n, Set *scene, int shadowId);
|
||||
bool shouldDrawShadow(int shadowId);
|
||||
void stopTalking();
|
||||
bool stopMumbleChore();
|
||||
void drawCostume(Costume *costume);
|
||||
/**
|
||||
* Given a start point and a destination this function returns a position
|
||||
* that doesn't collide with any actor.
|
||||
*/
|
||||
Math::Vector3d handleCollisionTo(const Math::Vector3d &from, const Math::Vector3d &pos) const;
|
||||
/**
|
||||
* Check if the line from pos to dest collides with this actor's bounding
|
||||
* box, and if yes return a point that, together with pos, defines a line
|
||||
* tangent with the bounding box.
|
||||
*/
|
||||
Math::Vector3d getTangentPos(const Math::Vector3d &pos, const Math::Vector3d &dest) const;
|
||||
|
||||
Math::Vector3d getSimplePuckVector() const;
|
||||
void calculateOrientation(const Math::Vector3d &pos, Math::Angle *pitch, Math::Angle *yaw, Math::Angle *roll);
|
||||
|
||||
bool getSphereInfo(bool adjustZ, float &size, Math::Vector3d &pos) const;
|
||||
EMIModel *findModelWithMesh(const Common::String &mesh);
|
||||
|
||||
Common::String _name;
|
||||
Common::String _setName; // The actual current set
|
||||
|
||||
Color _talkColor;
|
||||
Math::Vector3d _pos;
|
||||
Math::Angle _pitch, _yaw, _roll;
|
||||
float _walkRate, _turnRate;
|
||||
|
||||
bool _followBoxes; // Constrain to walkboxes
|
||||
bool _hasFollowedBoxes;
|
||||
float _reflectionAngle; // Maximum angle to turn by at walls
|
||||
bool _visible;
|
||||
float _scale;
|
||||
float _timeScale;
|
||||
bool _lookingMode;
|
||||
Common::String _talkSoundName;
|
||||
bool _talking;
|
||||
bool _backgroundTalk;
|
||||
ObjectPtr<LipSync> _lipSync;
|
||||
Common::List<Costume *> _costumeStack;
|
||||
|
||||
// Variables for gradual turning
|
||||
bool _turning;
|
||||
bool _singleTurning;
|
||||
// NOTE: The movement direction is separate from the direction
|
||||
// the actor's model is facing. The model's direction is gradually
|
||||
// updated to match the movement direction. This produces a smooth
|
||||
// turning animation while still allowing the actor to move in a
|
||||
// new direction immediately after reflecting off a wall.
|
||||
Math::Angle _moveYaw;
|
||||
Math::Angle _movePitch;
|
||||
Math::Angle _moveRoll;
|
||||
// This is used to increase momentarily the turn rate when needed
|
||||
float _turnRateMultiplier;
|
||||
|
||||
// Variables for walking to a point
|
||||
bool _walking;
|
||||
Math::Vector3d _destPos;
|
||||
|
||||
//chores
|
||||
class ActionChore {
|
||||
public:
|
||||
ActionChore();
|
||||
ActionChore(Costume *cost, int chore);
|
||||
|
||||
void play(bool fade = false, unsigned int time = fadeTime);
|
||||
void playLooping(bool fade = false, unsigned int time = fadeTime);
|
||||
void stop(bool fade = false, unsigned int time = fadeTime);
|
||||
void setLastFrame();
|
||||
|
||||
inline bool isValid() const { return _chore > -1 && _costume != nullptr; }
|
||||
bool isPlaying() const;
|
||||
inline bool equals(const Costume *cost, int chore) const {
|
||||
return (_costume == cost && _chore == chore);
|
||||
}
|
||||
|
||||
void saveState(SaveGame *state) const;
|
||||
void restoreState(SaveGame *state, Actor *actor);
|
||||
|
||||
Costume *_costume;
|
||||
int _chore;
|
||||
|
||||
static const unsigned int fadeTime;
|
||||
static const unsigned int talkFadeTime;
|
||||
};
|
||||
ActionChore _restChore;
|
||||
|
||||
ActionChore _walkChore;
|
||||
bool _walkedLast, _walkedCur;
|
||||
bool _running;
|
||||
|
||||
ActionChore _leftTurnChore, _rightTurnChore;
|
||||
int _lastTurnDir, _currTurnDir;
|
||||
|
||||
ActionChore _talkChore[10];
|
||||
int _talkAnim;
|
||||
|
||||
ActionChore _mumbleChore;
|
||||
|
||||
Shadow *_shadowArray;
|
||||
int _activeShadowSlot;
|
||||
|
||||
static ObjectPtr<Font> _sayLineFont;
|
||||
int _sayLineText;
|
||||
bool _mustPlaceText;
|
||||
|
||||
ActionChore *getTurnChore(int dir) {
|
||||
return (dir > 0 ? &_leftTurnChore : &_rightTurnChore);
|
||||
}
|
||||
|
||||
void freeCostume(Costume *costume);
|
||||
void freeCostumeChore(const Costume *toFree, ActionChore *chore);
|
||||
|
||||
// lookAt
|
||||
Math::Vector3d _lookAtVector;
|
||||
|
||||
// struct used for path finding
|
||||
struct PathNode {
|
||||
Sector *sect;
|
||||
PathNode *parent;
|
||||
Math::Vector3d pos;
|
||||
float dist;
|
||||
float cost;
|
||||
};
|
||||
Common::List<Math::Vector3d> _path;
|
||||
|
||||
CollisionMode _collisionMode;
|
||||
float _collisionScale;
|
||||
|
||||
bool _puckOrient;
|
||||
|
||||
static bool _isTalkingBackground;
|
||||
int _talkDelay;
|
||||
int _attachedActor;
|
||||
int _lookAtActor;
|
||||
Common::String _attachedJoint;
|
||||
AlphaMode _alphaMode;
|
||||
float _globalAlpha;
|
||||
|
||||
bool _inOverworld;
|
||||
|
||||
int _sortOrder;
|
||||
int _sectorSortOrder;
|
||||
bool _useParentSortOrder;
|
||||
|
||||
bool _fakeUnbound;
|
||||
bool _drawnToClean;
|
||||
|
||||
LightMode _lightMode;
|
||||
|
||||
Common::List<ObjectPtr<Material> > _materials;
|
||||
|
||||
// Highest vertex used in EMI
|
||||
const static unsigned int MAX_LOCAL_ALPHA_VERTICES = 48;
|
||||
Common::Array<float> _localAlpha;
|
||||
Common::Array<int> _localAlphaMode;
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
284
engines/grim/animation.cpp
Normal file
284
engines/grim/animation.cpp
Normal file
@@ -0,0 +1,284 @@
|
||||
/* 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/animation.h"
|
||||
#include "engines/grim/resource.h"
|
||||
#include "engines/grim/model.h"
|
||||
#include "engines/grim/debug.h"
|
||||
#include "engines/grim/savegame.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
Animation::Animation(const Common::String &keyframe, AnimManager *manager, int pr1, int pr2) :
|
||||
_manager(manager), _priority1(pr1), _priority2(pr2), _paused(true),
|
||||
_active(false), _time(-1), _fade(1.f), _fadeMode(None) {
|
||||
_keyframe = g_resourceloader->getKeyframe(keyframe);
|
||||
}
|
||||
|
||||
Animation::~Animation() {
|
||||
deactivate();
|
||||
}
|
||||
|
||||
void Animation::activate() {
|
||||
if (!_active) {
|
||||
_active = true;
|
||||
_manager->addAnimation(this, _priority1, _priority2);
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::deactivate() {
|
||||
if (_active) {
|
||||
_active = false;
|
||||
_manager->removeAnimation(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Animation::play(RepeatMode repeatMode) {
|
||||
_repeatMode = repeatMode;
|
||||
if (_repeatMode != Looping)
|
||||
_time = -1;
|
||||
_paused = false;
|
||||
// Reset the fading, so that a fading out a chore and playing another one with an animation in common
|
||||
// results in the animation being actually played. (You can check that with Olivia by the car in set me,
|
||||
// when jumping with j+ts; me.olivia_search_idles() in me.lua)
|
||||
if (_fadeMode == FadeOut)
|
||||
_fadeMode = None;
|
||||
activate();
|
||||
}
|
||||
|
||||
void Animation::fade(FadeMode fadeMode, int fadeLength) {
|
||||
if (!_active) {
|
||||
if (fadeMode == FadeIn) {
|
||||
_repeatMode = PauseAtEnd;
|
||||
_time = -1;
|
||||
_fade = 0.f;
|
||||
_paused = false;
|
||||
}
|
||||
}
|
||||
_fadeMode = fadeMode;
|
||||
_fadeLength = fadeLength;
|
||||
}
|
||||
|
||||
void Animation::pause(bool p) {
|
||||
_paused = p;
|
||||
}
|
||||
|
||||
void Animation::stop() {
|
||||
_fadeMode = None;
|
||||
_time = -1;
|
||||
_fade = 1.f;
|
||||
_paused = false;
|
||||
deactivate();
|
||||
}
|
||||
|
||||
bool Animation::getIsActive() const {
|
||||
return _active;
|
||||
}
|
||||
|
||||
Animation::FadeMode Animation::getFadeMode() const {
|
||||
return _fadeMode;
|
||||
|
||||
}
|
||||
|
||||
int Animation::update(uint time) {
|
||||
// For first time through newTime will be 0
|
||||
int newTime = 0;
|
||||
if (_time >= 0 && !_paused)
|
||||
newTime = _time + time;
|
||||
|
||||
int marker = 0;
|
||||
if (!_paused) {
|
||||
marker = _keyframe->getMarker(_time / 1000.f, newTime / 1000.f);
|
||||
_time = newTime;
|
||||
}
|
||||
|
||||
int animLength = (int)(_keyframe->getLength() * 1000);
|
||||
|
||||
if (_fadeMode != None) {
|
||||
if (_fadeMode == FadeIn) {
|
||||
_fade += (float)time / (float)_fadeLength;
|
||||
if (_fade >= 1.f) {
|
||||
_fade = 1.f;
|
||||
_fadeMode = None;
|
||||
}
|
||||
} else {
|
||||
_fade -= (float)time / (float)_fadeLength;
|
||||
if (_fade <= 0.f) {
|
||||
_fade = 0.f;
|
||||
// Don't reset the _fadeMode here. This way if fadeOut() was called
|
||||
// on a looping chore its keyframe animations will remain faded out
|
||||
// when it calls play() again.
|
||||
deactivate();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_fade = 1.f;
|
||||
}
|
||||
|
||||
if (_time > animLength) { // What to do at end?
|
||||
switch (_repeatMode) {
|
||||
case Once:
|
||||
if (_fadeMode == None)
|
||||
deactivate();
|
||||
else
|
||||
_time = animLength;
|
||||
break;
|
||||
case Looping:
|
||||
_time = -1;
|
||||
break;
|
||||
case PauseAtEnd:
|
||||
_time = animLength;
|
||||
_paused = true;
|
||||
break;
|
||||
case FadeAtEnd:
|
||||
if (_fadeMode != FadeOut) {
|
||||
_fadeMode = FadeOut;
|
||||
_fadeLength = 250;
|
||||
}
|
||||
_time = animLength;
|
||||
break;
|
||||
default:
|
||||
Debug::warning(Debug::Keyframes, "Unknown repeat mode %d for keyframe %s", _repeatMode, _keyframe->getFilename().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return marker;
|
||||
}
|
||||
|
||||
void Animation::saveState(SaveGame *state) const {
|
||||
state->writeBool(_active);
|
||||
state->writeLESint32((int)_repeatMode);
|
||||
state->writeLESint32(_time);
|
||||
state->writeLESint32((int)_fadeMode);
|
||||
state->writeFloat(_fade);
|
||||
state->writeLESint32(_fadeLength);
|
||||
state->writeBool(_paused);
|
||||
}
|
||||
|
||||
void Animation::restoreState(SaveGame *state) {
|
||||
bool active = state->readBool();
|
||||
_repeatMode = (RepeatMode)state->readLESint32();
|
||||
_time = state->readLESint32();
|
||||
_fadeMode = (FadeMode)state->readLESint32();
|
||||
_fade = state->readFloat();
|
||||
_fadeLength = state->readLESint32();
|
||||
_paused = state->readBool();
|
||||
|
||||
if (active)
|
||||
activate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @class AnimManager
|
||||
*/
|
||||
|
||||
AnimManager::AnimManager() {
|
||||
}
|
||||
|
||||
AnimManager::~AnimManager() {
|
||||
for (const AnimationEntry &entry : _activeAnims) {
|
||||
Animation *anim = entry._anim;
|
||||
// Don't call deactivate() here so we don't mess with the list we're using.
|
||||
anim->_manager = nullptr;
|
||||
anim->_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
void AnimManager::addAnimation(Animation *anim, int priority1, int priority2) {
|
||||
// Keep the list of animations sorted by priorities in descending order. Because
|
||||
// the animations have two different priorities, we add the animation to the list
|
||||
// with both priorities.
|
||||
Common::List<AnimationEntry>::iterator i;
|
||||
AnimationEntry entry;
|
||||
entry._anim = anim;
|
||||
entry._priority = priority1;
|
||||
entry._tagged = false;
|
||||
for (i = _activeAnims.begin(); i != _activeAnims.end(); ++i) {
|
||||
if (i->_priority < entry._priority) {
|
||||
_activeAnims.insert(i, entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == _activeAnims.end())
|
||||
_activeAnims.push_back(entry);
|
||||
|
||||
entry._priority = priority2;
|
||||
entry._tagged = true;
|
||||
for (i = _activeAnims.begin(); i != _activeAnims.end(); ++i) {
|
||||
if (i->_priority < entry._priority) {
|
||||
_activeAnims.insert(i, entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == _activeAnims.end())
|
||||
_activeAnims.push_back(entry);
|
||||
}
|
||||
|
||||
void AnimManager::removeAnimation(const Animation *anim) {
|
||||
Common::List<AnimationEntry>::iterator i;
|
||||
for (i = _activeAnims.begin(); i != _activeAnims.end(); ++i) {
|
||||
if (i->_anim == anim) {
|
||||
i = _activeAnims.erase(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimManager::animate(ModelNode *hier, int numNodes) {
|
||||
// Apply animation to each hierarchy node separately.
|
||||
for (int i = 0; i < numNodes; i++) {
|
||||
float remainingWeight = 1.0f;
|
||||
int currPriority = -1;
|
||||
float layerWeight = 0.0f;
|
||||
|
||||
// The animations are layered so that animations with a higher priority
|
||||
// are played regardless of the blend weights of lower priority animations.
|
||||
// The highest priority layer gets as much weight as it wants, while the
|
||||
// next layer gets the remaining amount and so on.
|
||||
for (Common::List<AnimationEntry>::iterator j = _activeAnims.begin(); j != _activeAnims.end(); ++j) {
|
||||
if (currPriority != j->_priority) {
|
||||
remainingWeight *= 1.0f - layerWeight;
|
||||
layerWeight = 0.0f;
|
||||
for (Common::List<AnimationEntry>::iterator k = j; k != _activeAnims.end(); ++k) {
|
||||
if (j->_priority != k->_priority)
|
||||
break;
|
||||
float time = k->_anim->_time / 1000.0f;
|
||||
if (k->_anim->_keyframe->isNodeAnimated(hier, i, time, k->_tagged))
|
||||
layerWeight += k->_anim->_fade;
|
||||
}
|
||||
|
||||
currPriority = j->_priority;
|
||||
if (remainingWeight <= 0.0f)
|
||||
break;
|
||||
}
|
||||
|
||||
float time = j->_anim->_time / 1000.0f;
|
||||
float weight = j->_anim->_fade;
|
||||
if (layerWeight > 1.0f)
|
||||
weight /= layerWeight;
|
||||
weight *= remainingWeight;
|
||||
j->_anim->_keyframe->animate(hier, i, time, weight, j->_tagged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
99
engines/grim/animation.h
Normal file
99
engines/grim/animation.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/* 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_ANIMATION_H
|
||||
#define GRIM_ANIMATION_H
|
||||
|
||||
#include "engines/grim/keyframe.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class SaveGame;
|
||||
class AnimManager;
|
||||
|
||||
class Animation {
|
||||
public:
|
||||
enum RepeatMode {
|
||||
Once = 0,
|
||||
Looping = 1,
|
||||
PauseAtEnd = 2,
|
||||
FadeAtEnd = 3
|
||||
};
|
||||
enum FadeMode {
|
||||
None = 0,
|
||||
FadeIn = 1,
|
||||
FadeOut = 2
|
||||
};
|
||||
|
||||
Animation(const Common::String &keyframe, AnimManager *manager, int pr1, int pr2);
|
||||
~Animation();
|
||||
void activate();
|
||||
void deactivate();
|
||||
void play(RepeatMode repeatMode);
|
||||
void fade(FadeMode fadeMode, int fadeLength);
|
||||
void pause(bool pause);
|
||||
void stop();
|
||||
bool getIsActive() const;
|
||||
FadeMode getFadeMode() const;
|
||||
|
||||
int update(uint time);
|
||||
|
||||
void saveState(SaveGame *state) const;
|
||||
void restoreState(SaveGame *state);
|
||||
|
||||
private:
|
||||
AnimManager *_manager;
|
||||
ObjectPtr<KeyframeAnim> _keyframe;
|
||||
int _priority1;
|
||||
int _priority2;
|
||||
bool _paused;
|
||||
bool _active;
|
||||
int _time;
|
||||
float _fade;
|
||||
RepeatMode _repeatMode;
|
||||
FadeMode _fadeMode;
|
||||
int _fadeLength;
|
||||
|
||||
friend class AnimManager;
|
||||
};
|
||||
|
||||
class AnimManager {
|
||||
public:
|
||||
AnimManager();
|
||||
~AnimManager();
|
||||
void addAnimation(Animation *anim, int pr1, int pr2);
|
||||
void removeAnimation(const Animation *anim);
|
||||
|
||||
void animate(ModelNode *hier, int numNodes);
|
||||
|
||||
private:
|
||||
struct AnimationEntry {
|
||||
Animation *_anim;
|
||||
int _priority;
|
||||
bool _tagged;
|
||||
};
|
||||
|
||||
Common::List<AnimationEntry> _activeAnims;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
537
engines/grim/bitmap.cpp
Normal file
537
engines/grim/bitmap.cpp
Normal file
@@ -0,0 +1,537 @@
|
||||
/* 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/endian.h"
|
||||
|
||||
#include "image/tga.h"
|
||||
|
||||
#include "engines/grim/savegame.h"
|
||||
#include "engines/grim/debug.h"
|
||||
#include "engines/grim/bitmap.h"
|
||||
#include "engines/grim/resource.h"
|
||||
#include "engines/grim/gfx_base.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
static bool decompress_codec3(const char *compressed, char *result, int maxBytes);
|
||||
|
||||
Common::HashMap<Common::String, BitmapData *> *BitmapData::_bitmaps = nullptr;
|
||||
|
||||
BitmapData *BitmapData::getBitmapData(const Common::String &fname) {
|
||||
Common::String str(fname);
|
||||
if (_bitmaps && _bitmaps->contains(str)) {
|
||||
BitmapData *b = (*_bitmaps)[str];
|
||||
++b->_refCount;
|
||||
return b;
|
||||
}
|
||||
|
||||
BitmapData *b = new BitmapData(fname);
|
||||
if (!_bitmaps) {
|
||||
_bitmaps = new Common::HashMap<Common::String, BitmapData *>();
|
||||
}
|
||||
(*_bitmaps)[str] = b;
|
||||
return b;
|
||||
}
|
||||
|
||||
BitmapData::BitmapData(const Common::String &fname) {
|
||||
_fname = fname;
|
||||
_refCount = 1;
|
||||
_data = nullptr;
|
||||
_loaded = false;
|
||||
_keepData = true;
|
||||
|
||||
// Initialize members to avoid warnings:
|
||||
_numImages = 0;
|
||||
_width = 0;
|
||||
_height = 0;
|
||||
_x = 0;
|
||||
_y = 0;
|
||||
_format = 0;
|
||||
_numTex = 0;
|
||||
_bpp = 0;
|
||||
_texIds = nullptr;
|
||||
_hasTransparency = 0;
|
||||
|
||||
_texc = nullptr;
|
||||
|
||||
_verts = nullptr;
|
||||
_layers = nullptr;
|
||||
|
||||
_numCoords = 0;
|
||||
_numVerts = 0;
|
||||
_numLayers = 0;
|
||||
|
||||
_userData = nullptr;
|
||||
}
|
||||
|
||||
void BitmapData::load() {
|
||||
if (_loaded) {
|
||||
return;
|
||||
}
|
||||
Common::SeekableReadStream *data = g_resourceloader->openNewStreamFile(_fname.c_str());
|
||||
if (!data)
|
||||
error("Couldn't open %s", _fname.c_str());
|
||||
|
||||
uint32 tag = data->readUint32BE();
|
||||
switch(tag) {
|
||||
case(MKTAG('B','M',' ',' ')): //Grim bitmap
|
||||
loadGrimBm(data);
|
||||
break;
|
||||
case(MKTAG('T','I','L','0')): // MI4 bitmap
|
||||
loadTile(data);
|
||||
break;
|
||||
default:
|
||||
if (!loadTGA(data)) // Try to load as TGA.
|
||||
Debug::error(Debug::Bitmaps, "Invalid magic loading bitmap");
|
||||
break;
|
||||
}
|
||||
delete data;
|
||||
_loaded = true;
|
||||
}
|
||||
|
||||
bool BitmapData::loadGrimBm(Common::SeekableReadStream *data) {
|
||||
uint32 tag2 = data->readUint32BE();
|
||||
if (tag2 != (MKTAG('F','\0','\0','\0')))
|
||||
return false;
|
||||
|
||||
int codec = data->readUint32LE();
|
||||
data->readUint32LE(); //_paletteIncluded
|
||||
_numImages = data->readUint32LE();
|
||||
_x = data->readUint32LE();
|
||||
_y = data->readUint32LE();
|
||||
data->readUint32LE(); //_transparentColor
|
||||
_format = data->readUint32LE();
|
||||
_bpp = data->readUint32LE();
|
||||
// uint32 redBits = data->readUint32LE();
|
||||
// uint32 greenBits = data->readUint32LE();
|
||||
// uint32 blueBits = data->readUint32LE();
|
||||
// uint32 redShift = data->readUint32LE();
|
||||
// uint32 greenShift = data->readUint32LE();
|
||||
// uint32 blueShift = data->readUint32LE();
|
||||
|
||||
// Hardcode the format, since the values saved in the files are garbage for some, like "ha_0_elvos.zbm".
|
||||
Graphics::PixelFormat pixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
|
||||
|
||||
data->seek(128, SEEK_SET);
|
||||
_width = data->readUint32LE();
|
||||
_height = data->readUint32LE();
|
||||
_hasTransparency = false;
|
||||
|
||||
_data = new Graphics::Surface[_numImages];
|
||||
data->seek(0x80, SEEK_SET);
|
||||
for (int i = 0; i < _numImages; i++) {
|
||||
data->seek(8, SEEK_CUR);
|
||||
_data[i].create(_width, _height, pixelFormat);
|
||||
if (codec == 0) {
|
||||
uint32 dsize = _bpp / 8 * _width * _height;
|
||||
data->read(_data[i].getPixels(), dsize);
|
||||
} else if (codec == 3) {
|
||||
int compressed_len = data->readUint32LE();
|
||||
char *compressed = new char[compressed_len];
|
||||
data->read(compressed, compressed_len);
|
||||
bool success = decompress_codec3(compressed, (char *)_data[i].getPixels(), _bpp / 8 * _width * _height);
|
||||
delete[] compressed;
|
||||
if (!success)
|
||||
warning(".. when loading image %s.", _fname.c_str());
|
||||
} else
|
||||
Debug::error(Debug::Bitmaps, "Unknown image codec in BitmapData ctor!");
|
||||
|
||||
#ifdef SCUMM_BIG_ENDIAN
|
||||
uint16 *d = (uint16 *)_data[i].getPixels();
|
||||
for (int j = 0; j < _width * _height; ++j) {
|
||||
d[j] = SWAP_BYTES_16(d[j]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Initially, no GPU-side textures created. the createBitmap
|
||||
// function will allocate some if necessary (and successful)
|
||||
_numTex = 0;
|
||||
_texIds = nullptr;
|
||||
|
||||
g_driver->createBitmap(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
BitmapData::BitmapData(const Graphics::Surface &buf, int w, int h, const char *fname) : _fname(fname) {
|
||||
_refCount = 1;
|
||||
Debug::debug(Debug::Bitmaps, "New bitmap loaded: %s\n", fname);
|
||||
_numImages = 1;
|
||||
_x = 0;
|
||||
_y = 0;
|
||||
_width = w;
|
||||
_height = h;
|
||||
_format = 1;
|
||||
_numTex = 0;
|
||||
_texIds = nullptr;
|
||||
_bpp = buf.format.bytesPerPixel * 8;
|
||||
_hasTransparency = false;
|
||||
_data = new Graphics::Surface[_numImages];
|
||||
_data[0].copyFrom(buf);
|
||||
_loaded = true;
|
||||
_keepData = true;
|
||||
|
||||
_userData = nullptr;
|
||||
_texc = nullptr;
|
||||
_verts = nullptr;
|
||||
_layers = nullptr;
|
||||
|
||||
_numCoords = 0;
|
||||
_numVerts = 0;
|
||||
_numLayers = 0;
|
||||
|
||||
g_driver->createBitmap(this);
|
||||
}
|
||||
|
||||
BitmapData::BitmapData() :
|
||||
_numImages(0), _width(0), _height(0), _x(0), _y(0), _format(0), _numTex(0),
|
||||
_bpp(0), _texIds(nullptr), _hasTransparency(false), _data(nullptr),
|
||||
_refCount(1), _loaded(false), _keepData(false), _texc(nullptr), _verts(nullptr),
|
||||
_layers(nullptr), _numCoords(0), _numVerts(0), _numLayers(0), _userData(nullptr) {
|
||||
}
|
||||
|
||||
BitmapData::~BitmapData() {
|
||||
_keepData = false;
|
||||
if (_loaded) {
|
||||
g_driver->destroyBitmap(this);
|
||||
}
|
||||
freeData();
|
||||
if (_bitmaps) {
|
||||
if (_bitmaps->contains(_fname)) {
|
||||
_bitmaps->erase(_fname);
|
||||
}
|
||||
if (_bitmaps->empty()) {
|
||||
delete _bitmaps;
|
||||
_bitmaps = nullptr;
|
||||
}
|
||||
}
|
||||
delete[] _texc;
|
||||
delete[] _layers;
|
||||
delete[] _verts;
|
||||
}
|
||||
|
||||
void BitmapData::freeData() {
|
||||
if (!_keepData && _data) {
|
||||
for (int i = 0; i < _numImages; ++i) {
|
||||
_data[i].free();
|
||||
}
|
||||
delete[] _data;
|
||||
_data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool BitmapData::loadTGA(Common::SeekableReadStream *data) {
|
||||
Image::TGADecoder dec;
|
||||
bool success = dec.loadStream(*data);
|
||||
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
const Graphics::Surface *surf = dec.getSurface();
|
||||
|
||||
_width = surf->w;
|
||||
_height = surf->h;
|
||||
_format = 1;
|
||||
_x = _y = 0;
|
||||
_bpp = surf->format.bytesPerPixel * 8;
|
||||
_numImages = 1;
|
||||
_data = new Graphics::Surface[1];
|
||||
_data[0].copyFrom(*surf);
|
||||
|
||||
g_driver->createBitmap(this);
|
||||
|
||||
freeData();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BitmapData::loadTile(Common::SeekableReadStream *o) {
|
||||
#ifdef ENABLE_MONKEY4
|
||||
_x = 0;
|
||||
_y = 0;
|
||||
_format = 1;
|
||||
o->seek(0, SEEK_SET);
|
||||
|
||||
/*uint32 id = */o->readUint32LE();
|
||||
// Should check that we actually HAVE a TIL
|
||||
uint32 bmoffset = o->readUint32LE();
|
||||
_numCoords = o->readUint32LE();
|
||||
_numLayers = o->readUint32LE();
|
||||
_numVerts = o->readUint32LE();
|
||||
|
||||
// skip some 0
|
||||
o->seek(16, SEEK_CUR);
|
||||
_texc = new float[_numCoords * 4];
|
||||
|
||||
for (uint32 i = 0; i < _numCoords * 4; ++i) {
|
||||
_texc[i] = o->readFloatLE();
|
||||
}
|
||||
|
||||
_layers = new Layer[_numLayers];
|
||||
for (uint32 i = 0; i < _numLayers; ++i) {
|
||||
_layers[i]._offset = o->readUint32LE();
|
||||
_layers[i]._numImages = o->readUint32LE();
|
||||
}
|
||||
|
||||
_verts = new Vert[_numVerts];
|
||||
for (uint32 i = 0; i < _numVerts; ++i) {
|
||||
_verts[i]._texid = o->readUint32LE();
|
||||
_verts[i]._pos = o->readUint32LE();
|
||||
_verts[i]._verts = o->readUint32LE();
|
||||
}
|
||||
|
||||
o->seek(16, SEEK_CUR);
|
||||
_numImages = o->readUint32LE();
|
||||
|
||||
o->seek(16, SEEK_CUR);
|
||||
_bpp = o->readUint32LE();
|
||||
|
||||
o->seek(bmoffset + 128);
|
||||
|
||||
_width = o->readUint32LE();
|
||||
_height = o->readUint32LE();
|
||||
o->seek(-8, SEEK_CUR);
|
||||
|
||||
_data = new Graphics::Surface[_numImages];
|
||||
|
||||
Graphics::PixelFormat format_16bpp = Graphics::PixelFormat(2, 5, 5, 5, 1, 0, 5, 10, 15);
|
||||
Graphics::PixelFormat format_32bpp = Graphics::PixelFormat::createFormatRGBA32();
|
||||
|
||||
int width = 256;
|
||||
int height = 256;
|
||||
|
||||
for (int i = 0; i < _numImages; ++i) {
|
||||
_data[i].create(width, height, (_bpp == 16) ? format_16bpp : format_32bpp);
|
||||
uint8 *d = (uint8 *)_data[i].getPixels();
|
||||
o->seek(8, SEEK_CUR);
|
||||
switch (_bpp) {
|
||||
case 16:
|
||||
#ifndef SCUMM_LITTLE_ENDIAN
|
||||
for (int y = 0; y < _height; ++y) {
|
||||
uint16 *d16 = (uint16 *)d;
|
||||
for (int x = 0; x < _width; ++x)
|
||||
d16[x] = o->readUint16LE();
|
||||
d += _data[i].pitch;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case 32:
|
||||
for (int y = 0; y < _height; ++y) {
|
||||
o->read(d, _width * (_bpp / 8));
|
||||
d += _data[i].pitch;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
g_driver->createBitmap(this);
|
||||
#endif // ENABLE_MONKEY4
|
||||
return true;
|
||||
}
|
||||
|
||||
const Graphics::Surface &BitmapData::getImageData(int num) const {
|
||||
assert(num >= 0);
|
||||
assert(num < _numImages);
|
||||
return _data[num];
|
||||
}
|
||||
|
||||
// Bitmap
|
||||
|
||||
Bitmap::Bitmap(const Common::String &fname) {
|
||||
_data = BitmapData::getBitmapData(fname);
|
||||
_currImage = 1;
|
||||
}
|
||||
|
||||
Bitmap::Bitmap(const Graphics::Surface &buf, int w, int h, const char *fname) {
|
||||
_data = new BitmapData(buf, w, h, fname);
|
||||
_currImage = 1;
|
||||
}
|
||||
|
||||
Bitmap::Bitmap() {
|
||||
_data = new BitmapData();
|
||||
_currImage = 0;
|
||||
}
|
||||
|
||||
Bitmap *Bitmap::create(const Common::String &filename) {
|
||||
if (!SearchMan.hasFile(Common::Path(filename))) {
|
||||
warning("Could not find bitmap %s", filename.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
Bitmap *b = new Bitmap(filename);
|
||||
return b;
|
||||
}
|
||||
|
||||
void Bitmap::saveState(SaveGame *state) const {
|
||||
state->writeString(getFilename());
|
||||
|
||||
state->writeLESint32(getActiveImage());
|
||||
}
|
||||
|
||||
void Bitmap::restoreState(SaveGame *state) {
|
||||
freeData();
|
||||
|
||||
Common::String fname = state->readString();
|
||||
_data = BitmapData::getBitmapData(fname);
|
||||
|
||||
_currImage = state->readLESint32();
|
||||
}
|
||||
|
||||
void Bitmap::draw() {
|
||||
_data->load();
|
||||
if (_currImage == 0)
|
||||
return;
|
||||
|
||||
g_driver->drawBitmap(this, _data->_x, _data->_y);
|
||||
}
|
||||
|
||||
void Bitmap::draw(int x, int y) {
|
||||
_data->load();
|
||||
if (_currImage == 0)
|
||||
return;
|
||||
|
||||
g_driver->drawBitmap(this, x, y, _data->_numLayers - 1);
|
||||
}
|
||||
|
||||
void Bitmap::drawLayer(uint32 layer) {
|
||||
_data->load();
|
||||
if (_currImage == 0)
|
||||
return;
|
||||
|
||||
g_driver->drawBitmap(this, _data->_x, _data->_y, layer);
|
||||
}
|
||||
|
||||
void Bitmap::setActiveImage(int n) {
|
||||
assert(n >= 0);
|
||||
_data->load();
|
||||
if ((n - 1) >= _data->_numImages) {
|
||||
warning("Bitmap::setActiveImage: no anim image: %d. (%s)", n, _data->_fname.c_str());
|
||||
} else {
|
||||
_currImage = n;
|
||||
}
|
||||
}
|
||||
|
||||
int Bitmap::getNumImages() const {
|
||||
_data->load();
|
||||
return _data->_numImages;
|
||||
}
|
||||
|
||||
int Bitmap::getNumLayers() const {
|
||||
_data->load();
|
||||
return _data->_numLayers;
|
||||
}
|
||||
|
||||
void Bitmap::freeData() {
|
||||
--_data->_refCount;
|
||||
if (_data->_refCount < 1) {
|
||||
delete _data;
|
||||
_data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Bitmap::~Bitmap() {
|
||||
freeData();
|
||||
}
|
||||
|
||||
const Graphics::PixelFormat &Bitmap::getPixelFormat(int num) const {
|
||||
return getData(num).format;
|
||||
}
|
||||
|
||||
void BitmapData::convertToColorFormat(int num, const Graphics::PixelFormat &format) {
|
||||
if (_data[num].format == format) {
|
||||
return;
|
||||
}
|
||||
_data[num].convertToInPlace(format);
|
||||
}
|
||||
|
||||
void BitmapData::convertToColorFormat(const Graphics::PixelFormat &format) {
|
||||
for (int i = 0; i < _numImages; ++i) {
|
||||
convertToColorFormat(i, format);
|
||||
}
|
||||
}
|
||||
|
||||
#define GET_BIT do { bit = bitstr_value & 1; \
|
||||
bitstr_len--; \
|
||||
bitstr_value >>= 1; \
|
||||
if (bitstr_len == 0) { \
|
||||
bitstr_value = READ_LE_UINT16(compressed); \
|
||||
bitstr_len = 16; \
|
||||
compressed += 2; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static bool decompress_codec3(const char *compressed, char *result, int maxBytes) {
|
||||
int bitstr_value = READ_LE_UINT16(compressed);
|
||||
int bitstr_len = 16;
|
||||
compressed += 2;
|
||||
bool bit;
|
||||
|
||||
int byteIndex = 0;
|
||||
for (;;) {
|
||||
GET_BIT;
|
||||
if (bit == 1) {
|
||||
if (byteIndex >= maxBytes) {
|
||||
warning("Buffer overflow when decoding image: decompress_codec3 walked past the input buffer!");
|
||||
return false;
|
||||
} else {
|
||||
*result++ = *compressed++;
|
||||
}
|
||||
++byteIndex;
|
||||
} else {
|
||||
GET_BIT;
|
||||
int copy_len, copy_offset;
|
||||
if (bit == 0) {
|
||||
GET_BIT;
|
||||
copy_len = 2 * bit;
|
||||
GET_BIT;
|
||||
copy_len += bit + 3;
|
||||
copy_offset = *(const uint8 *)(compressed++) - 0x100;
|
||||
} else {
|
||||
copy_offset = (*(const uint8 *)(compressed) | (*(const uint8 *)(compressed + 1) & 0xf0) << 4) - 0x1000;
|
||||
copy_len = (*(const uint8 *)(compressed + 1) & 0xf) + 3;
|
||||
compressed += 2;
|
||||
if (copy_len == 3) {
|
||||
copy_len = *(const uint8 *)(compressed++) + 1;
|
||||
if (copy_len == 1)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
while (copy_len > 0) {
|
||||
if (byteIndex >= maxBytes) {
|
||||
warning("Buffer overflow when decoding image: decompress_codec3 walked past the input buffer!");
|
||||
return false;
|
||||
} else {
|
||||
assert(byteIndex + copy_offset >= 0);
|
||||
assert(byteIndex + copy_offset < maxBytes);
|
||||
*result = result[copy_offset];
|
||||
result++;
|
||||
}
|
||||
++byteIndex;
|
||||
copy_len--;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
189
engines/grim/bitmap.h
Normal file
189
engines/grim/bitmap.h
Normal file
@@ -0,0 +1,189 @@
|
||||
/* 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_H
|
||||
#define GRIM_BITMAP_H
|
||||
|
||||
#include "graphics/pixelformat.h"
|
||||
|
||||
#include "common/endian.h"
|
||||
#include "common/hashmap.h"
|
||||
#include "common/hash-str.h"
|
||||
|
||||
#include "engines/grim/pool.h"
|
||||
|
||||
namespace Graphics {
|
||||
struct Surface;
|
||||
}
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace Grim {
|
||||
|
||||
/**
|
||||
* This BitmapData class keeps the actual bitmap data and can be shared
|
||||
* between Bitmap instances, by using getBitmapData.
|
||||
* Bitmap still keeps the data that can change between the instances
|
||||
* i.e. _x, _y and _currImage.
|
||||
* They are automatically deleted if they are not used by any bitmap anymore.
|
||||
*/
|
||||
class BitmapData {
|
||||
public:
|
||||
BitmapData(const Common::String &fname);
|
||||
BitmapData(const Graphics::Surface &buf, int w, int h, const char *fname);
|
||||
BitmapData();
|
||||
~BitmapData();
|
||||
|
||||
void freeData();
|
||||
|
||||
void load();
|
||||
|
||||
/**
|
||||
* Loads an EMI TILE-bitmap.
|
||||
*
|
||||
* @param data the data for the TILE.
|
||||
* @param len the length of the data.
|
||||
*/
|
||||
bool loadTile(Common::SeekableReadStream *data);
|
||||
bool loadGrimBm(Common::SeekableReadStream *data);
|
||||
bool loadTGA(Common::SeekableReadStream *data);
|
||||
|
||||
static BitmapData *getBitmapData(const Common::String &fname);
|
||||
static Common::HashMap<Common::String, BitmapData *> *_bitmaps;
|
||||
|
||||
const Graphics::Surface &getImageData(int num) const;
|
||||
|
||||
/**
|
||||
* Convert a bitmap to another color-format.
|
||||
*
|
||||
* @param format the format to convert to.
|
||||
*/
|
||||
void convertToColorFormat(const Graphics::PixelFormat &format);
|
||||
|
||||
/**
|
||||
* Convert a bitmap to another color-format.
|
||||
*
|
||||
* @param format the format to convert to.
|
||||
*/
|
||||
void convertToColorFormat(int num, const Graphics::PixelFormat &format);
|
||||
|
||||
Common::String _fname;
|
||||
int _numImages;
|
||||
int _width, _height, _x, _y;
|
||||
int _format;
|
||||
int _numTex;
|
||||
int _bpp;
|
||||
void *_texIds;
|
||||
bool _hasTransparency;
|
||||
bool _loaded;
|
||||
bool _keepData;
|
||||
|
||||
int _refCount;
|
||||
|
||||
float *_texc;
|
||||
|
||||
struct Vert {
|
||||
uint32 _texid;
|
||||
uint32 _pos;
|
||||
uint32 _verts;
|
||||
};
|
||||
struct Layer {
|
||||
uint32 _offset;
|
||||
uint32 _numImages;
|
||||
};
|
||||
Vert *_verts;
|
||||
Layer *_layers;
|
||||
uint32 _numCoords;
|
||||
uint32 _numVerts;
|
||||
uint32 _numLayers;
|
||||
|
||||
//private:
|
||||
Graphics::Surface *_data;
|
||||
void *_userData;
|
||||
};
|
||||
|
||||
class Bitmap : public PoolObject<Bitmap> {
|
||||
public:
|
||||
/**
|
||||
* Construct a bitmap from the given data.
|
||||
*
|
||||
* @oaram filename the filename of the bitmap
|
||||
* @param data the actual data to construct from
|
||||
* @param len the length of the data
|
||||
*/
|
||||
Bitmap(const Common::String &filename);
|
||||
Bitmap(const Graphics::Surface &buf, int width, int height, const char *filename);
|
||||
Bitmap();
|
||||
|
||||
static int32 getStaticTag() { return MKTAG('V', 'B', 'U', 'F'); }
|
||||
|
||||
static Bitmap *create(const Common::String &filename);
|
||||
|
||||
const Common::String &getFilename() const { return _data->_fname; }
|
||||
|
||||
void draw();
|
||||
void draw(int x, int y);
|
||||
|
||||
void drawLayer(uint32 layer);
|
||||
|
||||
/**
|
||||
* Set which image in an animated bitmap to use
|
||||
*
|
||||
* @param n the image to be selected
|
||||
*/
|
||||
void setActiveImage(int n);
|
||||
|
||||
int getNumImages() const;
|
||||
int getNumLayers() const;
|
||||
int getActiveImage() const { return _currImage; }
|
||||
bool getHasTransparency() const { return _data->_hasTransparency; }
|
||||
int getFormat() const { return _data->_format; }
|
||||
int getWidth() const { return _data->_width; }
|
||||
int getHeight() const { return _data->_height; }
|
||||
|
||||
const Graphics::Surface &getData(int num) const { return _data->getImageData(num); }
|
||||
const Graphics::Surface &getData() const { return getData(_currImage); }
|
||||
BitmapData *getBitmapData() const { return _data; }
|
||||
void *getTexIds() const { return _data->_texIds; }
|
||||
int getNumTex() const { return _data->_numTex; }
|
||||
const Graphics::PixelFormat &getPixelFormat(int num) const;
|
||||
|
||||
void saveState(SaveGame *state) const;
|
||||
void restoreState(SaveGame *state);
|
||||
|
||||
virtual ~Bitmap();
|
||||
|
||||
//private:
|
||||
void freeData();
|
||||
|
||||
BitmapData *_data;
|
||||
/**
|
||||
* Specifies a one-based index to the current image in BitmapData.
|
||||
* _currImage==0 means a null image is chosen.
|
||||
*/
|
||||
int _currImage;
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
66
engines/grim/color.cpp
Normal file
66
engines/grim/color.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/* 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/color.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
Color::Color() {
|
||||
_vals[0] = _vals[1] = _vals[2] = 0;
|
||||
}
|
||||
|
||||
Color::Color(byte r, byte g, byte b) {
|
||||
_vals[0] = r;
|
||||
_vals[1] = g;
|
||||
_vals[2] = b;
|
||||
}
|
||||
|
||||
Color::Color(const Color &c) {
|
||||
_vals[0] = c._vals[0];
|
||||
_vals[1] = c._vals[1];
|
||||
_vals[2] = c._vals[2];
|
||||
}
|
||||
|
||||
Color::Color(uint32 c) {
|
||||
_vals[0] = (c >> 16) & 0xFF;
|
||||
_vals[1] = (c >> 8) & 0xFF;
|
||||
_vals[2] = c & 0xFF;
|
||||
}
|
||||
|
||||
uint32 Color::toEncodedValue() {
|
||||
return (_vals[0] << 16) | (_vals[1] << 8) | _vals[2];
|
||||
}
|
||||
|
||||
Color &Color::operator =(const Color &c) {
|
||||
_vals[0] = c._vals[0];
|
||||
_vals[1] = c._vals[1];
|
||||
_vals[2] = c._vals[2];
|
||||
return *this;
|
||||
}
|
||||
|
||||
Color &Color::operator =(const Color *c) {
|
||||
_vals[0] = c->_vals[0];
|
||||
_vals[1] = c->_vals[1];
|
||||
_vals[2] = c->_vals[2];
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
54
engines/grim/color.h
Normal file
54
engines/grim/color.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* 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_COLOR_H
|
||||
#define GRIM_COLOR_H
|
||||
|
||||
#include "common/endian.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class Color {
|
||||
public:
|
||||
byte _vals[3];
|
||||
|
||||
Color();
|
||||
Color(byte r, byte g, byte b);
|
||||
Color(const Color &c);
|
||||
Color(uint32 c);
|
||||
|
||||
byte &getRed() { return _vals[0]; }
|
||||
byte getRed() const { return _vals[0]; }
|
||||
byte &getGreen() { return _vals[1]; }
|
||||
byte getGreen() const { return _vals[1]; }
|
||||
byte &getBlue() { return _vals[2]; }
|
||||
byte getBlue() const { return _vals[2]; }
|
||||
|
||||
uint32 toEncodedValue();
|
||||
|
||||
Color &operator =(const Color &c);
|
||||
Color &operator =(const Color *c);
|
||||
};
|
||||
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
55
engines/grim/colormap.cpp
Normal file
55
engines/grim/colormap.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/* 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/stream.h"
|
||||
|
||||
#include "engines/grim/colormap.h"
|
||||
#include "engines/grim/resource.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
// Load a colormap from the given data.
|
||||
CMap::CMap(const Common::String &fileName, Common::SeekableReadStream *data) :
|
||||
Object(), _fname(fileName) {
|
||||
uint32 tag = data->readUint32BE();
|
||||
if (tag != MKTAG('C','M','P',' '))
|
||||
error("Invalid magic loading colormap");
|
||||
|
||||
data->seek(64, SEEK_SET);
|
||||
data->read(_colors, sizeof(_colors));
|
||||
}
|
||||
|
||||
CMap::~CMap() {
|
||||
if (g_resourceloader)
|
||||
g_resourceloader->uncacheColormap(this);
|
||||
}
|
||||
|
||||
bool CMap::operator==(const CMap &c) const {
|
||||
if (_fname != c._fname) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
51
engines/grim/colormap.h
Normal file
51
engines/grim/colormap.h
Normal 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_COLORMAP_H
|
||||
#define GRIM_COLORMAP_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "engines/grim/object.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class CMap : public Object {
|
||||
public:
|
||||
// Load a colormap from the given data.
|
||||
CMap(const Common::String &fileName, Common::SeekableReadStream *data);
|
||||
~CMap();
|
||||
const Common::String &getFilename() const { return _fname; }
|
||||
|
||||
// The color data, in RGB format
|
||||
char _colors[256 * 3];
|
||||
Common::String _fname;
|
||||
|
||||
bool operator==(const CMap &c) const;
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
4
engines/grim/configure.engine
Normal file
4
engines/grim/configure.engine
Normal file
@@ -0,0 +1,4 @@
|
||||
# This file is included from the main "configure" script
|
||||
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] [components]
|
||||
add_engine grim "Grim" yes "monkey4" "Grim Fandango" "16bit 3d highres" "theoradec tinygl mpeg2"
|
||||
add_engine monkey4 "Escape from Monkey Island" no "" "" "bink"
|
||||
574
engines/grim/costume.cpp
Normal file
574
engines/grim/costume.cpp
Normal file
@@ -0,0 +1,574 @@
|
||||
/* 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/endian.h"
|
||||
|
||||
#include "engines/grim/debug.h"
|
||||
#include "engines/grim/colormap.h"
|
||||
#include "engines/grim/costume.h"
|
||||
#include "engines/grim/textsplit.h"
|
||||
#include "engines/grim/resource.h"
|
||||
#include "engines/grim/model.h"
|
||||
#include "engines/grim/savegame.h"
|
||||
#include "engines/grim/emi/modelemi.h"
|
||||
#include "engines/grim/costume/chore.h"
|
||||
#include "engines/grim/costume/head.h"
|
||||
#include "engines/grim/emi/costume/emianim_component.h"
|
||||
#include "engines/grim/emi/costume/emimesh_component.h"
|
||||
#include "engines/grim/emi/costume/emiskel_component.h"
|
||||
#include "engines/grim/costume/main_model_component.h"
|
||||
#include "engines/grim/costume/colormap_component.h"
|
||||
#include "engines/grim/costume/keyframe_component.h"
|
||||
#include "engines/grim/costume/mesh_component.h"
|
||||
#include "engines/grim/costume/lua_var_component.h"
|
||||
#include "engines/grim/costume/sound_component.h"
|
||||
#include "engines/grim/costume/bitmap_component.h"
|
||||
#include "engines/grim/costume/material_component.h"
|
||||
#include "engines/grim/costume/sprite_component.h"
|
||||
#include "engines/grim/costume/anim_component.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
// A costume in the Residual/GrimE engine consists of a set of
|
||||
// components, and a set of chores. Each component represents an
|
||||
// on-screen object, or a keyframe animation, or a sound effect; each
|
||||
// chore gives a set of instructions for how to move and/or activate
|
||||
// or deactivate each component at certain times.
|
||||
//
|
||||
// Each actor contains a stack of costumes, on which a new costume can
|
||||
// be pushed or from which an old costume can be popped at any time.
|
||||
// For the most part, these costumes are independent. The exception
|
||||
// is the main model component ('MMDL'), for which multiple costumes
|
||||
// share the same base 3D object (if they refer to the same file).
|
||||
//
|
||||
// This is complicated by the fact that multiple keyframe animations
|
||||
// can have an effect on the positions of the 3D objects. Each
|
||||
// keyframe animation has certain nodes internally "tagged", and the
|
||||
// keyframe components specify precedences for the tagged nodes and
|
||||
// for the non-tagged nodes. If the highest precedence for a given
|
||||
// node is given by multiple keyframe animations, their contributions
|
||||
// are averaged.
|
||||
//
|
||||
// Each component can implement several virtual methods which are
|
||||
// called by the costume:
|
||||
//
|
||||
// init() -- allows the component to initialize itself. This is
|
||||
// separate from the constructor since there are cases where
|
||||
// information from child components may be needed before
|
||||
// the object can be fully constructed. This is particularly
|
||||
// the case with colormaps, which are needed before even
|
||||
// starting to load a 3D model.
|
||||
// setKey(val) -- notifies the component of a change in the "state"
|
||||
// given by a playing chore
|
||||
// update() -- gives the component a chance to update its internal
|
||||
// state once every frame
|
||||
// draw() -- actually draws the component onto the screen
|
||||
// reset() -- notifies the component that a chore controlling it
|
||||
// has stopped
|
||||
//
|
||||
// For the 3D objects, a model's component first initializes internal
|
||||
// state for the model's nodes in its update() method. Then the
|
||||
// keyframes' update() methods work with this data to implement the
|
||||
// precedence and add up all contributions for the highest precedence.
|
||||
// Then the model's draw() method does the averaging and draws the
|
||||
// polygons accordingly. (Actually, this is a lie -- the top-level
|
||||
// 3D objects draw themselves and all their children. This makes it
|
||||
// easier to move objects Manny is holding when his hands move, for
|
||||
// example.)
|
||||
//
|
||||
// For bitmaps, the actual drawing is handled by the Set class. The
|
||||
// bitmaps to be drawn are associated to the needed camera setups
|
||||
// using NewObjectState; bitmaps marked OBJSTATE_UNDERLAY and
|
||||
// OBJSTATE_STATE are drawn first, then the 3D objects, then bitmaps
|
||||
// marked OBJSTATE_OVERLAY. So the BitmapComponent just needs to pass
|
||||
// along setKey requests to the actual bitmap object.
|
||||
|
||||
Costume::Costume(const Common::String &fname, Actor *owner, Costume *prevCost) :
|
||||
Object(), _head(nullptr), _chores(nullptr), _components(nullptr),
|
||||
_numComponents(0), _numChores(0), _fname(fname), _owner(owner) {
|
||||
_lookAtRate = 200;
|
||||
_prevCostume = prevCost;
|
||||
}
|
||||
|
||||
void Costume::load(Common::SeekableReadStream *data) {
|
||||
TextSplitter ts(_fname, data);
|
||||
ts.expectString("costume v0.1");
|
||||
ts.expectString("section tags");
|
||||
int numTags;
|
||||
ts.scanString(" numtags %d", 1, &numTags);
|
||||
tag32 *tags = new tag32[numTags];
|
||||
for (int i = 0; i < numTags; i++) {
|
||||
unsigned char t[4];
|
||||
int which;
|
||||
|
||||
// Obtain a tag ID from the file
|
||||
ts.scanString(" %d '%c%c%c%c'", 5, &which, &t[0], &t[1], &t[2], &t[3]);
|
||||
// Force characters to upper case
|
||||
for (int j = 0; j < 4; j++)
|
||||
t[j] = toupper(t[j]);
|
||||
memcpy(&tags[which], t, sizeof(tag32));
|
||||
tags[which] = FROM_BE_32(tags[which]);
|
||||
}
|
||||
|
||||
ts.expectString("section components");
|
||||
ts.scanString(" numcomponents %d", 1, &_numComponents);
|
||||
_components = new Component *[_numComponents]{};
|
||||
for (int i = 0; i < _numComponents; i++) {
|
||||
int id, tagID, hash, parentID, namePos;
|
||||
const char *line = ts.getCurrentLine();
|
||||
Component *prevComponent = nullptr;
|
||||
|
||||
if (sscanf(line, " %d %d %d %d %n", &id, &tagID, &hash, &parentID, &namePos) < 4)
|
||||
error("Bad component specification line: `%s'", line);
|
||||
ts.nextLine();
|
||||
|
||||
// A Parent ID of "-1" indicates that the component should
|
||||
// use the properties of the previous costume as a base
|
||||
if (parentID == -1) {
|
||||
if (_prevCostume) {
|
||||
// However, only the first item can actually share the
|
||||
// node hierarchy with the previous costume, so flag
|
||||
// that component so it knows what to do
|
||||
if (i == 0)
|
||||
parentID = -2;
|
||||
prevComponent = _prevCostume->_components[0];
|
||||
// Make sure that the component is valid
|
||||
if (!prevComponent->isComponentType('M','M','D','L'))
|
||||
prevComponent = nullptr;
|
||||
} else if (id > 0) {
|
||||
// Use the MainModelComponent of this costume as prevComponent,
|
||||
// so that the component can use its colormap.
|
||||
prevComponent = _components[0];
|
||||
}
|
||||
}
|
||||
// Actually load the appropriate component
|
||||
_components[id] = loadComponent(tags[tagID], parentID < 0 ? nullptr : _components[parentID], parentID, line + namePos, prevComponent);
|
||||
_components[id]->setCostume(this);
|
||||
}
|
||||
|
||||
delete[] tags;
|
||||
|
||||
for (int i = 0; i < _numComponents; i++) {
|
||||
if (_components[i]) {
|
||||
_components[i]->init();
|
||||
}
|
||||
}
|
||||
|
||||
ts.expectString("section chores");
|
||||
ts.scanString(" numchores %d", 1, &_numChores);
|
||||
_chores = new Chore *[_numChores];
|
||||
for (int i = 0; i < _numChores; i++) {
|
||||
int id, length, tracks;
|
||||
char name[32];
|
||||
ts.scanString(" %d %d %d %32s", 4, &id, &length, &tracks, name);
|
||||
_chores[id] = new Chore(name, i, this, length, tracks);
|
||||
Debug::debug(Debug::Chores, "Loaded chore: %s\n", name);
|
||||
}
|
||||
|
||||
ts.expectString("section keys");
|
||||
for (int i = 0; i < _numChores; i++) {
|
||||
int which;
|
||||
ts.scanString("chore %d", 1, &which);
|
||||
_chores[which]->load(ts);
|
||||
}
|
||||
|
||||
_head = new Head();
|
||||
}
|
||||
|
||||
Costume::~Costume() {
|
||||
stopChores();
|
||||
for (int i = _numComponents - 1; i >= 0; i--) {
|
||||
delete _components[i];
|
||||
}
|
||||
delete[] _components;
|
||||
|
||||
for (int i = 0; i < _numChores; ++i) {
|
||||
delete _chores[i];
|
||||
}
|
||||
delete[] _chores;
|
||||
delete _head;
|
||||
}
|
||||
|
||||
Component *Costume::loadComponent (tag32 tag, Component *parent, int parentID, const char *name, Component *prevComponent) {
|
||||
if (tag == MKTAG('M','M','D','L'))
|
||||
return new MainModelComponent(parent, parentID, name, prevComponent, tag);
|
||||
else if (tag == MKTAG('M','O','D','L'))
|
||||
return new ModelComponent(parent, parentID, name, prevComponent, tag);
|
||||
else if (tag == MKTAG('C','M','A','P'))
|
||||
return new ColormapComponent(parent, parentID, name, tag);
|
||||
else if (tag == MKTAG('K','E','Y','F'))
|
||||
return new KeyframeComponent(parent, parentID, name, tag);
|
||||
else if (tag == MKTAG('M','E','S','H'))
|
||||
return new MeshComponent(parent, parentID, name, tag);
|
||||
else if (tag == MKTAG('L','U','A','V'))
|
||||
return new LuaVarComponent(parent, parentID, name, tag);
|
||||
else if (tag == MKTAG('I','M','L','S'))
|
||||
return new SoundComponent(parent, parentID, name, tag);
|
||||
else if (tag == MKTAG('B','K','N','D'))
|
||||
return new BitmapComponent(parent, parentID, name, tag);
|
||||
else if (tag == MKTAG('M','A','T',' '))
|
||||
return new MaterialComponent(parent, parentID, name, tag);
|
||||
else if (tag == MKTAG('S','P','R','T'))
|
||||
return new SpriteComponent(parent, parentID, name, tag);
|
||||
else if (tag == MKTAG('A','N','I','M')) //Used in the demo
|
||||
return new AnimComponent(parent, parentID, name, tag);
|
||||
|
||||
char t[4];
|
||||
memcpy(t, &tag, sizeof(tag32));
|
||||
warning("loadComponent: Unknown tag '%c%c%c%c', name '%s'", t[0], t[1], t[2], t[3], name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ModelComponent *Costume::getMainModelComponent() const {
|
||||
for (int i = 0; i < _numComponents; i++) {
|
||||
// Needs to handle Main Models (pigeons) and normal Models
|
||||
// (when Manny climbs the rope)
|
||||
if (_components[i] && _components[i]->isComponentType('M','M','D','L'))
|
||||
return static_cast<ModelComponent *>(_components[i]);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ModelNode *Costume::getModelNodes() {
|
||||
ModelComponent *comp = getMainModelComponent();
|
||||
if (comp) {
|
||||
return comp->getHierarchy();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Model *Costume::getModel() {
|
||||
ModelComponent *comp = getMainModelComponent();
|
||||
if (comp) {
|
||||
return comp->getModel();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Costume::setChoreLastFrame(int num) {
|
||||
if (num < 0 || num >= _numChores) {
|
||||
Debug::warning(Debug::Chores, "Requested chore number %d is outside the range of chores (0-%d)", num, _numChores);
|
||||
return;
|
||||
}
|
||||
_chores[num]->setLastFrame();
|
||||
}
|
||||
|
||||
void Costume::setChoreLooping(int num, bool val) {
|
||||
if (num < 0 || num >= _numChores) {
|
||||
Debug::warning(Debug::Chores, "Requested chore number %d is outside the range of chores (0-%d)", num, _numChores);
|
||||
return;
|
||||
}
|
||||
_chores[num]->setLooping(val);
|
||||
}
|
||||
|
||||
void Costume::playChoreLooping(const char *name, uint msecs) {
|
||||
for (int i = 0; i < _numChores; ++i) {
|
||||
if (strcmp(_chores[i]->getName(), name) == 0) {
|
||||
playChoreLooping(i, msecs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
warning("Costume::playChoreLooping: Could not find chore: %s", name);
|
||||
return;
|
||||
}
|
||||
|
||||
void Costume::playChoreLooping(int num, uint msecs) {
|
||||
if (num < 0 || num >= _numChores) {
|
||||
Debug::warning(Debug::Chores, "Requested chore number %d is outside the range of chores (0-%d)", num, _numChores);
|
||||
return;
|
||||
}
|
||||
|
||||
_chores[num]->playLooping(msecs);
|
||||
if (Common::find(_playingChores.begin(), _playingChores.end(), _chores[num]) == _playingChores.end())
|
||||
_playingChores.push_back(_chores[num]);
|
||||
}
|
||||
|
||||
Chore *Costume::getChore(const char *name) {
|
||||
for (int i = 0; i < _numChores; ++i) {
|
||||
if (strcmp(_chores[i]->getName(), name) == 0) {
|
||||
return _chores[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int Costume::getChoreId(const char *name) {
|
||||
if (name == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0; i < _numChores; ++i) {
|
||||
if (strcmp(_chores[i]->getName(), name) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Costume::playChore(const char *name, uint msecs) {
|
||||
for (int i = 0; i < _numChores; ++i) {
|
||||
if (strcmp(_chores[i]->getName(), name) == 0) {
|
||||
playChore(i, msecs);
|
||||
return;
|
||||
}
|
||||
}
|
||||
warning("Costume::playChore: Could not find chore: %s", name);
|
||||
return;
|
||||
}
|
||||
|
||||
void Costume::playChore(int num, uint msecs) {
|
||||
if (num < 0 || num >= _numChores) {
|
||||
Debug::warning(Debug::Chores, "Requested chore number %d is outside the range of chores (0-%d)", num, _numChores);
|
||||
return;
|
||||
}
|
||||
_chores[num]->play(msecs);
|
||||
if (Common::find(_playingChores.begin(), _playingChores.end(), _chores[num]) == _playingChores.end())
|
||||
_playingChores.push_back(_chores[num]);
|
||||
}
|
||||
|
||||
void Costume::stopChore(int num, uint msecs) {
|
||||
if (num < 0 || num >= _numChores) {
|
||||
Debug::warning(Debug::Chores, "Requested chore number %d is outside the range of chores (0-%d)", num, _numChores);
|
||||
return;
|
||||
}
|
||||
_chores[num]->stop(msecs);
|
||||
}
|
||||
|
||||
void Costume::setColormap(const Common::String &map) {
|
||||
// Sometimes setColormap is called on a null costume,
|
||||
// see where raoul is gone in hh.set
|
||||
if (!map.size())
|
||||
return;
|
||||
_cmap = g_resourceloader->getColormap(map);
|
||||
for (int i = 0; i < _numComponents; i++)
|
||||
if (_components[i])
|
||||
_components[i]->setColormap(nullptr);
|
||||
}
|
||||
|
||||
void Costume::stopChores(bool ignoreLoopingChores, int msecs) {
|
||||
for (int i = 0; i < _numChores; i++) {
|
||||
if (ignoreLoopingChores && _chores[i]->isLooping()) {
|
||||
continue;
|
||||
}
|
||||
_chores[i]->stop(msecs);
|
||||
}
|
||||
}
|
||||
|
||||
void Costume::fadeChoreIn(int chore, uint msecs) {
|
||||
if (chore < 0 || chore >= _numChores) {
|
||||
Debug::warning(Debug::Chores, "Requested chore number %d is outside the range of chores (0-%d)", chore, _numChores);
|
||||
return;
|
||||
}
|
||||
_chores[chore]->fadeIn(msecs);
|
||||
if (Common::find(_playingChores.begin(), _playingChores.end(), _chores[chore]) == _playingChores.end())
|
||||
_playingChores.push_back(_chores[chore]);
|
||||
}
|
||||
|
||||
void Costume::fadeChoreOut(int chore, uint msecs) {
|
||||
if (chore < 0 || chore >= _numChores) {
|
||||
Debug::warning(Debug::Chores, "Requested chore number %d is outside the range of chores (0-%d)", chore, _numChores);
|
||||
return;
|
||||
}
|
||||
_chores[chore]->fadeOut(msecs);
|
||||
}
|
||||
|
||||
int Costume::isChoring(const char *name, bool excludeLooping) {
|
||||
for (int i = 0; i < _numChores; i++) {
|
||||
if (!strcmp(_chores[i]->getName(), name) && _chores[i]->isPlaying() && !(excludeLooping && _chores[i]->isLooping()))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Costume::isChoring(int num, bool excludeLooping) {
|
||||
if (num < 0 || num >= _numChores) {
|
||||
Debug::warning(Debug::Chores, "Requested chore number %d is outside the range of chores (0-%d)", num, _numChores);
|
||||
return -1;
|
||||
}
|
||||
if (_chores[num]->isPlaying() && !(excludeLooping && _chores[num]->isLooping()))
|
||||
return num;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
int Costume::isChoring(bool excludeLooping) {
|
||||
for (int i = 0; i < _numChores; i++) {
|
||||
if (_chores[i]->isPlaying() && !(excludeLooping && _chores[i]->isLooping()))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Costume::draw() {
|
||||
for (int i = 0; i < _numComponents; i++)
|
||||
if (_components[i])
|
||||
_components[i]->draw();
|
||||
}
|
||||
|
||||
void Costume::getBoundingBox(int *x1, int *y1, int *x2, int *y2) {
|
||||
for (int i = 0; i < _numComponents; i++) {
|
||||
if (_components[i] &&(_components[i]->isComponentType('M','M','D','L') ||
|
||||
_components[i]->isComponentType('M','O','D','L'))) {
|
||||
ModelComponent *c = static_cast<ModelComponent *>(_components[i]);
|
||||
c->getBoundingBox(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
if (_components[i] &&(_components[i]->isComponentType('m','e','s','h'))) {
|
||||
EMIMeshComponent *c = static_cast<EMIMeshComponent *>(_components[i]);
|
||||
c->getBoundingBox(x1, y1, x2, y2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Costume::update(uint time) {
|
||||
for (Common::List<Chore*>::iterator i = _playingChores.begin(); i != _playingChores.end(); ++i) {
|
||||
(*i)->update(time);
|
||||
if (!(*i)->isPlaying()) {
|
||||
i = _playingChores.erase(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
int marker = 0;
|
||||
for (int i = 0; i < _numComponents; i++) {
|
||||
if (_components[i]) {
|
||||
_components[i]->setMatrix(_matrix);
|
||||
int m = _components[i]->update(time);
|
||||
if (m > 0) {
|
||||
marker = m;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return marker;
|
||||
}
|
||||
|
||||
void Costume::animate() {
|
||||
for (int i = 0; i < _numComponents; i++) {
|
||||
if (_components[i]) {
|
||||
_components[i]->animate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Costume::moveHead(bool entering, const Math::Vector3d &lookAt) {
|
||||
_head->lookAt(entering, lookAt, _lookAtRate, _matrix);
|
||||
}
|
||||
|
||||
int Costume::getHeadJoint() const {
|
||||
return static_cast<Head *>(_head)->getJoint3();
|
||||
}
|
||||
|
||||
void Costume::setHead(int joint1, int joint2, int joint3, float maxRoll, float maxPitch, float maxYaw) {
|
||||
Head *head = static_cast<Head *>(_head);
|
||||
head->setJoints(joint1, joint2, joint3);
|
||||
head->loadJoints(getModelNodes());
|
||||
head->setMaxAngles(maxPitch, maxYaw, maxRoll);
|
||||
}
|
||||
|
||||
void Costume::setLookAtRate(float rate) {
|
||||
_lookAtRate = rate;
|
||||
}
|
||||
|
||||
float Costume::getLookAtRate() const {
|
||||
return _lookAtRate;
|
||||
}
|
||||
|
||||
void Costume::setPosRotate(const Math::Vector3d &pos, const Math::Angle &pitch,
|
||||
const Math::Angle &yaw, const Math::Angle &roll) {
|
||||
_matrix.setPosition(pos);
|
||||
_matrix.buildFromEuler(yaw, pitch, roll, Math::EO_ZXY);
|
||||
}
|
||||
|
||||
Math::Matrix4 Costume::getMatrix() const {
|
||||
return _matrix;
|
||||
}
|
||||
|
||||
Costume *Costume::getPreviousCostume() const {
|
||||
return _prevCostume;
|
||||
}
|
||||
|
||||
void Costume::saveState(SaveGame *state) const {
|
||||
if (_cmap) {
|
||||
state->writeBool(true);
|
||||
state->writeString(_cmap->getFilename());
|
||||
} else {
|
||||
state->writeBool(false);
|
||||
}
|
||||
|
||||
for (int i = 0; i < _numChores; ++i) {
|
||||
_chores[i]->saveState(state);
|
||||
}
|
||||
|
||||
for (int i = 0; i < _numComponents; ++i) {
|
||||
Component *c = _components[i];
|
||||
|
||||
if (c) {
|
||||
state->writeBool(c->_visible);
|
||||
c->saveState(state);
|
||||
}
|
||||
}
|
||||
|
||||
state->writeLEUint32(_playingChores.size());
|
||||
for (Common::List<Chore*>::const_iterator i = _playingChores.begin(); i != _playingChores.end(); ++i) {
|
||||
state->writeLESint32((*i)->getChoreId());
|
||||
}
|
||||
|
||||
state->writeFloat(_lookAtRate);
|
||||
_head->saveState(state);
|
||||
}
|
||||
|
||||
bool Costume::restoreState(SaveGame *state) {
|
||||
if (state->readBool()) {
|
||||
Common::String str = state->readString();
|
||||
setColormap(str);
|
||||
}
|
||||
|
||||
for (int i = 0; i < _numChores; ++i) {
|
||||
_chores[i]->restoreState(state);
|
||||
}
|
||||
|
||||
for (int i = 0; i < _numComponents; ++i) {
|
||||
Component *c = _components[i];
|
||||
|
||||
if (c) {
|
||||
c->_visible = state->readBool();
|
||||
if (state->saveMinorVersion() < 14) {
|
||||
// skip the old _matrix vector
|
||||
state->readVector3d();
|
||||
}
|
||||
c->restoreState(state);
|
||||
}
|
||||
}
|
||||
|
||||
int numPlayingChores = state->readLEUint32();
|
||||
for (int i = 0; i < numPlayingChores; ++i) {
|
||||
int id = state->readLESint32();
|
||||
_playingChores.push_back(_chores[id]);
|
||||
}
|
||||
|
||||
_lookAtRate = state->readFloat();
|
||||
_head->restoreState(state);
|
||||
_head->loadJoints(getModelNodes());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
127
engines/grim/costume.h
Normal file
127
engines/grim/costume.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/* 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_COSTUME_H
|
||||
#define GRIM_COSTUME_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "math/matrix4.h"
|
||||
|
||||
#include "engines/grim/object.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
typedef uint32 tag32;
|
||||
|
||||
class CMap;
|
||||
class Model;
|
||||
class ModelNode;
|
||||
class TextSplitter;
|
||||
class ModelComponent;
|
||||
class Component;
|
||||
class Chore;
|
||||
class BaseHead;
|
||||
class Actor;
|
||||
|
||||
class Costume : public Object {
|
||||
public:
|
||||
Costume(const Common::String &filename, Actor *owner, Costume *prevCost);
|
||||
|
||||
virtual ~Costume();
|
||||
virtual void load(Common::SeekableReadStream *data);
|
||||
|
||||
const Common::String &getFilename() const { return _fname; }
|
||||
void playChore(const char *name, uint msecs = 0);
|
||||
virtual void playChore(int num, uint msecs = 0);
|
||||
void playChoreLooping(const char *name, uint msecs = 0);
|
||||
virtual void playChoreLooping(int num, uint msecs = 0);
|
||||
void setChoreLastFrame(int num);
|
||||
void setChoreLooping(int num, bool val);
|
||||
void stopChore(int num, uint msecs = 0);
|
||||
void fadeChoreIn(int chore, uint msecs);
|
||||
void fadeChoreOut(int chore, uint msecs);
|
||||
ModelNode *getModelNodes();
|
||||
Model *getModel();
|
||||
void setColormap(const Common::String &map);
|
||||
void stopChores(bool ignoreLoopingChores = false, int msecs = 0);
|
||||
int isChoring(const char *name, bool excludeLooping);
|
||||
int isChoring(int num, bool excludeLooping);
|
||||
int isChoring(bool excludeLooping);
|
||||
int getNumChores() const { return _numChores; }
|
||||
Chore *getChore(const char *name);
|
||||
Chore *getChore(int i) { return _chores[i]; }
|
||||
int getChoreId(const char *name);
|
||||
const Common::List<Chore *> &getPlayingChores() const { return _playingChores; }
|
||||
|
||||
void setHead(int joint1, int joint2, int joint3, float maxRoll, float maxPitch, float maxYaw);
|
||||
void setLookAtRate(float rate);
|
||||
float getLookAtRate() const;
|
||||
virtual void moveHead(bool entering, const Math::Vector3d &lookAt);
|
||||
int getHeadJoint() const;
|
||||
|
||||
CMap *getCMap() { return _cmap; }
|
||||
|
||||
virtual int update(uint frameTime);
|
||||
void animate();
|
||||
virtual void draw();
|
||||
void getBoundingBox(int *x1, int *y1, int *x2, int *y2);
|
||||
void setPosRotate(const Math::Vector3d &pos, const Math::Angle &pitch,
|
||||
const Math::Angle &yaw, const Math::Angle &roll);
|
||||
Math::Matrix4 getMatrix() const;
|
||||
Actor *getOwner() const { return _owner; }
|
||||
|
||||
Costume *getPreviousCostume() const;
|
||||
|
||||
virtual void saveState(SaveGame *state) const;
|
||||
virtual bool restoreState(SaveGame *state);
|
||||
|
||||
Component *getComponent(int num) { return _components[num]; }
|
||||
protected:
|
||||
virtual Component *loadComponent(tag32 tag, Component *parent, int parentID, const char *name, Component *prevComponent);
|
||||
|
||||
void load(TextSplitter &ts, Costume *prevCost);
|
||||
|
||||
ModelComponent *getMainModelComponent() const;
|
||||
|
||||
Common::String _fname;
|
||||
Costume *_prevCostume;
|
||||
|
||||
int _numComponents;
|
||||
Component **_components;
|
||||
|
||||
BaseHead *_head;
|
||||
|
||||
ObjectPtr<CMap> _cmap;
|
||||
int _numChores;
|
||||
Chore **_chores;
|
||||
Common::List<Chore*> _playingChores;
|
||||
Math::Matrix4 _matrix;
|
||||
Actor *_owner;
|
||||
|
||||
float _lookAtRate;
|
||||
|
||||
friend class Chore;
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
81
engines/grim/costume/anim_component.cpp
Normal file
81
engines/grim/costume/anim_component.cpp
Normal 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
|
||||
43
engines/grim/costume/anim_component.h
Normal file
43
engines/grim/costume/anim_component.h
Normal 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
|
||||
61
engines/grim/costume/bitmap_component.cpp
Normal file
61
engines/grim/costume/bitmap_component.cpp
Normal 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
|
||||
37
engines/grim/costume/bitmap_component.h
Normal file
37
engines/grim/costume/bitmap_component.h
Normal 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
|
||||
246
engines/grim/costume/chore.cpp
Normal file
246
engines/grim/costume/chore.cpp
Normal 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
|
||||
96
engines/grim/costume/chore.h
Normal file
96
engines/grim/costume/chore.h
Normal 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
|
||||
44
engines/grim/costume/colormap_component.cpp
Normal file
44
engines/grim/costume/colormap_component.cpp
Normal 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
|
||||
39
engines/grim/costume/colormap_component.h
Normal file
39
engines/grim/costume/colormap_component.h
Normal 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
|
||||
100
engines/grim/costume/component.cpp
Normal file
100
engines/grim/costume/component.cpp
Normal 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
|
||||
84
engines/grim/costume/component.h
Normal file
84
engines/grim/costume/component.h
Normal 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
|
||||
249
engines/grim/costume/head.cpp
Normal file
249
engines/grim/costume/head.cpp
Normal 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
|
||||
98
engines/grim/costume/head.h
Normal file
98
engines/grim/costume/head.h
Normal 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
|
||||
133
engines/grim/costume/keyframe_component.cpp
Normal file
133
engines/grim/costume/keyframe_component.cpp
Normal 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
|
||||
51
engines/grim/costume/keyframe_component.h
Normal file
51
engines/grim/costume/keyframe_component.h
Normal 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
|
||||
36
engines/grim/costume/lua_var_component.cpp
Normal file
36
engines/grim/costume/lua_var_component.cpp
Normal 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
|
||||
37
engines/grim/costume/lua_var_component.h
Normal file
37
engines/grim/costume/lua_var_component.h
Normal 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
|
||||
83
engines/grim/costume/main_model_component.cpp
Normal file
83
engines/grim/costume/main_model_component.cpp
Normal 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
|
||||
47
engines/grim/costume/main_model_component.h
Normal file
47
engines/grim/costume/main_model_component.h
Normal 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
|
||||
78
engines/grim/costume/material_component.cpp
Normal file
78
engines/grim/costume/material_component.cpp
Normal 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
|
||||
47
engines/grim/costume/material_component.h
Normal file
47
engines/grim/costume/material_component.h
Normal 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
|
||||
92
engines/grim/costume/mesh_component.cpp
Normal file
92
engines/grim/costume/mesh_component.cpp
Normal 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
|
||||
58
engines/grim/costume/mesh_component.h
Normal file
58
engines/grim/costume/mesh_component.h
Normal 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
|
||||
210
engines/grim/costume/model_component.cpp
Normal file
210
engines/grim/costume/model_component.cpp
Normal 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
|
||||
64
engines/grim/costume/model_component.h
Normal file
64
engines/grim/costume/model_component.h
Normal 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
|
||||
72
engines/grim/costume/sound_component.cpp
Normal file
72
engines/grim/costume/sound_component.cpp
Normal 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
|
||||
40
engines/grim/costume/sound_component.h
Normal file
40
engines/grim/costume/sound_component.h
Normal 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
|
||||
111
engines/grim/costume/sprite_component.cpp
Normal file
111
engines/grim/costume/sprite_component.cpp
Normal 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
|
||||
48
engines/grim/costume/sprite_component.h
Normal file
48
engines/grim/costume/sprite_component.h
Normal 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
|
||||
11
engines/grim/credits.pl
Normal file
11
engines/grim/credits.pl
Normal file
@@ -0,0 +1,11 @@
|
||||
begin_section("Grim");
|
||||
add_person("James Brown", "ender", "Grim (retired)");
|
||||
add_person("Giulio Camuffo", "giucam", "Grim (retired)");
|
||||
add_person("Daniel Schepler", "", "Initial engine contributor");
|
||||
add_person("Dries Harnie", "Botje", "EMI");
|
||||
add_person("Paweł Kołodziejski", "aquadran", "Grim");
|
||||
add_person("Christian Krause", "chkr", "EMI (retired)");
|
||||
add_person("Einar Johan T. Sømåen", "somaen", "Grim, EMI");
|
||||
add_person("Joel Teichroeb", "klusark", "EMI");
|
||||
add_person("Joni Vähämäki", "Akz", "EMI (retired)");
|
||||
end_section();
|
||||
79
engines/grim/debug.cpp
Normal file
79
engines/grim/debug.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
/* 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/debug-channels.h"
|
||||
|
||||
#include "engines/grim/debug.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
void Debug::registerDebugChannels() {
|
||||
}
|
||||
|
||||
bool Debug::isChannelEnabled(DebugChannel chan) {
|
||||
return DebugMan.isDebugChannelEnabled(chan);
|
||||
}
|
||||
|
||||
void Debug::debug(DebugChannel channel, const char *s, ...) {
|
||||
if (isChannelEnabled(channel | Debug::Info)) {
|
||||
va_list args;
|
||||
va_start(args, s);
|
||||
Common::String buf = Common::String::vformat(s, args);
|
||||
va_end(args);
|
||||
|
||||
::debug("%s", buf.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void Debug::warning(DebugChannel channel, const char *s, ...) {
|
||||
if (isChannelEnabled(channel | Debug::Warning)) {
|
||||
va_list args;
|
||||
va_start(args, s);
|
||||
Common::String buf = Common::String::vformat(s, args);
|
||||
va_end(args);
|
||||
|
||||
::warning("%s", buf.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void Debug::error(DebugChannel channel, const char *s, ...) {
|
||||
if (isChannelEnabled(channel | Debug::Error)) {
|
||||
va_list args;
|
||||
va_start(args, s);
|
||||
Common::String buf = Common::String::vformat(s, args);
|
||||
va_end(args);
|
||||
|
||||
::error("%s", buf.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void Debug::error(const char *s, ...) {
|
||||
if (isChannelEnabled(Debug::Error)) {
|
||||
va_list args;
|
||||
va_start(args, s);
|
||||
Common::String buf = Common::String::vformat(s, args);
|
||||
va_end(args);
|
||||
|
||||
::error("%s", buf.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
95
engines/grim/debug.h
Normal file
95
engines/grim/debug.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/* 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_DEBUG_H
|
||||
#define GRIM_DEBUG_H
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/streamdebug.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class Debug {
|
||||
public:
|
||||
enum DebugChannel {
|
||||
Info = 1,
|
||||
Warning = 2 << 0,
|
||||
Error = 2 << 1,
|
||||
Engine = 2 << 2,
|
||||
Lua = 2 << 3,
|
||||
Bitmaps = 2 << 4,
|
||||
Models = 2 << 5,
|
||||
Actors = 2 << 6,
|
||||
Costumes = 2 << 7,
|
||||
Chores = 2 << 8,
|
||||
Fonts = 2 << 9,
|
||||
Keyframes = 2 << 10,
|
||||
Materials = 2 << 11,
|
||||
Movie = 2 << 12,
|
||||
Sound = 2 << 13,
|
||||
Scripts = 2 << 14,
|
||||
Sets = 2 << 15,
|
||||
TextObjects = 2 << 16,
|
||||
Patchr = 2 << 17,
|
||||
Lipsync = 2 << 18,
|
||||
Sprites = 2 << 19
|
||||
};
|
||||
|
||||
static void registerDebugChannels();
|
||||
static bool isChannelEnabled(DebugChannel chan);
|
||||
|
||||
/**
|
||||
* Prints a message to the console (stdout), only if the specified debug channel
|
||||
* or the channel Info are active.
|
||||
*
|
||||
* @param channel The debug channel to use.
|
||||
*/
|
||||
static void debug(DebugChannel channel, const char *s, ...);
|
||||
/**
|
||||
* Prints a message to the console (sterr), only if the specified debug channel
|
||||
* or the channel Warning are active.
|
||||
*
|
||||
* @param channel The debug channel to use.
|
||||
*/
|
||||
static void warning(DebugChannel channel, const char *s, ...);
|
||||
/**
|
||||
* Prints a message to the console (stderr) and exit the program immediately,
|
||||
* only if the specified debug channel or the channel Error are active.
|
||||
*
|
||||
* @param channel The debug channel to use.
|
||||
*/
|
||||
static void error(DebugChannel channel, const char *s, ...);
|
||||
/**
|
||||
* Prints a message to the console (stderr) and exit the program immediately,
|
||||
* only if the debug channel Error is active.
|
||||
*
|
||||
* @param channel The debug channel to use.
|
||||
*/
|
||||
static void error(const char *s, ...);
|
||||
};
|
||||
|
||||
inline Debug::DebugChannel operator|(Debug::DebugChannel a, Debug::DebugChannel b) {
|
||||
return (Debug::DebugChannel)((int)a | (int) b);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
137
engines/grim/debugger.cpp
Normal file
137
engines/grim/debugger.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
/* 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/config-manager.h"
|
||||
|
||||
#include "graphics/renderer.h"
|
||||
|
||||
#include "engines/grim/debugger.h"
|
||||
#include "engines/grim/md5check.h"
|
||||
#include "engines/grim/grim.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
Debugger::Debugger() :
|
||||
GUI::Debugger() {
|
||||
|
||||
registerCmd("check_gamedata", WRAP_METHOD(Debugger, cmd_checkFiles));
|
||||
registerCmd("lua_do", WRAP_METHOD(Debugger, cmd_lua_do));
|
||||
registerCmd("jump", WRAP_METHOD(Debugger, cmd_jump));
|
||||
registerCmd("renderer_set", WRAP_METHOD(Debugger, cmd_renderer_set));
|
||||
registerCmd("renderer_get", WRAP_METHOD(Debugger, cmd_renderer_get));
|
||||
registerCmd("save", WRAP_METHOD(Debugger, cmd_save));
|
||||
registerCmd("load", WRAP_METHOD(Debugger, cmd_load));
|
||||
}
|
||||
|
||||
Debugger::~Debugger() {
|
||||
|
||||
}
|
||||
|
||||
bool Debugger::cmd_checkFiles(int argc, const char **argv) {
|
||||
if (MD5Check::checkFiles()) {
|
||||
debugPrintf("All files are ok.\n");
|
||||
} else {
|
||||
debugPrintf("Some files are corrupted or missing.\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::cmd_lua_do(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
debugPrintf("Usage: lua_do <lua command>\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::String cmd;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
cmd += argv[i];
|
||||
cmd += " ";
|
||||
}
|
||||
cmd.deleteLastChar();
|
||||
debugPrintf("Executing command: <%s>\n", cmd.c_str());
|
||||
cmd = Common::String::format("__temp_fn__ = function()\n%s\nend\nstart_script(__temp_fn__)", cmd.c_str());
|
||||
g_grim->debugLua(cmd);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::cmd_jump(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
debugPrintf("Usage: jump <jump target>\n");
|
||||
return true;
|
||||
}
|
||||
// Escape from Monkey Island keeps the jump script in a separate file, so load it first
|
||||
if (g_grim->getGameType() == GType_MONKEY4) {
|
||||
Common::String loadJS = Common::String::format("dofile(\"_jumpscripts.lua\")\n");
|
||||
g_grim->debugLua(loadJS.c_str());
|
||||
}
|
||||
|
||||
// Start the jump_script Lua function with the desired target
|
||||
Common::String cmd = Common::String::format("start_script(jump_script,\"%s\")", argv[1]);
|
||||
g_grim->debugLua(cmd.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::cmd_renderer_set(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
debugPrintf("Usage: renderer_set <renderer>\n");
|
||||
debugPrintf("Where <renderer> is 'software', 'opengl' or 'opengl_shaders'\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
Graphics::RendererType renderer = Graphics::Renderer::parseTypeCode(argv[1]);
|
||||
if (renderer == Graphics::kRendererTypeDefault) {
|
||||
debugPrintf("Invalid renderer '%s'\n", argv[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
ConfMan.set("renderer", Graphics::Renderer::getTypeCode(renderer));
|
||||
g_grim->changeHardwareState();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Debugger::cmd_renderer_get(int argc, const char **argv) {
|
||||
auto rendererCodeStr = Graphics::Renderer::getTypeCode(g_grim->getRendererType());
|
||||
debugPrintf("%s\n", rendererCodeStr.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::cmd_save(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
debugPrintf("Usage: save <save name>\n");
|
||||
return true;
|
||||
}
|
||||
Common::String file = Common::String::format("%s.gsv", argv[1]);
|
||||
g_grim->saveGame(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Debugger::cmd_load(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
debugPrintf("Usage: load <save name>\n");
|
||||
return true;
|
||||
}
|
||||
Common::String file = Common::String::format("%s.gsv", argv[1]);
|
||||
g_grim->loadGame(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
47
engines/grim/debugger.h
Normal file
47
engines/grim/debugger.h
Normal 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_DEBUGGER_H
|
||||
#define GRIM_DEBUGGER_H
|
||||
|
||||
#include "common/debug.h"
|
||||
|
||||
#include "gui/debugger.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class Debugger : public GUI::Debugger {
|
||||
public:
|
||||
Debugger();
|
||||
virtual ~Debugger();
|
||||
|
||||
bool cmd_checkFiles(int argc, const char **argv);
|
||||
bool cmd_lua_do(int argc, const char **argv);
|
||||
bool cmd_jump(int argc, const char **argv);
|
||||
bool cmd_renderer_get(int argc, const char **argv);
|
||||
bool cmd_renderer_set(int argc, const char **argv);
|
||||
bool cmd_save(int argc, const char **argv);
|
||||
bool cmd_load(int argc, const char **argv);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
107
engines/grim/detection.cpp
Normal file
107
engines/grim/detection.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/* 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/advancedDetector.h"
|
||||
#include "grim/debug.h"
|
||||
#include "grim/detection.h"
|
||||
#include "grim/detection_tables.h"
|
||||
|
||||
static const DebugChannelDef debugFlagList[] = {
|
||||
{Grim::Debug::Info, "info", ""},
|
||||
{Grim::Debug::Warning, "warning", ""},
|
||||
{Grim::Debug::Error, "error", ""},
|
||||
{Grim::Debug::Engine, "engine", ""},
|
||||
{Grim::Debug::Lua, "lua", ""},
|
||||
{Grim::Debug::Bitmaps, "bitmaps", ""},
|
||||
{Grim::Debug::Models, "models", ""},
|
||||
{Grim::Debug::Actors, "actors", ""},
|
||||
{Grim::Debug::Costumes, "costumes", ""},
|
||||
{Grim::Debug::Chores, "chores", ""},
|
||||
{Grim::Debug::Fonts, "fonts", ""},
|
||||
{Grim::Debug::Keyframes, "keyframes", ""},
|
||||
{Grim::Debug::Movie, "movie", ""},
|
||||
{Grim::Debug::Sound, "sound", ""},
|
||||
{Grim::Debug::Scripts, "scripts", ""},
|
||||
{Grim::Debug::Sets, "sets", ""},
|
||||
{Grim::Debug::TextObjects, "textobjects", ""},
|
||||
{Grim::Debug::Patchr, "patchr", ""},
|
||||
{Grim::Debug::Lipsync, "lipsync", ""},
|
||||
{Grim::Debug::Sprites, "sprites", ""},
|
||||
DEBUG_CHANNEL_END
|
||||
};
|
||||
|
||||
namespace Grim {
|
||||
|
||||
static const PlainGameDescriptor grimGames[] = {
|
||||
{"grim", "Grim Fandango"},
|
||||
{"monkey4", "Escape From Monkey Island"},
|
||||
{nullptr, nullptr}
|
||||
};
|
||||
|
||||
class GrimMetaEngineDetection : public AdvancedMetaEngineDetection<Grim::GrimGameDescription> {
|
||||
public:
|
||||
GrimMetaEngineDetection() : AdvancedMetaEngineDetection(Grim::gameDescriptions, grimGames) {
|
||||
_guiOptions = GUIO_NOMIDI;
|
||||
_flags |= kADFlagCanTranscodeTraditionalChineseToSimplified;
|
||||
}
|
||||
|
||||
PlainGameDescriptor findGame(const char *gameid) const override {
|
||||
return Engines::findGameID(gameid, _gameIds, obsoleteGameIDsTable);
|
||||
}
|
||||
|
||||
Common::Error identifyGame(DetectedGame &game, const void **descriptor) override {
|
||||
Engines::upgradeTargetIfNecessary(obsoleteGameIDsTable);
|
||||
return AdvancedMetaEngineDetection::identifyGame(game, descriptor);
|
||||
}
|
||||
|
||||
const char *getEngineName() const override {
|
||||
return "Grim";
|
||||
}
|
||||
|
||||
const char *getName() const override {
|
||||
return "grim";
|
||||
}
|
||||
|
||||
const char *getOriginalCopyright() const override {
|
||||
return "LucasArts GrimE Games (C) LucasArts";
|
||||
}
|
||||
|
||||
const DebugChannelDef *getDebugChannels() const override {
|
||||
return debugFlagList;
|
||||
}
|
||||
|
||||
DetectedGame toDetectedGame(const ADDetectedGame &adGame, ADDetectedGameExtraInfo *extraInfo) const override {
|
||||
DetectedGame game = AdvancedMetaEngineDetection::toDetectedGame(adGame, extraInfo);
|
||||
GrimGameType gameID = reinterpret_cast<const GrimGameDescription *>(adGame.desc)->gameType;
|
||||
|
||||
if (gameID == GType_MONKEY4 && adGame.desc->language == Common::Language::ZH_TWN) {
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::ZH_TWN));
|
||||
game.appendGUIOptions(Common::getGameGUIOptionsDescriptionLanguage(Common::ZH_CHN));
|
||||
}
|
||||
|
||||
return game;
|
||||
}
|
||||
};
|
||||
|
||||
} // End of namespace Grim
|
||||
|
||||
|
||||
REGISTER_PLUGIN_STATIC(GRIM_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, Grim::GrimMetaEngineDetection);
|
||||
54
engines/grim/detection.h
Normal file
54
engines/grim/detection.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* 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_DETECTION_H
|
||||
#define GRIM_DETECTION_H
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
#include "engines/obsolete.h"
|
||||
|
||||
static const Engines::ObsoleteGameID obsoleteGameIDsTable[] = {
|
||||
{"grimdemo", "grim", Common::kPlatformWindows},
|
||||
{nullptr, nullptr, Common::kPlatformUnknown}
|
||||
};
|
||||
|
||||
namespace Grim {
|
||||
|
||||
enum GrimGameType {
|
||||
GType_GRIM,
|
||||
GType_MONKEY4
|
||||
};
|
||||
|
||||
struct GrimGameDescription {
|
||||
AD_GAME_DESCRIPTION_HELPERS(desc);
|
||||
|
||||
ADGameDescription desc;
|
||||
GrimGameType gameType;
|
||||
};
|
||||
|
||||
#define GAMEOPTION_LOAD_DATAUSR GUIO_GAMEOPTIONS1
|
||||
#define GAMEOPTION_SHOW_FPS GUIO_GAMEOPTIONS2
|
||||
|
||||
#define GUI_OPTIONS_GRIME GUIO2(GAMEOPTION_LOAD_DATAUSR, GAMEOPTION_SHOW_FPS)
|
||||
|
||||
} // End of namespace Grim
|
||||
|
||||
#endif // GRIM_DETECTION_H
|
||||
727
engines/grim/detection_tables.h
Normal file
727
engines/grim/detection_tables.h
Normal file
@@ -0,0 +1,727 @@
|
||||
/* 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_DETECTION_TABLES_H
|
||||
#define GRIM_DETECTION_TABLES_H
|
||||
|
||||
#include "grim/detection.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
static const GrimGameDescription gameDescriptions[] = {
|
||||
{
|
||||
// Grim Fandango English version (patched)
|
||||
{
|
||||
"grim",
|
||||
"",
|
||||
AD_ENTRY1s("VOX0001.LAB", "444f05f2af689c1bffd179b8b6a632bd", 57993159),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango English version (unpatched)
|
||||
{
|
||||
"grim",
|
||||
"",
|
||||
AD_ENTRY1s("VOX0001.LAB", "8b12ed530195c6c577436df27df62ecb", 58011176),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango English version (unpatched) + Chinese Fan translation
|
||||
{
|
||||
"grim",
|
||||
"",
|
||||
AD_ENTRY2s("VOX0001.LAB", "8b12ed530195c6c577436df27df62ecb", 58011176,
|
||||
"GRIM.TAB", "613d5c80480229837a14829cbc1e1d22", 273523),
|
||||
Common::ZH_CHN,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango English version (unpatched) + Polish Fan translation
|
||||
{
|
||||
"grim",
|
||||
"Fanmade",
|
||||
AD_ENTRY2s("VOX0001.LAB", "8b12ed530195c6c577436df27df62ecb", 58011176,
|
||||
"GRIM.TAB", "2b99efd92f782b791a464b1b8a16187a", 351510),
|
||||
Common::PL_POL,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango English version (patched) + Polish Fan translation
|
||||
{
|
||||
"grim",
|
||||
"Fanmade",
|
||||
AD_ENTRY2s("VOX0001.LAB", "444f05f2af689c1bffd179b8b6a632bd", 57993159,
|
||||
"GRIM.TAB", "2b99efd92f782b791a464b1b8a16187a", 351510),
|
||||
Common::PL_POL,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango English version (unpatched) + Russian Enpy translation
|
||||
{
|
||||
"grim",
|
||||
"ENPY",
|
||||
AD_ENTRY2s("VOX0001.LAB", "8b12ed530195c6c577436df27df62ecb", 58011176,
|
||||
"rus_font.lab", "df658c6a491a831d47a58eb21ccc7126", 162443),
|
||||
Common::RU_RUS,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
|
||||
{
|
||||
// Grim Fandango French version (un/patched ???)
|
||||
{
|
||||
"grim",
|
||||
"",
|
||||
AD_ENTRY1s("VOX0001.LAB", "19bc0dc9554257b1f021463de54f359f", 56268691),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango Russian (7Wolf) version
|
||||
{
|
||||
"grim",
|
||||
"7Wolf",
|
||||
AD_ENTRY1s("VOX0001.LAB", "b517dbb493679b1679036de1a1bfc8a5", 57180788),
|
||||
Common::RU_RUS,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango Russian (Fargus) version
|
||||
{
|
||||
"grim",
|
||||
"Fargus",
|
||||
AD_ENTRY1s("VOX0001.LAB", "a38708ba97960ee7ee59218489a485eb", 44691160),
|
||||
Common::RU_RUS,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango Portuguese version
|
||||
{
|
||||
"grim",
|
||||
"",
|
||||
AD_ENTRY1s("VOX0001.LAB", "89da4d4f4f90a8ea390450ed5a617f08", 57875710),
|
||||
Common::PT_BRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango Italian version
|
||||
{
|
||||
"grim",
|
||||
"",
|
||||
AD_ENTRY1s("VOX0001.LAB", "9e7075f3fb0427ae8136b290538d07dd", 62185775),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango Spanish version (patched)
|
||||
{
|
||||
"grim",
|
||||
"",
|
||||
AD_ENTRY1s("VOX0001.LAB", "85d3e9504c481c5ccf2119ea6e0f4e2f", 53831340),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango German version
|
||||
{
|
||||
"grim",
|
||||
"",
|
||||
AD_ENTRY1s("VOX0001.LAB", "d304aa402098de5966816c0a11e45816", 66829347),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango German version (CD protected) - unsupported
|
||||
{
|
||||
"grim",
|
||||
"",
|
||||
AD_ENTRY1s("VOX0001.LAB", "88e8e13a8164c0df62b1f2f4e9ab4583", 388753408),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSUPPORTED,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango Hebrew Fan translation (patched)
|
||||
{
|
||||
"grim",
|
||||
"",
|
||||
AD_ENTRY2s("LOCAL.LAB", "d22648d6787c2f8f0a789ee3ed0c08f7", 608,
|
||||
"VOX0001.LAB", "444f05f2af689c1bffd179b8b6a632bd", 57993159),
|
||||
Common::HE_ISR,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango Korean Fan translation (patched)
|
||||
{
|
||||
"grim",
|
||||
"",
|
||||
AD_ENTRY2s("VOX0001.LAB", "444f05f2af689c1bffd179b8b6a632bd", 57993159,
|
||||
"grim.ko.tab", NULL, AD_NO_SIZE),
|
||||
Common::KO_KOR,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
/* {
|
||||
// Grim Fandango German version (patched)
|
||||
{
|
||||
"grim",
|
||||
"",
|
||||
AD_ENTRY1s("grim.tab", "464138caf47e580cbb237dee10674b16", 398671),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango Spanish version
|
||||
{
|
||||
"grim",
|
||||
"",
|
||||
AD_ENTRY1s("grim.tab", "b1460cd029f13718f7f62c2403e047ec", 372709),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango Spanish version (patched)
|
||||
{
|
||||
"grim",
|
||||
"",
|
||||
AD_ENTRY1s("grim.tab", "b1460cd029f13718f7f62c2403e047ec", 372020),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango Italian version (patched)
|
||||
{
|
||||
"grim",
|
||||
"",
|
||||
AD_ENTRY1s("grim.tab", "2d99c796b7a4e5c421cae49dc29dab6c", 369242),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango French version (patched)
|
||||
{
|
||||
"grim",
|
||||
"",
|
||||
AD_ENTRY1s("grim.tab", "3bd00ca87214862c012ac99e1758dd83", 386292),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango Portuguese version (patched)
|
||||
{
|
||||
"grim",
|
||||
"",
|
||||
AD_ENTRY1s("grim.tab", "4dc16be476bb6036b423bc331ca8281a", 362994),
|
||||
Common::PT_BRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_NO_FLAGS,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
*/ {
|
||||
// Grim Fandango English demo version
|
||||
{
|
||||
"grim",
|
||||
"Demo",
|
||||
AD_ENTRY1s("gfdemo01.lab", "755cdac083f7f751bec7506402278f1a", 29489930),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango English demo version (with intro video)
|
||||
{
|
||||
"grim",
|
||||
"Demo",
|
||||
AD_ENTRY1s("gdemo001.lab", "c04c814093be829c4811a3a0aa80833d", 46615911),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango French demo version
|
||||
{
|
||||
"grim",
|
||||
"Demo",
|
||||
AD_ENTRY2s("gfdemo01.lab", "7df813f3809f2c0234213cfa4f6da062", 29533695,
|
||||
"voice001.lab", "7df474e03c23692ed02e4ce45f1a6b30", 13764168),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
|
||||
{
|
||||
// Grim Fandango German demo version
|
||||
{
|
||||
"grim",
|
||||
"Demo",
|
||||
AD_ENTRY2s("gfdemo01.lab", "7df813f3809f2c0234213cfa4f6da062", 29533695,
|
||||
"voice001.lab", "2788dc7fd226787f3a68ac9c853d2580", 16561196),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
|
||||
{
|
||||
// Grim Fandango Italian demo version
|
||||
{
|
||||
"grim",
|
||||
"Demo",
|
||||
AD_ENTRY2s("gfdemo01.lab", "7df813f3809f2c0234213cfa4f6da062", 29533695,
|
||||
"voice001.lab", "3b8ace62584380c66b73981e014ea40e", 14907410),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
|
||||
{
|
||||
// Grim Fandango Spanish demo version
|
||||
{
|
||||
"grim",
|
||||
"Demo",
|
||||
AD_ENTRY2s("gfdemo01.lab", "7df813f3809f2c0234213cfa4f6da062", 29533695,
|
||||
"voice001.lab", "a810ec11acaf9d76cd04d2f68fcdc912", 13367206),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
{
|
||||
// Grim Fandango Remastered
|
||||
{
|
||||
"grim",
|
||||
"Remastered",
|
||||
AD_ENTRY1s("VOX0001.LAB", "0ff872fb353707fbdb9579038d4cf31c", 382736476),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_REMASTERED,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_GRIM
|
||||
},
|
||||
|
||||
{
|
||||
// Escape from Monkey Island English
|
||||
{
|
||||
"monkey4",
|
||||
"",
|
||||
AD_ENTRY1s("artAll.m4b", "61959da91d864bf5f4588daa4a5a3019", 18515664),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
{
|
||||
// Escape from Monkey Island Chinese
|
||||
{
|
||||
"monkey4",
|
||||
"",
|
||||
AD_ENTRY2s("artAll.m4b", "61959da91d864bf5f4588daa4a5a3019", 18515664,
|
||||
"Script.tab", "ee08a95b6820f7b876940f6cd41dbae7", 618346),
|
||||
Common::ZH_TWN,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
{
|
||||
// Escape from Monkey Island German
|
||||
{
|
||||
"monkey4",
|
||||
"",
|
||||
AD_ENTRY1s("artAll.m4b", "007a33881478be6b6e0228d8888536ae", 18512568),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
{
|
||||
// Escape from Monkey Island Italian
|
||||
{
|
||||
"monkey4",
|
||||
"",
|
||||
AD_ENTRY1s("artAll.m4b", "d2f010c1cd1fd002eea403282a6b9a1e", 18513451),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
{
|
||||
// Escape from Monkey Island Spanish
|
||||
{
|
||||
"monkey4",
|
||||
"",
|
||||
AD_ENTRY1s("artAll.m4b", "0d459954031c086a0448d2eb3fa068a1", 18514404),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
{
|
||||
// Escape from Monkey Island French
|
||||
{
|
||||
"monkey4",
|
||||
"",
|
||||
AD_ENTRY1s("artAll.m4b", "151af0a694382af873f325fcea293bb1", 18514420),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
{
|
||||
// Escape from Monkey Island Portuguese
|
||||
{
|
||||
"monkey4",
|
||||
"",
|
||||
AD_ENTRY1s("artAll.m4b", "030e7637aee7886a3caad60cf102f797", 18515747),
|
||||
Common::PT_BRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
{
|
||||
// Escape from Monkey Island Russian
|
||||
{
|
||||
"monkey4",
|
||||
"",
|
||||
AD_ENTRY1s("artAll.m4b", "779561a70a11dd5686974f122fc1516c", 18500052),
|
||||
Common::RU_RUS,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
{
|
||||
// Escape from Monkey Island Polish fanmade
|
||||
{
|
||||
"monkey4",
|
||||
"Fanmade",
|
||||
AD_ENTRY1s("artAll.m4b", "451332012f4d947ef12da4f7d7f0e560", 18751712),
|
||||
Common::PL_POL,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
{
|
||||
// Escape from Monkey Island English (Mac)
|
||||
{
|
||||
"monkey4",
|
||||
"",
|
||||
AD_ENTRY2s("artAll.m4b", "61959da91d864bf5f4588daa4a5a3019", 18515664,
|
||||
"Monkey Island 4 Installer", "r:8230927789935674546c4b3f9b1368ea", 560139),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
{
|
||||
// Escape from Monkey Island German (Mac)
|
||||
{
|
||||
"monkey4",
|
||||
"",
|
||||
AD_ENTRY2s("artAll.m4b", "007a33881478be6b6e0228d8888536ae", 18512568,
|
||||
"EFMI Installer", "54298c7440dafedf33d2b27c7bb24052", 9241784),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
{
|
||||
// Escape from Monkey Island French (Mac)
|
||||
{
|
||||
"monkey4",
|
||||
"",
|
||||
AD_ENTRY2s("artAll.m4b", "151af0a694382af873f325fcea293bb1", 18514420,
|
||||
"Installation de Monkey Island 4", "8b22e2fadb4e72e8041c7bd896f1759d", 9242911),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformMacintosh,
|
||||
ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
|
||||
{
|
||||
// Escape from Monkey Island English PS2
|
||||
{
|
||||
"monkey4",
|
||||
"",
|
||||
AD_ENTRY1s("artAll.m4b", "0dc9a4df0d8553f277d8dc8e23b6249d", 34593974),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformPS2,
|
||||
ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
{
|
||||
// Escape from Monkey Island German PS2
|
||||
{
|
||||
"monkey4",
|
||||
"",
|
||||
AD_ENTRY1s("artAll.m4b", "5b5c7a3964c168eab44b82981db357d8", 34642186),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformPS2,
|
||||
ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
{
|
||||
// Escape from Monkey Island Italian PS2
|
||||
{
|
||||
"monkey4",
|
||||
"",
|
||||
AD_ENTRY1s("artAll.m4b", "2de68c8fd955c1a3c50202b072bde0cb", 34642651),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformPS2,
|
||||
ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
{
|
||||
// Escape from Monkey Island Spanish PS2
|
||||
{
|
||||
"monkey4",
|
||||
"",
|
||||
AD_ENTRY1s("artAll.m4b", "ff6689dcca36c249ec834a3019aeb397", 34642656),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformPS2,
|
||||
ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
{
|
||||
// Escape from Monkey Island French PS2
|
||||
{
|
||||
"monkey4",
|
||||
"",
|
||||
AD_ENTRY1s("artAll.m4b", "5ce964a19a8672944b9b62170e45ce28", 34593681),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformPS2,
|
||||
ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
|
||||
{
|
||||
// Escape from Monkey Island CD demo (English)
|
||||
{
|
||||
"monkey4",
|
||||
"CD Demo",
|
||||
AD_ENTRY2s("magdemo.lab", "9e7eaa1b9317ff47d5deeda0b2c42ce3", 19826116,
|
||||
"monkey4.exe", "119ee6b9380cc0e373287fabb25e0578", 884736),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO | ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
{
|
||||
// Escape from Monkey Island web demo (English)
|
||||
{
|
||||
"monkey4",
|
||||
"Web Demo",
|
||||
AD_ENTRY2s("magdemo.lab", "9e7eaa1b9317ff47d5deeda0b2c42ce3", 19826116,
|
||||
"i9n.lab", "274f8579b01e0872fe6f1ba267266149", 26951),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO | ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
{
|
||||
// Escape from Monkey Island demo (French)
|
||||
{
|
||||
"monkey4",
|
||||
"Demo",
|
||||
AD_ENTRY2s("magdemo.lab", "9e7eaa1b9317ff47d5deeda0b2c42ce3", 19826116,
|
||||
"i9n.lab", "7f1744990472261bdcbc02036ba9f7ec", 1718385),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO | ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
|
||||
{
|
||||
// Escape from Monkey Island demo (German)
|
||||
{
|
||||
"monkey4",
|
||||
"Demo",
|
||||
AD_ENTRY2s("magdemo.lab", "9e7eaa1b9317ff47d5deeda0b2c42ce3", 19826116,
|
||||
"i9n.lab", "28f6bc270b5c31970cc110c7656ff598", 1749051),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO | ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
|
||||
{
|
||||
// Escape from Monkey Island demo (Spanish)
|
||||
{
|
||||
"monkey4",
|
||||
"Demo",
|
||||
AD_ENTRY2s("magdemo.lab", "9e7eaa1b9317ff47d5deeda0b2c42ce3", 19826116,
|
||||
"i9n.lab", "53b20d930f6e8c2e0880ed7e336eeebc", 1740761),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_DEMO | ADGF_UNSTABLE,
|
||||
GUI_OPTIONS_GRIME
|
||||
},
|
||||
GType_MONKEY4
|
||||
},
|
||||
|
||||
{ AD_TABLE_END_MARKER, GType_GRIM }
|
||||
};
|
||||
|
||||
} // End of namespace Grim
|
||||
|
||||
#endif
|
||||
380
engines/grim/emi/animationemi.cpp
Normal file
380
engines/grim/emi/animationemi.cpp
Normal file
@@ -0,0 +1,380 @@
|
||||
/* 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/stream.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "math/vector3d.h"
|
||||
#include "math/quat.h"
|
||||
|
||||
#include "engines/grim/resource.h"
|
||||
#include "engines/grim/emi/animationemi.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
AnimationEmi::AnimationEmi(const Common::String &filename, Common::SeekableReadStream *data) :
|
||||
_name(""), _duration(0.0f), _numBones(0), _bones(nullptr) {
|
||||
_fname = filename;
|
||||
loadAnimation(data);
|
||||
}
|
||||
|
||||
// Use modelemi's solution for the LA-strings.
|
||||
void AnimationEmi::loadAnimation(Common::SeekableReadStream *data) {
|
||||
int len = data->readUint32LE();
|
||||
char *inString = new char[len];
|
||||
data->read(inString, len);
|
||||
_name = inString;
|
||||
delete[] inString;
|
||||
|
||||
_duration = 1000 * data->readFloatLE();
|
||||
_numBones = data->readUint32LE();
|
||||
|
||||
_bones = new Bone[_numBones];
|
||||
for (int i = 0; i < _numBones; i++) {
|
||||
_bones[i].loadBinary(data);
|
||||
}
|
||||
}
|
||||
|
||||
AnimationEmi::~AnimationEmi() {
|
||||
g_resourceloader->uncacheAnimationEmi(this);
|
||||
delete[] _bones;
|
||||
}
|
||||
|
||||
void Bone::loadBinary(Common::SeekableReadStream *data) {
|
||||
uint32 len = data->readUint32LE();
|
||||
char *inString = new char[len];
|
||||
data->read(inString, len);
|
||||
_boneName = inString;
|
||||
delete[] inString;
|
||||
_operation = data->readUint32LE();
|
||||
_priority = data->readUint32LE();
|
||||
_c = data->readUint32LE();
|
||||
_count = data->readUint32LE();
|
||||
|
||||
if (_operation == 3) { // Translation
|
||||
_translations = new AnimTranslation[_count];
|
||||
for (int j = 0; j < _count; j++) {
|
||||
_translations[j]._vec.readFromStream(data);
|
||||
_translations[j]._time = 1000 * data->readFloatLE();
|
||||
}
|
||||
} else if (_operation == 4) { // Rotation
|
||||
_rotations = new AnimRotation[_count];
|
||||
for (int j = 0; j < _count; j++) {
|
||||
_rotations[j]._quat.readFromStream(data);
|
||||
_rotations[j]._time = 1000 * data->readFloatLE();
|
||||
}
|
||||
} else {
|
||||
error("Unknown animation-operation %d", _operation);
|
||||
}
|
||||
}
|
||||
|
||||
Bone::~Bone() {
|
||||
if (_operation == 3) {
|
||||
delete[] _translations;
|
||||
} else if (_operation == 4) {
|
||||
delete[] _rotations;
|
||||
}
|
||||
}
|
||||
|
||||
AnimationStateEmi::AnimationStateEmi(const Common::String &anim) :
|
||||
_skel(nullptr), _looping(false), _active(false), _paused(false),
|
||||
_fadeMode(Animation::None), _fade(1.0f), _fadeLength(0), _time(-1), _startFade(1.0f),
|
||||
_boneJoints(nullptr) {
|
||||
_anim = g_resourceloader->getAnimationEmi(anim);
|
||||
if (_anim)
|
||||
_boneJoints = new int[_anim->_numBones];
|
||||
}
|
||||
|
||||
AnimationStateEmi::~AnimationStateEmi() {
|
||||
deactivate();
|
||||
delete[] _boneJoints;
|
||||
}
|
||||
|
||||
void AnimationStateEmi::activate() {
|
||||
if (!_active) {
|
||||
_active = true;
|
||||
if (_skel)
|
||||
_skel->addAnimation(this);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationStateEmi::deactivate() {
|
||||
if (_active) {
|
||||
_active = false;
|
||||
if (_skel)
|
||||
_skel->removeAnimation(this);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationStateEmi::update(uint time) {
|
||||
if (!_active)
|
||||
return;
|
||||
|
||||
if (!_anim) {
|
||||
deactivate();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_paused) {
|
||||
int durationMs = (int)_anim->_duration;
|
||||
if (_time >= durationMs) {
|
||||
if (_looping) {
|
||||
_time = _time % durationMs;
|
||||
} else {
|
||||
if (_fadeMode != Animation::FadeOut)
|
||||
deactivate();
|
||||
}
|
||||
}
|
||||
if (_time < 0) {
|
||||
_time = 0;
|
||||
} else {
|
||||
_time += time;
|
||||
}
|
||||
}
|
||||
|
||||
if (_fadeMode != Animation::None) {
|
||||
if (_fadeMode == Animation::FadeIn) {
|
||||
_fade += (float)time * (1.0f - _startFade) / _fadeLength;
|
||||
if (_fade >= 1.f) {
|
||||
_fade = 1.f;
|
||||
_fadeMode = Animation::None;
|
||||
}
|
||||
} else {
|
||||
_fade -= (float)time * _startFade / _fadeLength;
|
||||
if (_fade <= 0.f) {
|
||||
_fade = 0.f;
|
||||
// Don't reset the _fadeMode here. This way if fadeOut() was called
|
||||
// on a looping chore its keyframe animations will remain faded out
|
||||
// when it calls play() again.
|
||||
deactivate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationStateEmi::computeWeights() {
|
||||
if (_fade <= 0.0f)
|
||||
return;
|
||||
|
||||
for (int bone = 0; bone < _anim->_numBones; ++bone) {
|
||||
Bone &curBone = _anim->_bones[bone];
|
||||
int jointIndex = _boneJoints[bone];
|
||||
if (jointIndex == -1)
|
||||
continue;
|
||||
|
||||
AnimationLayer *layer = _skel->getLayer(curBone._priority);
|
||||
JointAnimation &jointAnim = layer->_jointAnims[jointIndex];
|
||||
|
||||
if (curBone._rotations) {
|
||||
jointAnim._rotWeight += _fade;
|
||||
}
|
||||
if (curBone._translations) {
|
||||
jointAnim._transWeight += _fade;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationStateEmi::animate() {
|
||||
if (_fade <= 0.0f)
|
||||
return;
|
||||
|
||||
if (_time < 0)
|
||||
return;
|
||||
|
||||
for (int bone = 0; bone < _anim->_numBones; ++bone) {
|
||||
Bone &curBone = _anim->_bones[bone];
|
||||
int jointIndex = _boneJoints[bone];
|
||||
if (jointIndex == -1)
|
||||
continue;
|
||||
|
||||
Joint *target = &_skel->_joints[jointIndex];
|
||||
AnimationLayer *layer = _skel->getLayer(curBone._priority);
|
||||
JointAnimation &jointAnim = layer->_jointAnims[jointIndex];
|
||||
|
||||
if (curBone._rotations) {
|
||||
int keyfIdx = -1;
|
||||
Math::Quaternion quat;
|
||||
|
||||
// Normalize the weight so that the sum of applied weights will equal 1.
|
||||
float normalizedRotWeight = _fade;
|
||||
if (jointAnim._rotWeight > 1.0f) {
|
||||
// Note: Division by unnormalized sum of weights.
|
||||
normalizedRotWeight = _fade / jointAnim._rotWeight;
|
||||
}
|
||||
|
||||
for (int curKeyFrame = 0; curKeyFrame < curBone._count; curKeyFrame++) {
|
||||
if (curBone._rotations[curKeyFrame]._time >= _time) {
|
||||
keyfIdx = curKeyFrame;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (keyfIdx == 0) {
|
||||
quat = curBone._rotations[0]._quat;
|
||||
}
|
||||
else if (keyfIdx != -1) {
|
||||
float timeDelta = curBone._rotations[keyfIdx]._time - curBone._rotations[keyfIdx - 1]._time;
|
||||
float interpVal = (_time - curBone._rotations[keyfIdx - 1]._time) / timeDelta;
|
||||
|
||||
quat = curBone._rotations[keyfIdx - 1]._quat.slerpQuat(curBone._rotations[keyfIdx]._quat, interpVal);
|
||||
}
|
||||
else {
|
||||
quat = curBone._rotations[curBone._count - 1]._quat;
|
||||
}
|
||||
|
||||
Math::Quaternion &quatFinal = jointAnim._quat;
|
||||
quat = target->_quat.inverse() * quat;
|
||||
quat = quatFinal * quat;
|
||||
quatFinal = quatFinal.slerpQuat(quat, normalizedRotWeight);
|
||||
}
|
||||
|
||||
if (curBone._translations) {
|
||||
int keyfIdx = -1;
|
||||
Math::Vector3d vec;
|
||||
|
||||
// Normalize the weight so that the sum of applied weights will equal 1.
|
||||
float normalizedTransWeight = _fade;
|
||||
if (jointAnim._transWeight > 1.0f) {
|
||||
// Note: Division by unnormalized sum of weights.
|
||||
normalizedTransWeight = _fade / jointAnim._transWeight;
|
||||
}
|
||||
|
||||
for (int curKeyFrame = 0; curKeyFrame < curBone._count; curKeyFrame++) {
|
||||
if (curBone._translations[curKeyFrame]._time >= _time) {
|
||||
keyfIdx = curKeyFrame;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (keyfIdx == 0) {
|
||||
vec = curBone._translations[0]._vec;
|
||||
}
|
||||
else if (keyfIdx != -1) {
|
||||
float timeDelta = curBone._translations[keyfIdx]._time - curBone._translations[keyfIdx - 1]._time;
|
||||
float interpVal = (_time - curBone._translations[keyfIdx - 1]._time) / timeDelta;
|
||||
|
||||
vec = curBone._translations[keyfIdx - 1]._vec +
|
||||
(curBone._translations[keyfIdx]._vec - curBone._translations[keyfIdx - 1]._vec) * interpVal;
|
||||
}
|
||||
else {
|
||||
vec = curBone._translations[curBone._count - 1]._vec;
|
||||
}
|
||||
|
||||
Math::Vector3d &posFinal = jointAnim._pos;
|
||||
vec = vec - target->_relMatrix.getPosition();
|
||||
posFinal = posFinal + vec * normalizedTransWeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationStateEmi::play() {
|
||||
if (!_active) {
|
||||
_time = -1;
|
||||
if (_fadeMode == Animation::FadeOut)
|
||||
_fadeMode = Animation::None;
|
||||
if (_fadeMode == Animation::FadeIn || _fade > 0.f)
|
||||
activate();
|
||||
}
|
||||
_paused = false;
|
||||
}
|
||||
|
||||
void AnimationStateEmi::stop() {
|
||||
_fadeMode = Animation::None;
|
||||
_time = -1;
|
||||
deactivate();
|
||||
}
|
||||
|
||||
void AnimationStateEmi::setPaused(bool paused) {
|
||||
_paused = paused;
|
||||
}
|
||||
|
||||
void AnimationStateEmi::setLooping(bool loop) {
|
||||
_looping = loop;
|
||||
}
|
||||
|
||||
void AnimationStateEmi::setSkeleton(Skeleton *skel) {
|
||||
if (skel != _skel) {
|
||||
if (_skel)
|
||||
_skel->removeAnimation(this);
|
||||
_skel = skel;
|
||||
if (_active)
|
||||
skel->addAnimation(this);
|
||||
|
||||
if (_anim) {
|
||||
for (int i = 0; i < _anim->_numBones; ++i) {
|
||||
_boneJoints[i] = skel->findJointIndex(_anim->_bones[i]._boneName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationStateEmi::fade(Animation::FadeMode mode, int fadeLength) {
|
||||
if (mode == Animation::None) {
|
||||
_fade = 1.f;
|
||||
} else if (_fadeMode != Animation::FadeOut && mode == Animation::FadeIn) {
|
||||
_fade = 0.f;
|
||||
}
|
||||
_startFade = _fade;
|
||||
_fadeMode = mode;
|
||||
_fadeLength = fadeLength;
|
||||
}
|
||||
|
||||
void AnimationStateEmi::advance(uint msecs) {
|
||||
if (_time >= 0) {
|
||||
_time += msecs;
|
||||
} else {
|
||||
_time = msecs;
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationStateEmi::saveState(SaveGame *state) {
|
||||
state->writeBool(_looping);
|
||||
state->writeBool(_active);
|
||||
state->writeBool(_paused);
|
||||
state->writeLESint32(_time);
|
||||
state->writeFloat(_fade);
|
||||
state->writeFloat(_startFade);
|
||||
state->writeLESint32((int)_fadeMode);
|
||||
state->writeLESint32(_fadeLength);
|
||||
}
|
||||
|
||||
void AnimationStateEmi::restoreState(SaveGame *state) {
|
||||
if (state->saveMinorVersion() >= 10) {
|
||||
_looping = state->readBool();
|
||||
bool active = state->readBool();
|
||||
_paused = state->readBool();
|
||||
if (state->saveMinorVersion() < 22) {
|
||||
_time = (uint)state->readFloat();
|
||||
} else {
|
||||
_time = state->readLESint32();
|
||||
}
|
||||
_fade = state->readFloat();
|
||||
_startFade = state->readFloat();
|
||||
_fadeMode = (Animation::FadeMode)state->readLESint32();
|
||||
_fadeLength = state->readLESint32();
|
||||
|
||||
if (active)
|
||||
activate();
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
113
engines/grim/emi/animationemi.h
Normal file
113
engines/grim/emi/animationemi.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/* 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_ANIMATIONEMI_H
|
||||
#define GRIM_ANIMATIONEMI_H
|
||||
|
||||
#include "common/str.h"
|
||||
|
||||
#include "math/mathfwd.h"
|
||||
#include "math/quat.h"
|
||||
|
||||
#include "engines/grim/animation.h"
|
||||
#include "engines/grim/object.h"
|
||||
#include "engines/grim/emi/skeleton.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
struct AnimRotation {
|
||||
Math::Quaternion _quat;
|
||||
float _time;
|
||||
};
|
||||
|
||||
struct AnimTranslation {
|
||||
Math::Vector3d _vec;
|
||||
float _time;
|
||||
};
|
||||
|
||||
struct Bone {
|
||||
Common::String _boneName;
|
||||
int _operation;
|
||||
int _priority;
|
||||
int _c;
|
||||
int _count;
|
||||
AnimRotation *_rotations;
|
||||
AnimTranslation *_translations;
|
||||
Joint *_target;
|
||||
Bone() : _rotations(NULL), _translations(NULL), _boneName(""), _operation(0), _target(NULL) {}
|
||||
~Bone();
|
||||
void loadBinary(Common::SeekableReadStream *data);
|
||||
};
|
||||
|
||||
class AnimationEmi : public Object {
|
||||
void loadAnimation(Common::SeekableReadStream *data);
|
||||
public:
|
||||
Common::String _name;
|
||||
Common::String _fname;
|
||||
float _duration;
|
||||
int _numBones;
|
||||
Bone *_bones;
|
||||
AnimationEmi(const Common::String &filename, Common::SeekableReadStream *data);
|
||||
~AnimationEmi();
|
||||
|
||||
const Common::String &getFilename() const { return _fname; }
|
||||
};
|
||||
|
||||
class AnimationStateEmi {
|
||||
public:
|
||||
AnimationStateEmi(const Common::String &anim);
|
||||
~AnimationStateEmi();
|
||||
|
||||
void update(uint time);
|
||||
void computeWeights();
|
||||
void animate();
|
||||
void play();
|
||||
void stop();
|
||||
void setPaused(bool paused);
|
||||
void setLooping(bool loop);
|
||||
void setSkeleton(Skeleton *skel);
|
||||
void fade(Animation::FadeMode mode, int fadeLength);
|
||||
void advance(uint msecs);
|
||||
void saveState(SaveGame *state);
|
||||
void restoreState(SaveGame *state);
|
||||
|
||||
private:
|
||||
void activate();
|
||||
void deactivate();
|
||||
|
||||
friend class Skeleton;
|
||||
|
||||
Skeleton *_skel;
|
||||
ObjectPtr<AnimationEmi> _anim;
|
||||
bool _looping;
|
||||
bool _active;
|
||||
bool _paused;
|
||||
int _time;
|
||||
float _fade;
|
||||
float _startFade;
|
||||
Animation::FadeMode _fadeMode;
|
||||
int _fadeLength;
|
||||
int *_boneJoints;
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
138
engines/grim/emi/costume/emianim_component.cpp
Normal file
138
engines/grim/emi/costume/emianim_component.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
/* 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/emi/costume/emianim_component.h"
|
||||
#include "engines/grim/emi/costume/emiskel_component.h"
|
||||
#include "engines/grim/resource.h"
|
||||
#include "engines/grim/costume.h"
|
||||
#include "engines/grim/emi/costumeemi.h"
|
||||
#include "engines/grim/emi/modelemi.h"
|
||||
#include "engines/grim/emi/skeleton.h"
|
||||
#include "engines/grim/emi/animationemi.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
EMIAnimComponent::EMIAnimComponent(Component *p, int parentID, const char *filename, Component *prevComponent, tag32 t) :
|
||||
Component(p, parentID, filename, t), _animState(nullptr) {
|
||||
}
|
||||
|
||||
EMIAnimComponent::~EMIAnimComponent() {
|
||||
delete _animState;
|
||||
}
|
||||
|
||||
void EMIAnimComponent::init() {
|
||||
_visible = true;
|
||||
_animState = new AnimationStateEmi(_name);
|
||||
}
|
||||
|
||||
int EMIAnimComponent::update(uint time) {
|
||||
EMISkelComponent *skel = ((EMICostume *)_cost)->_emiSkel;
|
||||
if (skel) {
|
||||
_animState->setSkeleton(skel->_obj);
|
||||
_animState->update(time);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EMIAnimComponent::setKey(int f) {
|
||||
switch (f) {
|
||||
case 0: // Stop
|
||||
_animState->stop();
|
||||
break;
|
||||
case 1: // Play
|
||||
_animState->play();
|
||||
break;
|
||||
case 2: // Pause
|
||||
_animState->setPaused(true);
|
||||
break;
|
||||
case 3: // Loop
|
||||
_animState->setLooping(true);
|
||||
_animState->play();
|
||||
break;
|
||||
case 4: // No loop
|
||||
_animState->setLooping(false);
|
||||
break;
|
||||
case 5: // Fade in 1
|
||||
_animState->fade(Animation::FadeIn, 1000);
|
||||
break;
|
||||
case 6: // Fade in 3/4
|
||||
_animState->fade(Animation::FadeIn, 750);
|
||||
break;
|
||||
case 7: // Fade in 1/2
|
||||
_animState->fade(Animation::FadeIn, 500);
|
||||
break;
|
||||
case 8: // Fade in 1/4
|
||||
_animState->fade(Animation::FadeIn, 250);
|
||||
break;
|
||||
case 9: // Fade in 1/8
|
||||
_animState->fade(Animation::FadeIn, 125);
|
||||
break;
|
||||
case 10: // Fade out 1
|
||||
_animState->fade(Animation::FadeOut, 1000);
|
||||
break;
|
||||
case 11: // Fade out 3/4
|
||||
_animState->fade(Animation::FadeOut, 750);
|
||||
break;
|
||||
case 12: // Fade out 1/2
|
||||
_animState->fade(Animation::FadeOut, 500);
|
||||
break;
|
||||
case 13: // Fade out 1/4
|
||||
_animState->fade(Animation::FadeOut, 250);
|
||||
break;
|
||||
case 14: // Fade out 1/8
|
||||
_animState->fade(Animation::FadeOut, 125);
|
||||
break;
|
||||
default:
|
||||
Debug::warning(Debug::Costumes, "Unknown key %d for component %s", f, _name.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void EMIAnimComponent::reset() {
|
||||
_visible = true;
|
||||
_animState->stop();
|
||||
}
|
||||
|
||||
void EMIAnimComponent::fade(Animation::FadeMode mode, int fadeLength) {
|
||||
_animState->fade(mode, fadeLength);
|
||||
}
|
||||
|
||||
void EMIAnimComponent::advance(uint msecs) {
|
||||
_animState->advance(msecs);
|
||||
}
|
||||
|
||||
void EMIAnimComponent::setPaused(bool paused) {
|
||||
_animState->setPaused(paused);
|
||||
}
|
||||
|
||||
void EMIAnimComponent::draw() {
|
||||
}
|
||||
|
||||
void EMIAnimComponent::saveState(SaveGame *state) {
|
||||
_animState->saveState(state);
|
||||
}
|
||||
|
||||
void EMIAnimComponent::restoreState(SaveGame *state) {
|
||||
_animState->restoreState(state);
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
54
engines/grim/emi/costume/emianim_component.h
Normal file
54
engines/grim/emi/costume/emianim_component.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* 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_EMI_ANIM_COMPONENT_H
|
||||
#define GRIM_EMI_ANIM_COMPONENT_H
|
||||
|
||||
#include "engines/grim/costume/component.h"
|
||||
|
||||
// This is mostly stubbed for testing the animation loading at the moment.
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class AnimationStateEmi;
|
||||
|
||||
class EMIAnimComponent : public Component {
|
||||
public:
|
||||
EMIAnimComponent(Component *parent, int parentID, const char *filename, Component *prevComponent, tag32 tag);
|
||||
~EMIAnimComponent();
|
||||
void init() override;
|
||||
void setKey(int) override;
|
||||
int update(uint time) override;
|
||||
void reset() override ;
|
||||
void fade(Animation::FadeMode mode, int fadeLength) override ;
|
||||
void advance(uint msecs) override ;
|
||||
void setPaused(bool paused) override;
|
||||
void draw() override;
|
||||
void saveState(SaveGame *state) override;
|
||||
void restoreState(SaveGame *state) override;
|
||||
|
||||
private:
|
||||
AnimationStateEmi *_animState;
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
140
engines/grim/emi/costume/emichore.cpp
Normal file
140
engines/grim/emi/costume/emichore.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
/* 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/emi/costume/emichore.h"
|
||||
#include "engines/grim/emi/modelemi.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
EMIChore::EMIChore(char name[32], int id, Costume *owner, int length, int numTracks) :
|
||||
Chore(name, id, owner, length, numTracks), _mesh(nullptr), _skeleton(nullptr),
|
||||
_fadeMode(Animation::None), _fade(1.f), _fadeLength(0), _startFade(1.0f) {
|
||||
}
|
||||
|
||||
void EMIChore::addComponent(Component *component) {
|
||||
if (component->isComponentType('m', 'e', 's', 'h')) {
|
||||
_mesh = static_cast<EMIMeshComponent *>(component);
|
||||
} else if (component->isComponentType('s', 'k', 'e', 'l')) {
|
||||
_skeleton = static_cast<EMISkelComponent *>(component);
|
||||
}
|
||||
if (_mesh && _mesh->_obj && _skeleton) {
|
||||
_mesh->_obj->setSkeleton(_skeleton->_obj);
|
||||
}
|
||||
}
|
||||
|
||||
void EMIChore::update(uint time) {
|
||||
if (!_playing || _paused)
|
||||
return;
|
||||
|
||||
if (_fadeMode != Animation::None) {
|
||||
if (_fadeMode == Animation::FadeIn) {
|
||||
_fade += (float)time * (1.0f - _startFade) / _fadeLength;
|
||||
if (_fade >= 1.f) {
|
||||
_fade = 1.f;
|
||||
_fadeMode = Animation::None;
|
||||
}
|
||||
} else {
|
||||
_fade -= (float)time * _startFade / _fadeLength;
|
||||
if (_fade <= 0.f) {
|
||||
_fade = 0.f;
|
||||
stop(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int newTime;
|
||||
if (_currTime < 0)
|
||||
newTime = 0; // For first time through
|
||||
else
|
||||
newTime = _currTime + time;
|
||||
|
||||
setKeys(_currTime, newTime);
|
||||
|
||||
if (_length >= 0 && newTime > _length) {
|
||||
if (!_looping && _fadeMode != Animation::FadeOut) {
|
||||
stop(0);
|
||||
}
|
||||
else {
|
||||
do {
|
||||
newTime -= _length;
|
||||
setKeys(-1, newTime);
|
||||
} while (newTime > _length);
|
||||
}
|
||||
}
|
||||
_currTime = newTime;
|
||||
}
|
||||
|
||||
void EMIChore::stop(uint msecs) {
|
||||
if (msecs > 0) {
|
||||
fade(Animation::FadeOut, msecs);
|
||||
} else {
|
||||
_playing = false;
|
||||
_hasPlayed = false;
|
||||
|
||||
for (int i = 0; i < _numTracks; i++) {
|
||||
Component *comp = getComponentForTrack(i);
|
||||
if (comp)
|
||||
comp->reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EMIChore::fade(Animation::FadeMode mode, uint msecs) {
|
||||
if (mode == Animation::None) {
|
||||
_fade = 1.0f;
|
||||
}
|
||||
_startFade = _fade;
|
||||
_fadeMode = mode;
|
||||
_fadeLength = msecs;
|
||||
|
||||
for (int i = 0; i < _numTracks; i++) {
|
||||
Component *comp = getComponentForTrack(i);
|
||||
if (comp) {
|
||||
comp->fade(mode, msecs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EMIChore::saveState(SaveGame *state) const {
|
||||
Chore::saveState(state);
|
||||
|
||||
state->writeLESint32((int)_fadeMode);
|
||||
state->writeFloat(_fade);
|
||||
state->writeFloat(_startFade);
|
||||
state->writeLESint32(_fadeLength);
|
||||
}
|
||||
|
||||
void EMIChore::restoreState(SaveGame *state) {
|
||||
Chore::restoreState(state);
|
||||
|
||||
if (state->saveMinorVersion() >= 10) {
|
||||
_fadeMode = (Animation::FadeMode)state->readLESint32();
|
||||
_fade = state->readFloat();
|
||||
_startFade = state->readFloat();
|
||||
_fadeLength = state->readLESint32();
|
||||
} else {
|
||||
if (_length == -1 && _playing)
|
||||
_currTime = -1;
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
60
engines/grim/emi/costume/emichore.h
Normal file
60
engines/grim/emi/costume/emichore.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/* 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_EMICHORE_H
|
||||
#define GRIM_EMICHORE_H
|
||||
|
||||
#include "engines/grim/costume/chore.h"
|
||||
#include "engines/grim/pool.h"
|
||||
#include "engines/grim/emi/costume/emimesh_component.h"
|
||||
#include "engines/grim/emi/costume/emiskel_component.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class EMIChore : public PoolObject<EMIChore>, public Chore {
|
||||
public:
|
||||
EMIChore(char name[32], int id, Costume *owner, int length, int numTracks);
|
||||
static int32 getStaticTag() { return MKTAG('C', 'H', 'O', 'R'); }
|
||||
|
||||
void update(uint msecs) override;
|
||||
void stop(uint msecs) override;
|
||||
void addComponent(Component *component);
|
||||
bool isWearChore() { return _mesh && _skeleton; }
|
||||
void saveState(SaveGame *state) const override;
|
||||
void restoreState(SaveGame *state) override;
|
||||
EMIMeshComponent *getMesh() { return _mesh; }
|
||||
EMISkelComponent *getSkeleton() { return _skeleton; }
|
||||
|
||||
private:
|
||||
void fade(Animation::FadeMode mode, uint msecs) override;
|
||||
|
||||
Animation::FadeMode _fadeMode;
|
||||
float _fade;
|
||||
float _startFade;
|
||||
int _fadeLength;
|
||||
|
||||
EMIMeshComponent *_mesh;
|
||||
EMISkelComponent *_skeleton;
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
168
engines/grim/emi/costume/emihead.cpp
Normal file
168
engines/grim/emi/costume/emihead.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
/* 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/emi/costume/emihead.h"
|
||||
#include "engines/grim/emi/costumeemi.h"
|
||||
#include "engines/grim/emi/skeleton.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
EMIHead::EMIHead(EMICostume *costume) : _yawRange(80.0f), _minPitch(-30.0f), _maxPitch(30.0f) {
|
||||
_cost = costume;
|
||||
}
|
||||
|
||||
void EMIHead::setJoint(const char *joint, const Math::Vector3d &offset) {
|
||||
_jointName = joint;
|
||||
_offset = offset;
|
||||
}
|
||||
|
||||
void EMIHead::setLimits(float yawRange, float maxPitch, float minPitch) {
|
||||
_yawRange = yawRange;
|
||||
_maxPitch = maxPitch;
|
||||
_minPitch = minPitch;
|
||||
}
|
||||
|
||||
void EMIHead::lookAt(bool entering, const Math::Vector3d &point, float rate, const Math::Matrix4 &matrix) {
|
||||
if (!_cost->_emiSkel || !_cost->_emiSkel->_obj)
|
||||
return;
|
||||
|
||||
if (_jointName.empty())
|
||||
return;
|
||||
|
||||
Joint *joint = _cost->_emiSkel->_obj->getJointNamed(_jointName);
|
||||
if (!joint)
|
||||
return;
|
||||
|
||||
Math::Quaternion lookAtQuat; // Note: Identity if not looking at anything.
|
||||
|
||||
if (entering) {
|
||||
Math::Matrix4 jointToWorld = _cost->getOwner()->getFinalMatrix() * joint->_finalMatrix;
|
||||
Math::Vector3d jointWorldPos = jointToWorld.getPosition();
|
||||
Math::Matrix4 worldToJoint = jointToWorld;
|
||||
worldToJoint.invertAffineOrthonormal();
|
||||
|
||||
Math::Vector3d targetDir = (point + _offset) - jointWorldPos;
|
||||
targetDir.normalize();
|
||||
|
||||
const Math::Vector3d worldUp(0, 1, 0);
|
||||
Math::Vector3d frontDir = Math::Vector3d(worldToJoint(0, 1), worldToJoint(1, 1), worldToJoint(2, 1)); // Look straight ahead. (+Y)
|
||||
Math::Vector3d modelFront(0, 0, 1);
|
||||
Math::Vector3d modelUp(0, 1, 0);
|
||||
|
||||
modelFront = modelFront * joint->_absMatrix.getRotation();
|
||||
modelUp = modelUp * joint->_absMatrix.getRotation();
|
||||
|
||||
// Generate a world-space look at matrix.
|
||||
Math::Matrix4 lookAtTM;
|
||||
lookAtTM.setToIdentity();
|
||||
|
||||
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",
|
||||
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",
|
||||
else
|
||||
lookAtTM.buildFromTargetDir(modelFront, targetDir, modelUp, worldUp);
|
||||
|
||||
// Convert from world-space to joint-space.
|
||||
lookAtTM = worldToJoint * lookAtTM;
|
||||
|
||||
// Apply angle limits.
|
||||
Math::Angle p, y, r;
|
||||
lookAtTM.getEuler(&y, &p, &r, Math::EO_ZXY);
|
||||
|
||||
y.clampDegrees(_yawRange);
|
||||
p.clampDegrees(_minPitch, _maxPitch);
|
||||
r.clampDegrees(30.0f);
|
||||
|
||||
lookAtTM.buildFromEuler(y, p, r, Math::EO_ZXY);
|
||||
|
||||
lookAtQuat.fromMatrix(lookAtTM.getRotation());
|
||||
}
|
||||
|
||||
if (_headRot != lookAtQuat) {
|
||||
Math::Quaternion diff = _headRot.inverse() * lookAtQuat;
|
||||
diff.normalize();
|
||||
float angle = 2 * acos(MIN(MAX(diff.w(), -1.0f), 1.0f));
|
||||
if (diff.w() < 0.0f) {
|
||||
angle = 2 * (float)M_PI - angle;
|
||||
}
|
||||
|
||||
float turnAmount = g_grim->getPerSecond(rate * ((float)M_PI / 180.0f));
|
||||
if (turnAmount < angle)
|
||||
_headRot = _headRot.slerpQuat(lookAtQuat, turnAmount / angle);
|
||||
else
|
||||
_headRot = lookAtQuat;
|
||||
}
|
||||
|
||||
if (_headRot != Math::Quaternion()) { // If not identity..
|
||||
joint->_animMatrix = joint->_animMatrix * _headRot.toMatrix();
|
||||
joint->_animQuat = joint->_animQuat * _headRot;
|
||||
_cost->_emiSkel->_obj->commitAnim();
|
||||
}
|
||||
}
|
||||
|
||||
void EMIHead::saveState(SaveGame *state) const {
|
||||
state->writeString(_jointName);
|
||||
state->writeVector3d(_offset);
|
||||
state->writeFloat(_headRot.x());
|
||||
state->writeFloat(_headRot.y());
|
||||
state->writeFloat(_headRot.z());
|
||||
state->writeFloat(_headRot.w());
|
||||
state->writeFloat(_yawRange);
|
||||
state->writeFloat(_minPitch);
|
||||
state->writeFloat(_maxPitch);
|
||||
}
|
||||
|
||||
void EMIHead::restoreState(SaveGame *state) {
|
||||
if (state->saveMinorVersion() >= 15) {
|
||||
_jointName = state->readString();
|
||||
_offset = state->readVector3d();
|
||||
_headRot.x() = state->readFloat();
|
||||
_headRot.y() = state->readFloat();
|
||||
_headRot.z() = state->readFloat();
|
||||
_headRot.w() = state->readFloat();
|
||||
if (state->saveMinorVersion() >= 16) {
|
||||
_yawRange = state->readFloat();
|
||||
_minPitch = state->readFloat();
|
||||
_maxPitch = state->readFloat();
|
||||
}
|
||||
} else {
|
||||
state->readLESint32();
|
||||
state->readLESint32();
|
||||
state->readLESint32();
|
||||
state->readFloat();
|
||||
state->readFloat();
|
||||
state->readFloat();
|
||||
if (state->saveMinorVersion() < 2) {
|
||||
state->readFloat();
|
||||
state->readFloat();
|
||||
} else {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
state->readFloat();
|
||||
state->readFloat();
|
||||
state->readFloat();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
57
engines/grim/emi/costume/emihead.h
Normal file
57
engines/grim/emi/costume/emihead.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/* 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_EMIHEAD_H
|
||||
#define GRIM_EMIHEAD_H
|
||||
|
||||
#include "math/vector3d.h"
|
||||
#include "math/quat.h"
|
||||
|
||||
#include "engines/grim/costume/head.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class EMICostume;
|
||||
|
||||
class EMIHead : public BaseHead {
|
||||
public:
|
||||
EMIHead(EMICostume *costume);
|
||||
|
||||
void setJoint(const char *joint, const Math::Vector3d &offset);
|
||||
void setLimits(float yawRange, float maxPitch, float minPitch);
|
||||
void lookAt(bool entering, const Math::Vector3d &point, float rate, const Math::Matrix4 &matrix) override;
|
||||
void loadJoints(ModelNode *nodes) override {}
|
||||
void saveState(SaveGame *state) const override;
|
||||
void restoreState(SaveGame *state) override;
|
||||
|
||||
private:
|
||||
EMICostume *_cost;
|
||||
Common::String _jointName;
|
||||
Math::Vector3d _offset;
|
||||
Math::Quaternion _headRot;
|
||||
float _yawRange;
|
||||
float _maxPitch;
|
||||
float _minPitch;
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
53
engines/grim/emi/costume/emiluacode_component.cpp
Normal file
53
engines/grim/emi/costume/emiluacode_component.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
/* 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/debug.h"
|
||||
|
||||
#include "engines/grim/debug.h"
|
||||
#include "engines/grim/emi/costume/emiluacode_component.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
EMILuaCodeComponent::EMILuaCodeComponent(Component *p, int parentID, const char *name, Component *prevComponent, tag32 t) : Component(p, parentID, name, t) {
|
||||
}
|
||||
|
||||
EMILuaCodeComponent::~EMILuaCodeComponent() {
|
||||
}
|
||||
|
||||
void EMILuaCodeComponent::init() {
|
||||
}
|
||||
|
||||
int EMILuaCodeComponent::update(uint time) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EMILuaCodeComponent::setKey(int val) {
|
||||
Debug::debug(Debug::Lua, "LuaC component: executing code [%s]", _name.c_str());
|
||||
lua_dostring(_name.c_str());
|
||||
}
|
||||
|
||||
void EMILuaCodeComponent::reset() {
|
||||
}
|
||||
|
||||
void EMILuaCodeComponent::draw() {
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
44
engines/grim/emi/costume/emiluacode_component.h
Normal file
44
engines/grim/emi/costume/emiluacode_component.h
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRIM_EMI_LUACODE_COMPONENT_H
|
||||
#define GRIM_EMI_LUACODE_COMPONENT_H
|
||||
|
||||
#include "engines/grim/costume/component.h"
|
||||
#include "engines/grim/lua/lua.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class EMILuaCodeComponent : public Component {
|
||||
public:
|
||||
EMILuaCodeComponent(Component *parent, int parentID, const char *name, Component *prevComponent, tag32 tag);
|
||||
~EMILuaCodeComponent();
|
||||
void init() override;
|
||||
int update(uint time) override;
|
||||
void reset() override;
|
||||
void draw() override;
|
||||
void setKey(int val) override;
|
||||
private:
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
55
engines/grim/emi/costume/emiluavar_component.cpp
Normal file
55
engines/grim/emi/costume/emiluavar_component.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/* 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/debug.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "engines/grim/debug.h"
|
||||
#include "engines/grim/emi/costume/emiluavar_component.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
EMILuaVarComponent::EMILuaVarComponent(Component *p, int parentID, const char *name, Component *prevComponent, tag32 t) : Component(p, parentID, name, t) {
|
||||
}
|
||||
|
||||
EMILuaVarComponent::~EMILuaVarComponent() {
|
||||
}
|
||||
|
||||
void EMILuaVarComponent::init() {
|
||||
}
|
||||
|
||||
int EMILuaVarComponent::update(uint time) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EMILuaVarComponent::setKey(int val) {
|
||||
Debug::debug(Debug::Lua, "LuaV component: setting %s to %d", _name.c_str(), val);
|
||||
lua_pushnumber(val);
|
||||
lua_setglobal(_name.c_str());
|
||||
}
|
||||
|
||||
void EMILuaVarComponent::reset() {
|
||||
}
|
||||
|
||||
void EMILuaVarComponent::draw() {
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
44
engines/grim/emi/costume/emiluavar_component.h
Normal file
44
engines/grim/emi/costume/emiluavar_component.h
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRIM_EMI_LUAVAR_COMPONENT_H
|
||||
#define GRIM_EMI_LUAVAR_COMPONENT_H
|
||||
|
||||
#include "engines/grim/lua/lua.h"
|
||||
#include "engines/grim/costume/component.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class EMILuaVarComponent : public Component {
|
||||
public:
|
||||
EMILuaVarComponent(Component *parent, int parentID, const char *name, Component *prevComponent, tag32 tag);
|
||||
~EMILuaVarComponent();
|
||||
void init() override;
|
||||
int update(uint time) override;
|
||||
void reset() override;
|
||||
void draw() override;
|
||||
void setKey(int val) override;
|
||||
private:
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
99
engines/grim/emi/costume/emimesh_component.cpp
Normal file
99
engines/grim/emi/costume/emimesh_component.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
/* 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/emi/costume/emimesh_component.h"
|
||||
#include "engines/grim/emi/modelemi.h"
|
||||
#include "engines/grim/resource.h"
|
||||
#include "engines/grim/costume.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
EMIMeshComponent::EMIMeshComponent(Component *p, int parentID, const char *filename, Component *prevComponent, tag32 t, EMICostume *costume) :
|
||||
Component(p, parentID, filename, t), _costume(costume), _obj(nullptr), _parentModel(nullptr), _hasComplained(false) {
|
||||
_hierShared = false;
|
||||
}
|
||||
|
||||
EMIMeshComponent::~EMIMeshComponent() {
|
||||
if (_hierShared) {
|
||||
_obj = nullptr; // Keep ~ModelComp from deleting it
|
||||
//_animation = NULL;
|
||||
} else {
|
||||
delete _obj;
|
||||
}
|
||||
|
||||
for (EMIMeshComponent *child : _children) {
|
||||
child->_obj = nullptr;
|
||||
//child->_hier = NULL;
|
||||
child->_parentModel = nullptr;
|
||||
}
|
||||
|
||||
if (_parentModel) {
|
||||
_parentModel->_children.remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
void EMIMeshComponent::init() {
|
||||
_visible = true;
|
||||
_obj = g_resourceloader->loadModelEMI(_name, _costume);
|
||||
}
|
||||
|
||||
int EMIMeshComponent::update(uint time) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EMIMeshComponent::reset() {
|
||||
_visible = true;
|
||||
}
|
||||
|
||||
void EMIMeshComponent::draw() {
|
||||
// If the object was drawn by being a component
|
||||
// of it's parent then don't draw it
|
||||
if (_parent && _parent->isVisible())
|
||||
return;
|
||||
if (!_obj) {
|
||||
if (!_hasComplained) {
|
||||
warning("Tried to draw component we have no file for %s", _name.c_str());
|
||||
_hasComplained = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Need to translate object to be in accordance
|
||||
// with the setup of the parent
|
||||
//translateObject(false);
|
||||
|
||||
_obj->draw();
|
||||
|
||||
// Need to un-translate when done
|
||||
//translateObject(true);
|
||||
}
|
||||
|
||||
void EMIMeshComponent::getBoundingBox(int *x1, int *y1, int *x2, int *y2) const {
|
||||
// If the object was drawn by being a component
|
||||
// of it's parent then don't draw it
|
||||
|
||||
if (_parent && _parent->isVisible())
|
||||
return;
|
||||
|
||||
if (_obj)
|
||||
_obj->getBoundingBox(x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
53
engines/grim/emi/costume/emimesh_component.h
Normal file
53
engines/grim/emi/costume/emimesh_component.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/* 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_EMI_MESH_COMPONENT_H
|
||||
#define GRIM_EMI_MESH_COMPONENT_H
|
||||
|
||||
#include "engines/grim/costume/component.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class EMICostume;
|
||||
class EMIModel;
|
||||
|
||||
class EMIMeshComponent : public Component {
|
||||
public:
|
||||
EMIMeshComponent(Component *parent, int parentID, const char *filename, Component *prevComponent, tag32 tag, EMICostume *costume);
|
||||
~EMIMeshComponent();
|
||||
void init() override;
|
||||
int update(uint time) override;
|
||||
void reset() override;
|
||||
void draw() override;
|
||||
void getBoundingBox(int *x1, int *y1, int *x2, int *y2) const;
|
||||
|
||||
public:
|
||||
EMICostume *_costume;
|
||||
bool _hierShared;
|
||||
Common::List<EMIMeshComponent*> _children;
|
||||
EMIMeshComponent *_parentModel;
|
||||
EMIModel *_obj;
|
||||
bool _hasComplained; // Temporary fix for warning-spam.
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
58
engines/grim/emi/costume/emiskel_component.cpp
Normal file
58
engines/grim/emi/costume/emiskel_component.cpp
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/grim/emi/costume/emiskel_component.h"
|
||||
#include "engines/grim/resource.h"
|
||||
#include "engines/grim/emi/modelemi.h"
|
||||
#include "engines/grim/emi/skeleton.h"
|
||||
#include "engines/grim/costume.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
EMISkelComponent::EMISkelComponent(Component *p, int parentID, const char *filename, Component *prevComponent, tag32 t) : Component(p, parentID, filename, t), _obj(nullptr), _parentModel(nullptr), _hierShared(false) {
|
||||
}
|
||||
|
||||
EMISkelComponent::~EMISkelComponent() {
|
||||
delete _obj;
|
||||
}
|
||||
|
||||
void EMISkelComponent::init() {
|
||||
_visible = true;
|
||||
_obj = g_resourceloader->loadSkeleton(_name);
|
||||
}
|
||||
|
||||
void EMISkelComponent::animate() {
|
||||
if (_obj)
|
||||
_obj->animate();
|
||||
}
|
||||
|
||||
int EMISkelComponent::update(uint time) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EMISkelComponent::reset() {
|
||||
_visible = true;
|
||||
}
|
||||
|
||||
void EMISkelComponent::draw() {
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
51
engines/grim/emi/costume/emiskel_component.h
Normal file
51
engines/grim/emi/costume/emiskel_component.h
Normal 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_EMI_SKEL_COMPONENT_H
|
||||
#define GRIM_EMI_SKEL_COMPONENT_H
|
||||
|
||||
#include "engines/grim/costume/component.h"
|
||||
|
||||
// This is mostly stubbed for testing the skeletonloading at the moment.
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class Skeleton;
|
||||
|
||||
class EMISkelComponent : public Component {
|
||||
public:
|
||||
EMISkelComponent(Component *parent, int parentID, const char *filename, Component *prevComponent, tag32 tag);
|
||||
~EMISkelComponent();
|
||||
void init() override;
|
||||
void animate() override;
|
||||
int update(uint time) override;
|
||||
void reset() override;
|
||||
void draw() override;
|
||||
|
||||
public:
|
||||
bool _hierShared;
|
||||
Component *_parentModel;
|
||||
Skeleton *_obj;
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
55
engines/grim/emi/costume/emisprite_component.cpp
Normal file
55
engines/grim/emi/costume/emisprite_component.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/* 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/emi/costume/emisprite_component.h"
|
||||
#include "engines/grim/emi/costumeemi.h"
|
||||
#include "engines/grim/resource.h"
|
||||
#include "engines/grim/costume.h"
|
||||
#include "engines/grim/sprite.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
EMISpriteComponent::EMISpriteComponent(Component *p, int parentID, const char *filename, Component *prevComponent, tag32 t) : Component(p, parentID, filename, t), _sprite(nullptr) {
|
||||
}
|
||||
|
||||
EMISpriteComponent::~EMISpriteComponent() {
|
||||
delete _sprite;
|
||||
}
|
||||
|
||||
void EMISpriteComponent::init() {
|
||||
EMICostume *c = static_cast<EMICostume *>(_cost);
|
||||
_sprite = g_resourceloader->loadSprite(_name, c);
|
||||
}
|
||||
|
||||
int EMISpriteComponent::update(uint time) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EMISpriteComponent::reset() {
|
||||
}
|
||||
|
||||
void EMISpriteComponent::draw() {
|
||||
if (_sprite) {
|
||||
_sprite->draw();
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
46
engines/grim/emi/costume/emisprite_component.h
Normal file
46
engines/grim/emi/costume/emisprite_component.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* 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_EMI_SPRITE_COMPONENT_H
|
||||
#define GRIM_EMI_SPRITE_COMPONENT_H
|
||||
|
||||
#include "engines/grim/costume/component.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class Sprite;
|
||||
|
||||
class EMISpriteComponent : public Component {
|
||||
public:
|
||||
EMISpriteComponent(Component *parent, int parentID, const char *filename, Component *prevComponent, tag32 tag);
|
||||
~EMISpriteComponent();
|
||||
void init() override;
|
||||
int update(uint time) override;
|
||||
void reset() override;
|
||||
void draw() override;
|
||||
|
||||
public:
|
||||
Sprite *_sprite;
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
59
engines/grim/emi/costume/emitexi_component.cpp
Normal file
59
engines/grim/emi/costume/emitexi_component.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
/* 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/debug.h"
|
||||
#include "engines/grim/material.h"
|
||||
#include "engines/grim/savegame.h"
|
||||
#include "engines/grim/emi/costumeemi.h"
|
||||
#include "engines/grim/emi/modelemi.h"
|
||||
#include "engines/grim/emi/costume/emimesh_component.h"
|
||||
#include "engines/grim/emi/costume/emitexi_component.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
EMITexiComponent::EMITexiComponent(Component *parent, int parentID, const char *filename, Component *prevComponent, tag32 tag) : Component(parent, parentID, filename, tag) {
|
||||
}
|
||||
|
||||
EMITexiComponent::~EMITexiComponent() {
|
||||
}
|
||||
|
||||
void EMITexiComponent::init() {
|
||||
EMICostume *c = static_cast<EMICostume *>(_cost);
|
||||
_mat = c->findMaterial(_name);
|
||||
}
|
||||
|
||||
int EMITexiComponent::update(uint time) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EMITexiComponent::setKey(int k) {
|
||||
if (_mat && _mat->getNumTextures() > k)
|
||||
_mat->setActiveTexture(k);
|
||||
}
|
||||
|
||||
void EMITexiComponent::reset() {
|
||||
}
|
||||
|
||||
void EMITexiComponent::draw() {
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
49
engines/grim/emi/costume/emitexi_component.h
Normal file
49
engines/grim/emi/costume/emitexi_component.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/* 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_EMI_TEXI_COMPONENT_H
|
||||
#define GRIM_EMI_TEXI_COMPONENT_H
|
||||
|
||||
#include "engines/grim/costume/component.h"
|
||||
#include "engines/grim/material.h"
|
||||
#include "engines/grim/resource.h"
|
||||
#include "engines/grim/model.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class EMITexiComponent : public Component {
|
||||
public:
|
||||
EMITexiComponent(Component *parent, int parentID, const char *filename, Component *prevComponent, tag32 tag);
|
||||
~EMITexiComponent();
|
||||
|
||||
void init() override;
|
||||
int update(uint time) override;
|
||||
void reset() override;
|
||||
void draw() override;
|
||||
void setKey(int k) override;
|
||||
|
||||
private:
|
||||
Material *_mat;
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
328
engines/grim/emi/costumeemi.cpp
Normal file
328
engines/grim/emi/costumeemi.cpp
Normal file
@@ -0,0 +1,328 @@
|
||||
/* 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/endian.h"
|
||||
|
||||
#include "engines/grim/debug.h"
|
||||
#include "engines/grim/costume.h"
|
||||
#include "engines/grim/grim.h"
|
||||
#include "engines/grim/resource.h"
|
||||
#include "engines/grim/actor.h"
|
||||
#include "engines/grim/emi/costumeemi.h"
|
||||
#include "engines/grim/emi/modelemi.h"
|
||||
#include "engines/grim/emi/skeleton.h"
|
||||
#include "engines/grim/emi/costume/emihead.h"
|
||||
#include "engines/grim/emi/costume/emianim_component.h"
|
||||
#include "engines/grim/emi/costume/emiluavar_component.h"
|
||||
#include "engines/grim/emi/costume/emiluacode_component.h"
|
||||
#include "engines/grim/emi/costume/emimesh_component.h"
|
||||
#include "engines/grim/emi/costume/emiskel_component.h"
|
||||
#include "engines/grim/emi/costume/emisprite_component.h"
|
||||
#include "engines/grim/emi/costume/emitexi_component.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
EMICostume::EMICostume(const Common::String &fname, Actor *owner, Costume *prevCost) :
|
||||
Costume(fname, owner, prevCost), _wearChore(nullptr), _emiSkel(nullptr) {
|
||||
}
|
||||
|
||||
void EMICostume::load(Common::SeekableReadStream *data) {
|
||||
Common::Array<Component *> components;
|
||||
|
||||
_numChores = data->readUint32LE();
|
||||
_chores = new Chore *[_numChores];
|
||||
for (int i = 0; i < _numChores; i++) {
|
||||
uint32 nameLength;
|
||||
Component *prevComponent = nullptr;
|
||||
nameLength = data->readUint32LE();
|
||||
assert(nameLength < 32);
|
||||
|
||||
char name[32];
|
||||
data->read(name, nameLength);
|
||||
float length = data->readFloatLE();
|
||||
int numTracks = data->readUint32LE();
|
||||
|
||||
if (length == 1000)
|
||||
length = -1.0f;
|
||||
else
|
||||
length *= 1000;
|
||||
|
||||
EMIChore *chore = new EMIChore(name, i, this, (int)length, numTracks);
|
||||
_chores[i] = chore;
|
||||
|
||||
for (int k = 0; k < numTracks; k++) {
|
||||
int componentNameLength = data->readUint32LE();
|
||||
|
||||
char *componentName = new char[componentNameLength];
|
||||
data->read(componentName, componentNameLength);
|
||||
|
||||
data->readUint32LE();
|
||||
int parentID = data->readUint32LE();
|
||||
if (parentID == -1 && _prevCostume) {
|
||||
// However, only the first item can actually share the
|
||||
// node hierarchy with the previous costume, so flag
|
||||
// that component so it knows what to do
|
||||
if (i == 0)
|
||||
parentID = -2;
|
||||
prevComponent = _prevCostume->getComponent(0);
|
||||
// Make sure that the component is valid
|
||||
if (!prevComponent->isComponentType('M', 'M', 'D', 'L'))
|
||||
prevComponent = nullptr;
|
||||
}
|
||||
// Actually load the appropriate component
|
||||
Component *component = loadEMIComponent(parentID < 0 ? nullptr : components[parentID], parentID, componentName, prevComponent);
|
||||
if (component) {
|
||||
component->setCostume(this);
|
||||
component->init();
|
||||
chore->addComponent(component);
|
||||
}
|
||||
|
||||
components.push_back(component);
|
||||
|
||||
ChoreTrack &track = chore->_tracks[k];
|
||||
track.numKeys = data->readUint32LE();
|
||||
track.keys = new TrackKey[track.numKeys];
|
||||
track.component = component;
|
||||
track.compID = -1; // -1 means "look at .component"
|
||||
|
||||
for (int j = 0; j < track.numKeys; j++) {
|
||||
float time, value;
|
||||
time = data->readFloatLE();
|
||||
value = data->readFloatLE();
|
||||
track.keys[j].time = (int)(time * 1000);
|
||||
length = MAX(length, time * 1000);
|
||||
track.keys[j].value = (int)value;
|
||||
}
|
||||
delete[] componentName;
|
||||
}
|
||||
}
|
||||
|
||||
_numComponents = components.size();
|
||||
_components = new Component *[_numComponents];
|
||||
for (int i = 0; i < _numComponents; ++i) {
|
||||
_components[i] = components[i];
|
||||
}
|
||||
|
||||
_head = new EMIHead(this);
|
||||
}
|
||||
|
||||
void EMICostume::playChore(int num, uint msecs) {
|
||||
// FIXME: Original EMI can play multiple instances of a chore at the same time.
|
||||
EMIChore *chore = static_cast<EMIChore *>(_chores[num]);
|
||||
if (chore->isWearChore()) {
|
||||
setWearChore(chore);
|
||||
}
|
||||
Costume::playChore(num, msecs);
|
||||
}
|
||||
|
||||
void EMICostume::playChoreLooping(int num, uint msecs) {
|
||||
// FIXME: Original EMI can play multiple instances of a chore at the same time.
|
||||
EMIChore *chore = static_cast<EMIChore *>(_chores[num]);
|
||||
if (chore->isWearChore()) {
|
||||
setWearChore(chore);
|
||||
}
|
||||
Costume::playChoreLooping(num, msecs);
|
||||
}
|
||||
|
||||
Component *EMICostume::loadEMIComponent(Component *parent, int parentID, const char *name, Component *prevComponent) {
|
||||
assert(name[0] == '!');
|
||||
++name;
|
||||
|
||||
char type[5];
|
||||
tag32 tag = 0;
|
||||
memcpy(&tag, name, 4);
|
||||
memcpy(&type, name, 4);
|
||||
type[4] = 0;
|
||||
tag = FROM_BE_32(tag);
|
||||
|
||||
name += 4;
|
||||
|
||||
if (tag == MKTAG('m', 'e', 's', 'h')) {
|
||||
return new EMIMeshComponent(parent, parentID, name, prevComponent, tag, this);
|
||||
} else if (tag == MKTAG('s', 'k', 'e', 'l')) {
|
||||
return new EMISkelComponent(parent, parentID, name, prevComponent, tag);
|
||||
} else if (tag == MKTAG('t', 'e', 'x', 'i')) {
|
||||
return new EMITexiComponent(parent, parentID, name, prevComponent, tag);
|
||||
} else if (tag == MKTAG('a', 'n', 'i', 'm')) {
|
||||
return new EMIAnimComponent(parent, parentID, name, prevComponent, tag);
|
||||
} else if (tag == MKTAG('l', 'u', 'a', 'c')) {
|
||||
return new EMILuaCodeComponent(parent, parentID, name, prevComponent, tag);
|
||||
} else if (tag == MKTAG('l', 'u', 'a', 'v')) {
|
||||
return new EMILuaVarComponent(parent, parentID, name, prevComponent, tag);
|
||||
} else if (tag == MKTAG('s', 'p', 'r', 't')) {
|
||||
return new EMISpriteComponent(parent, parentID, name, prevComponent, tag);
|
||||
} else if (tag == MKTAG('s', 'h', 'a', 'd')) {
|
||||
Debug::warning(Debug::Costumes, "Actor::loadComponentEMI Implement SHAD-handling: %s" , name);
|
||||
} else if (tag == MKTAG('a', 'w', 'g', 't')) {
|
||||
Debug::warning(Debug::Costumes, "Actor::loadComponentEMI Implement AWGT-handling: %s" , name);
|
||||
} else if (tag == MKTAG('s', 'n', 'd', '2')) {
|
||||
// ignore, this is a leftover from an earlier engine.
|
||||
} else {
|
||||
error("Actor::loadComponentEMI missing tag: %s for %s", name, type);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void EMICostume::draw() {
|
||||
bool drewMesh = false;
|
||||
for (Common::List<Chore*>::iterator it = _playingChores.begin(); it != _playingChores.end(); ++it) {
|
||||
Chore *c = (*it);
|
||||
if (!c->_playing)
|
||||
continue;
|
||||
for (int i = 0; i < c->_numTracks; ++i) {
|
||||
if (c->_tracks[i].component) {
|
||||
c->_tracks[i].component->draw();
|
||||
if (c->_tracks[i].component->isComponentType('m', 'e', 's', 'h'))
|
||||
drewMesh = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_wearChore && !drewMesh) {
|
||||
_wearChore->getMesh()->draw();
|
||||
}
|
||||
}
|
||||
|
||||
int EMICostume::update(uint time) {
|
||||
for (Common::List<Chore*>::iterator i = _playingChores.begin(); i != _playingChores.end(); ++i) {
|
||||
Chore *c = *i;
|
||||
c->update(time);
|
||||
|
||||
for (int t = 0; t < c->_numTracks; ++t) {
|
||||
if (c->_tracks[t].component) {
|
||||
c->_tracks[t].component->update(time);
|
||||
}
|
||||
}
|
||||
|
||||
if (!c->isPlaying()) {
|
||||
i = _playingChores.erase(i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EMICostume::saveState(SaveGame *state) const {
|
||||
Costume::saveState(state);
|
||||
|
||||
for (int i = 0; i < _numChores; ++i) {
|
||||
EMIChore *chore = (EMIChore *)_chores[i];
|
||||
state->writeLESint32(chore->getId());
|
||||
}
|
||||
|
||||
state->writeLESint32(_wearChore ? _wearChore->getChoreId() : -1);
|
||||
}
|
||||
|
||||
bool EMICostume::restoreState(SaveGame *state) {
|
||||
bool ret = Costume::restoreState(state);
|
||||
if (ret) {
|
||||
if (state->saveMinorVersion() >= 11) {
|
||||
EMIChore::Pool &pool = EMIChore::getPool();
|
||||
for (int i = 0; i < _numChores; ++i) {
|
||||
EMIChore *chore = (EMIChore *)_chores[i];
|
||||
int id = state->readLESint32();
|
||||
pool.removeObject(chore->getId());
|
||||
EMIChore* oldChore = pool.getObject(id);
|
||||
if (oldChore) {
|
||||
pool.removeObject(id);
|
||||
oldChore->setId(chore->getId());
|
||||
pool.addObject(oldChore);
|
||||
}
|
||||
chore->setId(id);
|
||||
pool.addObject(chore);
|
||||
}
|
||||
}
|
||||
|
||||
if (state->saveMinorVersion() < 13) {
|
||||
// Used to be active texture IDs for materials. Materials are now
|
||||
// managed by the owner Actor of this Costume.
|
||||
for (uint i = 0; i < _materials.size(); ++i) {
|
||||
state->readLESint32();
|
||||
}
|
||||
}
|
||||
|
||||
int id = state->readLESint32();
|
||||
if (id >= 0) {
|
||||
EMIChore *chore = static_cast<EMIChore *>(_chores[id]);
|
||||
setWearChore(chore);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Material *EMICostume::findMaterial(const Common::String &name) {
|
||||
return _owner->findMaterial(name);
|
||||
}
|
||||
|
||||
Material *EMICostume::loadMaterial(const Common::String &name, bool clamp) {
|
||||
MaterialPtr mat = _owner->loadMaterial(name, clamp);
|
||||
if (mat) {
|
||||
// Save a reference to the material, so it will not be freed during the
|
||||
// lifetime of this costume.
|
||||
if (Common::find(_materials.begin(), _materials.end(), mat) == _materials.end())
|
||||
_materials.push_back(mat);
|
||||
}
|
||||
return mat;
|
||||
}
|
||||
|
||||
void EMICostume::setWearChore(EMIChore *chore) {
|
||||
if (chore != _wearChore) {
|
||||
_wearChore = chore;
|
||||
|
||||
if (_emiSkel) {
|
||||
_emiSkel->reset();
|
||||
}
|
||||
_emiSkel = chore->getSkeleton();
|
||||
}
|
||||
}
|
||||
|
||||
void EMICostume::setHead(const char *joint, const Math::Vector3d &offset) {
|
||||
static_cast<EMIHead *>(_head)->setJoint(joint, offset);
|
||||
}
|
||||
|
||||
void EMICostume::setHeadLimits(float yawRange, float maxPitch, float minPitch) {
|
||||
static_cast<EMIHead *>(_head)->setLimits(yawRange, maxPitch, minPitch);
|
||||
}
|
||||
|
||||
EMIModel *EMICostume::getEMIModel() const {
|
||||
if (!_wearChore)
|
||||
return nullptr;
|
||||
return _wearChore->getMesh()->_obj;
|
||||
}
|
||||
|
||||
EMIModel *EMICostume::getEMIModel(int num) const {
|
||||
if (num >= _numChores) {
|
||||
return nullptr;
|
||||
}
|
||||
EMIChore *chore = static_cast<EMIChore *>(_chores[num]);
|
||||
if (chore == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
EMIMeshComponent *mesh = chore->getMesh();
|
||||
if (mesh == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return mesh->_obj;
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
77
engines/grim/emi/costumeemi.h
Normal file
77
engines/grim/emi/costumeemi.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/* 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_COSTUMEEMI_H
|
||||
#define GRIM_COSTUMEEMI_H
|
||||
|
||||
#include "common/stream.h"
|
||||
|
||||
#include "engines/grim/object.h"
|
||||
#include "engines/grim/costume.h"
|
||||
#include "engines/grim/emi/costume/emichore.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
typedef uint32 tag32;
|
||||
|
||||
class EMISkelComponent;
|
||||
class EMIMeshComponent;
|
||||
class Material;
|
||||
class EMIModel;
|
||||
|
||||
class EMICostume : public Costume {
|
||||
public:
|
||||
EMICostume(const Common::String &filename, Actor *owner, Costume *prevCost);
|
||||
|
||||
void load(Common::SeekableReadStream *data) override;
|
||||
|
||||
void draw() override;
|
||||
int update(uint time) override;
|
||||
|
||||
void playChore(int num, uint msecs = 0) override;
|
||||
void playChoreLooping(int num, uint msecs = 0) override;
|
||||
|
||||
void saveState(SaveGame *state) const override;
|
||||
bool restoreState(SaveGame *state) override;
|
||||
|
||||
Material *loadMaterial(const Common::String &name, bool clamp);
|
||||
Material *findMaterial(const Common::String &name);
|
||||
|
||||
void setHead(const char *joint, const Math::Vector3d &offset);
|
||||
void setHeadLimits(float yawRange, float maxPitch, float minPitch);
|
||||
|
||||
EMIModel *getEMIModel() const;
|
||||
EMIModel *getEMIModel(int num) const;
|
||||
public:
|
||||
EMIChore *_wearChore;
|
||||
EMISkelComponent *_emiSkel;
|
||||
private:
|
||||
Common::List<ObjectPtr<Material> > _materials;
|
||||
static bool compareChores(const Chore *c1, const Chore *c2);
|
||||
Component *loadEMIComponent(Component *parent, int parentID, const char *name, Component *prevComponent);
|
||||
void setWearChore(EMIChore *chore);
|
||||
|
||||
friend class Chore;
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
334
engines/grim/emi/emi.cpp
Normal file
334
engines/grim/emi/emi.cpp
Normal file
@@ -0,0 +1,334 @@
|
||||
/* 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/emi/emi.h"
|
||||
#include "engines/grim/emi/emi_registry.h"
|
||||
#include "engines/grim/emi/lua_v2.h"
|
||||
#include "engines/grim/primitives.h"
|
||||
#include "engines/grim/set.h"
|
||||
#include "engines/grim/gfx_base.h"
|
||||
#include "engines/grim/actor.h"
|
||||
|
||||
#include "graphics/surface.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
EMIEngine *g_emi = nullptr;
|
||||
|
||||
EMIEngine::EMIEngine(OSystem *syst, uint32 gameFlags, GrimGameType gameType, Common::Platform platform, Common::Language language) :
|
||||
GrimEngine(syst, gameFlags, gameType, platform, language), _sortOrderInvalidated(false), _textObjectsSortOrderInvalidated(true) {
|
||||
g_emi = this;
|
||||
g_emiregistry = new EmiRegistry();
|
||||
}
|
||||
|
||||
EMIEngine::~EMIEngine() {
|
||||
g_emi = nullptr;
|
||||
delete g_emiregistry;
|
||||
g_emiregistry = nullptr;
|
||||
}
|
||||
|
||||
LuaBase *EMIEngine::createLua() {
|
||||
return new Lua_V2();
|
||||
}
|
||||
|
||||
const char *EMIEngine::getUpdateFilename() {
|
||||
if (getGamePlatform() == Common::kPlatformWindows && !(getGameFlags() & ADGF_DEMO)) {
|
||||
switch (getGameLanguage()) {
|
||||
case Common::FR_FRA:
|
||||
return "MonkeyUpdate_FRA.exe";
|
||||
break;
|
||||
case Common::DE_DEU:
|
||||
return "MonkeyUpdate_DEU.exe";
|
||||
break;
|
||||
case Common::IT_ITA:
|
||||
return "MonkeyUpdate_ITA.exe";
|
||||
break;
|
||||
case Common::PT_BRA:
|
||||
return "MonkeyUpdate_BRZ.exe";
|
||||
break;
|
||||
case Common::ES_ESP:
|
||||
return "MonkeyUpdate_ESP.exe";
|
||||
break;
|
||||
case Common::EN_ANY:
|
||||
case Common::EN_GRB:
|
||||
case Common::EN_USA:
|
||||
default:
|
||||
return "MonkeyUpdate.exe";
|
||||
break;
|
||||
}
|
||||
} else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void EMIEngine::pushText() {
|
||||
for (TextObject *t : TextObject::getPool()) {
|
||||
t->incStackLevel();
|
||||
}
|
||||
invalidateTextObjectsSortOrder();
|
||||
}
|
||||
|
||||
void EMIEngine::popText() {
|
||||
Common::List<TextObject *> toDelete;
|
||||
|
||||
for (TextObject *t : TextObject::getPool()) {
|
||||
if (t->getStackLevel() == 0) {
|
||||
warning("Text stack top not empty; deleting object");
|
||||
toDelete.push_back(t);
|
||||
} else {
|
||||
t->decStackLevel();
|
||||
}
|
||||
}
|
||||
|
||||
while (!toDelete.empty()) {
|
||||
TextObject *t = toDelete.front();
|
||||
toDelete.pop_front();
|
||||
delete t;
|
||||
}
|
||||
|
||||
invalidateTextObjectsSortOrder();
|
||||
}
|
||||
|
||||
void EMIEngine::purgeText() {
|
||||
Common::List<TextObject *> toDelete;
|
||||
|
||||
for (TextObject *t : TextObject::getPool()) {
|
||||
if (t->getStackLevel() == 0) {
|
||||
toDelete.push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
while (!toDelete.empty()) {
|
||||
TextObject *t = toDelete.front();
|
||||
toDelete.pop_front();
|
||||
delete t;
|
||||
}
|
||||
|
||||
invalidateTextObjectsSortOrder();
|
||||
}
|
||||
|
||||
void EMIEngine::drawNormalMode() {
|
||||
_currSet->setupCamera();
|
||||
|
||||
g_driver->set3DMode();
|
||||
|
||||
if (_setupChanged) {
|
||||
cameraPostChangeHandle(_currSet->getSetup());
|
||||
_setupChanged = false;
|
||||
}
|
||||
|
||||
// Draw actors
|
||||
buildActiveActorsList();
|
||||
sortActiveActorsList();
|
||||
sortLayers();
|
||||
|
||||
Bitmap *background = _currSet->getCurrSetup()->_bkgndBm;
|
||||
background->_data->load();
|
||||
uint32 numLayers = background->_data->_numLayers;
|
||||
|
||||
Common::List<Layer *>::const_iterator nextLayer = _layers.begin();
|
||||
Common::List<Actor *>::const_iterator nextActor = _activeActors.begin();
|
||||
int32 currentLayer = numLayers - 1;
|
||||
|
||||
int aso = (nextActor != _activeActors.end()) ? (*nextActor)->getEffectiveSortOrder() : -1;
|
||||
int lso = (nextLayer != _layers.end()) ? (*nextLayer)->getSortOrder() : -1;
|
||||
int bgso = currentLayer * 10;
|
||||
|
||||
// interleave actors, background layers and additional stand-alone layers based
|
||||
// on their sortorder
|
||||
//
|
||||
// priority for same sort order:
|
||||
// background layers (highest priority)
|
||||
// stand-alone layers
|
||||
// actors
|
||||
while (1) {
|
||||
if (aso >= 0 && aso > bgso && aso > lso) {
|
||||
if ((*nextActor)->isVisible() && ! (*nextActor)->isInOverworld())
|
||||
(*nextActor)->draw();
|
||||
nextActor++;
|
||||
aso = (nextActor != _activeActors.end()) ? (*nextActor)->getEffectiveSortOrder() : -1;
|
||||
continue;
|
||||
}
|
||||
if (bgso >= 0 && bgso >= lso && bgso >= aso) {
|
||||
background->drawLayer(currentLayer);
|
||||
currentLayer--;
|
||||
bgso = currentLayer * 10;
|
||||
continue;
|
||||
}
|
||||
if (lso >= 0 && lso > bgso && lso >= aso) {
|
||||
(*nextLayer)->draw();
|
||||
nextLayer++;
|
||||
lso = (nextLayer != _layers.end()) ? (*nextLayer)->getSortOrder() : -1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Clear depth buffer before starting to draw the Overworld:
|
||||
* - all actors of the Overworld should cover any non-Overworld drawings
|
||||
* - Overworld actors need to use the depth Buffer so that e.g. the pause screen
|
||||
* is drawn above the inventory
|
||||
*/
|
||||
g_driver->clearDepthBuffer();
|
||||
|
||||
g_driver->drawDimPlane();
|
||||
|
||||
for (Actor *a : _activeActors) {
|
||||
if (a->isInOverworld())
|
||||
a->draw();
|
||||
}
|
||||
|
||||
// Draw Primitives
|
||||
for (PrimitiveObject *p : PrimitiveObject::getPool()) {
|
||||
p->draw();
|
||||
}
|
||||
|
||||
flagRefreshShadowMask(false);
|
||||
|
||||
}
|
||||
|
||||
void EMIEngine::storeSaveGameImage(SaveGame *state) {
|
||||
unsigned int width = 160, height = 120;
|
||||
Bitmap *screenshot = g_driver->getScreenshot(width, height, true);
|
||||
if (!screenshot) {
|
||||
warning("Unable to store screenshot.");
|
||||
return;
|
||||
}
|
||||
|
||||
// screenshots are not using the whole size of the texture
|
||||
// copy the actual screenshot to the correct position
|
||||
unsigned int texWidth = 256, texHeight = 128;
|
||||
unsigned int size = texWidth * texHeight;
|
||||
Graphics::Surface tmp = screenshot->getData(0);
|
||||
Graphics::Surface *buffer = tmp.scale(texWidth, texHeight, true);
|
||||
buffer->convertToInPlace(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
|
||||
|
||||
state->beginSection('SIMG');
|
||||
uint16 *data = (uint16 *)buffer->getPixels();
|
||||
for (unsigned int l = 0; l < size; l++) {
|
||||
state->writeLEUint16(data[l]);
|
||||
}
|
||||
state->endSection();
|
||||
delete screenshot;
|
||||
buffer->free();
|
||||
delete buffer;
|
||||
}
|
||||
|
||||
void EMIEngine::temporaryStoreSaveGameImage() {
|
||||
// store current rendered screen in g_driver
|
||||
g_grim->updateDisplayScene();
|
||||
g_driver->storeDisplay();
|
||||
}
|
||||
|
||||
void EMIEngine::updateDrawMode() {
|
||||
// For EMI, draw mode is just like normal mode with frozen frame time.
|
||||
updateNormalMode();
|
||||
}
|
||||
|
||||
void EMIEngine::invalidateTextObjectsSortOrder() {
|
||||
_textObjectsSortOrderInvalidated = true;
|
||||
}
|
||||
|
||||
void EMIEngine::invalidateActiveActorsList() {
|
||||
GrimEngine::invalidateActiveActorsList();
|
||||
invalidateSortOrder();
|
||||
}
|
||||
|
||||
void EMIEngine::invalidateSortOrder() {
|
||||
_sortOrderInvalidated = true;
|
||||
}
|
||||
|
||||
bool EMIEngine::compareTextLayer(const TextObject *x, const TextObject *y) {
|
||||
int xl = x->getLayer();
|
||||
int yl = y->getLayer();
|
||||
|
||||
if (xl == yl) {
|
||||
return x->getId() < y->getId();
|
||||
} else {
|
||||
return xl < yl;
|
||||
}
|
||||
}
|
||||
|
||||
bool EMIEngine::compareLayer(const Layer *x, const Layer *y) {
|
||||
return x->getSortOrder() > y->getSortOrder();
|
||||
}
|
||||
|
||||
void EMIEngine::drawTextObjects() {
|
||||
sortTextObjects();
|
||||
for (TextObject *t : _textObjects) {
|
||||
t->draw();
|
||||
}
|
||||
}
|
||||
|
||||
void EMIEngine::sortTextObjects() {
|
||||
if (!_textObjectsSortOrderInvalidated)
|
||||
return;
|
||||
|
||||
_textObjectsSortOrderInvalidated = false;
|
||||
|
||||
_textObjects.clear();
|
||||
for (TextObject *t : TextObject::getPool()) {
|
||||
if (t->getStackLevel() == 0) {
|
||||
_textObjects.push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
Common::sort(_textObjects.begin(), _textObjects.end(), compareTextLayer);
|
||||
}
|
||||
|
||||
void EMIEngine::sortLayers() {
|
||||
_layers.clear();
|
||||
for (Layer *l : Layer::getPool()) {
|
||||
_layers.push_back(l);
|
||||
}
|
||||
|
||||
Common::sort(_layers.begin(), _layers.end(), compareLayer);
|
||||
}
|
||||
|
||||
bool EMIEngine::compareActor(const Actor *x, const Actor *y) {
|
||||
if (x->getEffectiveSortOrder() == y->getEffectiveSortOrder()) {
|
||||
Set::Setup *setup = g_grim->getCurrSet()->getCurrSetup();
|
||||
Math::Matrix4 camRot = setup->_rot;
|
||||
|
||||
Math::Vector3d xp(x->getWorldPos() - setup->_pos);
|
||||
Math::Vector3d yp(y->getWorldPos() - setup->_pos);
|
||||
xp = xp * camRot.getRotation();
|
||||
yp = yp * camRot.getRotation();
|
||||
|
||||
if (fabs(xp.z() - yp.z()) < 0.001f) {
|
||||
return x->getId() < y->getId();
|
||||
} else {
|
||||
return xp.z() > yp.z();
|
||||
}
|
||||
}
|
||||
return x->getEffectiveSortOrder() > y->getEffectiveSortOrder();
|
||||
}
|
||||
|
||||
void EMIEngine::sortActiveActorsList() {
|
||||
if (!_sortOrderInvalidated) {
|
||||
return;
|
||||
}
|
||||
|
||||
_sortOrderInvalidated = false;
|
||||
|
||||
Common::sort(_activeActors.begin(), _activeActors.end(), compareActor);
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
73
engines/grim/emi/emi.h
Normal file
73
engines/grim/emi/emi.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/* 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 EMI_ENGINE_H
|
||||
#define EMI_ENGINE_H
|
||||
|
||||
#include "engines/grim/grim.h"
|
||||
#include "engines/grim/emi/layer.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class TextObject;
|
||||
class Actor;
|
||||
|
||||
class EMIEngine : public GrimEngine {
|
||||
public:
|
||||
EMIEngine(OSystem *syst, uint32 gameFlags, GrimGameType gameType, Common::Platform platform, Common::Language language);
|
||||
virtual ~EMIEngine();
|
||||
|
||||
const char *getUpdateFilename() override;
|
||||
|
||||
void pushText();
|
||||
void popText();
|
||||
void purgeText();
|
||||
|
||||
void invalidateActiveActorsList() override;
|
||||
void invalidateTextObjectsSortOrder() override;
|
||||
void invalidateSortOrder();
|
||||
void sortActiveActorsList();
|
||||
void temporaryStoreSaveGameImage();
|
||||
void storeSaveGameImage(SaveGame *state) override;
|
||||
|
||||
private:
|
||||
LuaBase *createLua() override;
|
||||
void drawNormalMode() override;
|
||||
void updateDrawMode() override;
|
||||
static bool compareTextLayer(const TextObject *x, const TextObject *y);
|
||||
void drawTextObjects() override;
|
||||
static bool compareActor(const Actor *x, const Actor *y);
|
||||
void sortTextObjects();
|
||||
static bool compareLayer(const Layer *x, const Layer *y);
|
||||
void sortLayers();
|
||||
|
||||
Common::List<TextObject *> _textObjects;
|
||||
Common::List<Layer *> _layers;
|
||||
|
||||
bool _textObjectsSortOrderInvalidated;
|
||||
bool _sortOrderInvalidated;
|
||||
};
|
||||
|
||||
extern EMIEngine *g_emi;
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
178
engines/grim/emi/emi_registry.cpp
Normal file
178
engines/grim/emi/emi_registry.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
/* 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/emi/emi_registry.h"
|
||||
#include "engines/grim/debug.h"
|
||||
|
||||
#include "audio/mixer.h"
|
||||
|
||||
#include "common/config-manager.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
EmiRegistry *g_emiregistry = nullptr;
|
||||
|
||||
const char *EmiRegistry::_translTable[][2] = {
|
||||
{"speech_mode", ""}, // Translated key not needed, see below
|
||||
{"vocvolume", "speech_volume"},
|
||||
{"sfxvolume", "sfx_volume"},
|
||||
{"musvolume", "music_volume"},
|
||||
{"textspeed", "talkspeed"},
|
||||
{"gamma", "gamma"},
|
||||
{"joystick_enabled", "joystick_enabled"},
|
||||
{"analog_mode", "analog_joystick_mode"},
|
||||
{"subtitles", "movie_subtitles"},
|
||||
{"camera_mode", "camera_relative_mode"},
|
||||
{"shadowfx", "shadow_effects"},
|
||||
{"vocfx", "audio_effects"},
|
||||
{"miscfx", "misc_video_effects"},
|
||||
{"moviequality", "movie_quality"},
|
||||
{"musicquality", "music_quality"},
|
||||
{nullptr,nullptr}
|
||||
};
|
||||
|
||||
const char *EmiRegistry::_boolValues[] = {
|
||||
"joystick_enabled",
|
||||
"analog_mode",
|
||||
"subtitles",
|
||||
"camera_mode",
|
||||
"vocfx",
|
||||
"moviequality",
|
||||
"musicquality",
|
||||
nullptr
|
||||
};
|
||||
|
||||
|
||||
EmiRegistry::EmiRegistry() {
|
||||
int i = 0;
|
||||
while (_translTable[i][0] != nullptr) {
|
||||
_transMap[_translTable[i][0]] = _translTable[i][1];
|
||||
++i;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (_boolValues[i] != nullptr) {
|
||||
_boolSet[_boolValues[i]] = true;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
uint EmiRegistry::convertTalkSpeedToGUI(uint talkspeed) const {
|
||||
return CLIP<uint>(talkspeed * 255 / 10, 0, 255);
|
||||
}
|
||||
|
||||
uint EmiRegistry::convertTalkSpeedFromGUI(uint talkspeed) const {
|
||||
return CLIP<uint>(talkspeed * 10 / 255, 1, 10);
|
||||
}
|
||||
|
||||
const Common::String EmiRegistry::convertGammaToRegistry(float gamma) const {
|
||||
return Common::String().format("%.2f", gamma);
|
||||
}
|
||||
|
||||
float EmiRegistry::convertGammaFromRegistry(const Common::String &gamma) const {
|
||||
float gamma_f;
|
||||
sscanf(gamma.c_str(), "%f", &gamma_f);
|
||||
return CLIP<float>(gamma_f, 0.5, 1.5);
|
||||
}
|
||||
|
||||
uint EmiRegistry::convertVolumeToMixer(uint emiVolume) const {
|
||||
float vol = float(emiVolume - 25)/(100 - 25)*Audio::Mixer::kMaxMixerVolume;
|
||||
return CLIP<uint>(uint(vol), 0, Audio::Mixer::kMaxMixerVolume);
|
||||
}
|
||||
|
||||
uint EmiRegistry::convertVolumeFromMixer(uint volume) const {
|
||||
float vol = float(volume)*(100 - 25)/Audio::Mixer::kMaxMixerVolume + 25;
|
||||
return CLIP<uint>(uint(vol), 0, Audio::Mixer::kMaxMixerVolume);
|
||||
}
|
||||
|
||||
uint EmiRegistry::convertSpeechModeFromGUI(bool subtitles, bool speechMute) const {
|
||||
if (!subtitles && !speechMute) // Speech only
|
||||
return 2;
|
||||
else if (subtitles && !speechMute) // Speech and subtitles
|
||||
return 3;
|
||||
else if (subtitles && speechMute) // Subtitles only
|
||||
return 1;
|
||||
else
|
||||
warning("Wrong configuration: Both subtitles and speech are off. Assuming subtitles only");
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool EmiRegistry::Get(const Common::String &key, float &res) const {
|
||||
Debug::debug(Debug::Engine, "GetResidualVMPreference(%s)", key.c_str());
|
||||
|
||||
if (!_transMap.contains(key))
|
||||
return false;
|
||||
|
||||
res = 0.;
|
||||
|
||||
if (key == "speech_mode") {
|
||||
if (!(ConfMan.hasKey("subtitles") && ConfMan.hasKey("speech_mute")))
|
||||
return false;
|
||||
|
||||
res = convertSpeechModeFromGUI(ConfMan.getBool("subtitles"), ConfMan.getBool("speech_mute"));
|
||||
} else {
|
||||
if (!(ConfMan.hasKey(_transMap[key])))
|
||||
return false;
|
||||
|
||||
if (key == "vocvolume" || key == "sfxvolume" || key == "musvolume")
|
||||
res = convertVolumeFromMixer(ConfMan.getInt(_transMap[key]));
|
||||
else if (key == "textspeed")
|
||||
res = convertTalkSpeedFromGUI(ConfMan.getInt(_transMap[key]));
|
||||
else if (key == "gamma")
|
||||
res = convertGammaFromRegistry(ConfMan.get(_transMap[key]));
|
||||
else if (key == "shadowfx")
|
||||
res = ConfMan.getBool(_transMap[key]) + 1;
|
||||
else if (_boolSet.contains(key))
|
||||
res = ConfMan.getBool(_transMap[key]);
|
||||
else
|
||||
res = ConfMan.getInt(_transMap[key]);
|
||||
}
|
||||
|
||||
Debug::debug(Debug::Engine, "Pushing %f", res);
|
||||
return true;
|
||||
}
|
||||
|
||||
void EmiRegistry::Set(const Common::String &key, float &value) {
|
||||
Debug::debug(Debug::Engine, "SetResidualVMPreference(%s, %f)", key.c_str(), value);
|
||||
|
||||
if (!_transMap.contains(key))
|
||||
return;
|
||||
|
||||
uint value_i = uint(value);
|
||||
|
||||
if (key == "speech_mode") {
|
||||
ConfMan.setBool("subtitles", (value_i == 1 || value_i == 3));
|
||||
ConfMan.setBool("speech_mute", (value_i == 1));
|
||||
} else if (key == "vocvolume" || key == "sfxvolume" || key == "musvolume")
|
||||
ConfMan.setInt(_transMap[key], convertVolumeToMixer(value_i));
|
||||
else if (key == "textspeed")
|
||||
ConfMan.setInt(_transMap[key], convertTalkSpeedToGUI(value_i));
|
||||
else if (key == "gamma")
|
||||
ConfMan.set(_transMap[key], convertGammaToRegistry(value));
|
||||
else if (key == "shadowfx")
|
||||
ConfMan.setBool(_transMap[key], (value_i == 2));
|
||||
else if (_boolSet.contains(key))
|
||||
ConfMan.setBool(_transMap[key], (value_i == 1));
|
||||
else
|
||||
ConfMan.setInt(_transMap[key], value_i);
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
63
engines/grim/emi/emi_registry.h
Normal file
63
engines/grim/emi/emi_registry.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* 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 EMI_REGISTRY_H
|
||||
#define EMI_REGISTRY_H
|
||||
|
||||
#include "common/str.h"
|
||||
#include "common/hashmap.h"
|
||||
#include "common/hash-str.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class EmiRegistry {
|
||||
public:
|
||||
EmiRegistry();
|
||||
~EmiRegistry() { }
|
||||
|
||||
bool Get(const Common::String &key, float &res) const;
|
||||
void Set(const Common::String &key, float &value);
|
||||
|
||||
private:
|
||||
uint convertVolumeToMixer(uint volume) const;
|
||||
uint convertVolumeFromMixer(uint volume) const;
|
||||
uint convertTalkSpeedToGUI(uint talkspeed) const;
|
||||
uint convertTalkSpeedFromGUI(uint talkspeed) const;
|
||||
bool convertSubtitlesToGUI(uint speechmode) const;
|
||||
bool convertSpeechMuteToGUI(uint speechmode) const;
|
||||
uint convertSpeechModeFromGUI(bool subtitles, bool speechMute) const;
|
||||
const Common::String convertGammaToRegistry(float gamma) const;
|
||||
float convertGammaFromRegistry(const Common::String &gamma) const;
|
||||
|
||||
typedef Common::HashMap<Common::String, bool, Common::IgnoreCase_Hash> StringSet;
|
||||
|
||||
Common::StringMap _transMap;
|
||||
StringSet _boolSet;
|
||||
|
||||
static const char *_boolValues[];
|
||||
static const char *_translTable[][2];
|
||||
};
|
||||
|
||||
extern EmiRegistry *g_emiregistry;
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
82
engines/grim/emi/layer.cpp
Normal file
82
engines/grim/emi/layer.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
/* 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/str.h"
|
||||
|
||||
#include "engines/grim/emi/layer.h"
|
||||
#include "engines/grim/bitmap.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
Layer::Layer() : _filename(""), _sortOrder(0), _frame(0), _bitmap(nullptr) {
|
||||
}
|
||||
|
||||
Layer::Layer(const Common::String &filename, int sortOrder) : _filename(filename), _sortOrder(sortOrder), _frame(0) {
|
||||
_bitmap = Bitmap::create(filename);
|
||||
}
|
||||
|
||||
Layer::~Layer() {
|
||||
delete _bitmap;
|
||||
}
|
||||
|
||||
void Layer::draw() {
|
||||
_bitmap->drawLayer(_frame);
|
||||
}
|
||||
|
||||
void Layer::setFrame(int frame) {
|
||||
int numframes = _bitmap->getNumLayers();
|
||||
if (frame >= numframes || frame < 0) {
|
||||
warning("Layer::setFrame: invalid frame number: %d, numLayers: %d", frame, numframes);
|
||||
return;
|
||||
}
|
||||
_frame = frame;
|
||||
}
|
||||
|
||||
void Layer::setSortOrder(int order) {
|
||||
_sortOrder = order;
|
||||
}
|
||||
|
||||
void Layer::advanceFrame(int num) {
|
||||
_frame += num;
|
||||
int numframes = _bitmap->getNumLayers();
|
||||
_frame %= numframes;
|
||||
}
|
||||
|
||||
void Layer::saveState(SaveGame *state) {
|
||||
if (_bitmap) {
|
||||
state->writeBool(true);
|
||||
state->writeString(_bitmap->getFilename());
|
||||
} else {
|
||||
state->writeBool(false);
|
||||
}
|
||||
state->writeLESint32(_frame);
|
||||
state->writeLESint32(_sortOrder);
|
||||
}
|
||||
|
||||
void Layer::restoreState(SaveGame *state) {
|
||||
bool hasBitmap = state->readBool();
|
||||
if (hasBitmap)
|
||||
_bitmap = Bitmap::create(state->readString());
|
||||
_frame = state->readLESint32();
|
||||
_sortOrder = state->readLESint32();
|
||||
}
|
||||
|
||||
}
|
||||
59
engines/grim/emi/layer.h
Normal file
59
engines/grim/emi/layer.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* 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_LAYER_H
|
||||
#define GRIM_LAYER_H
|
||||
|
||||
#include "common/endian.h"
|
||||
|
||||
#include "engines/grim/pool.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class Bitmap;
|
||||
|
||||
class Layer : public PoolObject<Layer> {
|
||||
public:
|
||||
Layer();
|
||||
Layer(const Common::String &filename, int sortOrder);
|
||||
~Layer();
|
||||
|
||||
static int32 getStaticTag() { return MKTAG('L','A','Y','R'); }
|
||||
|
||||
void draw();
|
||||
void setFrame(int frame);
|
||||
void setSortOrder(int order);
|
||||
void advanceFrame(int num);
|
||||
int getSortOrder() const { return _sortOrder; }
|
||||
|
||||
void saveState(SaveGame *state);
|
||||
void restoreState(SaveGame *state);
|
||||
|
||||
private:
|
||||
Common::String _filename;
|
||||
Bitmap *_bitmap;
|
||||
int _sortOrder;
|
||||
int _frame;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
914
engines/grim/emi/lua_v2.cpp
Normal file
914
engines/grim/emi/lua_v2.cpp
Normal file
@@ -0,0 +1,914 @@
|
||||
/* 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/endian.h"
|
||||
#include "common/savefile.h"
|
||||
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "engines/grim/emi/lua_v2.h"
|
||||
#include "engines/grim/emi/emi_registry.h"
|
||||
#include "engines/grim/emi/sound/emisound.h"
|
||||
#include "engines/grim/lua/lauxlib.h"
|
||||
#include "engines/grim/resource.h"
|
||||
#include "engines/grim/set.h"
|
||||
#include "engines/grim/grim.h"
|
||||
#include "engines/grim/gfx_base.h"
|
||||
#include "engines/grim/font.h"
|
||||
#include "engines/grim/emi/layer.h"
|
||||
#include "engines/grim/emi/emi.h"
|
||||
#include "engines/grim/movie/movie.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
void Lua_V2::UndimAll() {
|
||||
g_driver->setDimLevel(0);
|
||||
warning("Lua_V2::UndimAll: stub");
|
||||
}
|
||||
|
||||
void Lua_V2::UndimRegion() {
|
||||
lua_Object regionObj = lua_getparam(1);
|
||||
|
||||
if (lua_isnumber(regionObj)) {
|
||||
int region = (int)lua_getnumber(regionObj);
|
||||
// FIXME func(region);
|
||||
warning("Lua_V2::UndimRegion: region: %d", region);
|
||||
} else {
|
||||
lua_pushnil();
|
||||
// HACK: The demo uses this to undim the intro-screen.
|
||||
// thus UndimRegion(nil) might mean UndimScreen.
|
||||
g_driver->setDimLevel(0);
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::DimScreen() {
|
||||
lua_Object dimObj = lua_getparam(1);
|
||||
float dim = 0.6999f;
|
||||
|
||||
if (lua_isnumber(dimObj))
|
||||
dim = lua_getnumber(dimObj);
|
||||
|
||||
g_driver->setDimLevel(dim);
|
||||
// FIXME func(dim);
|
||||
warning("Lua_V2::DimScreen: dim: %f", dim);
|
||||
}
|
||||
|
||||
void Lua_V2::MakeCurrentSetup() {
|
||||
lua_Object setupObj = lua_getparam(1);
|
||||
if (lua_isnumber(setupObj)) {
|
||||
int num = (int)lua_getnumber(setupObj);
|
||||
g_grim->makeCurrentSetup(num);
|
||||
} else if (lua_isstring(setupObj)) {
|
||||
const char *setupName = lua_getstring(setupObj);
|
||||
error("Lua_V2::MakeCurrentSetup: Not implemented case: setup: %s", setupName);
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::LockBackground() {
|
||||
lua_Object filenameObj = lua_getparam(1);
|
||||
|
||||
if (!lua_isstring(filenameObj)) {
|
||||
lua_pushnil();
|
||||
return;
|
||||
}
|
||||
const char *filename = lua_getstring(filenameObj);
|
||||
warning("Lua_V2::LockBackground, filename: %s", filename);
|
||||
// FIXME: implement missing rest part of code
|
||||
}
|
||||
|
||||
void Lua_V2::UnLockBackground() {
|
||||
lua_Object filenameObj = lua_getparam(1);
|
||||
|
||||
if (!lua_isstring(filenameObj)) {
|
||||
lua_pushnil();
|
||||
return;
|
||||
}
|
||||
|
||||
const char *filename = lua_getstring(filenameObj);
|
||||
// FIXME: implement missin code
|
||||
warning("Lua_V2::UnLockBackground: stub, filename: %s", filename);
|
||||
}
|
||||
|
||||
void Lua_V2::MakeScreenTextures() {
|
||||
lua_Object indexObj = lua_getparam(1);
|
||||
|
||||
if (!lua_isnil(indexObj) && lua_isnumber(indexObj)) {
|
||||
//int index = (int)lua_getnumber(indexObj);
|
||||
// The index does not seem to matter
|
||||
|
||||
g_driver->makeScreenTextures();
|
||||
lua_pushnumber(1.0);
|
||||
} else {
|
||||
lua_pushnil();
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::ClearSpecialtyTexture() {
|
||||
// This seems to be used in the save/load menu
|
||||
// Not sure why the specialty textures need to be cleared.
|
||||
warning("Lua_V2::ClearSpecialtyTexture: stub");
|
||||
}
|
||||
|
||||
void Lua_V2::LoadBundle() {
|
||||
lua_Object paramObj = lua_getparam(1);
|
||||
if (lua_isstring(paramObj) || lua_isnil(paramObj)) {
|
||||
const char *name = lua_getstring(paramObj);
|
||||
// FIXME: implement missing function
|
||||
/* if (!func(name))
|
||||
lua_pushnil();
|
||||
else*/
|
||||
lua_pushnumber(1.0);
|
||||
warning("Lua_V2::LoadBundle: stub, name: %s", name);
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::AreWeInternational() {
|
||||
if (g_grim->getGameLanguage() != Common::EN_ANY)
|
||||
lua_pushnumber(1.0);
|
||||
}
|
||||
|
||||
void Lua_V2::GetCPUSpeed() {
|
||||
lua_pushnumber(500); // anything above 333 make best configuration
|
||||
}
|
||||
|
||||
// This should be correct, judging by the Demo
|
||||
// the only real difference from L1 is the lack of looping
|
||||
void Lua_V2::StartMovie() {
|
||||
lua_Object name = lua_getparam(1);
|
||||
lua_Object subtitlesObj = lua_getparam(2);
|
||||
|
||||
if (!lua_isstring(name)) {
|
||||
lua_pushnil();
|
||||
return;
|
||||
}
|
||||
Lua_V1::CleanBuffer();
|
||||
|
||||
bool showSubtitles = false;
|
||||
if (lua_isnumber(subtitlesObj)) {
|
||||
if ((int)lua_getnumber(subtitlesObj)) {
|
||||
showSubtitles = true;
|
||||
}
|
||||
}
|
||||
if (g_grim->getGameFlags() & ADGF_DEMO) {
|
||||
showSubtitles = true;
|
||||
}
|
||||
|
||||
GrimEngine::EngineMode prevEngineMode = g_grim->getMode();
|
||||
g_grim->setMode(GrimEngine::SmushMode);
|
||||
g_grim->setMovieSubtitle(nullptr);
|
||||
bool result = g_movie->play(lua_getstring(name), false, 0, 0, true, showSubtitles);
|
||||
if (!result)
|
||||
g_grim->setMode(prevEngineMode);
|
||||
pushbool(result);
|
||||
|
||||
// The following line causes issues after 9547a9b61674546077301bf09f89a2d120046d8e
|
||||
//g_grim->setMode(GrimEngine::SmushMode);
|
||||
}
|
||||
|
||||
void Lua_V2::EscapeMovie() {
|
||||
g_movie->stop();
|
||||
}
|
||||
|
||||
void Lua_V2::IsMoviePlaying() {
|
||||
pushbool(g_movie->isPlaying());
|
||||
}
|
||||
|
||||
void Lua_V2::SetActiveCD() {
|
||||
lua_Object cdObj = lua_getparam(1);
|
||||
int cd = (int)lua_getnumber(cdObj);
|
||||
|
||||
if (cd == 1 || cd == 2) {
|
||||
warning("Lua_V2::GetActiveCD: set to CD: %d", cd);
|
||||
// FIXME
|
||||
lua_pushnumber(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::GetActiveCD() {
|
||||
// FIXME: return current CD number 1 or 2, original can also avoid push any numer
|
||||
warning("Lua_V2::GetActiveCD: return const CD 1");
|
||||
lua_pushnumber(1);
|
||||
}
|
||||
|
||||
void Lua_V2::PurgeText() {
|
||||
g_emi->purgeText();
|
||||
}
|
||||
|
||||
void Lua_V2::GetFontDimensions() {
|
||||
lua_Object fontObj = lua_getparam(1);
|
||||
if (!lua_isstring(fontObj))
|
||||
return;
|
||||
|
||||
const char *fontName = lua_getstring(fontObj);
|
||||
|
||||
Font *font = Font::getByFileName(fontName);
|
||||
if (!font) {
|
||||
font = g_resourceloader->loadFont(fontName);
|
||||
}
|
||||
if (font) {
|
||||
int32 h = font->getBaseOffsetY();
|
||||
int32 w = font->getFontWidth();
|
||||
lua_pushnumber(w);
|
||||
lua_pushnumber(h);
|
||||
} else {
|
||||
warning("Lua_V2::GetFontDimensions for font '%s': returns 0,0", fontName);
|
||||
lua_pushnumber(0.f);
|
||||
lua_pushnumber(0.f);
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::GetTextCharPosition() {
|
||||
lua_Object textObj = lua_getparam(1);
|
||||
lua_Object posObj = lua_getparam(2);
|
||||
if (lua_isuserdata(textObj) && lua_tag(textObj) == MKTAG('T', 'E', 'X', 'T')) {
|
||||
TextObject *textObject = gettextobject(textObj);
|
||||
int pos = (int)lua_getnumber(posObj);
|
||||
float textPos = textObject->getTextCharPosition(pos);
|
||||
lua_pushnumber(textPos / 320.f);
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::GetTextObjectDimensions() {
|
||||
lua_Object textObj = lua_getparam(1);
|
||||
|
||||
if (lua_isuserdata(textObj) && lua_tag(textObj) == MKTAG('T', 'E', 'X', 'T')) {
|
||||
TextObject *textObject = gettextobject(textObj);
|
||||
lua_pushnumber(textObject->getBitmapWidth() / 320.f);
|
||||
lua_pushnumber(textObject->getBitmapHeight() / 240.f);
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::ToggleOverworld() {
|
||||
lua_Object boolObj = lua_getparam(1);
|
||||
bool backToNormal = (lua_isnil(boolObj) == 0);
|
||||
if (backToNormal) {
|
||||
GrimEngine::EngineMode previous = g_grim->getPreviousMode();
|
||||
g_grim->setPreviousMode(GrimEngine::OverworldMode);
|
||||
// HACK: ToggleOverworld is only called after we load a save game.
|
||||
// However, the engine saved PreviousMode as OverworldMode.
|
||||
// Reset it to normal here.
|
||||
if (previous == GrimEngine::OverworldMode)
|
||||
previous = GrimEngine::NormalMode;
|
||||
g_grim->setMode(previous);
|
||||
} else {
|
||||
GrimEngine::EngineMode previous = g_grim->getMode();
|
||||
g_grim->setPreviousMode(previous);
|
||||
g_grim->setMode(GrimEngine::OverworldMode);
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::ClearOverworld() {
|
||||
warning("Lua_V2::ClearOverworld: implement opcode");
|
||||
}
|
||||
|
||||
void Lua_V2::ScreenshotForSavegame() {
|
||||
g_emi->temporaryStoreSaveGameImage();
|
||||
}
|
||||
|
||||
void Lua_V2::EngineDisplay() {
|
||||
// dummy
|
||||
}
|
||||
|
||||
void Lua_V2::SetAmbientLight() {
|
||||
// dummy
|
||||
}
|
||||
|
||||
void Lua_V2::Display() {
|
||||
// dummy
|
||||
}
|
||||
|
||||
void Lua_V2::GetCameraPitch() {
|
||||
Set *set = g_grim->getCurrSet();
|
||||
if (set == nullptr) {
|
||||
lua_pushnil();
|
||||
return;
|
||||
}
|
||||
|
||||
Set::Setup *setup = set->getCurrSetup();
|
||||
float pitch;
|
||||
if (g_grim->getGameType() == GType_MONKEY4) {
|
||||
setup->getRotation(nullptr, nullptr, &pitch);
|
||||
} else {
|
||||
setup->getRotation(nullptr, &pitch, nullptr);
|
||||
}
|
||||
lua_pushnumber(pitch);
|
||||
}
|
||||
|
||||
void Lua_V2::GetCameraYaw() {
|
||||
Set *set = g_grim->getCurrSet();
|
||||
if (set == nullptr) {
|
||||
lua_pushnil();
|
||||
return;
|
||||
}
|
||||
|
||||
Set::Setup *setup = set->getCurrSetup();
|
||||
float yaw;
|
||||
if (g_grim->getGameType() == GType_MONKEY4) {
|
||||
setup->getRotation(nullptr, &yaw, nullptr);
|
||||
} else {
|
||||
setup->getRotation(&yaw, nullptr, nullptr);
|
||||
}
|
||||
lua_pushnumber(yaw);
|
||||
}
|
||||
|
||||
void Lua_V2::GetCameraRoll() {
|
||||
Set *set = g_grim->getCurrSet();
|
||||
if (set == nullptr) {
|
||||
lua_pushnil();
|
||||
return;
|
||||
}
|
||||
|
||||
Set::Setup *setup = set->getCurrSetup();
|
||||
float roll;
|
||||
if (g_grim->getGameType() == GType_MONKEY4) {
|
||||
setup->getRotation(&roll, nullptr, nullptr);
|
||||
} else {
|
||||
setup->getRotation(nullptr, nullptr, &roll);
|
||||
}
|
||||
lua_pushnumber(roll);
|
||||
}
|
||||
|
||||
void Lua_V2::PitchCamera() {
|
||||
lua_Object pitchObj = lua_getparam(1);
|
||||
if (!lua_isnumber(pitchObj)) {
|
||||
error("Lua_V2::PitchCamera - Parameter is not a number!");
|
||||
return;
|
||||
}
|
||||
|
||||
Set *set = g_grim->getCurrSet();
|
||||
if (set == nullptr)
|
||||
return;
|
||||
|
||||
Set::Setup *setup = set->getCurrSetup();
|
||||
setup->setPitch(Math::Angle(lua_getnumber(pitchObj)));
|
||||
}
|
||||
|
||||
void Lua_V2::YawCamera() {
|
||||
lua_Object yawObj = lua_getparam(1);
|
||||
if (!lua_isnumber(yawObj)) {
|
||||
error("Lua_V2::YawCamera - Parameter is not a number!");
|
||||
return;
|
||||
}
|
||||
|
||||
Set *set = g_grim->getCurrSet();
|
||||
if (set == nullptr)
|
||||
return;
|
||||
|
||||
Set::Setup *setup = set->getCurrSetup();
|
||||
setup->setYaw(Math::Angle(lua_getnumber(yawObj)));
|
||||
}
|
||||
|
||||
void Lua_V2::RollCamera() {
|
||||
lua_Object rollObj = lua_getparam(1);
|
||||
if (!lua_isnumber(rollObj)) {
|
||||
error("Lua_V2::RollCamera - Parameter is not a number!");
|
||||
return;
|
||||
}
|
||||
|
||||
Set *set = g_grim->getCurrSet();
|
||||
if (set == nullptr)
|
||||
return;
|
||||
|
||||
Set::Setup *setup = set->getCurrSetup();
|
||||
setup->setRoll(Math::Angle(lua_getnumber(rollObj)));
|
||||
}
|
||||
|
||||
void Lua_V2::PushText() {
|
||||
g_emi->pushText();
|
||||
}
|
||||
|
||||
void Lua_V2::PopText() {
|
||||
g_emi->popText();
|
||||
}
|
||||
|
||||
void Lua_V2::GetSectorName() {
|
||||
lua_Object xObj = lua_getparam(1);
|
||||
lua_Object yObj = lua_getparam(2);
|
||||
lua_Object zObj = lua_getparam(3);
|
||||
|
||||
if (!lua_isnumber(xObj) || !lua_isnumber(yObj) || !lua_isnumber(zObj)) {
|
||||
lua_pushnil();
|
||||
return;
|
||||
}
|
||||
float x, y, z;
|
||||
x = lua_getnumber(xObj);
|
||||
y = lua_getnumber(yObj);
|
||||
z = lua_getnumber(zObj);
|
||||
|
||||
Math::Vector3d pos(x, y, z);
|
||||
Set *set = g_grim->getCurrSet();
|
||||
Sector *sector = set->findPointSector(pos, Sector::NoneType);
|
||||
if (sector) {
|
||||
lua_pushstring(sector->getName().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::GammaEnabled() {
|
||||
warning("Lua_V2::GammaEnabled: implement opcode, pushing nil");
|
||||
lua_pushnil();
|
||||
}
|
||||
|
||||
void Lua_V2::FileFindFirst() {
|
||||
lua_Object extObj = lua_getparam(1);
|
||||
if (!lua_isstring(extObj)) {
|
||||
lua_pushnil();
|
||||
return;
|
||||
}
|
||||
|
||||
FileFindDispose();
|
||||
|
||||
const char *extension = lua_getstring(extObj);
|
||||
if (0 == strncmp(extension, "Saves/", 6))
|
||||
extension += 6;
|
||||
|
||||
// _menus.lua: saveload_menu.get_file_list searches for *.gsv.
|
||||
// This avoids conflicts with grim saves.
|
||||
if (0 == strcmp(extension, "*.gsv"))
|
||||
extension = "efmi###.gsv";
|
||||
|
||||
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
|
||||
g_grim->_listFiles = saveFileMan->listSavefiles(extension);
|
||||
Common::sort(g_grim->_listFiles.begin(), g_grim->_listFiles.end());
|
||||
g_grim->_listFilesIter = g_grim->_listFiles.begin();
|
||||
|
||||
if (g_grim->_listFilesIter == g_grim->_listFiles.end())
|
||||
lua_pushnil();
|
||||
else
|
||||
FileFindNext();
|
||||
}
|
||||
|
||||
void Lua_V2::ThumbnailFromFile() {
|
||||
lua_Object texIdObj = lua_getparam(1);
|
||||
lua_Object filenameObj = lua_getparam(2);
|
||||
|
||||
if (!lua_isnumber(texIdObj) || !lua_isstring(filenameObj)) {
|
||||
warning("Lua_V2::ThumbnailFromFile: wrong parameters");
|
||||
return;
|
||||
}
|
||||
int index = (int)lua_getnumber(texIdObj);
|
||||
Common::String filename(lua_getstring(filenameObj));
|
||||
|
||||
if (g_grim->getGameType() == GType_MONKEY4 &&
|
||||
g_grim->getGamePlatform() == Common::kPlatformPS2) {
|
||||
filename += ".ps2";
|
||||
}
|
||||
|
||||
int width = 256, height = 128;
|
||||
|
||||
SaveGame *savedState = SaveGame::openForLoading(filename);
|
||||
if (!savedState || !savedState->isCompatible()) {
|
||||
delete savedState;
|
||||
warning("Lua_V2::ThumbnailFromFile: savegame %s not compatible", filename.c_str());
|
||||
lua_pushnil();
|
||||
return;
|
||||
}
|
||||
int dataSize = savedState->beginSection('SIMG');
|
||||
if (dataSize != width * height * 2) {
|
||||
warning("Lua_V2::ThumbnailFromFile: savegame uses unexpected thumbnail size, ignore it");
|
||||
lua_pushnil();
|
||||
delete savedState;
|
||||
return;
|
||||
}
|
||||
uint16 *data = new uint16[dataSize / 2];
|
||||
for (int l = 0; l < dataSize / 2; l++) {
|
||||
data[l] = savedState->readLEUint16();
|
||||
}
|
||||
Graphics::Surface buf;
|
||||
buf.init(width, height, width * 2, (void *)data, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
|
||||
Bitmap *screenshot = new Bitmap(buf, width, height, "screenshot");
|
||||
if (!screenshot) {
|
||||
lua_pushnil();
|
||||
warning("Lua_V2::ThumbnailFromFile: Could not restore screenshot from file %s", filename.c_str());
|
||||
delete screenshot;
|
||||
delete[] data;
|
||||
delete savedState;
|
||||
return;
|
||||
}
|
||||
|
||||
screenshot->_data->convertToColorFormat(Graphics::PixelFormat::createFormatRGBA32());
|
||||
g_driver->createSpecialtyTexture(index, (const uint8 *)screenshot->getData(0).getPixels(), width, height);
|
||||
delete screenshot;
|
||||
delete[] data;
|
||||
savedState->endSection();
|
||||
delete savedState;
|
||||
|
||||
pushbool(true);
|
||||
}
|
||||
|
||||
void Lua_V2::GetMemoryCardId() {
|
||||
// 0 - No mem card
|
||||
// 1 - Not formatted
|
||||
// 2 - Not enough space
|
||||
// 3 - Error occurred
|
||||
lua_pushnumber(4);
|
||||
}
|
||||
|
||||
void Lua_V2::SetReplayMode() {
|
||||
lua_Object intObj = lua_getparam(1);
|
||||
lua_Object strObj = lua_getparam(2);
|
||||
|
||||
if (!lua_isnumber(intObj) || (!lua_isnil(strObj) && !lua_isstring(strObj))) {
|
||||
warning("Lua_V2::SetReplayMode: wrong parameters");
|
||||
return;
|
||||
}
|
||||
|
||||
int num = lua_getnumber(intObj);
|
||||
if (lua_isstring(strObj)) {
|
||||
const char *str = lua_getstring(strObj);
|
||||
warning("SetReplayMode(%d, %s)", num, str);
|
||||
} else {
|
||||
warning("SetReplayMode(%d)", num);
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::LocalizeString() {
|
||||
char msgId[50], buf[1000];
|
||||
lua_Object strObj = lua_getparam(1);
|
||||
msgId[0] = 0;
|
||||
|
||||
if (lua_isstring(strObj)) {
|
||||
const char *str = lua_getstring(strObj);
|
||||
Common::String msg = parseMsgText(str, msgId);
|
||||
Common::sprintf_s(buf, "/%s/%s", msgId, msg.c_str());
|
||||
|
||||
lua_pushstring(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::OverWorldToScreen() { // TODO
|
||||
lua_Object param1 = lua_getparam(1);
|
||||
lua_Object param2 = lua_getparam(2);
|
||||
lua_Object param3 = lua_getparam(3);
|
||||
|
||||
float x = 0, y = 0, z = 0;
|
||||
if (!lua_isnumber(param1) || !lua_isnumber(param2) || !lua_isnumber(param3)) {
|
||||
error("Param not a number for OverWorldToScreen");
|
||||
} else {
|
||||
x = lua_getnumber(param1);
|
||||
y = lua_getnumber(param2);
|
||||
z = lua_getnumber(param3);
|
||||
}
|
||||
|
||||
warning("Stub function: OverWorldToScreen(%f, %f, %f) - returning 0,0", x, y, z);
|
||||
|
||||
lua_pushnumber(0);
|
||||
lua_pushnumber(0);
|
||||
}
|
||||
|
||||
void Lua_V2::WorldToScreen() {
|
||||
lua_Object xObj = lua_getparam(1);
|
||||
lua_Object yObj = lua_getparam(2);
|
||||
lua_Object zObj = lua_getparam(3);
|
||||
if (!lua_isnumber(xObj) || !lua_isnumber(yObj) || !lua_isnumber(zObj)) {
|
||||
lua_pushnumber(0.0);
|
||||
lua_pushnumber(0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
float x = lua_getnumber(xObj);
|
||||
float y = lua_getnumber(yObj);
|
||||
float z = lua_getnumber(zObj);
|
||||
Math::Vector3d pos = Math::Vector3d(x, y, z);
|
||||
|
||||
const Set::Setup *setup = g_emi->getCurrSet()->getCurrSetup();
|
||||
Math::Matrix4 view = setup->_rot;
|
||||
view.transpose();
|
||||
|
||||
pos -= setup->_pos;
|
||||
pos = view.getRotation() * pos;
|
||||
pos.z() = -pos.z();
|
||||
|
||||
Math::Matrix4 proj = GfxBase::makeProjMatrix(setup->_fov, setup->_nclip, setup->_fclip);
|
||||
proj.transpose();
|
||||
Math::Vector4d screen = proj * Math::Vector4d(pos.x(), pos.y(), pos.z(), 1.0);
|
||||
screen /= screen.w();
|
||||
|
||||
lua_pushnumber(screen.x());
|
||||
lua_pushnumber(screen.y());
|
||||
}
|
||||
|
||||
void Lua_V2::NewLayer() {
|
||||
lua_Object param1 = lua_getparam(1);
|
||||
lua_Object param2 = lua_getparam(2);
|
||||
lua_Object param3 = lua_getparam(3);
|
||||
|
||||
const char *til = nullptr;
|
||||
int sortorder = 0; // zero = 0;
|
||||
if (lua_isstring(param1) && lua_isnumber(param2) && lua_isnumber(param3)) {
|
||||
til = lua_getstring(param1);
|
||||
sortorder = (int)lua_getnumber(param2);
|
||||
|
||||
// This one is always specified, but also always 0...
|
||||
//zero = (int)lua_getnumber(param3);
|
||||
|
||||
Layer *layer = new Layer(til, sortorder);
|
||||
|
||||
// Need to return something that can be looked up later
|
||||
lua_pushusertag(layer->getId(), MKTAG('L','A','Y','R'));
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::FreeLayer() {
|
||||
lua_Object param1 = lua_getparam(1);
|
||||
if (lua_isuserdata(param1) && lua_tag(param1) == MKTAG('L','A','Y','R')) {
|
||||
int layer = (int)lua_getuserdata(param1);
|
||||
Layer *l = Layer::getPool().getObject(layer);
|
||||
delete l;
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::AdvanceLayerFrame() {
|
||||
lua_Object param1 = lua_getparam(1);
|
||||
lua_Object param2 = lua_getparam(2);
|
||||
if (lua_isuserdata(param1) && lua_tag(param1) == MKTAG('L','A','Y','R') && lua_isnumber(param2)) {
|
||||
int layer = (int)lua_getuserdata(param1);
|
||||
int one = (int)lua_getnumber(param2);
|
||||
Layer *l = Layer::getPool().getObject(layer);
|
||||
if (!l) {
|
||||
warning("Lua_V2::AdvanceLayerFrame: no layer found");
|
||||
return;
|
||||
}
|
||||
l->advanceFrame(one);
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::SetLayerFrame() {
|
||||
lua_Object param1 = lua_getparam(1);
|
||||
lua_Object param2 = lua_getparam(2);
|
||||
if (lua_isuserdata(param1) && lua_tag(param1) == MKTAG('L','A','Y','R') && lua_isnumber(param2)) {
|
||||
int layer = (int)lua_getuserdata(param1);
|
||||
int one = (int)lua_getnumber(param2);
|
||||
Layer *l = Layer::getPool().getObject(layer);
|
||||
l->setFrame(one);
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::SetLayerSortOrder() {
|
||||
lua_Object param1 = lua_getparam(1);
|
||||
lua_Object param2 = lua_getparam(2);
|
||||
if (lua_isuserdata(param1) && lua_tag(param1) == MKTAG('L','A','Y','R') && lua_isnumber(param2)) {
|
||||
int layer = (int)lua_getuserdata(param1);
|
||||
int sortorder = (int)lua_getnumber(param2);
|
||||
Layer *l = Layer::getPool().getObject(layer);
|
||||
l->setSortOrder(sortorder);
|
||||
} else {
|
||||
warning("Lua_V2::SetLayerSortOrder: wrong parameters");
|
||||
}
|
||||
}
|
||||
|
||||
// Stub function for builtin functions not yet implemented
|
||||
/*static void stubWarning(const char *funcName) {
|
||||
warning("Stub function: %s", funcName);
|
||||
}*/
|
||||
|
||||
static void stubError(const char *funcName) {
|
||||
error("Stub function: %s", funcName);
|
||||
}
|
||||
|
||||
#define STUB_FUNC(name) void name() { stubWarning(#name); }
|
||||
#define STUB_FUNC2(name) void name() { stubError(#name); }
|
||||
|
||||
// Opcodes more or less differ to Grim Lua_V1::* LUA_OPCODEs
|
||||
// STUB_FUNC2(Lua_V2::SetActorWalkChore)
|
||||
// STUB_FUNC2(Lua_V2::SetActorTurnChores)
|
||||
// STUB_FUNC2(Lua_V2::SetActorRestChore)
|
||||
// STUB_FUNC2(Lua_V2::SetActorMumblechore)
|
||||
// STUB_FUNC2(Lua_V2::SetActorTalkChore)
|
||||
// STUB_FUNC2(Lua_V2::SetActorLookRate)
|
||||
// STUB_FUNC2(Lua_V2::GetActorLookRate)
|
||||
// STUB_FUNC2(Lua_V2::GetVisibleThings)
|
||||
// STUB_FUNC2(Lua_V2::GetActorRot)
|
||||
// STUB_FUNC2(Lua_V2::LockSet)
|
||||
// STUB_FUNC2(Lua_V2::UnLockSet)
|
||||
// STUB_FUNC2(Lua_V2::PlaySound)
|
||||
// STUB_FUNC2(Lua_V2::IsSoundPlaying)
|
||||
// STUB_FUNC2(Lua_V2::MakeSectorActive)
|
||||
// STUB_FUNC2(Lua_V2::TurnActorTo)
|
||||
// STUB_FUNC2(Lua_V2::GetAngleBetweenActors)
|
||||
// STUB_FUNC2(Lua_V2::ImStartSound)
|
||||
// STUB_FUNC2(Lua_V2::ImGetSfxVol)
|
||||
// STUB_FUNC2(Lua_V2::ImGetVoiceVol)
|
||||
// STUB_FUNC2(Lua_V2::ImGetMusicVol)
|
||||
// STUB_FUNC2(Lua_V2::ImSetSequence)
|
||||
// STUB_FUNC2(Lua_V2::ChangeTextObject)
|
||||
// STUB_FUNC2(Lua_V2::GetTextCharPosition)
|
||||
// STUB_FUNC2(Lua_V2::SetOffscreenTextPos)
|
||||
// STUB_FUNC2(Lua_V2::FadeInChore)
|
||||
// STUB_FUNC2(Lua_V2::FadeOutChore)
|
||||
// STUB_FUNC2(Lua_V2::SetLightPosition)
|
||||
// STUB_FUNC2(Lua_V2::GetAngleBetweenVectors)
|
||||
// STUB_FUNC2(Lua_V2::IsPointInSector)
|
||||
|
||||
// Stubbed functions with semi-known arguments:
|
||||
// TODO: Verify and implement these: (And add type-checking), also rename params
|
||||
void Lua_V2::NukeAllScriptLocks() {
|
||||
warning("Lua_V2::NukeAllScriptLocks() - TODO: Implement opcode");
|
||||
}
|
||||
|
||||
void Lua_V2::FRUTEY_Begin() {
|
||||
lua_Object param1 = lua_getparam(1);
|
||||
|
||||
if (!lua_isstring(param1))
|
||||
error("Lua_V2::FRUTEY_Begin - Unknown parameters");
|
||||
|
||||
const char *paramText = lua_getstring(param1);
|
||||
error("Lua_V2::FRUTEY_Begin(%s) - TODO: Implement opcode", paramText);
|
||||
}
|
||||
|
||||
void Lua_V2::FRUTEY_End() {
|
||||
error("Lua_V2::FRUTEY_End() - TODO: Implement opcode");
|
||||
}
|
||||
|
||||
void Lua_V2::RenderModeUser() {
|
||||
lua_Object param1 = lua_getparam(1);
|
||||
if (!lua_isnil(param1) && g_grim->getMode() != GrimEngine::DrawMode) {
|
||||
g_grim->setPreviousMode(g_grim->getMode());
|
||||
g_movie->pause(true);
|
||||
g_emiSound->pause(true);
|
||||
g_grim->setMode(GrimEngine::DrawMode);
|
||||
} else if (lua_isnil(param1) && g_grim->getMode() == GrimEngine::DrawMode) {
|
||||
g_movie->pause(false);
|
||||
g_emiSound->pause(false);
|
||||
g_grim->setMode(g_grim->getPreviousMode());
|
||||
}
|
||||
}
|
||||
|
||||
// Monkey specific LUA_OPCODEs only used for debug
|
||||
STUB_FUNC2(Lua_V2::ToggleDebugDraw)
|
||||
STUB_FUNC2(Lua_V2::ToggleDrawCameras)
|
||||
STUB_FUNC2(Lua_V2::ToggleDrawLights)
|
||||
STUB_FUNC2(Lua_V2::ToggleDrawSectors)
|
||||
STUB_FUNC2(Lua_V2::ToggleDrawBBoxes)
|
||||
STUB_FUNC2(Lua_V2::ToggleDrawFPS)
|
||||
STUB_FUNC2(Lua_V2::ToggleDrawPerformance)
|
||||
STUB_FUNC2(Lua_V2::ToggleDrawActorStats)
|
||||
STUB_FUNC2(Lua_V2::SectEditSelect)
|
||||
STUB_FUNC2(Lua_V2::SectEditPlace)
|
||||
STUB_FUNC2(Lua_V2::SectEditDelete)
|
||||
STUB_FUNC2(Lua_V2::SectEditInsert)
|
||||
STUB_FUNC2(Lua_V2::SectEditSortAdd)
|
||||
STUB_FUNC2(Lua_V2::SectEditForgetIt)
|
||||
|
||||
// ResidualVM-hacks:
|
||||
void Lua_V2::GetResidualVMPreference() {
|
||||
lua_Object keyObj = lua_getparam(1);
|
||||
|
||||
if (lua_isstring(keyObj)) {
|
||||
const Common::String key = lua_getstring(keyObj);
|
||||
|
||||
float value;
|
||||
if (g_emiregistry->Get(key, value))
|
||||
lua_pushnumber(value);
|
||||
else
|
||||
lua_pushnil();
|
||||
} else
|
||||
lua_pushnil();
|
||||
}
|
||||
|
||||
void Lua_V2::SetResidualVMPreference() {
|
||||
lua_Object keyObj = lua_getparam(1);
|
||||
lua_Object valueObj = lua_getparam(2);
|
||||
|
||||
if (lua_isstring(keyObj) && lua_isnumber(valueObj)) {
|
||||
const Common::String key = lua_getstring(keyObj);
|
||||
float value = lua_getnumber(valueObj);
|
||||
|
||||
g_emiregistry->Set(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
struct luaL_reg monkeyMainOpcodes[] = {
|
||||
// Monkey specific LUA_OPCODEs:
|
||||
{ "ScreenshotForSavegame", LUA_OPCODE(Lua_V2, ScreenshotForSavegame) },
|
||||
{ "GetActorWorldPos", LUA_OPCODE(Lua_V2, GetActorWorldPos) },
|
||||
{ "SetActiveCD", LUA_OPCODE(Lua_V2, SetActiveCD) },
|
||||
{ "GetActiveCD", LUA_OPCODE(Lua_V2, GetActiveCD) },
|
||||
{ "AreWeInternational", LUA_OPCODE(Lua_V2, AreWeInternational) },
|
||||
{ "MakeScreenTextures", LUA_OPCODE(Lua_V2, MakeScreenTextures) },
|
||||
{ "ThumbnailFromFile", LUA_OPCODE(Lua_V2, ThumbnailFromFile) },
|
||||
{ "ClearSpecialtyTexture", LUA_OPCODE(Lua_V2, ClearSpecialtyTexture) },
|
||||
{ "UnloadActor", LUA_OPCODE(Lua_V2, UnloadActor) },
|
||||
{ "PutActorInOverworld", LUA_OPCODE(Lua_V2, PutActorInOverworld) },
|
||||
{ "RemoveActorFromOverworld", LUA_OPCODE(Lua_V2, RemoveActorFromOverworld) },
|
||||
{ "ClearOverworld", LUA_OPCODE(Lua_V2, ClearOverworld) },
|
||||
{ "ToggleOverworld", LUA_OPCODE(Lua_V2, ToggleOverworld) },
|
||||
{ "ActorStopMoving", LUA_OPCODE(Lua_V2, ActorStopMoving) },
|
||||
{ "SetActorFOV", LUA_OPCODE(Lua_V2, SetActorFOV) },
|
||||
{ "SetActorLighting", LUA_OPCODE(Lua_V2, SetActorLighting) },
|
||||
{ "SetActorHeadLimits", LUA_OPCODE(Lua_V2, SetActorHeadLimits) },
|
||||
{ "ActorActivateShadow", LUA_OPCODE(Lua_V2, ActorActivateShadow) },
|
||||
{ "EnableActorPuck", LUA_OPCODE(Lua_V2, EnableActorPuck) },
|
||||
{ "SetActorGlobalAlpha", LUA_OPCODE(Lua_V2, SetActorGlobalAlpha) },
|
||||
{ "SetActorLocalAlpha", LUA_OPCODE(Lua_V2, SetActorLocalAlpha) },
|
||||
{ "SetActorSortOrder", LUA_OPCODE(Lua_V2, SetActorSortOrder) },
|
||||
{ "GetActorSortOrder", LUA_OPCODE(Lua_V2, GetActorSortOrder) },
|
||||
{ "AttachActor", LUA_OPCODE(Lua_V2, AttachActor) },
|
||||
{ "DetachActor", LUA_OPCODE(Lua_V2, DetachActor) },
|
||||
{ "IsChoreValid", LUA_OPCODE(Lua_V2, IsChoreValid) },
|
||||
{ "IsChorePlaying", LUA_OPCODE(Lua_V2, IsChorePlaying) },
|
||||
{ "IsChoreLooping", LUA_OPCODE(Lua_V2, IsChoreLooping) },
|
||||
{ "SetChoreLooping", LUA_OPCODE(Lua_V2, SetChoreLooping) },
|
||||
{ "StopActorChores", LUA_OPCODE(Lua_V2, StopActorChores) },
|
||||
{ "PlayChore", LUA_OPCODE(Lua_V2, PlayChore) },
|
||||
{ "StopChore", LUA_OPCODE(Lua_V2, StopChore) },
|
||||
{ "PauseChore", LUA_OPCODE(Lua_V2, PauseChore) },
|
||||
{ "AdvanceChore", LUA_OPCODE(Lua_V2, AdvanceChore) },
|
||||
{ "CompleteChore", LUA_OPCODE(Lua_V2, CompleteChore) },
|
||||
{ "LockChore", LUA_OPCODE(Lua_V2, LockChore) },
|
||||
{ "UnlockChore", LUA_OPCODE(Lua_V2, UnlockChore) },
|
||||
{ "LockChoreSet", LUA_OPCODE(Lua_V2, LockChoreSet) },
|
||||
{ "UnlockChoreSet", LUA_OPCODE(Lua_V2, UnlockChoreSet) },
|
||||
{ "LockBackground", LUA_OPCODE(Lua_V2, LockBackground) },
|
||||
{ "UnLockBackground", LUA_OPCODE(Lua_V2, UnLockBackground) },
|
||||
{ "EscapeMovie", LUA_OPCODE(Lua_V2, EscapeMovie) },
|
||||
{ "StopAllSounds", LUA_OPCODE(Lua_V2, StopAllSounds) },
|
||||
{ "LoadSound", LUA_OPCODE(Lua_V2, LoadSound) },
|
||||
{ "FreeSound", LUA_OPCODE(Lua_V2, FreeSound) },
|
||||
{ "PlayLoadedSound", LUA_OPCODE(Lua_V2, PlayLoadedSound) },
|
||||
{ "StopSound", LUA_OPCODE(Lua_V2, StopSound) },
|
||||
{ "SetGroupVolume", LUA_OPCODE(Lua_V2, SetGroupVolume) },
|
||||
{ "GetSoundVolume", LUA_OPCODE(Lua_V2, GetSoundVolume) },
|
||||
{ "SetSoundVolume", LUA_OPCODE(Lua_V2, SetSoundVolume) },
|
||||
{ "EnableAudioGroup", LUA_OPCODE(Lua_V2, EnableAudioGroup) },
|
||||
{ "EnableVoiceFX", LUA_OPCODE(Lua_V2, EnableVoiceFX) },
|
||||
{ "PlaySoundFrom", LUA_OPCODE(Lua_V2, PlaySoundFrom) },
|
||||
{ "PlayLoadedSoundFrom", LUA_OPCODE(Lua_V2, PlayLoadedSoundFrom) },
|
||||
{ "SetReverb", LUA_OPCODE(Lua_V2, SetReverb) },
|
||||
{ "UpdateSoundPosition", LUA_OPCODE(Lua_V2, UpdateSoundPosition) },
|
||||
{ "ImSelectSet", LUA_OPCODE(Lua_V2, ImSelectSet) },
|
||||
{ "ImStateHasLooped", LUA_OPCODE(Lua_V2, ImStateHasLooped) },
|
||||
{ "ImStateHasEnded", LUA_OPCODE(Lua_V2, ImStateHasEnded) },
|
||||
{ "ImPushState", LUA_OPCODE(Lua_V2, ImPushState) },
|
||||
{ "ImPopState", LUA_OPCODE(Lua_V2, ImPopState) },
|
||||
{ "ImFlushStack", LUA_OPCODE(Lua_V2, ImFlushStack) },
|
||||
{ "ImGetMillisecondPosition", LUA_OPCODE(Lua_V2, ImGetMillisecondPosition) },
|
||||
{ "GetSectorName", LUA_OPCODE(Lua_V2, GetSectorName) },
|
||||
{ "GetCameraYaw", LUA_OPCODE(Lua_V2, GetCameraYaw) },
|
||||
{ "YawCamera", LUA_OPCODE(Lua_V2, YawCamera) },
|
||||
{ "GetCameraPitch", LUA_OPCODE(Lua_V2, GetCameraPitch) },
|
||||
{ "PitchCamera", LUA_OPCODE(Lua_V2, PitchCamera) },
|
||||
{ "RollCamera", LUA_OPCODE(Lua_V2, RollCamera) },
|
||||
{ "UndimAll", LUA_OPCODE(Lua_V2, UndimAll) },
|
||||
{ "UndimRegion", LUA_OPCODE(Lua_V2, UndimRegion) },
|
||||
{ "GetCPUSpeed", LUA_OPCODE(Lua_V2, GetCPUSpeed) },
|
||||
{ "NewLayer", LUA_OPCODE(Lua_V2, NewLayer) },
|
||||
{ "FreeLayer", LUA_OPCODE(Lua_V2, FreeLayer) },
|
||||
{ "SetLayerSortOrder", LUA_OPCODE(Lua_V2, SetLayerSortOrder) },
|
||||
{ "SetLayerFrame", LUA_OPCODE(Lua_V2, SetLayerFrame) },
|
||||
{ "AdvanceLayerFrame", LUA_OPCODE(Lua_V2, AdvanceLayerFrame) },
|
||||
{ "PushText", LUA_OPCODE(Lua_V2, PushText) },
|
||||
{ "PopText", LUA_OPCODE(Lua_V2, PopText) },
|
||||
{ "NukeAllScriptLocks", LUA_OPCODE(Lua_V2, NukeAllScriptLocks) },
|
||||
{ "ToggleDebugDraw", LUA_OPCODE(Lua_V2, ToggleDebugDraw) },
|
||||
{ "ToggleDrawCameras", LUA_OPCODE(Lua_V2, ToggleDrawCameras) },
|
||||
{ "ToggleDrawLights", LUA_OPCODE(Lua_V2, ToggleDrawLights) },
|
||||
{ "ToggleDrawSectors", LUA_OPCODE(Lua_V2, ToggleDrawSectors) },
|
||||
{ "ToggleDrawBBoxes", LUA_OPCODE(Lua_V2, ToggleDrawBBoxes) },
|
||||
{ "ToggleDrawFPS", LUA_OPCODE(Lua_V2, ToggleDrawFPS) },
|
||||
{ "ToggleDrawPerformance", LUA_OPCODE(Lua_V2, ToggleDrawPerformance) },
|
||||
{ "ToggleDrawActorStats", LUA_OPCODE(Lua_V2, ToggleDrawActorStats) },
|
||||
{ "SectEditSelect", LUA_OPCODE(Lua_V2, SectEditSelect) },
|
||||
{ "SectEditPlace", LUA_OPCODE(Lua_V2, SectEditPlace) },
|
||||
{ "SectEditDelete", LUA_OPCODE(Lua_V2, SectEditDelete) },
|
||||
{ "SectEditInsert", LUA_OPCODE(Lua_V2, SectEditInsert) },
|
||||
{ "SectEditSortAdd", LUA_OPCODE(Lua_V2, SectEditSortAdd) },
|
||||
{ "SectEditForgetIt", LUA_OPCODE(Lua_V2, SectEditForgetIt) },
|
||||
{ "GammaEnabled", LUA_OPCODE(Lua_V2, GammaEnabled) },
|
||||
{ "FRUTEY_Begin", LUA_OPCODE(Lua_V2, FRUTEY_Begin) },
|
||||
{ "FRUTEY_End", LUA_OPCODE(Lua_V2, FRUTEY_End) },
|
||||
{ "LocalizeString", LUA_OPCODE(Lua_V2, LocalizeString) },
|
||||
// PS2:
|
||||
{ "GetMemoryCardId", LUA_OPCODE(Lua_V2, GetMemoryCardId) },
|
||||
{ "OverWorldToScreen", LUA_OPCODE(Lua_V2, OverWorldToScreen) },
|
||||
{ "SetReplayMode", LUA_OPCODE(Lua_V2, SetReplayMode) },
|
||||
// ResidualVM-hacks:
|
||||
{ "GetResidualVMPreference", LUA_OPCODE(Lua_V2, GetResidualVMPreference) },
|
||||
{ "SetResidualVMPreference", LUA_OPCODE(Lua_V2, SetResidualVMPreference) }
|
||||
};
|
||||
|
||||
void Lua_V2::registerOpcodes() {
|
||||
Lua_V1::registerOpcodes();
|
||||
|
||||
// Register main opcodes functions
|
||||
luaL_openlib(monkeyMainOpcodes, ARRAYSIZE(monkeyMainOpcodes));
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
194
engines/grim/emi/lua_v2.h
Normal file
194
engines/grim/emi/lua_v2.h
Normal file
@@ -0,0 +1,194 @@
|
||||
/* 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_V2
|
||||
#define GRIM_LUA_V2
|
||||
|
||||
#include "engines/grim/lua_v1.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class Lua_V2 : public Lua_V1 {
|
||||
public:
|
||||
typedef Lua_V2 LuaClass;
|
||||
void registerOpcodes() override;
|
||||
|
||||
protected:
|
||||
bool findCostume(lua_Object costumeObj, Actor *actor, Costume **costume) override;
|
||||
void setChoreAndCostume(lua_Object choreObj, lua_Object costumeObj, Actor *actor, Costume *&costume, int &chore);
|
||||
static uint convertEmiVolumeToMixer(uint emiVolume);
|
||||
static uint convertMixerVolumeToEmi(uint volume);
|
||||
static const uint MAX_EMI_VOLUME = 100;
|
||||
|
||||
DECLARE_LUA_OPCODE(UndimAll);
|
||||
DECLARE_LUA_OPCODE(SetActorLocalAlpha);
|
||||
DECLARE_LUA_OPCODE(UndimRegion);
|
||||
DECLARE_LUA_OPCODE(DimScreen) override;
|
||||
DECLARE_LUA_OPCODE(MakeCurrentSetup) override;
|
||||
DECLARE_LUA_OPCODE(SetActorGlobalAlpha);
|
||||
DECLARE_LUA_OPCODE(ImGetMillisecondPosition);
|
||||
DECLARE_LUA_OPCODE(RemoveActorFromOverworld);
|
||||
DECLARE_LUA_OPCODE(UnloadActor);
|
||||
DECLARE_LUA_OPCODE(SetActorWalkRate) override;
|
||||
DECLARE_LUA_OPCODE(GetActorWalkRate) override;
|
||||
DECLARE_LUA_OPCODE(SetActorTurnRate) override;
|
||||
DECLARE_LUA_OPCODE(SetReverb);
|
||||
DECLARE_LUA_OPCODE(LockBackground);
|
||||
DECLARE_LUA_OPCODE(UnLockBackground);
|
||||
DECLARE_LUA_OPCODE(LockChore);
|
||||
DECLARE_LUA_OPCODE(IsActorChoring) override;
|
||||
DECLARE_LUA_OPCODE(IsChoreValid);
|
||||
DECLARE_LUA_OPCODE(IsChorePlaying);
|
||||
DECLARE_LUA_OPCODE(StopChore);
|
||||
DECLARE_LUA_OPCODE(AdvanceChore);
|
||||
DECLARE_LUA_OPCODE(SetActorSortOrder);
|
||||
DECLARE_LUA_OPCODE(ActorActivateShadow);
|
||||
DECLARE_LUA_OPCODE(ActorStopMoving);
|
||||
DECLARE_LUA_OPCODE(ActorLookAt) override;
|
||||
DECLARE_LUA_OPCODE(PutActorInOverworld);
|
||||
DECLARE_LUA_OPCODE(GetActorWorldPos);
|
||||
DECLARE_LUA_OPCODE(MakeScreenTextures);
|
||||
DECLARE_LUA_OPCODE(PutActorInSet) override;
|
||||
DECLARE_LUA_OPCODE(LoadBundle) override;
|
||||
DECLARE_LUA_OPCODE(AreWeInternational);
|
||||
DECLARE_LUA_OPCODE(ImSetState) override;
|
||||
DECLARE_LUA_OPCODE(EnableVoiceFX);
|
||||
DECLARE_LUA_OPCODE(SetGroupVolume);
|
||||
DECLARE_LUA_OPCODE(EnableAudioGroup);
|
||||
DECLARE_LUA_OPCODE(ImSelectSet);
|
||||
DECLARE_LUA_OPCODE(GetActorChores) override;
|
||||
DECLARE_LUA_OPCODE(PlayActorChore) override;
|
||||
DECLARE_LUA_OPCODE(StopActorChores);
|
||||
DECLARE_LUA_OPCODE(SetActorLighting);
|
||||
DECLARE_LUA_OPCODE(SetActorCollisionMode) override;
|
||||
DECLARE_LUA_OPCODE(SetActorCollisionScale) override;
|
||||
DECLARE_LUA_OPCODE(GetActorPuckVector) override;
|
||||
DECLARE_LUA_OPCODE(SetActorHeadLimits);
|
||||
DECLARE_LUA_OPCODE(SetActorHead) override;
|
||||
DECLARE_LUA_OPCODE(SetActorFOV);
|
||||
DECLARE_LUA_OPCODE(AttachActor);
|
||||
DECLARE_LUA_OPCODE(DetachActor);
|
||||
DECLARE_LUA_OPCODE(GetCPUSpeed);
|
||||
DECLARE_LUA_OPCODE(StartMovie) override;
|
||||
DECLARE_LUA_OPCODE(IsMoviePlaying) override;
|
||||
DECLARE_LUA_OPCODE(SetActiveCD);
|
||||
DECLARE_LUA_OPCODE(GetActiveCD);
|
||||
DECLARE_LUA_OPCODE(PurgeText) override;
|
||||
DECLARE_LUA_OPCODE(ImFlushStack);
|
||||
DECLARE_LUA_OPCODE(LoadSound);
|
||||
DECLARE_LUA_OPCODE(ImSetMusicVol) override;
|
||||
DECLARE_LUA_OPCODE(ImSetSfxVol) override;
|
||||
DECLARE_LUA_OPCODE(ImSetVoiceVol) override;
|
||||
DECLARE_LUA_OPCODE(ImSetVoiceEffect) override;
|
||||
DECLARE_LUA_OPCODE(ToggleOverworld);
|
||||
DECLARE_LUA_OPCODE(ScreenshotForSavegame);
|
||||
DECLARE_LUA_OPCODE(EngineDisplay) override;
|
||||
DECLARE_LUA_OPCODE(SetAmbientLight) override;
|
||||
DECLARE_LUA_OPCODE(Display) override;
|
||||
DECLARE_LUA_OPCODE(ThumbnailFromFile);
|
||||
DECLARE_LUA_OPCODE(ClearSpecialtyTexture);
|
||||
DECLARE_LUA_OPCODE(ClearOverworld);
|
||||
DECLARE_LUA_OPCODE(EnableActorPuck);
|
||||
DECLARE_LUA_OPCODE(GetActorSortOrder);
|
||||
DECLARE_LUA_OPCODE(IsChoreLooping);
|
||||
DECLARE_LUA_OPCODE(SetChoreLooping);
|
||||
DECLARE_LUA_OPCODE(PlayChore);
|
||||
DECLARE_LUA_OPCODE(PauseChore);
|
||||
DECLARE_LUA_OPCODE(CompleteChore);
|
||||
DECLARE_LUA_OPCODE(UnlockChore);
|
||||
DECLARE_LUA_OPCODE(LockChoreSet);
|
||||
DECLARE_LUA_OPCODE(UnlockChoreSet);
|
||||
DECLARE_LUA_OPCODE(EscapeMovie);
|
||||
DECLARE_LUA_OPCODE(StopAllSounds);
|
||||
DECLARE_LUA_OPCODE(FreeSound);
|
||||
DECLARE_LUA_OPCODE(PlayLoadedSound);
|
||||
DECLARE_LUA_OPCODE(StopSound);
|
||||
DECLARE_LUA_OPCODE(PlaySound) override;
|
||||
DECLARE_LUA_OPCODE(IsSoundPlaying) override;
|
||||
DECLARE_LUA_OPCODE(GetSoundVolume);
|
||||
DECLARE_LUA_OPCODE(SetSoundVolume);
|
||||
DECLARE_LUA_OPCODE(PlaySoundFrom);
|
||||
DECLARE_LUA_OPCODE(PlayLoadedSoundFrom);
|
||||
DECLARE_LUA_OPCODE(UpdateSoundPosition);
|
||||
DECLARE_LUA_OPCODE(ImStateHasLooped);
|
||||
DECLARE_LUA_OPCODE(ImStateHasEnded);
|
||||
DECLARE_LUA_OPCODE(ImPushState);
|
||||
DECLARE_LUA_OPCODE(ImPopState);
|
||||
DECLARE_LUA_OPCODE(ImPause) override;
|
||||
DECLARE_LUA_OPCODE(ImResume) override;
|
||||
DECLARE_LUA_OPCODE(GetSectorName);
|
||||
DECLARE_LUA_OPCODE(GetCameraYaw);
|
||||
DECLARE_LUA_OPCODE(YawCamera);
|
||||
DECLARE_LUA_OPCODE(GetCameraPitch);
|
||||
DECLARE_LUA_OPCODE(GetCameraRoll) override;
|
||||
DECLARE_LUA_OPCODE(PitchCamera);
|
||||
DECLARE_LUA_OPCODE(RollCamera);
|
||||
DECLARE_LUA_OPCODE(NewLayer);
|
||||
DECLARE_LUA_OPCODE(FreeLayer);
|
||||
DECLARE_LUA_OPCODE(SetLayerSortOrder);
|
||||
DECLARE_LUA_OPCODE(SetLayerFrame);
|
||||
DECLARE_LUA_OPCODE(AdvanceLayerFrame);
|
||||
DECLARE_LUA_OPCODE(PushText);
|
||||
DECLARE_LUA_OPCODE(PopText);
|
||||
DECLARE_LUA_OPCODE(NukeAllScriptLocks);
|
||||
DECLARE_LUA_OPCODE(ToggleDebugDraw);
|
||||
DECLARE_LUA_OPCODE(ToggleDrawCameras);
|
||||
DECLARE_LUA_OPCODE(ToggleDrawLights);
|
||||
DECLARE_LUA_OPCODE(ToggleDrawSectors);
|
||||
DECLARE_LUA_OPCODE(ToggleDrawBBoxes);
|
||||
DECLARE_LUA_OPCODE(ToggleDrawFPS);
|
||||
DECLARE_LUA_OPCODE(ToggleDrawPerformance);
|
||||
DECLARE_LUA_OPCODE(ToggleDrawActorStats);
|
||||
DECLARE_LUA_OPCODE(SectEditSelect);
|
||||
DECLARE_LUA_OPCODE(SectEditPlace);
|
||||
DECLARE_LUA_OPCODE(SectEditDelete);
|
||||
DECLARE_LUA_OPCODE(SectEditInsert);
|
||||
DECLARE_LUA_OPCODE(SectEditSortAdd);
|
||||
DECLARE_LUA_OPCODE(SectEditForgetIt);
|
||||
DECLARE_LUA_OPCODE(FRUTEY_Begin);
|
||||
DECLARE_LUA_OPCODE(FRUTEY_End);
|
||||
DECLARE_LUA_OPCODE(GetFontDimensions) override;
|
||||
DECLARE_LUA_OPCODE(GetTextObjectDimensions) override;
|
||||
DECLARE_LUA_OPCODE(GetTextCharPosition) override;
|
||||
DECLARE_LUA_OPCODE(SetActorRestChore) override;
|
||||
DECLARE_LUA_OPCODE(SetActorWalkChore) override;
|
||||
DECLARE_LUA_OPCODE(SetActorTurnChores) override;
|
||||
DECLARE_LUA_OPCODE(SetActorTalkChore) override;
|
||||
DECLARE_LUA_OPCODE(SetActorMumblechore) override;
|
||||
DECLARE_LUA_OPCODE(GammaEnabled);
|
||||
DECLARE_LUA_OPCODE(FileFindFirst) override;
|
||||
DECLARE_LUA_OPCODE(WalkActorToAvoiding) override;
|
||||
DECLARE_LUA_OPCODE(WalkActorVector) override;
|
||||
DECLARE_LUA_OPCODE(LocalizeString) override;
|
||||
DECLARE_LUA_OPCODE(WorldToScreen) override;
|
||||
DECLARE_LUA_OPCODE(RenderModeUser) override;
|
||||
// PS2:
|
||||
DECLARE_LUA_OPCODE(GetMemoryCardId);
|
||||
DECLARE_LUA_OPCODE(OverWorldToScreen);
|
||||
DECLARE_LUA_OPCODE(SetReplayMode);
|
||||
// ResidualVM-hacks:
|
||||
DECLARE_LUA_OPCODE(GetResidualVMPreference);
|
||||
DECLARE_LUA_OPCODE(SetResidualVMPreference);
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
1098
engines/grim/emi/lua_v2_actor.cpp
Normal file
1098
engines/grim/emi/lua_v2_actor.cpp
Normal file
File diff suppressed because it is too large
Load Diff
592
engines/grim/emi/lua_v2_sound.cpp
Normal file
592
engines/grim/emi/lua_v2_sound.cpp
Normal file
@@ -0,0 +1,592 @@
|
||||
/* 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 "audio/mixer.h"
|
||||
#include "audio/audiostream.h"
|
||||
|
||||
#include "common/system.h"
|
||||
|
||||
#include "engines/grim/set.h"
|
||||
#include "engines/grim/emi/sound/emisound.h"
|
||||
#include "engines/grim/emi/lua_v2.h"
|
||||
#include "engines/grim/emi/poolsound.h"
|
||||
#include "engines/grim/lua/lua.h"
|
||||
#include "engines/grim/debug.h"
|
||||
#include "engines/grim/sound.h"
|
||||
#include "engines/grim/grim.h"
|
||||
#include "engines/grim/resource.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
// Helper function, not called from LUA directly
|
||||
uint Lua_V2::convertEmiVolumeToMixer(uint emiVolume) {
|
||||
// EmiVolume range: 0 .. 100
|
||||
// Mixer range: 0 .. kMaxChannelVolume
|
||||
float vol = float(emiVolume) / MAX_EMI_VOLUME * Audio::Mixer::kMaxChannelVolume;
|
||||
return CLIP<uint>(uint(vol), 0, Audio::Mixer::kMaxChannelVolume);
|
||||
}
|
||||
|
||||
// Helper function, not called from LUA directly
|
||||
uint Lua_V2::convertMixerVolumeToEmi(uint volume) {
|
||||
float vol = float(volume) * MAX_EMI_VOLUME / Audio::Mixer::kMaxChannelVolume;
|
||||
return CLIP<uint>(uint(vol), 0, MAX_EMI_VOLUME);
|
||||
}
|
||||
|
||||
// Note: debug output for volume values uses the engine's mixer range
|
||||
|
||||
void Lua_V2::ImGetMillisecondPosition() {
|
||||
lua_Object soundObj = lua_getparam(1);
|
||||
|
||||
if (lua_isnumber(soundObj)) {
|
||||
int sound = (int)lua_getnumber(soundObj);
|
||||
// FIXME int ms = func(sound);
|
||||
// lua_pushnumber(ms);
|
||||
// push -1 for now
|
||||
// Currently a bit of guesswork, and probably wrong, as the stateId
|
||||
// is ignored by emisound (which only has one music-track now).
|
||||
uint32 msPos = g_emiSound->getMsPos(sound);
|
||||
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::ImGetMillisecondPosition: sound: %d ms: %d", sound, msPos);
|
||||
lua_pushnumber(msPos);
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::SetReverb() {
|
||||
lua_Object eaxObj = lua_getparam(1);
|
||||
lua_Object decayObj = lua_getparam(2);
|
||||
lua_Object mixObj = lua_getparam(3);
|
||||
lua_Object predelayObj = lua_getparam(4);
|
||||
lua_Object dampingObj = lua_getparam(5);
|
||||
|
||||
if (!lua_isnumber(eaxObj))
|
||||
return;
|
||||
|
||||
int eax = (int)lua_getnumber(eaxObj);
|
||||
int param = 0;
|
||||
float decay = -1;
|
||||
float mix = -1;
|
||||
float predelay = -1;
|
||||
float damping = -1;
|
||||
|
||||
if (eax == 60) {
|
||||
param = 26;
|
||||
} else if (eax == 70) {
|
||||
param = 27;
|
||||
} else if (eax >= 0 && eax <= 25) {
|
||||
param = eax;
|
||||
// there is some table, initialy is like eax
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (lua_isnumber(decayObj))
|
||||
decay = lua_getnumber(decayObj);
|
||||
if (lua_isnumber(mixObj))
|
||||
mix = lua_getnumber(mixObj);
|
||||
if (lua_isnumber(predelayObj))
|
||||
predelay = lua_getnumber(predelayObj);
|
||||
if (lua_isnumber(dampingObj))
|
||||
damping = lua_getnumber(dampingObj);
|
||||
|
||||
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::SetReverb, eax: %d, decay: %f, mix: %f, predelay: %f, damping: %f", param, decay, mix, predelay, damping);
|
||||
// FIXME: func(param, decay, mix, predelay, damping);
|
||||
}
|
||||
|
||||
void Lua_V2::ImSetState() {
|
||||
lua_Object stateObj = lua_getparam(1);
|
||||
if (!lua_isnumber(stateObj))
|
||||
return;
|
||||
|
||||
int state = (int)lua_getnumber(stateObj);
|
||||
g_imuseState = state;
|
||||
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::ImSetState: stub, state: %d", state);
|
||||
}
|
||||
|
||||
void Lua_V2::ImStateHasEnded() {
|
||||
lua_Object stateObj = lua_getparam(1);
|
||||
if (!lua_isnumber(stateObj))
|
||||
return;
|
||||
|
||||
int state = (int)lua_getnumber(stateObj);
|
||||
|
||||
pushbool(g_emiSound->stateHasEnded(state));
|
||||
|
||||
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::ImStateHasEnded: state %d.", state);
|
||||
}
|
||||
|
||||
// TODO: Implement this:
|
||||
void Lua_V2::ImStateHasLooped() {
|
||||
lua_Object stateObj = lua_getparam(1);
|
||||
if (!lua_isnumber(stateObj))
|
||||
return;
|
||||
|
||||
int state = (int)lua_getnumber(stateObj);
|
||||
|
||||
pushbool(g_emiSound->stateHasLooped(state));
|
||||
}
|
||||
|
||||
void Lua_V2::EnableVoiceFX() {
|
||||
lua_Object stateObj = lua_getparam(1);
|
||||
|
||||
bool state = false;
|
||||
if (!lua_isnil(stateObj))
|
||||
state = true;
|
||||
|
||||
// FIXME: func(state);
|
||||
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::EnableVoiceFX: implement opcode, state: %d", (int)state);
|
||||
}
|
||||
|
||||
void Lua_V2::SetGroupVolume() {
|
||||
lua_Object groupObj = lua_getparam(1);
|
||||
lua_Object volumeObj = lua_getparam(2);
|
||||
|
||||
if (!lua_isnumber(groupObj))
|
||||
return;
|
||||
int group = (int)lua_getnumber(groupObj);
|
||||
|
||||
int volume = Audio::Mixer::kMaxChannelVolume;
|
||||
if (lua_isnumber(volumeObj))
|
||||
volume = convertEmiVolumeToMixer((int)lua_getnumber(volumeObj));
|
||||
|
||||
switch (group) {
|
||||
case 1: // SFX
|
||||
g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume);
|
||||
g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, volume);
|
||||
break;
|
||||
case 2: // Voice
|
||||
g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, volume);
|
||||
break;
|
||||
case 3: // Music
|
||||
g_system->getMixer()->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume);
|
||||
break;
|
||||
default:
|
||||
error("Lua_V2::SetGroupVolume - unknown group %d", group);
|
||||
}
|
||||
// FIXME: func(group, volume);
|
||||
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::SetGroupVolume: group: %d, volume %d", group, volume);
|
||||
}
|
||||
|
||||
void Lua_V2::EnableAudioGroup() {
|
||||
lua_Object groupObj = lua_getparam(1);
|
||||
lua_Object stateObj = lua_getparam(2);
|
||||
|
||||
if (!lua_isnumber(groupObj))
|
||||
return;
|
||||
int group = (int)lua_getnumber(groupObj);
|
||||
|
||||
bool state = false;
|
||||
if (!lua_isnil(stateObj))
|
||||
state = true;
|
||||
|
||||
// FIXME: func(group, state);
|
||||
switch (group) {
|
||||
case 1: // SFX
|
||||
g_system->getMixer()->muteSoundType(Audio::Mixer::kSFXSoundType, !state);
|
||||
g_system->getMixer()->muteSoundType(Audio::Mixer::kPlainSoundType, !state);
|
||||
break;
|
||||
case 2: // Voice
|
||||
g_system->getMixer()->muteSoundType(Audio::Mixer::kSpeechSoundType, !state);
|
||||
break;
|
||||
case 3: // Music
|
||||
g_system->getMixer()->muteSoundType(Audio::Mixer::kMusicSoundType, !state);
|
||||
break;
|
||||
default:
|
||||
error("Lua_V2::EnableAudioGroup - unknown group %d", group);
|
||||
}
|
||||
|
||||
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::EnableAudioGroup: group: %d, state %d", group, (int)state);
|
||||
}
|
||||
|
||||
void Lua_V2::ImSelectSet() {
|
||||
lua_Object qualityObj = lua_getparam(1);
|
||||
|
||||
if (lua_isnumber(qualityObj)) {
|
||||
int quality = (int)lua_getnumber(qualityObj);
|
||||
// FIXME: func(quality);
|
||||
g_emiSound->selectMusicSet(quality);
|
||||
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::ImSelectSet: quality mode: %d", quality);
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::ImFlushStack() {
|
||||
// FIXME
|
||||
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::ImFlushStack: currently guesswork");
|
||||
g_emiSound->flushStack();
|
||||
}
|
||||
|
||||
static Common::String addSoundSuffix(const char *fname) {
|
||||
Common::String filename = fname;
|
||||
if (!(g_grim->getGameFlags() & ADGF_DEMO)) {
|
||||
if (g_grim->getGamePlatform() == Common::kPlatformPS2) {
|
||||
filename += ".scx";
|
||||
} else {
|
||||
if (!filename.hasSuffix(".aif") && !filename.hasSuffix(".AIF")) {
|
||||
filename += ".aif";
|
||||
}
|
||||
}
|
||||
}
|
||||
return filename;
|
||||
}
|
||||
|
||||
void Lua_V2::LoadSound() {
|
||||
lua_Object strObj = lua_getparam(1);
|
||||
|
||||
if (!lua_isstring(strObj))
|
||||
return;
|
||||
|
||||
const char *str = lua_getstring(strObj);
|
||||
|
||||
Common::String filename = addSoundSuffix(str);
|
||||
|
||||
PoolSound *sound = new PoolSound(filename);
|
||||
lua_pushusertag(sound->getId(), MKTAG('A', 'I', 'F', 'F'));
|
||||
}
|
||||
|
||||
void Lua_V2::FreeSound() {
|
||||
lua_Object idObj = lua_getparam(1);
|
||||
if (!lua_isuserdata(idObj) || lua_tag(idObj) != MKTAG('A', 'I', 'F', 'F'))
|
||||
return;
|
||||
PoolSound *sound = PoolSound::getPool().getObject(lua_getuserdata(idObj));
|
||||
delete sound;
|
||||
}
|
||||
|
||||
void Lua_V2::PlayLoadedSound() {
|
||||
lua_Object idObj = lua_getparam(1);
|
||||
lua_Object loopingObj = lua_getparam(2);
|
||||
lua_Object volumeObj = lua_getparam(3);
|
||||
// FIXME: unknown parameter
|
||||
/*lua_Object bool2Obj =*/ lua_getparam(4);
|
||||
|
||||
if (!lua_isuserdata(idObj) || lua_tag(idObj) != MKTAG('A', 'I', 'F', 'F')) {
|
||||
// can't use error since it actually may happen:
|
||||
// when entering the bait shop after the termites were already put on Mandrill's cane,
|
||||
// the LUA code will not load the termite sound files but the script which starts
|
||||
// the sounds is running anyway
|
||||
warning("Lua_V2::PlayLoadedSound - ERROR: Unknown parameters");
|
||||
return;
|
||||
}
|
||||
|
||||
bool looping = !lua_isnil(loopingObj);
|
||||
|
||||
PoolSound *sound = PoolSound::getPool().getObject(lua_getuserdata(idObj));
|
||||
if (!sound) {
|
||||
warning("Lua_V2::PlayLoadedSound: can't find requested sound object");
|
||||
return;
|
||||
}
|
||||
|
||||
int volume = MAX_EMI_VOLUME;
|
||||
if (!lua_isnumber(volumeObj)) {
|
||||
// In the demo when the dart hits the balloon in the scumm bar, nil is passed
|
||||
// to the volume parameter.
|
||||
warning("Lua_V2::PlayLoadedSound - Unexpected parameter found, using default volume");
|
||||
} else {
|
||||
volume = (int)lua_getnumber(volumeObj);
|
||||
}
|
||||
sound->setVolume(convertEmiVolumeToMixer(volume));
|
||||
sound->play(looping);
|
||||
}
|
||||
|
||||
void Lua_V2::PlayLoadedSoundFrom() {
|
||||
lua_Object idObj = lua_getparam(1);
|
||||
lua_Object xObj = lua_getparam(2);
|
||||
lua_Object yObj = lua_getparam(3);
|
||||
lua_Object zObj = lua_getparam(4);
|
||||
lua_Object volumeOrLoopingObj = lua_getparam(5);
|
||||
lua_Object volumeObj = lua_getparam(6);
|
||||
|
||||
if (!lua_isuserdata(idObj) || lua_tag(idObj) != MKTAG('A', 'I', 'F', 'F')) {
|
||||
warning("Lua_V2::PlayLoadedSoundFrom - ERROR: Unknown parameters");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!lua_isnumber(xObj) || !lua_isnumber(yObj) || !lua_isnumber(zObj) ||
|
||||
!lua_isnumber(volumeObj)) {
|
||||
error("Lua_V2::PlayLoadedSoundFrom - ERROR: Unknown parameters");
|
||||
return;
|
||||
}
|
||||
|
||||
float x = lua_getnumber(xObj);
|
||||
float y = lua_getnumber(yObj);
|
||||
float z = lua_getnumber(zObj);
|
||||
|
||||
int volume = MAX_EMI_VOLUME;
|
||||
bool looping = false;
|
||||
|
||||
if (lua_isnumber(volumeOrLoopingObj)) {
|
||||
volume = (int)lua_getnumber(volumeOrLoopingObj);
|
||||
// special handling if 5th parameter is a boolean
|
||||
if (volume <= 1) {
|
||||
looping = volume;
|
||||
volume = (int)lua_getnumber(volumeObj);
|
||||
}
|
||||
} else {
|
||||
volume = (int)lua_getnumber(volumeObj);
|
||||
looping = !lua_isnil(volumeOrLoopingObj);
|
||||
}
|
||||
|
||||
PoolSound *sound = PoolSound::getPool().getObject(lua_getuserdata(idObj));
|
||||
if (!sound) {
|
||||
warning("Lua_V2::PlayLoadedSoundFrom: can't find requested sound object");
|
||||
return;
|
||||
}
|
||||
Math::Vector3d pos(x, y, z);
|
||||
sound->setVolume(convertEmiVolumeToMixer(volume));
|
||||
sound->playFrom(pos, looping);
|
||||
}
|
||||
|
||||
void Lua_V2::StopSound() {
|
||||
lua_Object idObj = lua_getparam(1);
|
||||
|
||||
if (!lua_isuserdata(idObj) || lua_tag(idObj) != MKTAG('A', 'I', 'F', 'F')) {
|
||||
warning("Lua_V2::StopSound - ERROR: Unknown parameters");
|
||||
return;
|
||||
}
|
||||
|
||||
PoolSound *sound = PoolSound::getPool().getObject(lua_getuserdata(idObj));
|
||||
if (!sound) {
|
||||
warning("Lua_V2::StopSound: can't find requested sound object");
|
||||
return;
|
||||
}
|
||||
sound->stop();
|
||||
}
|
||||
|
||||
void Lua_V2::IsSoundPlaying() {
|
||||
lua_Object idObj = lua_getparam(1);
|
||||
|
||||
if (!lua_isuserdata(idObj) || lua_tag(idObj) != MKTAG('A', 'I', 'F', 'F')) {
|
||||
// can't use error since it actually may happen during normal operation
|
||||
warning("Lua_V2::IsSoundPlaying - ERROR: Unknown parameters");
|
||||
pushbool(false);
|
||||
return;
|
||||
}
|
||||
|
||||
PoolSound *sound = PoolSound::getPool().getObject(lua_getuserdata(idObj));
|
||||
if (sound) {
|
||||
if (sound->isPlaying()) {
|
||||
pushbool(true);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
warning("Lua_V2::IsSoundPlaying: no sound track associated");
|
||||
}
|
||||
pushbool(false);
|
||||
}
|
||||
|
||||
void Lua_V2::PlaySound() {
|
||||
lua_Object strObj = lua_getparam(1);
|
||||
lua_Object volumeObj = lua_getparam(2);
|
||||
|
||||
if (!lua_isstring(strObj)) {
|
||||
error("Lua_V2::PlaySound - ERROR: Unknown parameters");
|
||||
return;
|
||||
}
|
||||
const char *str = lua_getstring(strObj);
|
||||
|
||||
int volume = MAX_EMI_VOLUME;
|
||||
if (!lua_isnumber(volumeObj)) {
|
||||
warning("Lua_V2::PlaySound - Unexpected parameter(s) found, using default volume for %s", str);
|
||||
} else {
|
||||
volume = (int)lua_getnumber(volumeObj);
|
||||
}
|
||||
|
||||
Common::String filename = addSoundSuffix(str);
|
||||
|
||||
if (!g_emiSound->startSfx(filename, convertEmiVolumeToMixer(volume))) {
|
||||
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::PlaySound: Could not open sound '%s'", filename.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::PlaySoundFrom() {
|
||||
lua_Object strObj = lua_getparam(1);
|
||||
lua_Object xObj = lua_getparam(2);
|
||||
lua_Object yObj = lua_getparam(3);
|
||||
lua_Object zObj = lua_getparam(4);
|
||||
// FIXME: unknown parameter
|
||||
lua_Object volumeOrUnknownObj = lua_getparam(5);
|
||||
lua_Object volumeObj = lua_getparam(6);
|
||||
|
||||
int volume = MAX_EMI_VOLUME;
|
||||
|
||||
if (!lua_isstring(strObj)) {
|
||||
error("Lua_V2::PlaySoundFrom - ERROR: Unknown parameters");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!lua_isnumber(xObj) || !lua_isnumber(yObj) || !lua_isnumber(zObj)) {
|
||||
error("Lua_V2::PlayLoadedSoundFrom - ERROR: Unknown parameters");
|
||||
return;
|
||||
}
|
||||
float x = lua_getnumber(xObj);
|
||||
float y = lua_getnumber(yObj);
|
||||
float z = lua_getnumber(zObj);
|
||||
|
||||
// arg5 is optional and if present, it is FALSE
|
||||
if (lua_isnumber(volumeObj)) {
|
||||
volume = (int)lua_getnumber(volumeObj);
|
||||
} else if (lua_isnumber(volumeOrUnknownObj)) {
|
||||
volume = (int)lua_getnumber(volumeOrUnknownObj);
|
||||
} else {
|
||||
error("Lua_V2::PlaySoundFrom - ERROR: Unknown parameters");
|
||||
return;
|
||||
}
|
||||
|
||||
const char *str = lua_getstring(strObj);
|
||||
Common::String filename = addSoundSuffix(str);
|
||||
|
||||
Math::Vector3d pos(x, y, z);
|
||||
|
||||
if (!g_emiSound->startSfxFrom(filename.c_str(), pos, convertEmiVolumeToMixer(volume))) {
|
||||
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::PlaySoundFrom: Could not open sound '%s'", filename.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::GetSoundVolume() {
|
||||
lua_Object idObj = lua_getparam(1);
|
||||
if (!lua_isuserdata(idObj) || lua_tag(idObj) != MKTAG('A', 'I', 'F', 'F')) {
|
||||
error("Lua_V2::GetSoundVolume: Unknown Parameters");
|
||||
return;
|
||||
}
|
||||
PoolSound *sound = PoolSound::getPool().getObject(lua_getuserdata(idObj));
|
||||
if (sound) {
|
||||
lua_pushnumber(convertMixerVolumeToEmi(sound->getVolume()));
|
||||
} else {
|
||||
warning("Lua_V2::GetSoundVolume: can't find sound track");
|
||||
lua_pushnumber(convertMixerVolumeToEmi(Audio::Mixer::kMaxChannelVolume));
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::SetSoundVolume() {
|
||||
lua_Object idObj = lua_getparam(1);
|
||||
lua_Object volumeObj = lua_getparam(2);
|
||||
if (!lua_isuserdata(idObj) || lua_tag(idObj) != MKTAG('A', 'I', 'F', 'F')) {
|
||||
error("Lua_V2::SetSoundVolume: no valid sound id");
|
||||
return;
|
||||
}
|
||||
if (!lua_isnumber(volumeObj)) {
|
||||
error("Lua_V2::SetSoundVolume - ERROR: Unknown parameters");
|
||||
return;
|
||||
}
|
||||
|
||||
int volume = (int)lua_getnumber(volumeObj);
|
||||
PoolSound *sound = PoolSound::getPool().getObject(lua_getuserdata(idObj));
|
||||
|
||||
if (sound) {
|
||||
sound->setVolume(convertEmiVolumeToMixer(volume));
|
||||
} else {
|
||||
warning("Lua_V2:SetSoundVolume: can't find sound track");
|
||||
}
|
||||
}
|
||||
|
||||
void Lua_V2::UpdateSoundPosition() {
|
||||
lua_Object idObj = lua_getparam(1);
|
||||
lua_Object param2 = lua_getparam(2);
|
||||
lua_Object param3 = lua_getparam(3);
|
||||
lua_Object param4 = lua_getparam(4);
|
||||
|
||||
if (!lua_isuserdata(idObj) || lua_tag(idObj) != MKTAG('A', 'I', 'F', 'F'))
|
||||
return;
|
||||
|
||||
if (!lua_isnumber(param2) || !lua_isnumber(param3) || !lua_isnumber(param4))
|
||||
return;
|
||||
|
||||
float x = lua_getnumber(param2);
|
||||
float y = lua_getnumber(param3);
|
||||
float z = lua_getnumber(param4);
|
||||
PoolSound *sound = PoolSound::getPool().getObject(lua_getuserdata(idObj));
|
||||
if (!sound)
|
||||
return;
|
||||
Math::Vector3d pos(x, y, z);
|
||||
sound->setPosition(pos);
|
||||
}
|
||||
|
||||
void Lua_V2::ImSetMusicVol() {
|
||||
// This only seems to be used in the demo.
|
||||
lua_Object volumeObj = lua_getparam(1);
|
||||
|
||||
if (!lua_isnumber(volumeObj))
|
||||
return;
|
||||
int volume = (int)lua_getnumber(volumeObj);
|
||||
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::ImSetMusicVol: implement opcode, wants volume %d", convertEmiVolumeToMixer(volume));
|
||||
}
|
||||
|
||||
void Lua_V2::ImSetSfxVol() {
|
||||
// This only seems to be used in the demo.
|
||||
lua_Object volumeObj = lua_getparam(1);
|
||||
|
||||
if (!lua_isnumber(volumeObj))
|
||||
return;
|
||||
int volume = (int)lua_getnumber(volumeObj);
|
||||
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::ImSetSfxVol: implement opcode, wants volume %d", convertEmiVolumeToMixer(volume));
|
||||
}
|
||||
|
||||
void Lua_V2::ImSetVoiceVol() {
|
||||
// This only seems to be used in the demo.
|
||||
lua_Object volumeObj = lua_getparam(1);
|
||||
|
||||
if (!lua_isnumber(volumeObj))
|
||||
return;
|
||||
int volume = (int)lua_getnumber(volumeObj);
|
||||
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::ImSetVoiceVol: implement opcode, wants volume %d", convertEmiVolumeToMixer(volume));
|
||||
}
|
||||
|
||||
void Lua_V2::ImSetVoiceEffect() {
|
||||
// This only seems to be used in the demo.
|
||||
lua_Object strObj = lua_getparam(1);
|
||||
|
||||
if (!lua_isstring(strObj))
|
||||
return;
|
||||
|
||||
const char *str = lua_getstring(strObj);
|
||||
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::ImSetVoiceEffect: implement opcode, wants effect %s", str);
|
||||
}
|
||||
|
||||
void Lua_V2::StopAllSounds() {
|
||||
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::StopAllSounds: implement opcode");
|
||||
}
|
||||
|
||||
void Lua_V2::ImPushState() {
|
||||
lua_Object stateObj = lua_getparam(1);
|
||||
//lua_Object unknownBoolObj = lua_getparam(2);
|
||||
|
||||
g_emiSound->pushStateToStack();
|
||||
|
||||
if (lua_isnumber(stateObj)) {
|
||||
int state = (int)lua_getnumber(stateObj);
|
||||
g_imuseState = state;
|
||||
}
|
||||
|
||||
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::ImPushState: currently guesswork");
|
||||
}
|
||||
void Lua_V2::ImPopState() {
|
||||
g_emiSound->popStateFromStack();
|
||||
Debug::debug(Debug::Sound | Debug::Scripts, "Lua_V2::ImPopState: currently guesswork");
|
||||
}
|
||||
|
||||
// Used in the demo only.
|
||||
void Lua_V2::ImPause() {
|
||||
g_emiSound->pause(true);
|
||||
}
|
||||
|
||||
// Used in the demo only.
|
||||
void Lua_V2::ImResume() {
|
||||
g_emiSound->pause(false);
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
484
engines/grim/emi/modelemi.cpp
Normal file
484
engines/grim/emi/modelemi.cpp
Normal file
@@ -0,0 +1,484 @@
|
||||
/* 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/endian.h"
|
||||
|
||||
#include "engines/grim/debug.h"
|
||||
#include "engines/grim/grim.h"
|
||||
#include "engines/grim/material.h"
|
||||
#include "engines/grim/gfx_base.h"
|
||||
#include "engines/grim/resource.h"
|
||||
#include "engines/grim/set.h"
|
||||
#include "engines/grim/emi/costumeemi.h"
|
||||
#include "engines/grim/emi/modelemi.h"
|
||||
#include "engines/grim/emi/animationemi.h"
|
||||
#include "engines/grim/emi/skeleton.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
struct Vector3int {
|
||||
uint16 _x;
|
||||
uint16 _y;
|
||||
uint16 _z;
|
||||
void setVal(uint16 x, uint16 y, uint16 z) {
|
||||
_x = x; _y = y; _z = z;
|
||||
}
|
||||
};
|
||||
|
||||
struct BoneInfo {
|
||||
int _incFac;
|
||||
int _joint;
|
||||
float _weight;
|
||||
};
|
||||
|
||||
Common::String readLAString(Common::ReadStream *ms) {
|
||||
int strLength = ms->readUint32LE();
|
||||
char *readString = new char[strLength];
|
||||
ms->read(readString, strLength);
|
||||
|
||||
Common::String retVal(readString);
|
||||
delete[] readString;
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
void EMIMeshFace::loadFace(Common::SeekableReadStream *data) {
|
||||
_flags = data->readUint32LE();
|
||||
_hasTexture = data->readUint32LE();
|
||||
|
||||
if (_hasTexture)
|
||||
_texID = data->readUint32LE();
|
||||
_faceLength = data->readUint32LE();
|
||||
_faceLength = _faceLength / 3;
|
||||
int x = 0, y = 0, z = 0;
|
||||
_indexes = new Vector3int[_faceLength];
|
||||
int j = 0;
|
||||
for (uint32 i = 0; i < _faceLength; i ++) {
|
||||
if (g_grim->getGamePlatform() == Common::kPlatformPS2) {
|
||||
x = data->readUint32LE();
|
||||
y = data->readUint32LE();
|
||||
z = data->readUint32LE();
|
||||
} else {
|
||||
x = data->readUint16LE();
|
||||
y = data->readUint16LE();
|
||||
z = data->readUint16LE();
|
||||
}
|
||||
_indexes[j++].setVal(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
EMIMeshFace::~EMIMeshFace() {
|
||||
delete[] _indexes;
|
||||
}
|
||||
|
||||
void EMIModel::setTex(uint32 index) {
|
||||
if (index < _numTextures && _mats[index]) {
|
||||
_mats[index]->select();
|
||||
g_driver->setBlendMode(_texFlags[index] & BlendAdditive);
|
||||
}
|
||||
}
|
||||
|
||||
void EMIModel::loadMesh(Common::SeekableReadStream *data) {
|
||||
//int strLength = 0; // Useful for PS2-strings
|
||||
|
||||
Common::String nameString = readLAString(data);
|
||||
|
||||
for (uint l = 0; l < nameString.size(); ++l) {
|
||||
if (nameString[l] == '\\') {
|
||||
nameString.setChar('/', l);
|
||||
}
|
||||
}
|
||||
_meshName = nameString;
|
||||
_radius = data->readFloatLE();
|
||||
_center->readFromStream(data);
|
||||
|
||||
_boxData->readFromStream(data);
|
||||
_boxData2->readFromStream(data);
|
||||
|
||||
_numTexSets = data->readUint32LE();
|
||||
_setType = data->readUint32LE();
|
||||
_numTextures = data->readUint32LE();
|
||||
|
||||
_texNames = new Common::String[_numTextures];
|
||||
_texFlags = new uint32[_numTextures];
|
||||
|
||||
for (uint32 i = 0; i < _numTextures; i++) {
|
||||
_texNames[i] = readLAString(data);
|
||||
_texFlags[i] = data->readUint32LE();
|
||||
if (_texFlags[i] & ~(BlendAdditive)) {
|
||||
Debug::debug(Debug::Models, "Model %s has unknown flags (%d) for texture %s", nameString.c_str(), _texFlags[i], _texNames[i].c_str());
|
||||
}
|
||||
}
|
||||
|
||||
prepareTextures();
|
||||
|
||||
int type = data->readUint32LE();
|
||||
// Check that it is one of the known types
|
||||
// 3 is no texture vertecies
|
||||
// 18 is no normals
|
||||
// 19 is regular
|
||||
assert(type == 19 || type == 18 || type == 3);
|
||||
|
||||
_numVertices = data->readUint32LE();
|
||||
|
||||
_lighting = new Math::Vector3d[_numVertices];
|
||||
for (int i = 0; i < _numVertices; i++) {
|
||||
_lighting[i].set(1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
// Vertices
|
||||
_vertices = new Math::Vector3d[_numVertices];
|
||||
_drawVertices = new Math::Vector3d[_numVertices];
|
||||
for (int i = 0; i < _numVertices; i++) {
|
||||
_vertices[i].readFromStream(data);
|
||||
_drawVertices[i] = _vertices[i];
|
||||
}
|
||||
_normals = new Math::Vector3d[_numVertices];
|
||||
_drawNormals = new Math::Vector3d[_numVertices];
|
||||
if (type != 18) {
|
||||
for (int i = 0; i < _numVertices; i++) {
|
||||
_normals[i].readFromStream(data);
|
||||
_drawNormals[i] = _normals[i];
|
||||
}
|
||||
}
|
||||
_colorMap = new EMIColormap[_numVertices];
|
||||
for (int i = 0; i < _numVertices; ++i) {
|
||||
_colorMap[i].r = data->readByte();
|
||||
_colorMap[i].g = data->readByte();
|
||||
_colorMap[i].b = data->readByte();
|
||||
_colorMap[i].a = data->readByte();
|
||||
}
|
||||
if (type != 3) {
|
||||
_texVerts = new Math::Vector2d[_numVertices];
|
||||
for (int i = 0; i < _numVertices; i++) {
|
||||
_texVerts[i].readFromStream(data);
|
||||
}
|
||||
}
|
||||
// Faces
|
||||
|
||||
_numFaces = data->readUint32LE();
|
||||
if (data->eos()) {
|
||||
_numFaces = 0;
|
||||
_faces = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
_faces = new EMIMeshFace[_numFaces];
|
||||
|
||||
for (uint32 j = 0; j < _numFaces; j++) {
|
||||
_faces[j].setParent(this);
|
||||
_faces[j].loadFace(data);
|
||||
}
|
||||
|
||||
int hasBones = data->readUint32LE();
|
||||
|
||||
if (hasBones == 1) {
|
||||
_numBones = data->readUint32LE();
|
||||
_boneNames = new Common::String[_numBones];
|
||||
for (int i = 0; i < _numBones; i++) {
|
||||
_boneNames[i] = readLAString(data);
|
||||
}
|
||||
|
||||
_numBoneInfos = data->readUint32LE();
|
||||
_boneInfos = new BoneInfo[_numBoneInfos];
|
||||
|
||||
for (int i = 0; i < _numBoneInfos; i++) {
|
||||
_boneInfos[i]._incFac = data->readUint32LE();
|
||||
_boneInfos[i]._joint = data->readUint32LE();
|
||||
_boneInfos[i]._weight = data->readFloatLE();
|
||||
}
|
||||
} else {
|
||||
_numBones = 0;
|
||||
_numBoneInfos = 0;
|
||||
}
|
||||
prepareForRender();
|
||||
}
|
||||
|
||||
void EMIModel::setSkeleton(Skeleton *skel) {
|
||||
if (_skeleton == skel) {
|
||||
return;
|
||||
}
|
||||
_skeleton = skel;
|
||||
if (!skel || !_numBoneInfos) {
|
||||
return;
|
||||
}
|
||||
delete[] _vertexBoneInfo; _vertexBoneInfo = nullptr;
|
||||
_vertexBoneInfo = new int[_numBoneInfos];
|
||||
for (int i = 0; i < _numBoneInfos; i++) {
|
||||
_vertexBoneInfo[i] = _skeleton->findJointIndex(_boneNames[_boneInfos[i]._joint]);
|
||||
}
|
||||
}
|
||||
|
||||
void EMIModel::prepareForRender() {
|
||||
if (!_skeleton || !_vertexBoneInfo)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < _numVertices; i++) {
|
||||
_drawVertices[i].set(0.0f, 0.0f, 0.0f);
|
||||
_drawNormals[i].set(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
int boneVert = -1;
|
||||
for (int i = 0; i < _numBoneInfos; i++) {
|
||||
if (_boneInfos[i]._incFac == 1) {
|
||||
boneVert++;
|
||||
}
|
||||
|
||||
int jointIndex = _vertexBoneInfo[i];
|
||||
const Math::Matrix4 &jointMatrix = _skeleton->_joints[jointIndex]._finalMatrix;
|
||||
const Math::Matrix4 &bindPose = _skeleton->_joints[jointIndex]._absMatrix;
|
||||
|
||||
Math::Vector3d vert = _vertices[boneVert];
|
||||
vert -= bindPose.getPosition();
|
||||
vert = vert * bindPose.getRotation();
|
||||
jointMatrix.transform(&vert, true);
|
||||
_drawVertices[boneVert] += vert * _boneInfos[i]._weight;
|
||||
|
||||
Math::Vector3d normal = _normals[boneVert];
|
||||
normal = normal * bindPose.getRotation();
|
||||
jointMatrix.transform(&normal, false);
|
||||
_drawNormals[boneVert] += normal * _boneInfos[i]._weight;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _numVertices; i++) {
|
||||
_drawNormals[i].normalize();
|
||||
}
|
||||
|
||||
g_driver->updateEMIModel(this);
|
||||
}
|
||||
|
||||
void EMIModel::prepareTextures() {
|
||||
_mats = new Material*[_numTextures];
|
||||
for (uint32 i = 0; i < _numTextures; i++) {
|
||||
_mats[i] = _costume->loadMaterial(_texNames[i], false);
|
||||
}
|
||||
}
|
||||
|
||||
void EMIModel::draw() {
|
||||
prepareForRender();
|
||||
|
||||
Actor *actor = _costume->getOwner();
|
||||
Math::Matrix4 modelToWorld = actor->getFinalMatrix();
|
||||
|
||||
if (!actor->isInOverworld()) {
|
||||
Math::AABB bounds = calculateWorldBounds(modelToWorld);
|
||||
if (bounds.isValid() && !g_grim->getCurrSet()->getFrustum().isInside(bounds))
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_driver->supportsShaders()) {
|
||||
// If shaders are not available, we calculate lighting in software.
|
||||
Actor::LightMode lightMode = actor->getLightMode();
|
||||
if (lightMode != Actor::LightNone) {
|
||||
if (lightMode != Actor::LightStatic)
|
||||
_lightingDirty = true;
|
||||
|
||||
if (_lightingDirty) {
|
||||
updateLighting(modelToWorld);
|
||||
_lightingDirty = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (actor->getLightMode() == Actor::LightNone) {
|
||||
g_driver->disableLights();
|
||||
}
|
||||
}
|
||||
// We will need to add a call to the skeleton, to get the modified vertices, but for now,
|
||||
// I'll be happy with just static drawing
|
||||
for (uint32 i = 0; i < _numFaces; i++) {
|
||||
setTex(_faces[i]._texID);
|
||||
g_driver->drawEMIModelFace(this, &_faces[i]);
|
||||
}
|
||||
|
||||
if (g_driver->supportsShaders() && actor->getLightMode() == Actor::LightNone) {
|
||||
g_driver->enableLights();
|
||||
}
|
||||
}
|
||||
|
||||
void EMIModel::updateLighting(const Math::Matrix4 &modelToWorld) {
|
||||
// Current lighting implementation mimics the NormDyn mode of the original game, even if
|
||||
// FastDyn is requested. We assume that FastDyn mode was used only for the purpose of
|
||||
// performance optimization, but NormDyn mode is visually superior in all cases.
|
||||
|
||||
Common::Array<Grim::Light *> activeLights;
|
||||
bool hasAmbient = false;
|
||||
|
||||
Actor *actor = _costume->getOwner();
|
||||
|
||||
for (Light *l : g_grim->getCurrSet()->getLights(actor->isInOverworld())) {
|
||||
if (l->_enabled) {
|
||||
activeLights.push_back(l);
|
||||
if (l->_type == Light::Ambient)
|
||||
hasAmbient = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < _numVertices; i++) {
|
||||
Math::Vector3d &result = _lighting[i];
|
||||
result.set(0.0f, 0.0f, 0.0f);
|
||||
|
||||
Math::Vector3d normal = _drawNormals[i];
|
||||
Math::Vector3d vertex = _drawVertices[i];
|
||||
modelToWorld.transform(&vertex, true);
|
||||
modelToWorld.transform(&normal, false);
|
||||
|
||||
for (uint j = 0; j < activeLights.size(); ++j) {
|
||||
Light *l = activeLights[j];
|
||||
float shade = l->_intensity;
|
||||
|
||||
if (l->_type != Light::Ambient) {
|
||||
// Direction of incident light
|
||||
Math::Vector3d dir = l->_dir;
|
||||
|
||||
if (l->_type != Light::Direct) {
|
||||
dir = l->_pos - vertex;
|
||||
float distSq = dir.getSquareMagnitude();
|
||||
if (distSq > l->_falloffFar * l->_falloffFar)
|
||||
continue;
|
||||
|
||||
dir.normalize();
|
||||
|
||||
if (distSq > l->_falloffNear * l->_falloffNear) {
|
||||
float dist = sqrt(distSq);
|
||||
float attn = 1.0f - (dist - l->_falloffNear) / (l->_falloffFar - l->_falloffNear);
|
||||
shade *= attn;
|
||||
}
|
||||
}
|
||||
|
||||
if (l->_type == Light::Spot) {
|
||||
float cosAngle = l->_dir.dotProduct(dir);
|
||||
if (cosAngle < 0.0f)
|
||||
continue;
|
||||
|
||||
float angle = acos(MIN(cosAngle, 1.0f));
|
||||
if (angle > l->_penumbraangle)
|
||||
continue;
|
||||
|
||||
if (angle > l->_umbraangle)
|
||||
shade *= 1.0f - (angle - l->_umbraangle) / (l->_penumbraangle - l->_umbraangle);
|
||||
}
|
||||
|
||||
float dot = MAX(0.0f, normal.dotProduct(dir));
|
||||
shade *= dot;
|
||||
}
|
||||
|
||||
Math::Vector3d color;
|
||||
color.x() = l->_color.getRed() / 255.0f;
|
||||
color.y() = l->_color.getGreen() / 255.0f;
|
||||
color.z() = l->_color.getBlue() / 255.0f;
|
||||
|
||||
result += color * shade;
|
||||
}
|
||||
|
||||
if (!hasAmbient) {
|
||||
// If the set does not specify an ambient light, a default ambient light is used
|
||||
// instead. The effect of this is visible for example in the set gmi.
|
||||
result += Math::Vector3d(0.5f, 0.5f, 0.5f);
|
||||
}
|
||||
|
||||
float max = MAX(MAX(result.x(), result.y()), result.z());
|
||||
if (max > 1.0f) {
|
||||
result.x() = result.x() / max;
|
||||
result.y() = result.y() / max;
|
||||
result.z() = result.z() / max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EMIModel::getBoundingBox(int *x1, int *y1, int *x2, int *y2) const {
|
||||
int winX1, winY1, winX2, winY2;
|
||||
g_driver->getScreenBoundingBox(this, &winX1, &winY1, &winX2, &winY2);
|
||||
if (winX1 != -1 && winY1 != -1 && winX2 != -1 && winY2 != -1) {
|
||||
*x1 = MIN(*x1, winX1);
|
||||
*y1 = MIN(*y1, winY1);
|
||||
*x2 = MAX(*x2, winX2);
|
||||
*y2 = MAX(*y2, winY2);
|
||||
}
|
||||
}
|
||||
|
||||
Math::AABB EMIModel::calculateWorldBounds(const Math::Matrix4 &matrix) const {
|
||||
Math::AABB bounds;
|
||||
for (int i = 0; i < _numVertices; i++) {
|
||||
bounds.expand(_drawVertices[i]);
|
||||
}
|
||||
bounds.transform(matrix);
|
||||
return bounds;
|
||||
}
|
||||
|
||||
EMIModel::EMIModel(const Common::String &filename, Common::SeekableReadStream *data, EMICostume *costume) :
|
||||
_fname(filename), _costume(costume) {
|
||||
_meshAlphaMode = Actor::AlphaOff;
|
||||
_meshAlpha = 1.0;
|
||||
_numVertices = 0;
|
||||
_vertices = nullptr;
|
||||
_drawVertices = nullptr;
|
||||
_normals = nullptr;
|
||||
_drawNormals = nullptr;
|
||||
_colorMap = nullptr;
|
||||
_texVerts = nullptr;
|
||||
_numFaces = 0;
|
||||
_faces = nullptr;
|
||||
_numTextures = 0;
|
||||
_texNames = nullptr;
|
||||
_mats = nullptr;
|
||||
_numBones = 0;
|
||||
_boneInfos = nullptr;
|
||||
_numBoneInfos = 0;
|
||||
_vertexBoneInfo = nullptr;
|
||||
_skeleton = nullptr;
|
||||
_radius = 0;
|
||||
_center = new Math::Vector3d();
|
||||
_boxData = new Math::Vector3d();
|
||||
_boxData2 = new Math::Vector3d();
|
||||
_numTexSets = 0;
|
||||
_setType = 0;
|
||||
_boneNames = nullptr;
|
||||
_lighting = nullptr;
|
||||
_lightingDirty = true;
|
||||
_texFlags = nullptr;
|
||||
|
||||
loadMesh(data);
|
||||
g_driver->createEMIModel(this);
|
||||
}
|
||||
|
||||
EMIModel::~EMIModel() {
|
||||
g_driver->destroyEMIModel(this);
|
||||
|
||||
delete[] _vertices;
|
||||
delete[] _drawVertices;
|
||||
delete[] _normals;
|
||||
delete[] _drawNormals;
|
||||
delete[] _colorMap;
|
||||
delete[] _texVerts;
|
||||
delete[] _faces;
|
||||
delete[] _texNames;
|
||||
delete[] _mats;
|
||||
delete[] _boneInfos;
|
||||
delete[] _vertexBoneInfo;
|
||||
delete[] _boneNames;
|
||||
delete[] _lighting;
|
||||
delete[] _texFlags;
|
||||
delete _center;
|
||||
delete _boxData;
|
||||
delete _boxData2;
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
148
engines/grim/emi/modelemi.h
Normal file
148
engines/grim/emi/modelemi.h
Normal file
@@ -0,0 +1,148 @@
|
||||
/* 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_MODELEMI_H
|
||||
#define GRIM_MODELEMI_H
|
||||
|
||||
#include "engines/grim/object.h"
|
||||
#include "engines/grim/actor.h"
|
||||
|
||||
#include "math/matrix4.h"
|
||||
#include "math/vector2d.h"
|
||||
#include "math/vector3d.h"
|
||||
#include "math/vector4d.h"
|
||||
#include "math/aabb.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class Material;
|
||||
|
||||
struct EMIColormap {
|
||||
unsigned char r, g, b, a;
|
||||
};
|
||||
|
||||
// Todo: port this to math::vector
|
||||
struct Vector3int;
|
||||
|
||||
class EMICostume;
|
||||
class EMIModel;
|
||||
struct BoneInfo;
|
||||
struct Bone;
|
||||
class Skeleton;
|
||||
|
||||
class EMIMeshFace {
|
||||
public:
|
||||
Vector3int *_indexes;
|
||||
uint32 _indicesEBO;
|
||||
uint32 _faceLength;
|
||||
uint32 _numFaces;
|
||||
uint32 _hasTexture;
|
||||
uint32 _texID;
|
||||
uint32 _flags;
|
||||
EMIModel *_parent;
|
||||
|
||||
enum MeshFaceFlags {
|
||||
kNoLighting = 0x20, // guessed, but distinctive for screen actors
|
||||
kAlphaBlend = 0x10000,
|
||||
kUnknownBlend = 0x40000 // used only in intro screen actors
|
||||
};
|
||||
|
||||
EMIMeshFace() : _faceLength(0), _numFaces(0), _hasTexture(0), _texID(0), _flags(0), _indexes(NULL), _parent(NULL), _indicesEBO(0) { }
|
||||
~EMIMeshFace();
|
||||
void loadFace(Common::SeekableReadStream *data);
|
||||
void setParent(EMIModel *m) { _parent = m; }
|
||||
void render();
|
||||
};
|
||||
|
||||
/* TODO: Remember to credit JohnDoe for his EMIMeshViewer, as most of the Skeletal
|
||||
* math, and understandings comes from his Delphi-code.
|
||||
*/
|
||||
class EMIModel : public Object {
|
||||
public:
|
||||
enum TextureFlags {
|
||||
BlendAdditive = 0x400
|
||||
// There are more flags, but their purpose is currently unknown.
|
||||
};
|
||||
|
||||
Common::String _meshName;
|
||||
Actor::AlphaMode _meshAlphaMode;
|
||||
float _meshAlpha;
|
||||
int _numVertices;
|
||||
Math::Vector3d *_vertices;
|
||||
Math::Vector3d *_drawVertices;
|
||||
Math::Vector3d *_normals;
|
||||
Math::Vector3d *_drawNormals;
|
||||
Math::Vector3d *_lighting;
|
||||
EMIColormap *_colorMap;
|
||||
Math::Vector2d *_texVerts;
|
||||
|
||||
uint32 _numFaces;
|
||||
EMIMeshFace *_faces;
|
||||
uint32 _numTextures;
|
||||
Common::String *_texNames;
|
||||
uint32 *_texFlags;
|
||||
Material **_mats;
|
||||
|
||||
Skeleton *_skeleton;
|
||||
|
||||
int _numBones;
|
||||
|
||||
// Bone-stuff:
|
||||
int _numBoneInfos;
|
||||
BoneInfo *_boneInfos;
|
||||
Common::String *_boneNames;
|
||||
int *_vertexBoneInfo;
|
||||
|
||||
// Stuff we dont know how to use:
|
||||
float _radius;
|
||||
Math::Vector3d *_center;
|
||||
Math::Vector3d *_boxData;
|
||||
Math::Vector3d *_boxData2;
|
||||
int _numTexSets;
|
||||
int _setType;
|
||||
|
||||
Common::String _fname;
|
||||
EMICostume *_costume;
|
||||
|
||||
void *_userData;
|
||||
bool _lightingDirty;
|
||||
|
||||
public:
|
||||
EMIModel(const Common::String &filename, Common::SeekableReadStream *data, EMICostume *costume);
|
||||
~EMIModel();
|
||||
void setTex(uint32 index);
|
||||
void setSkeleton(Skeleton *skel);
|
||||
void loadMesh(Common::SeekableReadStream *data);
|
||||
void prepareForRender();
|
||||
void prepareTextures();
|
||||
void draw();
|
||||
void updateLighting(const Math::Matrix4 &modelToWorld);
|
||||
void getBoundingBox(int *x1, int *y1, int *x2, int *y2) const;
|
||||
Math::AABB calculateWorldBounds(const Math::Matrix4 &matrix) const;
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
118
engines/grim/emi/poolsound.cpp
Normal file
118
engines/grim/emi/poolsound.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
/* 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/str.h"
|
||||
|
||||
#include "engines/grim/emi/sound/emisound.h"
|
||||
#include "engines/grim/emi/poolsound.h"
|
||||
#include "engines/grim/resource.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
PoolSound::PoolSound() : _filename(""), _loaded(false), _soundId(0) {
|
||||
}
|
||||
|
||||
PoolSound::PoolSound(const Common::String &filename) : _filename(""), _loaded(false), _soundId(0) {
|
||||
openFile(filename);
|
||||
}
|
||||
|
||||
// Called when the engine restarts or Lua code calls FreeSound
|
||||
PoolSound::~PoolSound() {
|
||||
if (_loaded) {
|
||||
g_emiSound->freeLoadedSound(_soundId);
|
||||
}
|
||||
}
|
||||
|
||||
void PoolSound::setVolume(int volume) {
|
||||
if (_loaded) {
|
||||
g_emiSound->setLoadedSoundVolume(_soundId, volume);
|
||||
}
|
||||
}
|
||||
|
||||
void PoolSound::setBalance(int balance) {
|
||||
if (_loaded) {
|
||||
g_emiSound->setLoadedSoundPan(_soundId, balance);
|
||||
}
|
||||
}
|
||||
|
||||
void PoolSound::setPosition(Math::Vector3d &pos) {
|
||||
if (_loaded) {
|
||||
g_emiSound->setLoadedSoundPosition(_soundId, pos);
|
||||
}
|
||||
}
|
||||
|
||||
void PoolSound::play(bool looping) {
|
||||
if (_loaded) {
|
||||
g_emiSound->playLoadedSound(_soundId, looping);
|
||||
}
|
||||
}
|
||||
|
||||
void PoolSound::playFrom(const Math::Vector3d &pos, bool looping) {
|
||||
if (_loaded) {
|
||||
g_emiSound->playLoadedSoundFrom(_soundId, pos, looping);
|
||||
}
|
||||
}
|
||||
|
||||
void PoolSound::stop() {
|
||||
if (_loaded) {
|
||||
g_emiSound->stopLoadedSound(_soundId);
|
||||
}
|
||||
}
|
||||
|
||||
int PoolSound::getVolume() {
|
||||
if (_loaded) {
|
||||
return g_emiSound->getLoadedSoundVolume(_soundId);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool PoolSound::isPlaying() {
|
||||
if (_loaded) {
|
||||
return g_emiSound->getLoadedSoundStatus(_soundId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PoolSound::openFile(const Common::String &filename) {
|
||||
_filename = filename;
|
||||
_loaded = g_emiSound->loadSfx(filename.c_str(), _soundId);
|
||||
if (!_loaded) {
|
||||
warning("Could not open PoolSound file %s", filename.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void PoolSound::saveState(SaveGame *state) {
|
||||
state->writeBool(_loaded);
|
||||
state->writeLESint32(_soundId);
|
||||
}
|
||||
|
||||
void PoolSound::restoreState(SaveGame *state) {
|
||||
if (state->saveMinorVersion() >= 21) {
|
||||
_loaded = state->readBool();
|
||||
_soundId = state->readLESint32();
|
||||
} else {
|
||||
bool hasStream = state->readBool();
|
||||
if (hasStream)
|
||||
openFile(state->readString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
59
engines/grim/emi/poolsound.h
Normal file
59
engines/grim/emi/poolsound.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* 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_POOLSOUND_H
|
||||
#define GRIM_POOLSOUND_H
|
||||
|
||||
#include "common/endian.h"
|
||||
|
||||
#include "engines/grim/pool.h"
|
||||
|
||||
#include "math/vector3d.h"
|
||||
|
||||
namespace Grim {
|
||||
class PoolSound : public PoolObject<PoolSound> {
|
||||
public:
|
||||
PoolSound();
|
||||
PoolSound(const Common::String &filename);
|
||||
~PoolSound();
|
||||
|
||||
void openFile(const Common::String &filename);
|
||||
void play(bool looping);
|
||||
void playFrom(const Math::Vector3d &pos, bool looping);
|
||||
void setVolume(int volume);
|
||||
void setBalance(int balance);
|
||||
void setPosition(Math::Vector3d &pos);
|
||||
void stop();
|
||||
int getVolume();
|
||||
bool isPlaying();
|
||||
void saveState(SaveGame *state);
|
||||
void restoreState(SaveGame *state);
|
||||
|
||||
static int32 getStaticTag() { return MKTAG('A','I','F','F'); }
|
||||
|
||||
private:
|
||||
Common::String _filename;
|
||||
int _soundId;
|
||||
bool _loaded;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
228
engines/grim/emi/skeleton.cpp
Normal file
228
engines/grim/emi/skeleton.cpp
Normal file
@@ -0,0 +1,228 @@
|
||||
/* 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/stream.h"
|
||||
|
||||
#include "math/vector3d.h"
|
||||
#include "math/vector4d.h"
|
||||
#include "math/quat.h"
|
||||
|
||||
#include "engines/grim/debug.h"
|
||||
#include "engines/grim/emi/animationemi.h"
|
||||
#include "engines/grim/emi/skeleton.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
#define ROTATE_OP 4
|
||||
#define TRANSLATE_OP 3
|
||||
|
||||
Skeleton::Skeleton(const Common::String &filename, Common::SeekableReadStream *data) :
|
||||
_numJoints(0), _joints(nullptr), _animLayers(nullptr) {
|
||||
loadSkeleton(data);
|
||||
}
|
||||
|
||||
Skeleton::~Skeleton() {
|
||||
for (int i = 0; i < MAX_ANIMATION_LAYERS; ++i) {
|
||||
delete[] _animLayers[i]._jointAnims;
|
||||
}
|
||||
delete[] _animLayers;
|
||||
delete[] _joints;
|
||||
}
|
||||
|
||||
void Skeleton::loadSkeleton(Common::SeekableReadStream *data) {
|
||||
_numJoints = data->readUint32LE();
|
||||
_joints = new Joint[_numJoints];
|
||||
|
||||
char inString[32];
|
||||
|
||||
for (int i = 0; i < _numJoints; i++) {
|
||||
data->read(inString, 32);
|
||||
_joints[i]._name = inString;
|
||||
data->read(inString, 32);
|
||||
_joints[i]._parent = inString;
|
||||
|
||||
_joints[i]._trans.readFromStream(data);
|
||||
_joints[i]._quat.readFromStream(data);
|
||||
|
||||
_joints[i]._parentIndex = findJointIndex(_joints[i]._parent);
|
||||
|
||||
_jointsMap[_joints[i]._name] = i;
|
||||
}
|
||||
initBones();
|
||||
resetAnim();
|
||||
}
|
||||
|
||||
void Skeleton::initBone(int index) {
|
||||
// The matrix should have identity at this point.
|
||||
_joints[index]._quat.toMatrix(_joints[index]._relMatrix);
|
||||
// Might need to be translate instead.
|
||||
_joints[index]._relMatrix.setPosition(_joints[index]._trans);
|
||||
if (_joints[index]._parentIndex == -1) {
|
||||
_joints[index]._absMatrix = _joints[index]._relMatrix;
|
||||
} else {
|
||||
_joints[index]._absMatrix = _joints[_joints[index]._parentIndex]._absMatrix;
|
||||
|
||||
// Might be the other way around.
|
||||
_joints[index]._absMatrix = _joints[index]._absMatrix * _joints[index]._relMatrix;
|
||||
}
|
||||
}
|
||||
|
||||
void Skeleton::initBones() {
|
||||
for (int i = 0; i < _numJoints; i++) {
|
||||
initBone(i);
|
||||
}
|
||||
|
||||
_animLayers = new AnimationLayer[MAX_ANIMATION_LAYERS];
|
||||
for (int i = 0; i < MAX_ANIMATION_LAYERS; ++i) {
|
||||
_animLayers[i]._jointAnims = new JointAnimation[_numJoints];
|
||||
}
|
||||
}
|
||||
|
||||
void Skeleton::resetAnim() {
|
||||
for (int i = 0; i < MAX_ANIMATION_LAYERS; ++i) {
|
||||
AnimationLayer &layer = _animLayers[i];
|
||||
for (int j = 0; j < _numJoints; ++j) {
|
||||
JointAnimation &jointAnim = layer._jointAnims[j];
|
||||
jointAnim._pos.set(0.f, 0.f, 0.f);
|
||||
jointAnim._quat.set(0.f, 0.f, 0.f, 1.f);
|
||||
jointAnim._transWeight = 0.0f;
|
||||
jointAnim._rotWeight = 0.0f;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < _numJoints; ++i) {
|
||||
_joints[i]._animMatrix = _joints[i]._relMatrix;
|
||||
_joints[i]._animQuat = _joints[i]._quat;
|
||||
}
|
||||
}
|
||||
|
||||
void Skeleton::animate() {
|
||||
resetAnim();
|
||||
|
||||
// This first pass over the animations calculates bone-specific sums of blend weights for all
|
||||
// animation layers. The sums must be pre-computed in order to be able to normalize the blend
|
||||
// weights properly in the next step.
|
||||
for (Common::List<AnimationStateEmi*>::iterator j = _activeAnims.begin(); j != _activeAnims.end(); ++j) {
|
||||
(*j)->computeWeights();
|
||||
}
|
||||
|
||||
// Now make a second pass over the animations to actually accumulate animation to layers.
|
||||
for (Common::List<AnimationStateEmi*>::iterator j = _activeAnims.begin(); j != _activeAnims.end(); ++j) {
|
||||
(*j)->animate();
|
||||
}
|
||||
|
||||
// Blend the layers together in priority order to produce the final result. Highest priority
|
||||
// layer will get as much weight as it wants, while the next highest priority will get the
|
||||
// amount that remains and so on.
|
||||
for (int i = 0; i < _numJoints; ++i) {
|
||||
float remainingTransWeight = 1.0f;
|
||||
float remainingRotWeight = 1.0f;
|
||||
|
||||
for (int j = MAX_ANIMATION_LAYERS - 1; j >= 0; --j) {
|
||||
AnimationLayer &layer = _animLayers[j];
|
||||
JointAnimation &jointAnim = layer._jointAnims[i];
|
||||
|
||||
if (remainingRotWeight > 0.0f && jointAnim._rotWeight != 0.0f) {
|
||||
Math::Vector3d pos = _joints[i]._animMatrix.getPosition();
|
||||
_joints[i]._animQuat = _joints[i]._animQuat.slerpQuat(_joints[i]._animQuat * jointAnim._quat, remainingRotWeight);
|
||||
_joints[i]._animQuat.toMatrix(_joints[i]._animMatrix);
|
||||
_joints[i]._animMatrix.setPosition(pos);
|
||||
|
||||
remainingRotWeight *= 1.0f - jointAnim._rotWeight;
|
||||
}
|
||||
|
||||
if (remainingTransWeight > 0.0f && jointAnim._transWeight != 0.0f) {
|
||||
Math::Vector3d pos = _joints[i]._animMatrix.getPosition();
|
||||
Math::Vector3d delta = jointAnim._pos;
|
||||
_joints[i]._animMatrix.setPosition(pos + delta * remainingTransWeight);
|
||||
|
||||
remainingTransWeight *= 1.0f - jointAnim._transWeight;
|
||||
}
|
||||
|
||||
if (remainingRotWeight <= 0.0f && remainingTransWeight <= 0.0f)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
commitAnim();
|
||||
}
|
||||
|
||||
void Skeleton::addAnimation(AnimationStateEmi *anim) {
|
||||
_activeAnims.push_back(anim);
|
||||
}
|
||||
void Skeleton::removeAnimation(AnimationStateEmi *anim) {
|
||||
_activeAnims.remove(anim);
|
||||
}
|
||||
|
||||
void Skeleton::commitAnim() {
|
||||
for (int m = 0; m < _numJoints; ++m) {
|
||||
const Joint *parent = getParentJoint(&_joints[m]);
|
||||
if (parent) {
|
||||
_joints[m]._finalMatrix = parent->_finalMatrix * _joints[m]._animMatrix;
|
||||
_joints[m]._finalQuat = parent->_finalQuat * _joints[m]._animQuat;
|
||||
} else {
|
||||
_joints[m]._finalMatrix = _joints[m]._animMatrix;
|
||||
_joints[m]._finalQuat = _joints[m]._animQuat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Skeleton::findJointIndex(const Common::String &name) const {
|
||||
JointMap::const_iterator it = _jointsMap.find(name);
|
||||
if (it != _jointsMap.end())
|
||||
return it->_value;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool Skeleton::hasJoint(const Common::String &name) const {
|
||||
return name.empty() || findJointIndex(name) >= 0;
|
||||
}
|
||||
|
||||
Joint *Skeleton::getJointNamed(const Common::String &name) const {
|
||||
int idx = findJointIndex(name);
|
||||
if (name.empty()) {
|
||||
return & _joints[0];
|
||||
} else if (idx == -1) {
|
||||
warning("Skeleton has no joint named '%s'!", name.c_str());
|
||||
return nullptr;
|
||||
} else {
|
||||
return & _joints[idx];
|
||||
}
|
||||
}
|
||||
|
||||
Joint *Skeleton::getParentJoint(const Joint *j) const {
|
||||
assert(j);
|
||||
if (j->_parentIndex == -1)
|
||||
return nullptr;
|
||||
return &_joints[j->_parentIndex];
|
||||
}
|
||||
|
||||
int Skeleton::getJointIndex(const Joint *j) const {
|
||||
int idx = j - _joints;
|
||||
assert(idx >= 0 && idx < _numJoints);
|
||||
return idx;
|
||||
}
|
||||
|
||||
AnimationLayer* Skeleton::getLayer(int priority) const {
|
||||
assert(priority >= 0 && priority < MAX_ANIMATION_LAYERS);
|
||||
return &_animLayers[priority];
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
103
engines/grim/emi/skeleton.h
Normal file
103
engines/grim/emi/skeleton.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/* 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_SKELETON_H
|
||||
#define GRIM_SKELETON_H
|
||||
|
||||
#include "common/hashmap.h"
|
||||
#include "common/hash-str.h"
|
||||
|
||||
#include "math/mathfwd.h"
|
||||
#include "math/quat.h"
|
||||
|
||||
#include "engines/grim/object.h"
|
||||
#include "engines/grim/actor.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class AnimationStateEmi;
|
||||
class AnimationEmi;
|
||||
|
||||
struct Joint {
|
||||
Common::String _name;
|
||||
Common::String _parent;
|
||||
Math::Vector3d _trans;
|
||||
Math::Quaternion _quat;
|
||||
int _parentIndex;
|
||||
Math::Matrix4 _absMatrix;
|
||||
Math::Matrix4 _relMatrix;
|
||||
Math::Matrix4 _animMatrix;
|
||||
Math::Quaternion _animQuat;
|
||||
Math::Matrix4 _finalMatrix;
|
||||
Math::Quaternion _finalQuat;
|
||||
};
|
||||
|
||||
struct JointAnimation {
|
||||
Math::Vector3d _pos;
|
||||
Math::Quaternion _quat;
|
||||
float _transWeight;
|
||||
float _rotWeight;
|
||||
};
|
||||
|
||||
struct AnimationLayer {
|
||||
JointAnimation* _jointAnims;
|
||||
};
|
||||
|
||||
class Skeleton : public Object {
|
||||
|
||||
void loadSkeleton(Common::SeekableReadStream *data);
|
||||
void initBone(int index);
|
||||
void initBones();
|
||||
void resetAnim();
|
||||
public:
|
||||
// Note: EMI uses priority 5 at most.
|
||||
static const int MAX_ANIMATION_LAYERS = 8;
|
||||
|
||||
int _numJoints;
|
||||
Joint *_joints;
|
||||
|
||||
typedef Common::HashMap<Common::String, int, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> JointMap;
|
||||
JointMap _jointsMap;
|
||||
|
||||
Skeleton(const Common::String &filename, Common::SeekableReadStream *data);
|
||||
~Skeleton();
|
||||
void animate();
|
||||
void commitAnim();
|
||||
void addAnimation(AnimationStateEmi *anim);
|
||||
void removeAnimation(AnimationStateEmi *anim);
|
||||
int findJointIndex(const Common::String &name) const;
|
||||
bool hasJoint(const Common::String &name) const;
|
||||
Joint *getJointNamed(const Common::String &name) const;
|
||||
Joint *getParentJoint(const Joint *j) const;
|
||||
int getJointIndex(const Joint *j) const;
|
||||
AnimationLayer* getLayer(int priority) const;
|
||||
private:
|
||||
AnimationLayer *_animLayers;
|
||||
Common::List<AnimationStateEmi*> _activeAnims;
|
||||
};
|
||||
|
||||
} // end of namespace Grim
|
||||
|
||||
#endif
|
||||
101
engines/grim/emi/sound/aifftrack.cpp
Normal file
101
engines/grim/emi/sound/aifftrack.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/* 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/mutex.h"
|
||||
|
||||
#include "audio/mixer.h"
|
||||
#include "audio/audiostream.h"
|
||||
#include "audio/decoders/aiff.h"
|
||||
|
||||
#include "engines/grim/debug.h"
|
||||
#include "engines/grim/resource.h"
|
||||
#include "engines/grim/emi/sound/aifftrack.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
AIFFTrack::AIFFTrack(Audio::Mixer::SoundType soundType) {
|
||||
_soundType = soundType;
|
||||
_looping = false;
|
||||
// A preloaded AIFF track may be played multiple times, so we don't
|
||||
// want to dispose after playing. The destructor of SoundTrack will
|
||||
// take care of disposing the stream instead.
|
||||
_disposeAfterPlaying = DisposeAfterUse::NO;
|
||||
}
|
||||
|
||||
AIFFTrack::~AIFFTrack() {
|
||||
stop();
|
||||
if (_handle) {
|
||||
g_system->getMixer()->stopHandle(*_handle);
|
||||
delete _handle;
|
||||
}
|
||||
}
|
||||
|
||||
bool AIFFTrack::openSound(const Common::String &filename, const Common::String &soundName, const Audio::Timestamp *start) {
|
||||
Common::SeekableReadStream *file = g_resourceloader->openNewStreamFile(filename, true);
|
||||
if (!file) {
|
||||
Debug::debug(Debug::Sound, "Stream for %s not open", soundName.c_str());
|
||||
return false;
|
||||
}
|
||||
_soundName = soundName;
|
||||
Audio::RewindableAudioStream *aiffStream = Audio::makeAIFFStream(file, DisposeAfterUse::YES);
|
||||
Audio::SeekableAudioStream *seekStream = dynamic_cast<Audio::SeekableAudioStream *>(aiffStream);
|
||||
_stream = aiffStream;
|
||||
if (start)
|
||||
seekStream->seek(*start);
|
||||
if (!_stream)
|
||||
return false;
|
||||
_handle = new Audio::SoundHandle();
|
||||
return true;
|
||||
}
|
||||
|
||||
void AIFFTrack::setLooping(bool looping) {
|
||||
if (_looping == looping)
|
||||
return;
|
||||
_looping = looping;
|
||||
if (looping && _stream) {
|
||||
_stream = Audio::makeLoopingAudioStream(dynamic_cast<Audio::SeekableAudioStream *>(_stream), 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool AIFFTrack::play() {
|
||||
if (_stream) {
|
||||
Audio::RewindableAudioStream *stream = dynamic_cast<Audio::RewindableAudioStream *>(_stream);
|
||||
if (!_looping) {
|
||||
stream->rewind();
|
||||
}
|
||||
return SoundTrack::play();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AIFFTrack::isPlaying() {
|
||||
if (!_handle)
|
||||
return false;
|
||||
|
||||
return g_system->getMixer()->isSoundHandleActive(*_handle);
|
||||
}
|
||||
|
||||
Audio::Timestamp AIFFTrack::getPos() {
|
||||
// FIXME: Return actual stream position.
|
||||
return g_system->getMixer()->getSoundElapsedTime(*_handle);
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
53
engines/grim/emi/sound/aifftrack.h
Normal file
53
engines/grim/emi/sound/aifftrack.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/* 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_AIFFTRACK_H
|
||||
#define GRIM_AIFFTRACK_H
|
||||
|
||||
#include "common/str.h"
|
||||
#include "common/stream.h"
|
||||
|
||||
#include "engines/grim/emi/sound/track.h"
|
||||
|
||||
namespace Audio {
|
||||
class AudioStream;
|
||||
class SoundHandle;
|
||||
}
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class AIFFTrack : public SoundTrack {
|
||||
public:
|
||||
AIFFTrack(Audio::Mixer::SoundType soundType);
|
||||
~AIFFTrack();
|
||||
bool openSound(const Common::String &filename, const Common::String &soundName, const Audio::Timestamp *start = nullptr) override;
|
||||
bool isPlaying() override;
|
||||
bool isStreamOpen() { return _stream != NULL; }
|
||||
void setLooping(bool looping) override;
|
||||
bool isLooping() const override { return _looping; }
|
||||
bool play() override;
|
||||
Audio::Timestamp getPos() override;
|
||||
private:
|
||||
bool _looping;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
207
engines/grim/emi/sound/codecs/scx.cpp
Normal file
207
engines/grim/emi/sound/codecs/scx.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
/* 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 "audio/audiostream.h"
|
||||
#include "audio/decoders/xa.h"
|
||||
|
||||
#include "common/memstream.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/stream.h"
|
||||
|
||||
#include "engines/grim/emi/sound/codecs/scx.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
SCXStream::SCXStream(Common::SeekableReadStream *stream, const Audio::Timestamp *start, DisposeAfterUse::Flag disposeAfterUse) {
|
||||
static const uint32 stereoChannelNames[SCX_MAX_CHANNELS] = { MKTAG('L', 'E', 'F', 'T'), MKTAG('R', 'G', 'H', 'T') };
|
||||
|
||||
stream->readUint32BE(); // 'SCRX'
|
||||
stream->readUint32LE();
|
||||
|
||||
_blockSize = stream->readUint16LE();
|
||||
/* totalBlockSize = */ stream->readUint16LE();
|
||||
|
||||
if (_blockSize & 0xf)
|
||||
error("Bad SCX block size %04x", _blockSize);
|
||||
|
||||
// Base our channel count based off the block size
|
||||
_channels = (_blockSize == 0) ? 1 : 2;
|
||||
|
||||
stream->skip(12);
|
||||
|
||||
uint32 channelSize[SCX_MAX_CHANNELS];
|
||||
for (int i = 0; i < _channels; i++) {
|
||||
uint32 tag = stream->readUint32BE();
|
||||
|
||||
if (isStereo()) {
|
||||
if (tag != stereoChannelNames[i])
|
||||
error("Bad stereo channel tag found '%s'", tag2str(tag));
|
||||
} else if (tag != MKTAG('M', 'O', 'N', 'O'))
|
||||
error("Bad mono channel tag found '%s'", tag2str(tag));
|
||||
|
||||
channelSize[i] = stream->readUint32LE();
|
||||
}
|
||||
|
||||
stream->seek(0x80);
|
||||
|
||||
uint32 leftRate = 0, rightRate = 0;
|
||||
for (int i = 0; i < _channels; i++) {
|
||||
if (stream->readUint32BE() != MKTAG('V', 'A', 'G', 'p'))
|
||||
error("Bad VAG header");
|
||||
|
||||
/* uint32 version = */ stream->readUint32BE();
|
||||
stream->readUint32BE();
|
||||
stream->readUint32BE();
|
||||
|
||||
if (i == 0)
|
||||
leftRate = stream->readUint32BE();
|
||||
else
|
||||
rightRate = stream->readUint32BE();
|
||||
|
||||
stream->skip(12); // skip useless info
|
||||
stream->skip(16); // skip name
|
||||
stream->skip(16); // skip zeroes
|
||||
}
|
||||
|
||||
if (isStereo() && leftRate != rightRate)
|
||||
error("Mismatching SCX rates");
|
||||
|
||||
_rate = leftRate;
|
||||
|
||||
if (isStereo()) {
|
||||
// TODO: Make XAStream allow for appending data (similar to how ScummVM
|
||||
// handles AAC/QDM2. For now, we de-interleave the XA ADPCM data and then
|
||||
// re-interleave in readBuffer().
|
||||
// Of course, in doing something that does better streaming, it would
|
||||
// screw up the XA loop points. So, I'm not really sure what is best atm.
|
||||
byte *leftOut = (byte*)malloc(channelSize[0]);
|
||||
byte *rightOut = (byte*)malloc(channelSize[1]);
|
||||
Common::MemoryWriteStream *leftStream = new Common::MemoryWriteStream(leftOut, channelSize[0]);
|
||||
Common::MemoryWriteStream *rightStream = new Common::MemoryWriteStream(rightOut, channelSize[1]);
|
||||
byte *buf = new byte[_blockSize];
|
||||
|
||||
while (stream->pos() < stream->size()) {
|
||||
stream->read(buf, _blockSize);
|
||||
leftStream->write(buf, _blockSize);
|
||||
stream->read(buf, _blockSize);
|
||||
rightStream->write(buf, _blockSize);
|
||||
}
|
||||
|
||||
_fileStreams[0] = new Common::MemoryReadStream(leftOut, channelSize[0], DisposeAfterUse::YES);
|
||||
_fileStreams[1] = new Common::MemoryReadStream(rightOut, channelSize[1], DisposeAfterUse::YES);
|
||||
|
||||
_xaStreams[0] = Audio::makeXAStream(_fileStreams[0], _rate);
|
||||
_xaStreams[1] = Audio::makeXAStream(_fileStreams[1], _rate);
|
||||
|
||||
delete[] buf;
|
||||
delete leftStream;
|
||||
delete rightStream;
|
||||
} else {
|
||||
_fileStreams[0] = stream->readStream(channelSize[0]);
|
||||
_fileStreams[1] = nullptr;
|
||||
_xaStreams[0] = Audio::makeXAStream(_fileStreams[0], _rate);
|
||||
_xaStreams[1] = nullptr;
|
||||
}
|
||||
|
||||
if (start) {
|
||||
// Read data from the sound stream until we hit the desired start position.
|
||||
// We do this instead of seeking so the loop point gets set up properly.
|
||||
int samples = (int)((int64)start->msecs() * _rate / 1000);
|
||||
int16 temp[1024];
|
||||
while (samples > 0) {
|
||||
samples -= _xaStreams[0]->readBuffer(temp, samples < 1024 ? samples : 1024);
|
||||
if (_xaStreams[1]) {
|
||||
_xaStreams[1]->readBuffer(temp, samples < 1024 ? samples : 1024);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (disposeAfterUse == DisposeAfterUse::YES)
|
||||
delete stream;
|
||||
}
|
||||
|
||||
SCXStream::~SCXStream() {
|
||||
for (int i = 0; i < SCX_MAX_CHANNELS; i++)
|
||||
delete _xaStreams[i];
|
||||
}
|
||||
|
||||
int SCXStream::readBuffer(int16 *buffer, const int numSamples) {
|
||||
if (isStereo()) {
|
||||
// Needs to be divisible by the channel count
|
||||
assert((numSamples % 2) == 0);
|
||||
|
||||
// TODO: As per above, this probably should do more actual streaming
|
||||
|
||||
// Decode enough data from each channel
|
||||
int samplesPerChannel = numSamples / 2;
|
||||
int16 *leftSamples = new int16[samplesPerChannel];
|
||||
int16 *rightSamples = new int16[samplesPerChannel];
|
||||
|
||||
int samplesDecodedLeft = _xaStreams[0]->readBuffer(leftSamples, samplesPerChannel);
|
||||
int samplesDecodedRight = _xaStreams[1]->readBuffer(rightSamples, samplesPerChannel);
|
||||
assert(samplesDecodedLeft == samplesDecodedRight);
|
||||
(void)samplesDecodedRight;
|
||||
|
||||
// Now re-interleave the data
|
||||
int samplesDecoded = 0;
|
||||
int16 *leftSrc = leftSamples, *rightSrc = rightSamples;
|
||||
for (; samplesDecoded < samplesDecodedLeft * 2; samplesDecoded += 2) {
|
||||
*buffer++ = *leftSrc++;
|
||||
*buffer++ = *rightSrc++;
|
||||
}
|
||||
|
||||
delete[] leftSamples;
|
||||
delete[] rightSamples;
|
||||
return samplesDecoded;
|
||||
}
|
||||
|
||||
// Just read from the stream directly for mono
|
||||
return _xaStreams[0]->readBuffer(buffer, numSamples);
|
||||
}
|
||||
|
||||
bool SCXStream::rewind() {
|
||||
if (!_xaStreams[0]->rewind())
|
||||
return false;
|
||||
|
||||
return !isStereo() || _xaStreams[1]->rewind();
|
||||
}
|
||||
|
||||
Audio::Timestamp SCXStream::getPos() const {
|
||||
int32 pos = _fileStreams[0]->pos();
|
||||
|
||||
// Each XA ADPCM block of 16 bytes decompresses to 28 samples.
|
||||
int32 samples = pos * 28 / 16;
|
||||
uint32 msecs = (uint32)((int64)samples * 1000 / _rate);
|
||||
|
||||
return Audio::Timestamp(msecs);
|
||||
}
|
||||
|
||||
SCXStream *makeSCXStream(Common::SeekableReadStream *stream, const Audio::Timestamp *start, DisposeAfterUse::Flag disposeAfterUse) {
|
||||
if (stream->readUint32BE() != MKTAG('S', 'C', 'R', 'X')) {
|
||||
delete stream;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
stream->seek(0);
|
||||
return new SCXStream(stream, start, disposeAfterUse);
|
||||
}
|
||||
|
||||
} // End of namespace Grim
|
||||
71
engines/grim/emi/sound/codecs/scx.h
Normal file
71
engines/grim/emi/sound/codecs/scx.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/* 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_SCX_H
|
||||
#define GRIM_SCX_H
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace Grim {
|
||||
|
||||
// I've only ever seen up to two
|
||||
#define SCX_MAX_CHANNELS 2
|
||||
|
||||
class SCXStream : public Audio::RewindableAudioStream {
|
||||
public:
|
||||
SCXStream(Common::SeekableReadStream *stream, const Audio::Timestamp *start, DisposeAfterUse::Flag disposeAfterUse);
|
||||
~SCXStream();
|
||||
|
||||
bool isStereo() const override { return _channels == 2; }
|
||||
bool endOfData() const override { return _xaStreams[0]->endOfData(); }
|
||||
int getRate() const override { return _rate; }
|
||||
int readBuffer(int16 *buffer, const int numSamples) override;
|
||||
|
||||
bool rewind() override;
|
||||
Audio::Timestamp getPos() const;
|
||||
|
||||
private:
|
||||
int _channels;
|
||||
int _rate;
|
||||
uint16 _blockSize;
|
||||
|
||||
Common::SeekableReadStream *_fileStreams[SCX_MAX_CHANNELS];
|
||||
Audio::RewindableAudioStream *_xaStreams[SCX_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
/**
|
||||
* Takes an input stream containing SCX sound data and creates
|
||||
* a RewindableAudioStream from that.
|
||||
*
|
||||
* @param stream the SeekableReadStream from which to read the SCX data
|
||||
* @param disposeAfterUse whether to delete the stream after use
|
||||
* @return a new RewindableAudioStream, or NULL, if an error occurred
|
||||
*/
|
||||
SCXStream *makeSCXStream(
|
||||
Common::SeekableReadStream *stream,
|
||||
const Audio::Timestamp *start,
|
||||
DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES);
|
||||
|
||||
} // End of namespace Grim
|
||||
|
||||
#endif
|
||||
1094
engines/grim/emi/sound/emisound.cpp
Normal file
1094
engines/grim/emi/sound/emisound.cpp
Normal file
File diff suppressed because it is too large
Load Diff
146
engines/grim/emi/sound/emisound.h
Normal file
146
engines/grim/emi/sound/emisound.h
Normal file
@@ -0,0 +1,146 @@
|
||||
/* 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_MSS_H
|
||||
#define GRIM_MSS_H
|
||||
|
||||
#include "audio/mixer.h"
|
||||
|
||||
#include "common/str.h"
|
||||
#include "common/stack.h"
|
||||
#include "common/mutex.h"
|
||||
#include "common/hashmap.h"
|
||||
|
||||
#include "math/vector3d.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class SoundTrack;
|
||||
class SaveGame;
|
||||
|
||||
struct MusicEntry {
|
||||
int _x;
|
||||
int _y;
|
||||
int _sync;
|
||||
int _trim;
|
||||
int _id;
|
||||
Common::String _type;
|
||||
Common::String _name;
|
||||
Common::String _filename;
|
||||
};
|
||||
|
||||
// Currently this class only implements the exact functions called in iMuse
|
||||
// from Actor, to allow for splitting that into EMI-sound and iMuse without
|
||||
// changing iMuse.
|
||||
class EMISound {
|
||||
public:
|
||||
EMISound(int fps);
|
||||
~EMISound();
|
||||
bool startVoice(const Common::String &soundName, int volume = static_cast<int>(Audio::Mixer::kMaxChannelVolume), int pan = 64);
|
||||
bool startSfx(const Common::String &soundName, int volume = static_cast<int>(Audio::Mixer::kMaxChannelVolume), int pan = 64);
|
||||
bool startSfxFrom(const Common::String &soundName, const Math::Vector3d &pos, int volume = static_cast<int>(Audio::Mixer::kMaxChannelVolume));
|
||||
bool getSoundStatus(const Common::String &soundName);
|
||||
void stopSound(const Common::String &soundName);
|
||||
int32 getPosIn16msTicks(const Common::String &soundName);
|
||||
|
||||
void setVolume(const Common::String &soundName, int volume);
|
||||
void setPan(const Common::String &soundName, int pan); /* pan: 0 .. 127 */
|
||||
|
||||
bool loadSfx(const Common::String &soundName, int &id);
|
||||
void playLoadedSound(int id, bool looping);
|
||||
void playLoadedSoundFrom(int id, const Math::Vector3d &pos, bool looping);
|
||||
void setLoadedSoundLooping(int id, bool looping);
|
||||
void stopLoadedSound(int id);
|
||||
void freeLoadedSound(int id);
|
||||
void setLoadedSoundVolume(int id, int volume);
|
||||
void setLoadedSoundPan(int id, int pan);
|
||||
void setLoadedSoundPosition(int id, const Math::Vector3d &pos);
|
||||
bool getLoadedSoundStatus(int id);
|
||||
int getLoadedSoundVolume(int id);
|
||||
|
||||
void setMusicState(int stateId);
|
||||
void selectMusicSet(int setId);
|
||||
|
||||
bool stateHasLooped(int stateId);
|
||||
bool stateHasEnded(int stateId);
|
||||
|
||||
void restoreState(SaveGame *savedState);
|
||||
void saveState(SaveGame *savedState);
|
||||
|
||||
void pushStateToStack();
|
||||
void popStateFromStack();
|
||||
void flushStack();
|
||||
void pause(bool paused);
|
||||
void flushTracks();
|
||||
|
||||
uint32 getMsPos(int stateId);
|
||||
|
||||
void updateSoundPositions();
|
||||
|
||||
private:
|
||||
struct StackEntry {
|
||||
int _state;
|
||||
SoundTrack *_track;
|
||||
};
|
||||
|
||||
typedef Common::List<SoundTrack *> TrackList;
|
||||
TrackList _playingTracks;
|
||||
SoundTrack *_musicTrack;
|
||||
MusicEntry *_musicTable;
|
||||
Common::String _musicPrefix;
|
||||
Common::Stack<StackEntry> _stateStack;
|
||||
// A mutex to avoid concurrent modification of the sound channels by the engine thread
|
||||
// and the timer callback, which may run in a different thread.
|
||||
Common::Mutex _mutex;
|
||||
|
||||
typedef Common::HashMap<int, SoundTrack *> TrackMap;
|
||||
TrackMap _preloadedTrackMap;
|
||||
|
||||
int _curMusicState;
|
||||
int _numMusicStates;
|
||||
int _callbackFps;
|
||||
int _curTrackId;
|
||||
|
||||
static void timerHandler(void *refConf);
|
||||
void removeItem(SoundTrack *item);
|
||||
TrackList::iterator getPlayingTrackByName(const Common::String &name);
|
||||
void freeChannel(int32 channel);
|
||||
void initMusicTable();
|
||||
|
||||
void callback();
|
||||
void updateTrack(SoundTrack *track);
|
||||
void freePlayingSounds();
|
||||
void freeLoadedSounds();
|
||||
SoundTrack *initTrack(const Common::String &soundName, Audio::Mixer::SoundType soundType, const Audio::Timestamp *start = nullptr) const;
|
||||
SoundTrack *restartTrack(SoundTrack *track);
|
||||
bool startSound(const Common::String &soundName, Audio::Mixer::SoundType soundType, int volume, int pan);
|
||||
bool startSoundFrom(const Common::String &soundName, Audio::Mixer::SoundType soundType, const Math::Vector3d &pos, int volume);
|
||||
void saveTrack(SoundTrack *track, SaveGame *savedState);
|
||||
SoundTrack *restoreTrack(SaveGame *savedState);
|
||||
MusicEntry *initMusicTableDemo(const Common::String &filename);
|
||||
void initMusicTableRetail(MusicEntry *table, const Common::String &filename);
|
||||
};
|
||||
|
||||
extern EMISound *g_emiSound;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
223
engines/grim/emi/sound/mp3track.cpp
Normal file
223
engines/grim/emi/sound/mp3track.cpp
Normal file
@@ -0,0 +1,223 @@
|
||||
/* 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/mutex.h"
|
||||
#include "audio/mixer.h"
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
#include "audio/decoders/mp3.h"
|
||||
|
||||
#include "engines/grim/debug.h"
|
||||
#include "engines/grim/resource.h"
|
||||
#include "engines/grim/textsplit.h"
|
||||
#include "engines/grim/emi/sound/mp3track.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
/**
|
||||
* This is a an extension of Audio::SubLooppingAudioStream that adds a start
|
||||
* time parameter as well as a getter for the stream position.
|
||||
*/
|
||||
class EMISubLoopingAudioStream : public Audio::AudioStream {
|
||||
public:
|
||||
EMISubLoopingAudioStream(Audio::SeekableAudioStream *stream, uint loops,
|
||||
const Audio::Timestamp start,
|
||||
const Audio::Timestamp loopStart,
|
||||
const Audio::Timestamp loopEnd,
|
||||
DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES)
|
||||
: _parent(stream, disposeAfterUse),
|
||||
_pos(convertTimeToStreamPos(start, getRate(), isStereo())),
|
||||
_loopStart(convertTimeToStreamPos(loopStart, getRate(), isStereo())),
|
||||
_loopEnd(convertTimeToStreamPos(loopEnd, getRate(), isStereo())),
|
||||
_done(false), _hasLooped(false) {
|
||||
assert(loopStart < loopEnd);
|
||||
|
||||
if (!_parent->seek(_pos))
|
||||
_done = true;
|
||||
}
|
||||
|
||||
int readBuffer(int16 *buffer, const int numSamples) override {
|
||||
if (_done)
|
||||
return 0;
|
||||
|
||||
int framesLeft = MIN(_loopEnd.frameDiff(_pos), numSamples);
|
||||
int framesRead = _parent->readBuffer(buffer, framesLeft);
|
||||
_pos = _pos.addFrames(framesRead);
|
||||
|
||||
if (framesRead < framesLeft && _parent->endOfData()) {
|
||||
// TODO: Proper error indication.
|
||||
_done = true;
|
||||
return framesRead;
|
||||
}
|
||||
else if (_pos == _loopEnd) {
|
||||
if (!_parent->seek(_loopStart)) {
|
||||
// TODO: Proper error indication.
|
||||
_done = true;
|
||||
return framesRead;
|
||||
}
|
||||
|
||||
_pos = _loopStart;
|
||||
framesLeft = numSamples - framesLeft;
|
||||
_hasLooped = true;
|
||||
return framesRead + readBuffer(buffer + framesRead, framesLeft);
|
||||
}
|
||||
else {
|
||||
return framesRead;
|
||||
}
|
||||
}
|
||||
|
||||
bool hasLooped() const { return _hasLooped; }
|
||||
bool endOfData() const override { return _done; }
|
||||
|
||||
bool isStereo() const override { return _parent->isStereo(); }
|
||||
int getRate() const override { return _parent->getRate(); }
|
||||
Audio::Timestamp getPos() const { return _pos; }
|
||||
|
||||
private:
|
||||
Common::DisposablePtr<Audio::SeekableAudioStream> _parent;
|
||||
|
||||
Audio::Timestamp _pos;
|
||||
Audio::Timestamp _loopStart, _loopEnd;
|
||||
|
||||
bool _done;
|
||||
bool _hasLooped;
|
||||
};
|
||||
|
||||
void MP3Track::parseRIFFHeader(Common::SeekableReadStream *data) {
|
||||
uint32 tag = data->readUint32BE();
|
||||
if (tag == MKTAG('R','I','F','F')) {
|
||||
_endFlag = false;
|
||||
data->seek(18, SEEK_CUR);
|
||||
_channels = data->readByte();
|
||||
data->readByte();
|
||||
_freq = data->readUint32LE();
|
||||
data->seek(6, SEEK_CUR);
|
||||
_bits = data->readByte();
|
||||
data->seek(5, SEEK_CUR);
|
||||
_regionLength = data->readUint32LE();
|
||||
_headerSize = 44;
|
||||
} else {
|
||||
error("Unknown file header");
|
||||
}
|
||||
}
|
||||
|
||||
MP3Track::JMMCuePoints MP3Track::parseJMMFile(const Common::String &filename) {
|
||||
JMMCuePoints cuePoints;
|
||||
Common::SeekableReadStream *stream = g_resourceloader->openNewStreamFile(filename);
|
||||
if (stream) {
|
||||
TextSplitter ts(filename, stream);
|
||||
float startMs = 0.0f;
|
||||
float loopStartMs = 0.0f, loopEndMs = 0.0f;
|
||||
|
||||
ts.scanString(".start %f", 1, &startMs);
|
||||
if (ts.checkString(".jump"))
|
||||
ts.scanString(".jump %f %f", 2, &loopEndMs, &loopStartMs);
|
||||
|
||||
// Use microsecond precision for the timestamps.
|
||||
cuePoints._start = Audio::Timestamp(startMs / 1000, (int)(startMs * 1000) % 1000000, 1000000);
|
||||
cuePoints._loopStart = Audio::Timestamp(loopStartMs / 1000, (int)(loopStartMs * 1000) % 1000000, 1000000);
|
||||
cuePoints._loopEnd = Audio::Timestamp(loopEndMs / 1000, (int)(loopEndMs * 1000) % 1000000, 1000000);
|
||||
}
|
||||
delete stream;
|
||||
return cuePoints;
|
||||
}
|
||||
|
||||
MP3Track::MP3Track(Audio::Mixer::SoundType soundType) {
|
||||
_soundType = soundType;
|
||||
_headerSize = 0;
|
||||
_regionLength = 0;
|
||||
_freq = 0;
|
||||
_bits = 0,
|
||||
_channels = 0;
|
||||
_endFlag = false;
|
||||
_looping = false;
|
||||
}
|
||||
|
||||
MP3Track::~MP3Track() {
|
||||
stop();
|
||||
if (_handle) {
|
||||
g_system->getMixer()->stopHandle(*_handle);
|
||||
delete _handle;
|
||||
}
|
||||
}
|
||||
|
||||
bool MP3Track::openSound(const Common::String &filename, const Common::String &soundName, const Audio::Timestamp *start) {
|
||||
Common::SeekableReadStream *file = g_resourceloader->openNewStreamFile(filename);
|
||||
if (!file) {
|
||||
Debug::debug(Debug::Sound, "Stream for %s not open", soundName.c_str());
|
||||
return false;
|
||||
}
|
||||
_soundName = soundName;
|
||||
#ifndef USE_MAD
|
||||
warning("Cannot open %s, MP3 support not enabled", soundName.c_str());
|
||||
return true;
|
||||
#else
|
||||
parseRIFFHeader(file);
|
||||
|
||||
MP3Track::JMMCuePoints cuePoints;
|
||||
if (soundName.size() > 4) {
|
||||
cuePoints = parseJMMFile(Common::String(filename.c_str(), filename.size() - 4) + ".jmm");
|
||||
}
|
||||
|
||||
if (start)
|
||||
cuePoints._start = *start;
|
||||
|
||||
Audio::SeekableAudioStream *mp3Stream = Audio::makeMP3Stream(file, DisposeAfterUse::YES);
|
||||
|
||||
if (cuePoints._loopEnd <= cuePoints._loopStart) {
|
||||
_stream = mp3Stream;
|
||||
mp3Stream->seek(cuePoints._start);
|
||||
_looping = false;
|
||||
} else {
|
||||
_stream = new EMISubLoopingAudioStream(mp3Stream, 0, cuePoints._start, cuePoints._loopStart, cuePoints._loopEnd);
|
||||
_looping = true;
|
||||
}
|
||||
_handle = new Audio::SoundHandle();
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MP3Track::hasLooped() {
|
||||
if (!_stream || !_looping)
|
||||
return false;
|
||||
EMISubLoopingAudioStream *las = static_cast<EMISubLoopingAudioStream*>(_stream);
|
||||
return las->hasLooped();
|
||||
}
|
||||
|
||||
bool MP3Track::isPlaying() {
|
||||
if (!_handle)
|
||||
return false;
|
||||
|
||||
return g_system->getMixer()->isSoundHandleActive(*_handle);
|
||||
}
|
||||
|
||||
Audio::Timestamp MP3Track::getPos() {
|
||||
if (!_stream)
|
||||
return Audio::Timestamp(0);
|
||||
if (_looping) {
|
||||
EMISubLoopingAudioStream *slas = static_cast<EMISubLoopingAudioStream*>(_stream);
|
||||
return slas->getPos();
|
||||
} else {
|
||||
return g_system->getMixer()->getSoundElapsedTime(*_handle);
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
64
engines/grim/emi/sound/mp3track.h
Normal file
64
engines/grim/emi/sound/mp3track.h
Normal 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_MP3TRACK_H
|
||||
#define GRIM_MP3TRACK_H
|
||||
|
||||
#include "common/str.h"
|
||||
#include "common/stream.h"
|
||||
|
||||
#include "audio/timestamp.h"
|
||||
|
||||
#include "engines/grim/emi/sound/track.h"
|
||||
|
||||
namespace Audio {
|
||||
class AudioStream;
|
||||
class SoundHandle;
|
||||
}
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class MP3Track : public SoundTrack {
|
||||
struct JMMCuePoints {
|
||||
Audio::Timestamp _start;
|
||||
Audio::Timestamp _loopStart;
|
||||
Audio::Timestamp _loopEnd;
|
||||
};
|
||||
uint32 _headerSize;
|
||||
uint32 _regionLength;
|
||||
uint32 _freq;
|
||||
char _bits;
|
||||
char _channels;
|
||||
bool _endFlag;
|
||||
bool _looping;
|
||||
void parseRIFFHeader(Common::SeekableReadStream *data);
|
||||
JMMCuePoints parseJMMFile(const Common::String &filename);
|
||||
public:
|
||||
MP3Track(Audio::Mixer::SoundType soundType);
|
||||
~MP3Track();
|
||||
bool openSound(const Common::String &filename, const Common::String &soundName, const Audio::Timestamp *start = nullptr) override;
|
||||
bool hasLooped() override;
|
||||
bool isPlaying() override;
|
||||
Audio::Timestamp getPos() override;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
95
engines/grim/emi/sound/scxtrack.cpp
Normal file
95
engines/grim/emi/sound/scxtrack.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
/* 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/mutex.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "audio/mixer.h"
|
||||
#include "audio/audiostream.h"
|
||||
|
||||
#include "engines/grim/debug.h"
|
||||
#include "engines/grim/resource.h"
|
||||
#include "engines/grim/emi/sound/codecs/scx.h"
|
||||
#include "engines/grim/emi/sound/scxtrack.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
SCXTrack::SCXTrack(Audio::Mixer::SoundType soundType) {
|
||||
_disposeAfterPlaying = DisposeAfterUse::NO;
|
||||
_soundType = soundType;
|
||||
_looping = false;
|
||||
}
|
||||
|
||||
SCXTrack::~SCXTrack() {
|
||||
stop();
|
||||
if (_handle) {
|
||||
g_system->getMixer()->stopHandle(*_handle);
|
||||
delete _handle;
|
||||
}
|
||||
}
|
||||
|
||||
bool SCXTrack::openSound(const Common::String &filename, const Common::String &soundName, const Audio::Timestamp *start) {
|
||||
Common::SeekableReadStream *file = g_resourceloader->openNewStreamFile(filename);
|
||||
if (!file) {
|
||||
Debug::debug(Debug::Sound, "Stream for %s not open", soundName.c_str());
|
||||
return false;
|
||||
}
|
||||
_soundName = soundName;
|
||||
Audio::RewindableAudioStream *scxStream = makeSCXStream(file, start, DisposeAfterUse::YES);
|
||||
_stream = scxStream;
|
||||
_handle = new Audio::SoundHandle();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SCXTrack::isPlaying() {
|
||||
if (!_handle)
|
||||
return false;
|
||||
|
||||
return g_system->getMixer()->isSoundHandleActive(*_handle);
|
||||
}
|
||||
|
||||
Audio::Timestamp SCXTrack::getPos() {
|
||||
if (!_stream || _looping)
|
||||
return Audio::Timestamp(0);
|
||||
return dynamic_cast<SCXStream*>(_stream)->getPos();
|
||||
}
|
||||
|
||||
bool SCXTrack::play() {
|
||||
if (_stream) {
|
||||
Audio::RewindableAudioStream *stream = dynamic_cast<Audio::RewindableAudioStream *>(_stream);
|
||||
if (!_looping) {
|
||||
stream->rewind();
|
||||
}
|
||||
return SoundTrack::play();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SCXTrack::setLooping(bool looping) {
|
||||
if (_looping == looping)
|
||||
return;
|
||||
_looping = looping;
|
||||
if (looping && _stream) {
|
||||
_stream = Audio::makeLoopingAudioStream(dynamic_cast<Audio::RewindableAudioStream *>(_stream), 0);
|
||||
}
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
52
engines/grim/emi/sound/scxtrack.h
Normal file
52
engines/grim/emi/sound/scxtrack.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/* 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_SCXTRACK_H
|
||||
#define GRIM_SCXTRACK_H
|
||||
|
||||
#include "common/str.h"
|
||||
#include "common/stream.h"
|
||||
|
||||
#include "engines/grim/emi/sound/track.h"
|
||||
|
||||
namespace Audio {
|
||||
class AudioStream;
|
||||
class SoundHandle;
|
||||
}
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class SCXTrack : public SoundTrack {
|
||||
public:
|
||||
SCXTrack(Audio::Mixer::SoundType soundType);
|
||||
~SCXTrack();
|
||||
bool openSound(const Common::String &filename, const Common::String &soundName, const Audio::Timestamp *start = nullptr) override;
|
||||
bool isPlaying() override;
|
||||
Audio::Timestamp getPos() override;
|
||||
bool play() override;
|
||||
void setLooping(bool looping) override;
|
||||
|
||||
private:
|
||||
bool _looping;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
154
engines/grim/emi/sound/track.cpp
Normal file
154
engines/grim/emi/sound/track.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
/* 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/mutex.h"
|
||||
#include "common/str.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "audio/mixer.h"
|
||||
#include "audio/audiostream.h"
|
||||
|
||||
#include "engines/grim/savegame.h"
|
||||
#include "engines/grim/emi/sound/track.h"
|
||||
#include "engines/grim/grim.h"
|
||||
#include "engines/grim/set.h"
|
||||
|
||||
namespace Grim {
|
||||
|
||||
SoundTrack::SoundTrack() {
|
||||
_stream = nullptr;
|
||||
_handle = nullptr;
|
||||
_paused = false;
|
||||
_positioned = false;
|
||||
_balance = 0;
|
||||
_volume = Audio::Mixer::kMaxChannelVolume;
|
||||
_disposeAfterPlaying = DisposeAfterUse::YES;
|
||||
_sync = 0;
|
||||
_fadeMode = FadeNone;
|
||||
_fade = 1.0f;
|
||||
_attenuation = 1.0f;
|
||||
|
||||
// Initialize to a plain sound for now
|
||||
_soundType = Audio::Mixer::kPlainSoundType;
|
||||
}
|
||||
|
||||
SoundTrack::~SoundTrack() {
|
||||
if (_stream && (_disposeAfterPlaying == DisposeAfterUse::NO || !_handle))
|
||||
delete _stream;
|
||||
}
|
||||
|
||||
Common::String SoundTrack::getSoundName() {
|
||||
return _soundName;
|
||||
}
|
||||
|
||||
void SoundTrack::setSoundName(const Common::String &name) {
|
||||
_soundName = name;
|
||||
}
|
||||
|
||||
void SoundTrack::setVolume(int volume) {
|
||||
_volume = MIN(volume, static_cast<int>(Audio::Mixer::kMaxChannelVolume));
|
||||
if (_handle) {
|
||||
g_system->getMixer()->setChannelVolume(*_handle, (byte)getEffectiveVolume());
|
||||
}
|
||||
}
|
||||
|
||||
void SoundTrack::setPosition(bool positioned, const Math::Vector3d &pos) {
|
||||
_positioned = positioned;
|
||||
_pos = pos;
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
void SoundTrack::updatePosition() {
|
||||
if (!_positioned)
|
||||
return;
|
||||
|
||||
Set *set = g_grim->getCurrSet();
|
||||
Set::Setup *setup = set->getCurrSetup();
|
||||
Math::Vector3d cameraPos = setup->_pos;
|
||||
Math::Vector3d vector = _pos - cameraPos;
|
||||
float distance = vector.getMagnitude();
|
||||
if (_volume == 0) {
|
||||
_attenuation = 0.0f;
|
||||
} else {
|
||||
_attenuation = MAX(0.0f, 1.0f - distance / (_volume * 100.0f / Audio::Mixer::kMaxChannelVolume));
|
||||
}
|
||||
|
||||
Math::Matrix4 worldRot = setup->_rot;
|
||||
Math::Vector3d relPos = (_pos - setup->_pos);
|
||||
Math::Vector3d p(relPos);
|
||||
p = p * worldRot.getRotation();
|
||||
float angle = atan2(p.x(), p.z());
|
||||
float pan = sin(angle);
|
||||
_balance = (int)(pan * 127.0f);
|
||||
|
||||
if (_handle) {
|
||||
g_system->getMixer()->setChannelBalance(*_handle, _balance);
|
||||
g_system->getMixer()->setChannelVolume(*_handle, (byte)getEffectiveVolume());
|
||||
}
|
||||
}
|
||||
|
||||
void SoundTrack::setBalance(int balance) {
|
||||
if (_positioned)
|
||||
return;
|
||||
_balance = balance;
|
||||
if (_handle) {
|
||||
g_system->getMixer()->setChannelBalance(*_handle, _balance);
|
||||
}
|
||||
}
|
||||
|
||||
bool SoundTrack::play() {
|
||||
if (_stream) {
|
||||
if (isPlaying()) {
|
||||
warning("sound: %s already playing, don't start again!", _soundName.c_str());
|
||||
return true;
|
||||
}
|
||||
// If _disposeAfterPlaying is NO, the destructor will take care of the stream.
|
||||
g_system->getMixer()->playStream(_soundType, _handle, _stream, -1, (byte)getEffectiveVolume(), _balance, _disposeAfterPlaying);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SoundTrack::pause() {
|
||||
_paused = !_paused;
|
||||
if (_stream) {
|
||||
g_system->getMixer()->pauseHandle(*_handle, _paused);
|
||||
}
|
||||
}
|
||||
|
||||
void SoundTrack::stop() {
|
||||
if (_handle)
|
||||
g_system->getMixer()->stopHandle(*_handle);
|
||||
}
|
||||
|
||||
void SoundTrack::setFade(float fade) {
|
||||
_fade = fade;
|
||||
if (_handle) {
|
||||
g_system->getMixer()->setChannelVolume(*_handle, (byte)getEffectiveVolume());
|
||||
}
|
||||
}
|
||||
|
||||
int SoundTrack::getEffectiveVolume() {
|
||||
return _volume * _attenuation * _fade;
|
||||
}
|
||||
|
||||
} // end of namespace Grim
|
||||
106
engines/grim/emi/sound/track.h
Normal file
106
engines/grim/emi/sound/track.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/* 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_SOUNDTRACK_H
|
||||
#define GRIM_SOUNDTRACK_H
|
||||
|
||||
#include "audio/mixer.h"
|
||||
#include "audio/timestamp.h"
|
||||
|
||||
#include "math/vector3d.h"
|
||||
|
||||
namespace Common {
|
||||
class String;
|
||||
}
|
||||
|
||||
namespace Audio {
|
||||
class AudioStream;
|
||||
class SoundHandle;
|
||||
}
|
||||
|
||||
namespace Grim {
|
||||
|
||||
class SaveGame;
|
||||
|
||||
/**
|
||||
* @class Super-class for the different codecs used in EMI
|
||||
*/
|
||||
class SoundTrack {
|
||||
public:
|
||||
enum FadeMode {
|
||||
FadeNone,
|
||||
FadeIn,
|
||||
FadeOut
|
||||
};
|
||||
protected:
|
||||
Common::String _soundName;
|
||||
Audio::AudioStream *_stream;
|
||||
Audio::SoundHandle *_handle;
|
||||
Audio::Mixer::SoundType _soundType;
|
||||
DisposeAfterUse::Flag _disposeAfterPlaying;
|
||||
bool _paused;
|
||||
bool _positioned;
|
||||
Math::Vector3d _pos;
|
||||
FadeMode _fadeMode;
|
||||
float _fade;
|
||||
float _attenuation;
|
||||
int _balance;
|
||||
int _volume;
|
||||
int _sync;
|
||||
public:
|
||||
SoundTrack();
|
||||
virtual ~SoundTrack();
|
||||
virtual bool openSound(const Common::String &filename, const Common::String &voiceName, const Audio::Timestamp *start = nullptr) = 0;
|
||||
virtual bool isPlaying() = 0;
|
||||
virtual bool play();
|
||||
virtual void pause();
|
||||
virtual void stop();
|
||||
|
||||
void fadeIn() { _fadeMode = FadeIn; }
|
||||
void fadeOut() { _fadeMode = FadeOut; }
|
||||
void setFadeMode(FadeMode fadeMode) { _fadeMode = fadeMode; }
|
||||
void setFade(float fade);
|
||||
float getFade() const { return _fade; }
|
||||
FadeMode getFadeMode() const { return _fadeMode; }
|
||||
void setBalance(int balance);
|
||||
void setVolume(int volume);
|
||||
void setPosition(bool positioned, const Math::Vector3d &pos = Math::Vector3d());
|
||||
void updatePosition();
|
||||
void setSync(int sync) { _sync = sync; }
|
||||
int getEffectiveVolume();
|
||||
int getVolume() const { return _volume; }
|
||||
int getBalance() const { return _balance; }
|
||||
int getSync() const { return _sync; }
|
||||
virtual Audio::Timestamp getPos() = 0;
|
||||
Common::String getSoundName();
|
||||
void setSoundName(const Common::String &name);
|
||||
virtual bool hasLooped() { return false; }
|
||||
virtual void setLooping(bool looping) { }
|
||||
virtual bool isLooping() const { return false; }
|
||||
bool isPaused() const { return _paused; }
|
||||
bool isPositioned() const { return _positioned; }
|
||||
Math::Vector3d getWorldPos() const { return _pos; }
|
||||
Audio::Mixer::SoundType getSoundType() const { return _soundType; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user