mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-07 18:31:37 +00:00
480 lines
13 KiB
C++
480 lines
13 KiB
C++
/* 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 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 SCI_GRAPHICS_TEXT32_H
|
|
#define SCI_GRAPHICS_TEXT32_H
|
|
|
|
#include "sci/graphics/celobj32.h"
|
|
#include "sci/graphics/frameout.h"
|
|
|
|
namespace Sci {
|
|
|
|
enum TextAlign {
|
|
kTextAlignLeft = 0,
|
|
kTextAlignCenter = 1,
|
|
kTextAlignRight = 2
|
|
};
|
|
|
|
enum BitmapFlags {
|
|
kBitmapRemap = 2
|
|
};
|
|
|
|
#define BITMAP_PROPERTY(size, property, offset)\
|
|
inline uint##size get##property() const {\
|
|
return READ_SCI11ENDIAN_UINT##size(_bitmap + (offset));\
|
|
}\
|
|
inline void set##property(uint##size value) {\
|
|
WRITE_SCI11ENDIAN_UINT##size(_bitmap + (offset), (value));\
|
|
}
|
|
|
|
/**
|
|
* A convenience class for creating and modifying in-memory
|
|
* bitmaps.
|
|
*/
|
|
class BitmapResource {
|
|
byte *_bitmap;
|
|
reg_t _object;
|
|
|
|
/**
|
|
* Gets the size of the bitmap header for the current
|
|
* engine version.
|
|
*/
|
|
static inline uint16 getBitmapHeaderSize() {
|
|
// TODO: These values are accurate for each engine, but there may be no reason
|
|
// to not simply just always use size 40, since SCI2.1mid does not seem to
|
|
// actually store any data above byte 40, and SCI2 did not allow bitmaps with
|
|
// scaling resolutions other than the default (320x200). Perhaps SCI3 used
|
|
// the extra bytes, or there is some reason why they tried to align the header
|
|
// size with other headers like pic headers?
|
|
// uint32 bitmapHeaderSize;
|
|
// if (getSciVersion() >= SCI_VERSION_2_1_MIDDLE) {
|
|
// bitmapHeaderSize = 46;
|
|
// } else if (getSciVersion() == SCI_VERSION_2_1_EARLY) {
|
|
// bitmapHeaderSize = 40;
|
|
// } else {
|
|
// bitmapHeaderSize = 36;
|
|
// }
|
|
// return bitmapHeaderSize;
|
|
return 46;
|
|
}
|
|
|
|
/**
|
|
* Gets the byte size of a bitmap with the given width
|
|
* and height.
|
|
*/
|
|
static inline uint32 getBitmapSize(const uint16 width, const uint16 height) {
|
|
return width * height + getBitmapHeaderSize();
|
|
}
|
|
|
|
public:
|
|
/**
|
|
* Create a bitmap resource for an existing bitmap.
|
|
* Ownership of the bitmap is retained by the caller.
|
|
*/
|
|
inline BitmapResource(reg_t bitmap) :
|
|
_bitmap(g_sci->getEngineState()->_segMan->getHunkPointer(bitmap)),
|
|
_object(bitmap) {
|
|
if (_bitmap == nullptr || getUncompressedDataOffset() != getBitmapHeaderSize()) {
|
|
error("Invalid Text bitmap %04x:%04x", PRINT_REG(bitmap));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Allocates and initialises a new bitmap in the given
|
|
* segment manager.
|
|
*/
|
|
inline BitmapResource(SegManager *segMan, const int16 width, const int16 height, const uint8 skipColor, const int16 displaceX, const int16 displaceY, const int16 scaledWidth, const int16 scaledHeight, const uint32 hunkPaletteOffset, const bool remap) {
|
|
|
|
_object = segMan->allocateHunkEntry("Bitmap()", getBitmapSize(width, height));
|
|
_bitmap = segMan->getHunkPointer(_object);
|
|
|
|
const uint16 bitmapHeaderSize = getBitmapHeaderSize();
|
|
|
|
setWidth(width);
|
|
setHeight(height);
|
|
setDisplace(Common::Point(displaceX, displaceY));
|
|
setSkipColor(skipColor);
|
|
_bitmap[9] = 0;
|
|
WRITE_SCI11ENDIAN_UINT16(_bitmap + 10, 0);
|
|
setRemap(remap);
|
|
setDataSize(width * height);
|
|
WRITE_SCI11ENDIAN_UINT32(_bitmap + 16, 0);
|
|
setHunkPaletteOffset(hunkPaletteOffset);
|
|
setDataOffset(bitmapHeaderSize);
|
|
setUncompressedDataOffset(bitmapHeaderSize);
|
|
setControlOffset(0);
|
|
setScaledWidth(scaledWidth);
|
|
setScaledHeight(scaledHeight);
|
|
}
|
|
|
|
reg_t getObject() const {
|
|
return _object;
|
|
}
|
|
|
|
BITMAP_PROPERTY(16, Width, 0);
|
|
BITMAP_PROPERTY(16, Height, 2);
|
|
|
|
inline Common::Point getDisplace() const {
|
|
return Common::Point(
|
|
(int16)READ_SCI11ENDIAN_UINT16(_bitmap + 4),
|
|
(int16)READ_SCI11ENDIAN_UINT16(_bitmap + 6)
|
|
);
|
|
}
|
|
|
|
inline void setDisplace(const Common::Point &displace) {
|
|
WRITE_SCI11ENDIAN_UINT16(_bitmap + 4, (uint16)displace.x);
|
|
WRITE_SCI11ENDIAN_UINT16(_bitmap + 6, (uint16)displace.y);
|
|
}
|
|
|
|
inline uint8 getSkipColor() const {
|
|
return _bitmap[8];
|
|
}
|
|
|
|
inline void setSkipColor(const uint8 skipColor) {
|
|
_bitmap[8] = skipColor;
|
|
}
|
|
|
|
inline bool getRemap() const {
|
|
return READ_SCI11ENDIAN_UINT16(_bitmap + 10) & kBitmapRemap;
|
|
}
|
|
|
|
inline void setRemap(const bool remap) {
|
|
uint16 flags = READ_SCI11ENDIAN_UINT16(_bitmap + 10);
|
|
if (remap) {
|
|
flags |= kBitmapRemap;
|
|
} else {
|
|
flags &= ~kBitmapRemap;
|
|
}
|
|
WRITE_SCI11ENDIAN_UINT16(_bitmap + 10, flags);
|
|
}
|
|
|
|
BITMAP_PROPERTY(32, DataSize, 12);
|
|
|
|
inline uint32 getHunkPaletteOffset() const {
|
|
return READ_SCI11ENDIAN_UINT32(_bitmap + 20);
|
|
}
|
|
|
|
void setHunkPaletteOffset(uint32 hunkPaletteOffset) {
|
|
if (hunkPaletteOffset) {
|
|
hunkPaletteOffset += getBitmapHeaderSize();
|
|
}
|
|
|
|
WRITE_SCI11ENDIAN_UINT32(_bitmap + 20, hunkPaletteOffset);
|
|
}
|
|
|
|
BITMAP_PROPERTY(32, DataOffset, 24);
|
|
|
|
// NOTE: This property is used as a "magic number" for
|
|
// validating that a block of memory is a valid bitmap,
|
|
// and so is always set to the size of the header.
|
|
BITMAP_PROPERTY(32, UncompressedDataOffset, 28);
|
|
|
|
// NOTE: This property always seems to be zero
|
|
BITMAP_PROPERTY(32, ControlOffset, 32);
|
|
|
|
inline uint16 getScaledWidth() const {
|
|
if (getDataOffset() >= 40) {
|
|
return READ_SCI11ENDIAN_UINT16(_bitmap + 36);
|
|
}
|
|
|
|
// SCI2 bitmaps did not have scaling ability
|
|
return 320;
|
|
}
|
|
|
|
inline void setScaledWidth(uint16 scaledWidth) {
|
|
if (getDataOffset() >= 40) {
|
|
WRITE_SCI11ENDIAN_UINT16(_bitmap + 36, scaledWidth);
|
|
}
|
|
}
|
|
|
|
inline uint16 getScaledHeight() const {
|
|
if (getDataOffset() >= 40) {
|
|
return READ_SCI11ENDIAN_UINT16(_bitmap + 38);
|
|
}
|
|
|
|
// SCI2 bitmaps did not have scaling ability
|
|
return 200;
|
|
}
|
|
|
|
inline void setScaledHeight(uint16 scaledHeight) {
|
|
if (getDataOffset() >= 40) {
|
|
WRITE_SCI11ENDIAN_UINT16(_bitmap + 38, scaledHeight);
|
|
}
|
|
}
|
|
|
|
inline byte *getPixels() {
|
|
return _bitmap + getUncompressedDataOffset();
|
|
}
|
|
};
|
|
|
|
class GfxFont;
|
|
|
|
/**
|
|
* This class handles text calculation and rendering for
|
|
* SCI32 games. The text calculation system in SCI32 is
|
|
* nearly the same as SCI16, which means this class behaves
|
|
* similarly. Notably, GfxText32 maintains drawing
|
|
* parameters across multiple calls.
|
|
*/
|
|
class GfxText32 {
|
|
private:
|
|
SegManager *_segMan;
|
|
GfxCache *_cache;
|
|
|
|
/**
|
|
* The resource ID of the default font used by the game.
|
|
*
|
|
* @todo Check all SCI32 games to learn what their
|
|
* default font is.
|
|
*/
|
|
static int16 _defaultFontId;
|
|
|
|
/**
|
|
* The width and height of the currently active text
|
|
* bitmap, in text-system coordinates.
|
|
*
|
|
* @note These are unsigned in the actual engine.
|
|
*/
|
|
int16 _width, _height;
|
|
|
|
/**
|
|
* The color used to draw text.
|
|
*/
|
|
uint8 _foreColor;
|
|
|
|
/**
|
|
* The background color of the text box.
|
|
*/
|
|
uint8 _backColor;
|
|
|
|
/**
|
|
* The transparent color of the text box. Used when
|
|
* compositing the bitmap onto the screen.
|
|
*/
|
|
uint8 _skipColor;
|
|
|
|
/**
|
|
* The rect where the text is drawn within the bitmap.
|
|
* This rect is clipped to the dimensions of the bitmap.
|
|
*/
|
|
Common::Rect _textRect;
|
|
|
|
/**
|
|
* The text being drawn to the currently active text
|
|
* bitmap.
|
|
*/
|
|
Common::String _text;
|
|
|
|
/**
|
|
* The font being used to draw the text.
|
|
*/
|
|
GuiResourceId _fontId;
|
|
|
|
/**
|
|
* The color of the text box border.
|
|
*/
|
|
int16 _borderColor;
|
|
|
|
/**
|
|
* TODO: Document
|
|
*/
|
|
bool _dimmed;
|
|
|
|
/**
|
|
* The text alignment for the drawn text.
|
|
*/
|
|
TextAlign _alignment;
|
|
|
|
int16 _field_20;
|
|
|
|
/**
|
|
* TODO: Document
|
|
*/
|
|
int16 _field_22;
|
|
|
|
int _field_2C, _field_30, _field_34, _field_38;
|
|
|
|
int16 _field_3C;
|
|
|
|
/**
|
|
* The position of the text draw cursor.
|
|
*/
|
|
Common::Point _drawPosition;
|
|
|
|
void drawFrame(const Common::Rect &rect, const int16 size, const uint8 color, const bool doScaling);
|
|
|
|
void drawChar(const char charIndex);
|
|
void drawText(const uint index, uint length);
|
|
|
|
/**
|
|
* Gets the length of the longest run of text available
|
|
* within the currently loaded text, starting from the
|
|
* given `charIndex` and running for up to `maxWidth`
|
|
* pixels. Returns the number of characters that can be
|
|
* written, and mutates the value pointed to by
|
|
* `charIndex` to point to the index of the next
|
|
* character to render.
|
|
*/
|
|
uint getLongest(uint *charIndex, const int16 maxWidth);
|
|
|
|
/**
|
|
* Gets the pixel width of a substring of the currently
|
|
* loaded text, without scaling.
|
|
*/
|
|
int16 getTextWidth(const uint index, uint length) const;
|
|
|
|
inline Common::Rect scaleRect(const Common::Rect &rect) {
|
|
Common::Rect scaledRect(rect);
|
|
int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
|
|
int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
|
|
Ratio scaleX(_scaledWidth, scriptWidth);
|
|
Ratio scaleY(_scaledHeight, scriptHeight);
|
|
mulinc(scaledRect, scaleX, scaleY);
|
|
return scaledRect;
|
|
}
|
|
|
|
public:
|
|
GfxText32(SegManager *segMan, GfxCache *fonts);
|
|
|
|
/**
|
|
* The memory handle of the currently active bitmap.
|
|
*/
|
|
reg_t _bitmap;
|
|
|
|
/**
|
|
* The size of the x-dimension of the coordinate system
|
|
* used by the text renderer.
|
|
*/
|
|
int16 _scaledWidth;
|
|
|
|
/**
|
|
* The size of the y-dimension of the coordinate system
|
|
* used by the text renderer.
|
|
*/
|
|
int16 _scaledHeight;
|
|
|
|
/**
|
|
* The currently active font resource used to write text
|
|
* into the bitmap.
|
|
*
|
|
* @note SCI engine builds the font table directly
|
|
* inside of FontMgr; we use GfxFont instead.
|
|
*/
|
|
GfxFont *_font;
|
|
|
|
/**
|
|
* Creates a plain font bitmap with a flat color
|
|
* background.
|
|
*/
|
|
reg_t createFontBitmap(int16 width, int16 height, const Common::Rect &rect, const Common::String &text, const uint8 foreColor, const uint8 backColor, const uint8 skipColor, const GuiResourceId fontId, TextAlign alignment, const int16 borderColor, bool dimmed, const bool doScaling);
|
|
|
|
/**
|
|
* Creates a font bitmap with a view background.
|
|
*/
|
|
reg_t createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &rect, const Common::String &text, const int16 foreColor, const int16 backColor, const GuiResourceId fontId, const int16 skipColor, const int16 borderColor, const bool dimmed);
|
|
|
|
/**
|
|
* Creates a font bitmap with a title.
|
|
*/
|
|
reg_t createTitledBitmap(const int16 width, const int16 height, const Common::Rect &textRect, const Common::String &text, const int16 foreColor, const int16 backColor, const int16 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, Common::String &title, const int16 titleForeColor, const int16 titleBackColor, const GuiResourceId titleFontId, const bool doScaling);
|
|
|
|
inline int scaleUpWidth(int value) const {
|
|
const int scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
|
|
return (value * scriptWidth + _scaledWidth - 1) / _scaledWidth;
|
|
}
|
|
|
|
inline int scaleUpHeight(int value) const {
|
|
const int scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
|
|
return (value * scriptHeight + _scaledHeight - 1) / _scaledHeight;
|
|
}
|
|
|
|
/**
|
|
* Draws the text to the bitmap.
|
|
*/
|
|
void drawTextBox();
|
|
|
|
/**
|
|
* Draws the given text to the bitmap.
|
|
*
|
|
* @note The original engine holds a reference to a
|
|
* shared string which lets the text be updated from
|
|
* outside of the font manager. Instead, we give this
|
|
* extra signature to send the text to draw.
|
|
*
|
|
* TODO: Use shared string instead?
|
|
*/
|
|
void drawTextBox(const Common::String &text);
|
|
|
|
/**
|
|
* Erases the given rect by filling with the background
|
|
* color.
|
|
*/
|
|
void erase(const Common::Rect &rect, const bool doScaling);
|
|
|
|
void invertRect(const reg_t bitmap, const int16 bitmapStride, const Common::Rect &rect, const uint8 foreColor, const uint8 backColor, const bool doScaling);
|
|
|
|
/**
|
|
* Sets the font to be used for rendering and
|
|
* calculation of text dimensions.
|
|
*/
|
|
void setFont(const GuiResourceId fontId);
|
|
|
|
/**
|
|
* Gets the width of a character.
|
|
*/
|
|
uint16 getCharWidth(const char charIndex, const bool doScaling) const;
|
|
|
|
/**
|
|
* Retrieves the width and height of a block of text.
|
|
*/
|
|
Common::Rect getTextSize(const Common::String &text, const int16 maxWidth, bool doScaling);
|
|
|
|
/**
|
|
* Gets the pixel width of a substring of the currently
|
|
* loaded text, with scaling.
|
|
*/
|
|
int16 getTextWidth(const Common::String &text, const uint index, const uint length);
|
|
|
|
/**
|
|
* Retrieves the width of a line of text.
|
|
*/
|
|
int16 getStringWidth(const Common::String &text);
|
|
|
|
/**
|
|
* Gets the number of characters of `text`, starting
|
|
* from `index`, that can be safely rendered into
|
|
* `textRect`.
|
|
*/
|
|
int16 getTextCount(const Common::String &text, const uint index, const Common::Rect &textRect, const bool doScaling);
|
|
|
|
/**
|
|
* Gets the number of characters of `text`, starting
|
|
* from `index`, that can be safely rendered into
|
|
* `textRect` using the given font.
|
|
*/
|
|
int16 getTextCount(const Common::String &text, const uint index, const GuiResourceId fontId, const Common::Rect &textRect, const bool doScaling);
|
|
};
|
|
|
|
} // End of namespace Sci
|
|
|
|
#endif
|