scummvm/engines/grim/actor.h
Vincent Pelletier bad3de8a12 GRIM: Drop off-screen buffers
These were present to implement actor freezing in software rendering mode
in the way original engine was intended for performance reason.
In residualvm, software rendering will generalise the principle through
dirty-rectangles management, so off-screen buffers should not be needed.

Also, properly implementing them requires invasive changes (move previous
draw call list from global OpenGL context to individual off-screen buffers,
along with associated linear vertex allocator, adding a new draw call to
track requested buffer changes until final on-screen frame buffer
presentation).
So instead of such added complexity, lie to lua API about actor not being
in set but keep it in so it is part of normal redraw sequence.

Fixes disappearing actors in cn, bi.
Likely also fixes at, ly, sh, mn, dd which uses free/thaw lua API, but
which I did not check.
2017-05-02 09:51:47 +00:00

740 lines
19 KiB
C++

/* ResidualVM - A 3D game interpreter
*
* ResidualVM 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#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;
byte *shadowMask;
int shadowMaskSize;
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 lenght 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 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