scummvm/engines/saga2/sprite.h

391 lines
12 KiB
C
Raw Normal View History

2021-05-17 18:47:39 +00:00
/* 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.
2021-05-17 18:47:39 +00:00
*
* 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/>.
2021-05-17 18:47:39 +00:00
*
*
* Based on the original sources
* Faery Tale II -- The Halls of the Dead
* (c) 1993-1996 The Wyrmkeep Entertainment Co.
*/
#ifndef SAGA2_SPRITE_H
#define SAGA2_SPRITE_H
#include "saga2/rect.h"
2021-05-17 18:47:39 +00:00
namespace Saga2 {
class gPort;
class gPixelMap;
2021-05-17 18:47:39 +00:00
/* ===================================================================== *
Basic sprite structures
* ===================================================================== */
// Sprite: A structure representing a single sprite
struct Sprite {
Extent16 size; // size of sprite
Point16 offset; // sprite origin point
byte *data;
uint32 dataSize;
2021-06-15 14:06:50 +00:00
Sprite(Common::SeekableReadStream *stream);
~Sprite();
2021-05-17 18:47:39 +00:00
// sprite data follows.
};
// SpriteSet: A bunch of sprites in a single resource
struct SpriteSet {
uint32 count; // number of images in the range
Sprite **sprites;
2021-05-17 18:47:39 +00:00
// (variable-length array)
// sprite structures follow table
2021-06-15 14:06:50 +00:00
SpriteSet(Common::SeekableReadStream *stream);
~SpriteSet();
2021-05-17 18:47:39 +00:00
// Member function to return a sprite from the set
Sprite *sprite(int16 index) {
return sprites[index];
2021-05-17 18:47:39 +00:00
}
// Sprite &operator[]( int32 index )
// {
2021-06-07 16:19:10 +00:00
// return (Sprite *)( (uint8 *)this + offsets[index] );
2021-05-17 18:47:39 +00:00
// }
};
2021-06-03 09:47:26 +00:00
extern SpriteSet *objectSprites, // object sprites
*mentalSprites, // intagible object sprites
*weaponSprites[], // weapon sprites
*missileSprites; // missile sprites
2021-05-17 18:47:39 +00:00
/* ===================================================================== *
Describes the facing directions of actor sprites
* ===================================================================== */
enum spriteFacingDirections {
2022-10-29 12:49:08 +00:00
kSprFaceDown = 0,
kSprFaceDownLeft,
kSprFaceLeft,
kSprFaceUpLeft,
kSprFaceUp
2021-05-17 18:47:39 +00:00
};
/* ===================================================================== *
ActorPose: Describes an element of a choreographed action
* ===================================================================== */
2022-10-29 12:49:08 +00:00
const int kNumPoseFacings = 8;
2021-05-17 18:47:39 +00:00
// Describes a single entry in an actor sequence
struct ActorPose {
// Sequence element flags
enum {
// Indicates which of the sprites should be drawn flipped
// left-to-right
2022-10-29 12:49:08 +00:00
kActorFlipped = (1 << 0), // actor spr flipped left/right
kLeftObjectFlipped = (1 << 1), // left hand object flipped
kRightObjectFlipped = (1 << 2), // right hand object flipped
2021-05-17 18:47:39 +00:00
// Indicates the front-to-back priority of the objects
2022-10-29 12:49:08 +00:00
kLeftObjectInFront = (1 << 3), // left object in front of actor
kRightObjectInFront = (1 << 4), // right object in front of actor
kLeftOverRight = (1 << 5) // left in front of right
2021-05-17 18:47:39 +00:00
};
uint16 flags; // sequence element flags
uint8 actorFrameIndex, // actor sprite index
actorFrameBank; // which bank actor frame is in
uint8 leftObjectIndex, // index of obj in left hand
rightObjectIndex; // index of obj in right hand
Point16 leftObjectOffset, // offset of left-hand obj.
rightObjectOffset; // offset of right-hand obj.
// 14 bytes
2021-06-20 11:20:06 +00:00
ActorPose();
ActorPose(Common::SeekableReadStream *stream);
void load(Common::SeekableReadStream *stream);
2021-07-07 00:25:04 +00:00
void write(Common::MemoryWriteStreamDynamic *out);
2021-05-17 18:47:39 +00:00
};
// A choreographed sequence of frames
struct ActorAnimation {
// For each facing direction, the offset to the
// table of poses for that sequence, and the number of poses
// in the sequence.
2022-10-29 12:49:08 +00:00
uint16 start[kNumPoseFacings];
uint16 count[kNumPoseFacings];
2021-06-20 11:20:06 +00:00
ActorAnimation(Common::SeekableReadStream *stream);
// 32 bytes
2021-05-17 18:47:39 +00:00
};
struct ActorAnimSet {
2021-06-20 11:20:06 +00:00
uint32 numAnimations; // number of animations
uint32 poseOffset; // offset to poses table
ActorAnimation **animations;
ActorPose **poses;
uint32 numPoses;
2021-05-17 18:47:39 +00:00
};
/* ===================================================================== *
Sprite color lookup tables
* ===================================================================== */
2021-06-07 16:19:10 +00:00
typedef uint8 ColorTable[256];
2021-05-17 18:47:39 +00:00
// List of color schemes for sprites
struct ColorScheme {
2021-06-07 16:19:10 +00:00
uint8 bank[11];
2021-05-17 18:47:39 +00:00
uint8 speechColor;
2021-06-07 16:19:10 +00:00
char name[32];
ColorScheme() {}
ColorScheme(Common::SeekableReadStream *stream);
};
class ColorSchemeList {
public:
int _count;
ColorScheme **_schemes;
ColorSchemeList(int count, Common::SeekableReadStream *stream);
2021-07-11 22:42:40 +00:00
~ColorSchemeList();
2021-05-17 18:47:39 +00:00
};
/* ===================================================================== *
Composite sprites (characters made from several component sprites)
* ===================================================================== */
struct SpriteComponent {
Sprite *sp; // the sprite to draw
Point16 offset; // offset from given origin
uint8 *colorTable; // color lookup table
2021-06-13 14:56:52 +00:00
uint8 flipped; // true if horizontally flipped.
2021-05-17 18:47:39 +00:00
};
enum spriteEffectFlags {
2022-10-29 12:49:08 +00:00
kSprFXGhosted = (1 << 0), // semi-translucent dither
kSprFXTerrainMask = (1 << 1), // mask sprite to terrain
kSprFXGhostIfObscured = (1 << 2) // apply ghosted effect if
2021-05-17 18:47:39 +00:00
// obscured by terrain
};
/* ===================================================================== *
Object sprite information structure
* ===================================================================== */
struct ObjectSpriteInfo {
Sprite *sp; // object sprite
bool flipped; // mirror sprite horizontally
};
/* ===================================================================== *
Actor Appearance
* ===================================================================== */
// Bits which represent the various "banks" of sprites for
// each actor.
// REM: I think we want more banks than this...
enum spriteBankNums {
2022-10-29 12:49:08 +00:00
kSprStandBankNum = 0,
kSprWalkBankNum,
kSprRunBankNum,
kSprKneelBankNum,
kSprLeapBankNum,
kSprClimbBankNum,
kSprTalkBankNum,
kSprFight1HBankNum,
kSprFight2HBankNum,
kSprFireBankNum,
kSprPassiveBankNum,
kSprUpStairsBankNum,
kSprDnStairsBankNum,
kSprSitBankNum,
kSprBankCount
2021-05-17 18:47:39 +00:00
};
enum spriteBankBits {
2022-10-29 12:49:08 +00:00
kSprStandBank = (1 << kSprStandBankNum),
kSprWalkBank = (1 << kSprWalkBankNum),
kSprRunBank = (1 << kSprRunBankNum),
kSprKneelBank = (1 << kSprKneelBankNum),
kSprLeapBank = (1 << kSprLeapBankNum),
kSprClimbBank = (1 << kSprClimbBankNum),
kSprTalkBank = (1 << kSprTalkBankNum),
kSprFight1HBank = (1 << kSprFight1HBankNum),
kSprFight2HBank = (1 << kSprFight2HBankNum),
kSprFireBank = (1 << kSprFireBankNum),
kSprPassiveBank = (1 << kSprPassiveBankNum),
kSprUpStairsBank = (1 << kSprUpStairsBankNum),
kSprDnStairsBank = (1 << kSprDnStairsBankNum),
kSprSitBank = (1 << kSprSitBankNum)
2021-05-17 18:47:39 +00:00
};
// This structure is used to contain all of the items needed
// to draw an actor, including sprite set, frame list, and
// wielding offsets.
//
// There is an LRU cache of these structures maintained by
// the sprite coordinator.
2021-06-20 11:20:06 +00:00
class ActorAppearance {
2021-05-17 18:47:39 +00:00
public:
int16 _useCount; // how many actors using this
uint32 _id;
2021-05-17 18:47:39 +00:00
ActorAnimSet *_poseList; // list of action sequences
ColorSchemeList *_schemeList; // color remapping info
2021-05-17 18:47:39 +00:00
2022-10-29 12:49:08 +00:00
SpriteSet *_spriteBanks[kSprBankCount];
2021-05-17 18:47:39 +00:00
void loadSpriteBanks(int16 banksNeeded);
// Determine if this bank is loaded
bool isBankLoaded(int16 bank) {
return _spriteBanks[bank] != nullptr;
2021-05-17 18:47:39 +00:00
}
// A request to load a bank.
void requestBank(int16 bank) {
// Initiate a load of the sprite bank needed.
2021-06-07 15:43:05 +00:00
if (!isBankLoaded(bank))
2021-05-17 18:47:39 +00:00
loadSpriteBanks((int16)(1 << bank));
}
2021-06-19 08:30:14 +00:00
ActorAnimation *animation(int num) {
if (_poseList == nullptr)
2021-06-20 12:07:28 +00:00
return nullptr;
if (num >= (int)_poseList->numAnimations) {
warning("ActorPose:animation(), animation number is too high, %d >= %d", num, _poseList->numAnimations);
2021-06-20 12:07:28 +00:00
return nullptr;
}
if (_poseList)
return _poseList->animations[num];
2021-06-19 08:30:14 +00:00
return nullptr;
}
ActorPose *pose(ActorAnimation *anim, int dir, int num) {
if (_poseList == nullptr)
2021-06-19 08:30:14 +00:00
return nullptr;
2021-06-20 11:20:06 +00:00
if (num < 0 || num >= anim->count[dir])
num = 0;
2021-06-19 08:30:14 +00:00
num += anim->start[dir];
2021-06-20 11:20:06 +00:00
if (num >= (int)_poseList->numPoses) {
warning("ActorPose::pose(), pose number is too high, %d >= %d", num, _poseList->numPoses);
2021-06-20 11:20:06 +00:00
return nullptr;
}
return _poseList->poses[num];
2021-06-19 08:30:14 +00:00
}
2021-05-17 18:47:39 +00:00
};
/* ===================================================================== *
Prototypes
* ===================================================================== */
2021-09-11 09:13:35 +00:00
void initSprites();
void cleanupSprites();
2021-05-17 18:47:39 +00:00
struct TilePoint;
2021-05-17 18:47:39 +00:00
// Draw a plain sprite into a gPort, no masking or clipping
void DrawSprite(gPort &port, const Point16 &dest, Sprite *sp);
// Draw a composite sprite with both masking and color mapping
void DrawCompositeMaskedSprite(
gPort &port, // destination gPort
SpriteComponent *scList, // list of components
int16 numParts, // number of components
const Point16 &destPoint, // where to render to
const TilePoint &loc, // location on map
int16 effects, // effects flags
bool *obscured = NULL); // set if object is obscured by terrain
// Draw a single sprite with color mapping only
void DrawColorMappedSprite(
gPort &port, // destination gPort
const Point16 &destPoint, // where to render to
Sprite *sp, // sprite pointer
uint8 *colorTable); // color remapping table
// Color map a sprite into a gPixelMap.
void ExpandColorMappedSprite(
gPixelMap &map, // destination gPixelMap
Sprite *sp, // sprite pointer
uint8 *colorTable); // color remapping table
// Return a specific pixel from a sprite for mouse hit test
uint8 GetSpritePixel(
Sprite *sp, // sprite pointer
2021-06-13 14:56:52 +00:00
int16 flipped, // true if sprite was flipped
2021-05-17 18:47:39 +00:00
const Point16 &testPoint); // where to render to
// Return the number of visible pixels in a sprite after terrain masking
uint16 visiblePixelsInSprite(
Sprite *sp, // sprite pointer
bool flipped, // is sprite flipped
ColorTable colors, // sprite's color table
Point16 drawPos, // XY position of sprite
TilePoint loc, // UVZ coordinates of sprite
uint16 roofID); // ID of ripped roof
// Assemble a color lookup table
void buildColorTable(
uint8 *colorTable, // color table to build
uint8 *colorOptions, // colors ranges chosen
int16 numOptions);
// Functions to load and release an actor appearance
ActorAppearance *LoadActorAppearance(uint32 id, int16 banksNeeded);
void ReleaseActorAppearance(ActorAppearance *aa);
} // end of namespace Saga2
#endif