scummvm/engines/saga2/sprite.h

391 lines
12 KiB
C
Raw Normal View History

2021-05-17 20:47:39 +02: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 20:47:39 +02: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 20:47:39 +02: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 20:47:39 +02:00
namespace Saga2 {
class gPort;
class gPixelMap;
2021-05-17 20:47:39 +02:00
/* ===================================================================== *
Basic sprite structures
* ===================================================================== */
// Sprite: A structure representing a single sprite
struct Sprite {
Extent16 size; // size of sprite
Point16 offset; // sprite origin point
2021-06-15 23:06:50 +09:00
byte *_data;
uint32 _dataSize;
2021-06-15 23:06:50 +09:00
Sprite(Common::SeekableReadStream *stream);
~Sprite();
2021-05-17 20:47:39 +02:00
// sprite data follows.
};
// SpriteSet: A bunch of sprites in a single resource
struct SpriteSet {
uint32 count; // number of images in the range
2021-06-15 23:06:50 +09:00
Sprite **_sprites;
2021-05-17 20:47:39 +02:00
// (variable-length array)
// sprite structures follow table
2021-06-15 23:06:50 +09:00
SpriteSet(Common::SeekableReadStream *stream);
~SpriteSet();
2021-05-17 20:47:39 +02:00
// Member function to return a sprite from the set
Sprite *sprite(int16 index) {
2021-06-15 23:06:50 +09:00
return _sprites[index];
2021-05-17 20:47:39 +02:00
}
// Sprite &operator[]( int32 index )
// {
2021-06-07 18:19:10 +02:00
// return (Sprite *)( (uint8 *)this + offsets[index] );
2021-05-17 20:47:39 +02:00
// }
};
2021-06-03 18:47:26 +09:00
extern SpriteSet *objectSprites, // object sprites
*mentalSprites, // intagible object sprites
*weaponSprites[], // weapon sprites
*missileSprites; // missile sprites
2021-05-17 20:47:39 +02:00
/* ===================================================================== *
Describes the facing directions of actor sprites
* ===================================================================== */
enum spriteFacingDirections {
sprFaceDown = 0,
sprFaceDownLeft,
sprFaceLeft,
sprFaceUpLeft,
sprFaceUp
};
/* ===================================================================== *
ActorPose: Describes an element of a choreographed action
* ===================================================================== */
const int numPoseFacings = 8;
// 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
actorFlipped = (1 << 0), // actor spr flipped left/right
leftObjectFlipped = (1 << 1), // left hand object flipped
rightObjectFlipped = (1 << 2), // right hand object flipped
// Indicates the front-to-back priority of the objects
leftObjectInFront = (1 << 3), // left object in front of actor
rightObjectInFront = (1 << 4), // right object in front of actor
leftOverRight = (1 << 5) // left in front of right
2021-05-17 20:47:39 +02: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 13:20:06 +02:00
ActorPose();
ActorPose(Common::SeekableReadStream *stream);
void load(Common::SeekableReadStream *stream);
2021-07-07 09:25:04 +09:00
void write(Common::MemoryWriteStreamDynamic *out);
2021-05-17 20:47:39 +02: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.
2021-06-20 13:20:06 +02:00
uint16 start[numPoseFacings];
uint16 count[numPoseFacings];
ActorAnimation(Common::SeekableReadStream *stream);
// 32 bytes
2021-05-17 20:47:39 +02:00
};
struct ActorAnimSet {
2021-06-20 13:20:06 +02:00
uint32 numAnimations; // number of animations
uint32 poseOffset; // offset to poses table
ActorAnimation **animations;
ActorPose **poses;
uint32 numPoses;
2021-05-17 20:47:39 +02:00
};
/* ===================================================================== *
Sprite color lookup tables
* ===================================================================== */
2021-06-07 18:19:10 +02:00
typedef uint8 ColorTable[256];
2021-05-17 20:47:39 +02:00
// List of color schemes for sprites
struct ColorScheme {
2021-06-07 18:19:10 +02:00
uint8 bank[11];
2021-05-17 20:47:39 +02:00
uint8 speechColor;
2021-06-07 18:19:10 +02:00
char name[32];
ColorScheme() {}
ColorScheme(Common::SeekableReadStream *stream);
};
class ColorSchemeList {
public:
int _count;
ColorScheme **_schemes;
ColorSchemeList(int count, Common::SeekableReadStream *stream);
2021-07-12 00:42:40 +02:00
~ColorSchemeList();
2021-05-17 20:47:39 +02: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 16:56:52 +02:00
uint8 flipped; // true if horizontally flipped.
2021-05-17 20:47:39 +02:00
};
enum spriteEffectFlags {
sprFXGhosted = (1 << 0), // semi-translucent dither
sprFXTerrainMask = (1 << 1), // mask sprite to terrain
sprFXGhostIfObscured = (1 << 2) // apply ghosted effect if
2021-05-17 20:47:39 +02: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 {
sprStandBankNum = 0,
sprWalkBankNum,
sprRunBankNum,
sprKneelBankNum,
sprLeapBankNum,
sprClimbBankNum,
sprTalkBankNum,
sprFight1HBankNum,
sprFight2HBankNum,
sprFireBankNum,
sprPassiveBankNum,
sprUpStairsBankNum,
sprDnStairsBankNum,
sprSitBankNum,
sprBankCount
2021-05-17 20:47:39 +02:00
};
enum spriteBankBits {
sprStandBank = (1 << sprStandBankNum),
sprWalkBank = (1 << sprWalkBankNum),
sprRunBank = (1 << sprRunBankNum),
sprKneelBank = (1 << sprKneelBankNum),
sprLeapBank = (1 << sprLeapBankNum),
sprClimbBank = (1 << sprClimbBankNum),
sprTalkBank = (1 << sprTalkBankNum),
sprFight1HBank = (1 << sprFight1HBankNum),
sprFight2HBank = (1 << sprFight2HBankNum),
sprFireBank = (1 << sprFireBankNum),
sprPassiveBank = (1 << sprPassiveBankNum),
sprUpStairsBank = (1 << sprUpStairsBankNum),
sprDnStairsBank = (1 << sprDnStairsBankNum),
sprSitBank = (1 << sprSitBankNum)
2021-05-17 20:47:39 +02: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 13:20:06 +02:00
class ActorAppearance {
2021-05-17 20:47:39 +02:00
public:
int16 useCount; // how many actors using this
uint32 id;
2021-06-07 23:12:14 +09:00
ActorAnimSet *poseList; // list of action sequences
2021-06-17 18:58:03 +09:00
ColorSchemeList *schemeList; // color remapping info
2021-05-17 20:47:39 +02:00
2021-06-07 18:19:10 +02:00
SpriteSet *spriteBanks[sprBankCount];
2021-05-17 20:47:39 +02:00
void loadSpriteBanks(int16 banksNeeded);
// Determine if this bank is loaded
bool isBankLoaded(int16 bank) {
2021-06-08 00:43:05 +09:00
return spriteBanks[bank] != nullptr;
2021-05-17 20:47:39 +02:00
}
// A request to load a bank.
void requestBank(int16 bank) {
// Initiate a load of the sprite bank needed.
2021-06-08 00:43:05 +09:00
if (!isBankLoaded(bank))
2021-05-17 20:47:39 +02:00
loadSpriteBanks((int16)(1 << bank));
}
2021-06-19 17:30:14 +09:00
ActorAnimation *animation(int num) {
2021-06-20 14:07:28 +02:00
if (poseList == nullptr)
return nullptr;
2021-06-23 04:00:16 +09:00
if (num >= (int)poseList->numAnimations) {
2021-06-20 14:07:28 +02:00
warning("ActorPose:animation(), animation number is too high, %d >= %d", num, poseList->numAnimations);
return nullptr;
}
2021-06-19 17:30:14 +09:00
if (poseList)
2021-06-20 13:20:06 +02:00
return poseList->animations[num];
2021-06-19 17:30:14 +09:00
return nullptr;
}
ActorPose *pose(ActorAnimation *anim, int dir, int num) {
if (poseList == nullptr)
return nullptr;
2021-06-20 13:20:06 +02:00
if (num < 0 || num >= anim->count[dir])
num = 0;
2021-06-19 17:30:14 +09:00
num += anim->start[dir];
2021-06-20 13:20:06 +02:00
2021-06-23 04:00:16 +09:00
if (num >= (int)poseList->numPoses) {
2021-06-20 13:20:06 +02:00
warning("ActorPose::pose(), pose number is too high, %d >= %d", num, poseList->numPoses);
return nullptr;
}
return poseList->poses[num];
2021-06-19 17:30:14 +09:00
}
2021-05-17 20:47:39 +02:00
};
/* ===================================================================== *
Prototypes
* ===================================================================== */
2021-09-11 12:13:35 +03:00
void initSprites();
void cleanupSprites();
2021-05-17 20:47:39 +02:00
struct TilePoint;
2021-05-17 20:47:39 +02: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 16:56:52 +02:00
int16 flipped, // true if sprite was flipped
2021-05-17 20:47:39 +02: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