mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-15 06:08:35 +00:00
SAGA: (ITE/PC98) - prepare font class for Japanese rendering
Reorganize font code into sub classes to allow independent rendering of the Japanese ROM font. No actual implementation for the Japanese rendering yet.
This commit is contained in:
parent
b1972dea57
commit
fa671a2c40
@ -29,434 +29,64 @@
|
||||
#include "saga/font.h"
|
||||
#include "saga/render.h"
|
||||
|
||||
#include "graphics/sjis.h"
|
||||
|
||||
namespace Saga {
|
||||
|
||||
Font::Font(SagaEngine *vm) : _vm(vm) {
|
||||
int i;
|
||||
Font::FontId Font::knownFont2FontIdx(KnownFont font) {
|
||||
FontId fontId = kSmallFont;
|
||||
|
||||
// Load font module resource context
|
||||
// The demo version of IHNM has 3 font types (like ITE), not 6 (like the full version of IHNM)
|
||||
if (_vm->getGameId() == GID_ITE || _vm->isIHNMDemo()) {
|
||||
switch (font) {
|
||||
case (kKnownFontSmall):
|
||||
default:
|
||||
fontId = kSmallFont;
|
||||
break;
|
||||
case (kKnownFontMedium):
|
||||
fontId = kMediumFont;
|
||||
break;
|
||||
case (kKnownFontBig):
|
||||
fontId = kBigFont;
|
||||
break;
|
||||
|
||||
assert(_vm->getFontsCount() > 0);
|
||||
case (kKnownFontVerb):
|
||||
fontId = kSmallFont;
|
||||
break;
|
||||
case (kKnownFontScript):
|
||||
fontId = kMediumFont;
|
||||
break;
|
||||
case (kKnownFontPause):
|
||||
fontId = _vm->_font->valid(kBigFont) ? kBigFont : kMediumFont;
|
||||
break;
|
||||
}
|
||||
#ifdef ENABLE_IHNM
|
||||
} else if (_vm->getGameId() == GID_IHNM && !_vm->isIHNMDemo()) {
|
||||
switch (font) {
|
||||
case (kKnownFontSmall):
|
||||
default:
|
||||
fontId = kSmallFont;
|
||||
break;
|
||||
case (kKnownFontMedium):
|
||||
fontId = kMediumFont;
|
||||
break;
|
||||
case (kKnownFontBig):
|
||||
fontId = kBigFont;
|
||||
break;
|
||||
|
||||
_fonts.resize(_vm->getFontsCount());
|
||||
for (i = 0; i < _vm->getFontsCount(); i++) {
|
||||
#ifdef __DS__
|
||||
_fonts[i].outline.font = NULL;
|
||||
_fonts[i].normal.font = NULL;
|
||||
case (kKnownFontVerb):
|
||||
fontId = kIHNMFont8;
|
||||
break;
|
||||
case (kKnownFontScript):
|
||||
fontId = kIHNMMainFont;
|
||||
break;
|
||||
case (kKnownFontPause):
|
||||
fontId = kMediumFont; // unchecked
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
loadFont(&_fonts[i], _vm->getFontDescription(i)->fontResourceId);
|
||||
}
|
||||
|
||||
_fontMapping = 0;
|
||||
}
|
||||
|
||||
Font::~Font() {
|
||||
debug(8, "Font::~Font(): Freeing fonts.");
|
||||
|
||||
#ifdef __DS__
|
||||
for (int i = 0; i < _vm->getFontsCount(); i++) {
|
||||
if (_fonts[i].outline.font) {
|
||||
free(_fonts[i].outline.font);
|
||||
}
|
||||
|
||||
if (_fonts[i].normal.font) {
|
||||
free(_fonts[i].normal.font);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Font::loadFont(FontData *font, uint32 fontResourceId) {
|
||||
ByteArray fontResourceData;
|
||||
int numBits;
|
||||
int c;
|
||||
ResourceContext *fontContext;
|
||||
|
||||
debug(1, "Font::loadFont(): Reading fontResourceId %d...", fontResourceId);
|
||||
|
||||
fontContext = _vm->_resource->getContext(GAME_RESOURCEFILE);
|
||||
if (fontContext == NULL) {
|
||||
error("Font::Font() resource context not found");
|
||||
}
|
||||
|
||||
// Load font resource
|
||||
_vm->_resource->loadResource(fontContext, fontResourceId, fontResourceData);
|
||||
|
||||
if (fontResourceData.size() < FONT_DESCSIZE) {
|
||||
error("Font::loadFont() Invalid font length (%i < %i)", (int)fontResourceData.size(), FONT_DESCSIZE);
|
||||
}
|
||||
|
||||
ByteArrayReadStreamEndian readS(fontResourceData, fontContext->isBigEndian());
|
||||
|
||||
// Read font header
|
||||
font->normal.header.charHeight = readS.readUint16();
|
||||
font->normal.header.charWidth = readS.readUint16();
|
||||
font->normal.header.rowLength = readS.readUint16();
|
||||
|
||||
|
||||
debug(2, "Character width: %d", font->normal.header.charWidth);
|
||||
debug(2, "Character height: %d", font->normal.header.charHeight);
|
||||
debug(2, "Row padding: %d", font->normal.header.rowLength);
|
||||
|
||||
for (c = 0; c < FONT_CHARCOUNT; c++) {
|
||||
font->normal.fontCharEntry[c].index = readS.readUint16();
|
||||
}
|
||||
|
||||
for (c = 0; c < FONT_CHARCOUNT; c++) {
|
||||
numBits = font->normal.fontCharEntry[c].width = readS.readByte();
|
||||
font->normal.fontCharEntry[c].byteWidth = getByteLen(numBits);
|
||||
}
|
||||
|
||||
for (c = 0; c < FONT_CHARCOUNT; c++) {
|
||||
font->normal.fontCharEntry[c].flag = readS.readByte();
|
||||
}
|
||||
|
||||
for (c = 0; c < FONT_CHARCOUNT; c++) {
|
||||
font->normal.fontCharEntry[c].tracking = readS.readByte();
|
||||
}
|
||||
|
||||
if (readS.pos() != FONT_DESCSIZE) {
|
||||
error("Invalid font resource size");
|
||||
}
|
||||
|
||||
#ifndef __DS__
|
||||
font->normal.font.resize(fontResourceData.size() - FONT_DESCSIZE);
|
||||
memcpy(font->normal.font.getBuffer(), fontResourceData.getBuffer() + FONT_DESCSIZE, fontResourceData.size() - FONT_DESCSIZE);
|
||||
#else
|
||||
if (font->normal.font) {
|
||||
free(font->normal.font);
|
||||
}
|
||||
|
||||
font->normal.font = (byte *) malloc(fontResourceData.size() - FONT_DESCSIZE);
|
||||
memcpy(font->normal.font, fontResourceData.getBuffer() + FONT_DESCSIZE, fontResourceData.size() - FONT_DESCSIZE);
|
||||
#endif
|
||||
|
||||
// Create outline font style
|
||||
createOutline(font);
|
||||
}
|
||||
|
||||
void Font::createOutline(FontData *font) {
|
||||
int i;
|
||||
int row;
|
||||
int newByteWidth;
|
||||
int newRowLength = 0;
|
||||
int currentByte;
|
||||
byte *basePointer;
|
||||
byte *srcPointer;
|
||||
byte *destPointer1;
|
||||
byte *destPointer2;
|
||||
byte *destPointer3;
|
||||
byte charRep;
|
||||
|
||||
// Populate new font style character data
|
||||
for (i = 0; i < FONT_CHARCOUNT; i++) {
|
||||
newByteWidth = 0;
|
||||
|
||||
font->outline.fontCharEntry[i].index = newRowLength;
|
||||
font->outline.fontCharEntry[i].tracking = font->normal.fontCharEntry[i].tracking;
|
||||
font->outline.fontCharEntry[i].flag = font->normal.fontCharEntry[i].flag;
|
||||
|
||||
if (font->normal.fontCharEntry[i].width != 0)
|
||||
newByteWidth = getByteLen(font->normal.fontCharEntry[i].width + 2);
|
||||
|
||||
font->outline.fontCharEntry[i].width = font->normal.fontCharEntry[i].width + 2;
|
||||
font->outline.fontCharEntry[i].byteWidth = newByteWidth;
|
||||
|
||||
newRowLength += newByteWidth;
|
||||
}
|
||||
|
||||
debug(2, "New row length: %d", newRowLength);
|
||||
|
||||
font->outline.header = font->normal.header;
|
||||
font->outline.header.charWidth += 2;
|
||||
font->outline.header.charHeight += 2;
|
||||
font->outline.header.rowLength = newRowLength;
|
||||
|
||||
// Allocate new font representation storage
|
||||
#ifdef __DS__
|
||||
if (font->outline.font) {
|
||||
free(font->outline.font);
|
||||
}
|
||||
|
||||
font->outline.font = (byte *) calloc(newRowLength * font->outline.header.charHeight, 1);
|
||||
#else
|
||||
font->outline.font.resize(newRowLength * font->outline.header.charHeight);
|
||||
#endif
|
||||
|
||||
|
||||
// Generate outline font representation
|
||||
for (i = 0; i < FONT_CHARCOUNT; i++) {
|
||||
for (row = 0; row < font->normal.header.charHeight; row++) {
|
||||
for (currentByte = 0; currentByte < font->outline.fontCharEntry[i].byteWidth; currentByte++) {
|
||||
basePointer = &font->outline.font[font->outline.fontCharEntry[i].index + currentByte];
|
||||
destPointer1 = basePointer + newRowLength * row;
|
||||
destPointer2 = basePointer + newRowLength * (row + 1);
|
||||
destPointer3 = basePointer + newRowLength * (row + 2);
|
||||
if (currentByte > 0) {
|
||||
// Get last two columns from previous byte
|
||||
srcPointer = &font->normal.font[font->normal.header.rowLength * row + font->normal.fontCharEntry[i].index + (currentByte - 1)];
|
||||
charRep = *srcPointer;
|
||||
*destPointer1 |= ((charRep << 6) | (charRep << 7));
|
||||
*destPointer2 |= ((charRep << 6) | (charRep << 7));
|
||||
*destPointer3 |= ((charRep << 6) | (charRep << 7));
|
||||
}
|
||||
|
||||
if (currentByte < font->normal.fontCharEntry[i].byteWidth) {
|
||||
srcPointer = &font->normal.font[font->normal.header.rowLength * row + font->normal.fontCharEntry[i].index + currentByte];
|
||||
charRep = *srcPointer;
|
||||
*destPointer1 |= charRep | (charRep >> 1) | (charRep >> 2);
|
||||
*destPointer2 |= charRep | (charRep >> 1) | (charRep >> 2);
|
||||
*destPointer3 |= charRep | (charRep >> 1) | (charRep >> 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "Hollow out" character to prevent overdraw
|
||||
for (row = 0; row < font->normal.header.charHeight; row++) {
|
||||
for (currentByte = 0; currentByte < font->outline.fontCharEntry[i].byteWidth; currentByte++) {
|
||||
destPointer2 = &font->outline.font[font->outline.header.rowLength * (row + 1) + font->outline.fontCharEntry[i].index + currentByte];
|
||||
if (currentByte > 0) {
|
||||
// Get last two columns from previous byte
|
||||
srcPointer = &font->normal.font[font->normal.header.rowLength * row + font->normal.fontCharEntry[i].index + (currentByte - 1)];
|
||||
*destPointer2 &= ((*srcPointer << 7) ^ 0xFFU);
|
||||
}
|
||||
|
||||
if (currentByte < font->normal.fontCharEntry[i].byteWidth) {
|
||||
srcPointer = &font->normal.font[font->normal.header.rowLength * row + font->normal.fontCharEntry[i].index + currentByte];
|
||||
*destPointer2 &= ((*srcPointer >> 1) ^ 0xFFU);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Font::translateChar(int charId) {
|
||||
if (charId <= 127 || (_vm->getLanguage() == Common::RU_RUS && charId <= 254))
|
||||
return charId; // normal character
|
||||
else
|
||||
return _charMap[charId - 128]; // extended character
|
||||
}
|
||||
|
||||
// Returns the horizontal length in pixels of the graphical representation
|
||||
// of at most 'count' characters of the string 'text', taking
|
||||
// into account any formatting options specified by 'flags'.
|
||||
// If 'count' is 0, all characters of 'test' are counted.
|
||||
int Font::getStringWidth(FontId fontId, const char *text, size_t count, FontEffectFlags flags) {
|
||||
FontData *font;
|
||||
size_t ct;
|
||||
int width = 0;
|
||||
int ch;
|
||||
const byte *txt;
|
||||
|
||||
|
||||
font = getFont(fontId);
|
||||
|
||||
txt = (const byte *) text;
|
||||
|
||||
for (ct = count; *txt && (!count || ct > 0); txt++, ct--) {
|
||||
ch = *txt & 0xFFU;
|
||||
// Translate character
|
||||
ch = translateChar(ch);
|
||||
assert(ch < FONT_CHARCOUNT);
|
||||
width += font->normal.fontCharEntry[ch].tracking;
|
||||
}
|
||||
|
||||
if ((flags & kFontBold) || (flags & kFontOutline)) {
|
||||
width += 1;
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
|
||||
void Font::draw(FontId fontId, const char *text, size_t count, const Common::Point &point,
|
||||
int color, int effectColor, FontEffectFlags flags) {
|
||||
FontData *font;
|
||||
Point offsetPoint(point);
|
||||
|
||||
font = getFont(fontId);
|
||||
|
||||
if (flags & kFontOutline) {
|
||||
offsetPoint.x--;
|
||||
offsetPoint.y--;
|
||||
outFont(font->outline, text, count, offsetPoint, effectColor, flags);
|
||||
outFont(font->normal, text, count, point, color, flags);
|
||||
} else if (flags & kFontShadow) {
|
||||
offsetPoint.x--;
|
||||
offsetPoint.y++;
|
||||
outFont(font->normal, text, count, offsetPoint, effectColor, flags);
|
||||
outFont(font->normal, text, count, point, color, flags);
|
||||
} else { // FONT_NORMAL
|
||||
outFont(font->normal, text, count, point, color, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void Font::outFont(const FontStyle &drawFont, const char *text, size_t count, const Common::Point &point, int color, FontEffectFlags flags) {
|
||||
const byte *textPointer;
|
||||
const byte *c_dataPointer;
|
||||
int c_code;
|
||||
int charRow = 0;
|
||||
Point textPoint(point);
|
||||
|
||||
byte *outputPointer;
|
||||
byte *outputPointer_min;
|
||||
byte *outputPointer_max;
|
||||
|
||||
int row = 0;
|
||||
int rowLimit = 0;
|
||||
|
||||
int c_byte_len;
|
||||
int c_byte;
|
||||
int c_bit;
|
||||
int ct;
|
||||
|
||||
if ((point.x > _vm->_gfx->getBackBufferWidth()) || (point.y > _vm->_gfx->getBackBufferHeight())) {
|
||||
// Output string can't be visible
|
||||
return;
|
||||
}
|
||||
|
||||
textPointer = (const byte *)text;
|
||||
ct = count;
|
||||
|
||||
// Draw string one character at a time, maximum of 'draw_str'_ct
|
||||
// characters, or no limit if 'draw_str_ct' is 0
|
||||
for (; *textPointer && (!count || ct); textPointer++, ct--) {
|
||||
c_code = *textPointer & 0xFFU;
|
||||
|
||||
// Translate character
|
||||
if (_fontMapping == 0) { // Check font mapping debug flag
|
||||
// Default game behavior
|
||||
|
||||
// It seems that this font mapping causes problems with non-english
|
||||
// versions of IHNM, so it has been changed to apply for ITE only.
|
||||
// It doesn't make any difference for the English version of IHNM.
|
||||
// Fixes bug #1796045: "IHNM: Spanish font wrong".
|
||||
if (!(flags & kFontDontmap) && _vm->getGameId() == GID_ITE) {
|
||||
if (_vm->getLanguage() != Common::IT_ITA) {
|
||||
c_code = translateChar(c_code);
|
||||
} else {
|
||||
// The in-game fonts of the Italian version should not be mapped.
|
||||
// The ones in the intro are hardcoded and should be mapped normally.
|
||||
if (_vm->_scene->isInIntro())
|
||||
c_code = translateChar(c_code);
|
||||
}
|
||||
}
|
||||
} else if (_fontMapping == 1) {
|
||||
// Force font mapping
|
||||
c_code = translateChar(c_code);
|
||||
} else {
|
||||
// In all other cases, ignore font mapping
|
||||
}
|
||||
assert(c_code < FONT_CHARCOUNT);
|
||||
|
||||
// Check if character is defined
|
||||
if ((drawFont.fontCharEntry[c_code].index == 0) && (c_code != FONT_FIRSTCHAR)) {
|
||||
#if FONT_SHOWUNDEFINED
|
||||
// A tab character appears in the IHNM demo instructions screen, so filter
|
||||
// it out here
|
||||
if (c_code == FONT_CH_SPACE || c_code == FONT_CH_TAB) {
|
||||
textPoint.x += drawFont.fontCharEntry[c_code].tracking;
|
||||
continue;
|
||||
}
|
||||
c_code = FONT_CH_QMARK;
|
||||
#else
|
||||
// Character code is not defined, but advance tracking
|
||||
// ( Not defined if offset is 0, except for 33 ('!') which
|
||||
// is defined )
|
||||
textPoint.x += drawFont.fontCharEntry[c_code].tracking;
|
||||
continue;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get length of character in bytes
|
||||
c_byte_len = ((drawFont.fontCharEntry[c_code].width - 1) / 8) + 1;
|
||||
rowLimit = (_vm->_gfx->getBackBufferHeight() < (textPoint.y + drawFont.header.charHeight)) ? _vm->_gfx->getBackBufferHeight() : textPoint.y + drawFont.header.charHeight;
|
||||
charRow = 0;
|
||||
|
||||
for (row = textPoint.y; row < rowLimit; row++, charRow++) {
|
||||
// Clip negative rows */
|
||||
if (row < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
outputPointer = _vm->_gfx->getBackBufferPixels() + (_vm->_gfx->getBackBufferPitch() * row) + textPoint.x;
|
||||
outputPointer_min = _vm->_gfx->getBackBufferPixels() + (_vm->_gfx->getBackBufferPitch() * row) + (textPoint.x > 0 ? textPoint.x : 0);
|
||||
outputPointer_max = outputPointer + (_vm->_gfx->getBackBufferPitch() - textPoint.x);
|
||||
|
||||
// If character starts off the screen, jump to next character
|
||||
if (outputPointer < outputPointer_min) {
|
||||
break;
|
||||
}
|
||||
|
||||
c_dataPointer = &drawFont.font[charRow * drawFont.header.rowLength + drawFont.fontCharEntry[c_code].index];
|
||||
|
||||
for (c_byte = 0; c_byte < c_byte_len; c_byte++, c_dataPointer++) {
|
||||
// Check each bit, draw pixel if bit is set
|
||||
for (c_bit = 7; c_bit >= 0 && (outputPointer < outputPointer_max); c_bit--) {
|
||||
if ((*c_dataPointer >> c_bit) & 0x01) {
|
||||
*outputPointer = (byte)color;
|
||||
}
|
||||
outputPointer++;
|
||||
} // end per-bit processing
|
||||
} // end per-byte processing
|
||||
} // end per-row processing
|
||||
|
||||
// Advance tracking position
|
||||
textPoint.x += drawFont.fontCharEntry[c_code].tracking;
|
||||
} // end per-character processing
|
||||
|
||||
rowLimit = (_vm->_gfx->getBackBufferHeight() < (textPoint.y + drawFont.header.charHeight)) ? _vm->_gfx->getBackBufferHeight() : textPoint.y + drawFont.header.charHeight;
|
||||
_vm->_render->addDirtyRect(Common::Rect(point.x, point.y, textPoint.x, rowLimit));
|
||||
}
|
||||
|
||||
|
||||
void Font::textDraw(FontId fontId, const char *text, const Common::Point &point, int color, int effectColor, FontEffectFlags flags) {
|
||||
int textWidth;
|
||||
int textLength;
|
||||
int fitWidth;
|
||||
Common::Point textPoint(point);
|
||||
|
||||
textLength = strlen(text);
|
||||
|
||||
if (!(flags & kFontCentered)) {
|
||||
// Text is not centered; No formatting required
|
||||
draw(fontId, text, textLength, point, color, effectColor, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
// Text is centered... format output
|
||||
// Enforce minimum and maximum center points for centered text
|
||||
if (textPoint.x < TEXT_CENTERLIMIT) {
|
||||
textPoint.x = TEXT_CENTERLIMIT;
|
||||
}
|
||||
|
||||
if (textPoint.x > _vm->_gfx->getBackBufferWidth() - TEXT_CENTERLIMIT) {
|
||||
textPoint.x = _vm->_gfx->getBackBufferWidth() - TEXT_CENTERLIMIT;
|
||||
}
|
||||
|
||||
if (textPoint.x < (TEXT_MARGIN * 2)) {
|
||||
// Text can't be centered if it's too close to the margin
|
||||
return;
|
||||
}
|
||||
|
||||
textWidth = getStringWidth(fontId, text, textLength, flags);
|
||||
|
||||
if (textPoint.x < (_vm->_gfx->getBackBufferWidth() / 2)) {
|
||||
// Fit to right side
|
||||
fitWidth = (textPoint.x - TEXT_MARGIN) * 2;
|
||||
} else {
|
||||
// Fit to left side
|
||||
fitWidth = ((_vm->_gfx->getBackBufferWidth() - TEXT_MARGIN) - textPoint.x) * 2;
|
||||
}
|
||||
|
||||
if (fitWidth < textWidth) {
|
||||
warning("text too long to be displayed in one line");
|
||||
textWidth = fitWidth;
|
||||
}
|
||||
// Entire string fits, draw it
|
||||
textPoint.x = textPoint.x - (textWidth / 2);
|
||||
draw(fontId, text, textLength, textPoint, color, effectColor, flags);
|
||||
return fontId;
|
||||
}
|
||||
|
||||
int Font::getHeight(FontId fontId, const char *text, int width, FontEffectFlags flags) {
|
||||
@ -649,60 +279,456 @@ void Font::textDrawRect(FontId fontId, const char *text, const Common::Rect &rec
|
||||
}
|
||||
}
|
||||
|
||||
Font::FontId Font::knownFont2FontIdx(KnownFont font) {
|
||||
FontId fontId = kSmallFont;
|
||||
void Font::textDraw(FontId fontId, const char *text, const Common::Point &point, int color, int effectColor, FontEffectFlags flags) {
|
||||
int textWidth;
|
||||
int textLength;
|
||||
int fitWidth;
|
||||
Common::Point textPoint(point);
|
||||
|
||||
// The demo version of IHNM has 3 font types (like ITE), not 6 (like the full version of IHNM)
|
||||
if (_vm->getGameId() == GID_ITE || _vm->isIHNMDemo()) {
|
||||
switch (font) {
|
||||
case (kKnownFontSmall):
|
||||
default:
|
||||
fontId = kSmallFont;
|
||||
break;
|
||||
case (kKnownFontMedium):
|
||||
fontId = kMediumFont;
|
||||
break;
|
||||
case (kKnownFontBig):
|
||||
fontId = kBigFont;
|
||||
break;
|
||||
textLength = strlen(text);
|
||||
|
||||
case (kKnownFontVerb):
|
||||
fontId = kSmallFont;
|
||||
break;
|
||||
case (kKnownFontScript):
|
||||
fontId = kMediumFont;
|
||||
break;
|
||||
case (kKnownFontPause):
|
||||
fontId = _vm->_font->valid(kBigFont) ? kBigFont : kMediumFont;
|
||||
break;
|
||||
}
|
||||
#ifdef ENABLE_IHNM
|
||||
} else if (_vm->getGameId() == GID_IHNM && !_vm->isIHNMDemo()) {
|
||||
switch (font) {
|
||||
case (kKnownFontSmall):
|
||||
default:
|
||||
fontId = kSmallFont;
|
||||
break;
|
||||
case (kKnownFontMedium):
|
||||
fontId = kMediumFont;
|
||||
break;
|
||||
case (kKnownFontBig):
|
||||
fontId = kBigFont;
|
||||
break;
|
||||
|
||||
case (kKnownFontVerb):
|
||||
fontId = kIHNMFont8;
|
||||
break;
|
||||
case (kKnownFontScript):
|
||||
fontId = kIHNMMainFont;
|
||||
break;
|
||||
case (kKnownFontPause):
|
||||
fontId = kMediumFont; // unchecked
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (!(flags & kFontCentered)) {
|
||||
// Text is not centered; No formatting required
|
||||
draw(fontId, text, textLength, point, color, effectColor, flags);
|
||||
return;
|
||||
}
|
||||
return fontId;
|
||||
|
||||
// Text is centered... format output
|
||||
// Enforce minimum and maximum center points for centered text
|
||||
if (textPoint.x < TEXT_CENTERLIMIT) {
|
||||
textPoint.x = TEXT_CENTERLIMIT;
|
||||
}
|
||||
|
||||
if (textPoint.x > _vm->_gfx->getBackBufferWidth() - TEXT_CENTERLIMIT) {
|
||||
textPoint.x = _vm->_gfx->getBackBufferWidth() - TEXT_CENTERLIMIT;
|
||||
}
|
||||
|
||||
if (textPoint.x < (TEXT_MARGIN * 2)) {
|
||||
// Text can't be centered if it's too close to the margin
|
||||
return;
|
||||
}
|
||||
|
||||
textWidth = getStringWidth(fontId, text, textLength, flags);
|
||||
|
||||
if (textPoint.x < (_vm->_gfx->getBackBufferWidth() / 2)) {
|
||||
// Fit to right side
|
||||
fitWidth = (textPoint.x - TEXT_MARGIN) * 2;
|
||||
} else {
|
||||
// Fit to left side
|
||||
fitWidth = ((_vm->_gfx->getBackBufferWidth() - TEXT_MARGIN) - textPoint.x) * 2;
|
||||
}
|
||||
|
||||
if (fitWidth < textWidth) {
|
||||
warning("text too long to be displayed in one line");
|
||||
textWidth = fitWidth;
|
||||
}
|
||||
// Entire string fits, draw it
|
||||
textPoint.x = textPoint.x - (textWidth / 2);
|
||||
draw(fontId, text, textLength, textPoint, color, effectColor, flags);
|
||||
}
|
||||
|
||||
DefaultFont::DefaultFont(SagaEngine *vm) : Font(vm), _fontMapping(0) {
|
||||
int i;
|
||||
|
||||
// Load font module resource context
|
||||
|
||||
assert(_vm->getFontsCount() > 0);
|
||||
|
||||
_fonts.resize(_vm->getFontsCount());
|
||||
for (i = 0; i < _vm->getFontsCount(); i++) {
|
||||
#ifdef __DS__
|
||||
_fonts[i].outline.font = NULL;
|
||||
_fonts[i].normal.font = NULL;
|
||||
#endif
|
||||
loadFont(&_fonts[i], _vm->getFontDescription(i)->fontResourceId);
|
||||
}
|
||||
}
|
||||
|
||||
DefaultFont::~DefaultFont() {
|
||||
debug(8, "DefaultFont::~DefaultFont(): Freeing fonts.");
|
||||
|
||||
#ifdef __DS__
|
||||
for (int i = 0; i < _vm->getFontsCount(); i++) {
|
||||
if (_fonts[i].outline.font) {
|
||||
free(_fonts[i].outline.font);
|
||||
}
|
||||
|
||||
if (_fonts[i].normal.font) {
|
||||
free(_fonts[i].normal.font);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int DefaultFont::translateChar(int charId) {
|
||||
if (charId <= 127 || (_vm->getLanguage() == Common::RU_RUS && charId <= 254))
|
||||
return charId; // normal character
|
||||
else
|
||||
return _charMap[charId - 128]; // extended character
|
||||
}
|
||||
|
||||
// Returns the horizontal length in pixels of the graphical representation
|
||||
// of at most 'count' characters of the string 'text', taking
|
||||
// into account any formatting options specified by 'flags'.
|
||||
// If 'count' is 0, all characters of 'test' are counted.
|
||||
int DefaultFont::getStringWidth(FontId fontId, const char *text, size_t count, FontEffectFlags flags) {
|
||||
size_t ct;
|
||||
int width = 0;
|
||||
int ch;
|
||||
const byte *txt;
|
||||
FontData *font = getFont(fontId);
|
||||
txt = (const byte *) text;
|
||||
|
||||
for (ct = count; *txt && (!count || ct > 0); txt++, ct--) {
|
||||
ch = *txt & 0xFFU;
|
||||
// Translate character
|
||||
ch = translateChar(ch);
|
||||
assert(ch < FONT_CHARCOUNT);
|
||||
width += font->normal.fontCharEntry[ch].tracking;
|
||||
}
|
||||
|
||||
if ((flags & kFontBold) || (flags & kFontOutline)) {
|
||||
width += 1;
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
void DefaultFont::draw(FontId fontId, const char *text, size_t count, const Common::Point &point,
|
||||
int color, int effectColor, FontEffectFlags flags) {
|
||||
|
||||
Point offsetPoint(point);
|
||||
FontData *font = getFont(fontId);
|
||||
|
||||
if (flags & kFontOutline) {
|
||||
offsetPoint.x--;
|
||||
offsetPoint.y--;
|
||||
outFont(font->outline, text, count, offsetPoint, effectColor, flags);
|
||||
outFont(font->normal, text, count, point, color, flags);
|
||||
} else if (flags & kFontShadow) {
|
||||
offsetPoint.x--;
|
||||
offsetPoint.y++;
|
||||
outFont(font->normal, text, count, offsetPoint, effectColor, flags);
|
||||
outFont(font->normal, text, count, point, color, flags);
|
||||
} else { // FONT_NORMAL
|
||||
outFont(font->normal, text, count, point, color, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void DefaultFont::outFont(const FontStyle &drawFont, const char *text, size_t count, const Common::Point &point, int color, FontEffectFlags flags) {
|
||||
const byte *textPointer;
|
||||
const byte *c_dataPointer;
|
||||
int c_code;
|
||||
int charRow = 0;
|
||||
Point textPoint(point);
|
||||
|
||||
byte *outputPointer;
|
||||
byte *outputPointer_min;
|
||||
byte *outputPointer_max;
|
||||
|
||||
int row = 0;
|
||||
int rowLimit = 0;
|
||||
|
||||
int c_byte_len;
|
||||
int c_byte;
|
||||
int c_bit;
|
||||
int ct;
|
||||
|
||||
if ((point.x > _vm->_gfx->getBackBufferWidth()) || (point.y > _vm->_gfx->getBackBufferHeight())) {
|
||||
// Output string can't be visible
|
||||
return;
|
||||
}
|
||||
|
||||
textPointer = (const byte *)text;
|
||||
ct = count;
|
||||
|
||||
// Draw string one character at a time, maximum of 'draw_str'_ct
|
||||
// characters, or no limit if 'draw_str_ct' is 0
|
||||
for (; *textPointer && (!count || ct); textPointer++, ct--) {
|
||||
c_code = *textPointer & 0xFFU;
|
||||
|
||||
// Translate character
|
||||
if (_fontMapping == 0) { // Check font mapping debug flag
|
||||
// Default game behavior
|
||||
|
||||
// It seems that this font mapping causes problems with non-english
|
||||
// versions of IHNM, so it has been changed to apply for ITE only.
|
||||
// It doesn't make any difference for the English version of IHNM.
|
||||
// Fixes bug #1796045: "IHNM: Spanish font wrong".
|
||||
if (!(flags & kFontDontmap) && _vm->getGameId() == GID_ITE) {
|
||||
if (_vm->getLanguage() != Common::IT_ITA) {
|
||||
c_code = translateChar(c_code);
|
||||
} else {
|
||||
// The in-game fonts of the Italian version should not be mapped.
|
||||
// The ones in the intro are hardcoded and should be mapped normally.
|
||||
if (_vm->_scene->isInIntro())
|
||||
c_code = translateChar(c_code);
|
||||
}
|
||||
}
|
||||
} else if (_fontMapping == 1) {
|
||||
// Force font mapping
|
||||
c_code = translateChar(c_code);
|
||||
} else {
|
||||
// In all other cases, ignore font mapping
|
||||
}
|
||||
assert(c_code < FONT_CHARCOUNT);
|
||||
|
||||
// Check if character is defined
|
||||
if ((drawFont.fontCharEntry[c_code].index == 0) && (c_code != FONT_FIRSTCHAR)) {
|
||||
#if FONT_SHOWUNDEFINED
|
||||
// A tab character appears in the IHNM demo instructions screen, so filter
|
||||
// it out here
|
||||
if (c_code == FONT_CH_SPACE || c_code == FONT_CH_TAB) {
|
||||
textPoint.x += drawFont.fontCharEntry[c_code].tracking;
|
||||
continue;
|
||||
}
|
||||
c_code = FONT_CH_QMARK;
|
||||
#else
|
||||
// Character code is not defined, but advance tracking
|
||||
// ( Not defined if offset is 0, except for 33 ('!') which
|
||||
// is defined )
|
||||
textPoint.x += drawFont.fontCharEntry[c_code].tracking;
|
||||
continue;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get length of character in bytes
|
||||
c_byte_len = ((drawFont.fontCharEntry[c_code].width - 1) / 8) + 1;
|
||||
rowLimit = (_vm->_gfx->getBackBufferHeight() < (textPoint.y + drawFont.header.charHeight)) ? _vm->_gfx->getBackBufferHeight() : textPoint.y + drawFont.header.charHeight;
|
||||
charRow = 0;
|
||||
|
||||
for (row = textPoint.y; row < rowLimit; row++, charRow++) {
|
||||
// Clip negative rows */
|
||||
if (row < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
outputPointer = _vm->_gfx->getBackBufferPixels() + (_vm->_gfx->getBackBufferPitch() * row) + textPoint.x;
|
||||
outputPointer_min = _vm->_gfx->getBackBufferPixels() + (_vm->_gfx->getBackBufferPitch() * row) + (textPoint.x > 0 ? textPoint.x : 0);
|
||||
outputPointer_max = outputPointer + (_vm->_gfx->getBackBufferPitch() - textPoint.x);
|
||||
|
||||
// If character starts off the screen, jump to next character
|
||||
if (outputPointer < outputPointer_min) {
|
||||
break;
|
||||
}
|
||||
|
||||
c_dataPointer = &drawFont.font[charRow * drawFont.header.rowLength + drawFont.fontCharEntry[c_code].index];
|
||||
|
||||
for (c_byte = 0; c_byte < c_byte_len; c_byte++, c_dataPointer++) {
|
||||
// Check each bit, draw pixel if bit is set
|
||||
for (c_bit = 7; c_bit >= 0 && (outputPointer < outputPointer_max); c_bit--) {
|
||||
if ((*c_dataPointer >> c_bit) & 0x01) {
|
||||
*outputPointer = (byte)color;
|
||||
}
|
||||
outputPointer++;
|
||||
} // end per-bit processing
|
||||
} // end per-byte processing
|
||||
} // end per-row processing
|
||||
|
||||
// Advance tracking position
|
||||
textPoint.x += drawFont.fontCharEntry[c_code].tracking;
|
||||
} // end per-character processing
|
||||
|
||||
rowLimit = (_vm->_gfx->getBackBufferHeight() < (textPoint.y + drawFont.header.charHeight)) ? _vm->_gfx->getBackBufferHeight() : textPoint.y + drawFont.header.charHeight;
|
||||
_vm->_render->addDirtyRect(Common::Rect(point.x, point.y, textPoint.x, rowLimit));
|
||||
}
|
||||
|
||||
void DefaultFont::loadFont(FontData *font, uint32 fontResourceId) {
|
||||
ByteArray fontResourceData;
|
||||
int numBits;
|
||||
int c;
|
||||
ResourceContext *fontContext;
|
||||
|
||||
debug(1, "Font::loadFont(): Reading fontResourceId %d...", fontResourceId);
|
||||
|
||||
fontContext = _vm->_resource->getContext(GAME_RESOURCEFILE);
|
||||
if (fontContext == NULL) {
|
||||
error("DefaultFont::Font() resource context not found");
|
||||
}
|
||||
|
||||
// Load font resource
|
||||
_vm->_resource->loadResource(fontContext, fontResourceId, fontResourceData);
|
||||
|
||||
if (fontResourceData.size() < FONT_DESCSIZE) {
|
||||
error("DefaultFont::loadFont() Invalid font length (%i < %i)", (int)fontResourceData.size(), FONT_DESCSIZE);
|
||||
}
|
||||
|
||||
ByteArrayReadStreamEndian readS(fontResourceData, fontContext->isBigEndian());
|
||||
|
||||
// Read font header
|
||||
font->normal.header.charHeight = readS.readUint16();
|
||||
font->normal.header.charWidth = readS.readUint16();
|
||||
font->normal.header.rowLength = readS.readUint16();
|
||||
|
||||
|
||||
debug(2, "Character width: %d", font->normal.header.charWidth);
|
||||
debug(2, "Character height: %d", font->normal.header.charHeight);
|
||||
debug(2, "Row padding: %d", font->normal.header.rowLength);
|
||||
|
||||
for (c = 0; c < FONT_CHARCOUNT; c++) {
|
||||
font->normal.fontCharEntry[c].index = readS.readUint16();
|
||||
}
|
||||
|
||||
for (c = 0; c < FONT_CHARCOUNT; c++) {
|
||||
numBits = font->normal.fontCharEntry[c].width = readS.readByte();
|
||||
font->normal.fontCharEntry[c].byteWidth = getByteLen(numBits);
|
||||
}
|
||||
|
||||
for (c = 0; c < FONT_CHARCOUNT; c++) {
|
||||
font->normal.fontCharEntry[c].flag = readS.readByte();
|
||||
}
|
||||
|
||||
for (c = 0; c < FONT_CHARCOUNT; c++) {
|
||||
font->normal.fontCharEntry[c].tracking = readS.readByte();
|
||||
}
|
||||
|
||||
if (readS.pos() != FONT_DESCSIZE) {
|
||||
error("Invalid font resource size");
|
||||
}
|
||||
|
||||
#ifndef __DS__
|
||||
font->normal.font.resize(fontResourceData.size() - FONT_DESCSIZE);
|
||||
memcpy(font->normal.font.getBuffer(), fontResourceData.getBuffer() + FONT_DESCSIZE, fontResourceData.size() - FONT_DESCSIZE);
|
||||
#else
|
||||
if (font->normal.font) {
|
||||
free(font->normal.font);
|
||||
}
|
||||
|
||||
font->normal.font = (byte *)malloc(fontResourceData.size() - FONT_DESCSIZE);
|
||||
memcpy(font->normal.font, fontResourceData.getBuffer() + FONT_DESCSIZE, fontResourceData.size() - FONT_DESCSIZE);
|
||||
#endif
|
||||
|
||||
// Create outline font style
|
||||
createOutline(font);
|
||||
}
|
||||
|
||||
void DefaultFont::createOutline(FontData *font) {
|
||||
int i;
|
||||
int row;
|
||||
int newByteWidth;
|
||||
int newRowLength = 0;
|
||||
int currentByte;
|
||||
byte *basePointer;
|
||||
byte *srcPointer;
|
||||
byte *destPointer1;
|
||||
byte *destPointer2;
|
||||
byte *destPointer3;
|
||||
byte charRep;
|
||||
|
||||
// Populate new font style character data
|
||||
for (i = 0; i < FONT_CHARCOUNT; i++) {
|
||||
newByteWidth = 0;
|
||||
|
||||
font->outline.fontCharEntry[i].index = newRowLength;
|
||||
font->outline.fontCharEntry[i].tracking = font->normal.fontCharEntry[i].tracking;
|
||||
font->outline.fontCharEntry[i].flag = font->normal.fontCharEntry[i].flag;
|
||||
|
||||
if (font->normal.fontCharEntry[i].width != 0)
|
||||
newByteWidth = getByteLen(font->normal.fontCharEntry[i].width + 2);
|
||||
|
||||
font->outline.fontCharEntry[i].width = font->normal.fontCharEntry[i].width + 2;
|
||||
font->outline.fontCharEntry[i].byteWidth = newByteWidth;
|
||||
|
||||
newRowLength += newByteWidth;
|
||||
}
|
||||
|
||||
debug(2, "New row length: %d", newRowLength);
|
||||
|
||||
font->outline.header = font->normal.header;
|
||||
font->outline.header.charWidth += 2;
|
||||
font->outline.header.charHeight += 2;
|
||||
font->outline.header.rowLength = newRowLength;
|
||||
|
||||
// Allocate new font representation storage
|
||||
#ifdef __DS__
|
||||
if (font->outline.font) {
|
||||
free(font->outline.font);
|
||||
}
|
||||
|
||||
font->outline.font = (byte *)calloc(newRowLength * font->outline.header.charHeight, 1);
|
||||
#else
|
||||
font->outline.font.resize(newRowLength * font->outline.header.charHeight);
|
||||
#endif
|
||||
|
||||
|
||||
// Generate outline font representation
|
||||
for (i = 0; i < FONT_CHARCOUNT; i++) {
|
||||
for (row = 0; row < font->normal.header.charHeight; row++) {
|
||||
for (currentByte = 0; currentByte < font->outline.fontCharEntry[i].byteWidth; currentByte++) {
|
||||
basePointer = &font->outline.font[font->outline.fontCharEntry[i].index + currentByte];
|
||||
destPointer1 = basePointer + newRowLength * row;
|
||||
destPointer2 = basePointer + newRowLength * (row + 1);
|
||||
destPointer3 = basePointer + newRowLength * (row + 2);
|
||||
if (currentByte > 0) {
|
||||
// Get last two columns from previous byte
|
||||
srcPointer = &font->normal.font[font->normal.header.rowLength * row + font->normal.fontCharEntry[i].index + (currentByte - 1)];
|
||||
charRep = *srcPointer;
|
||||
*destPointer1 |= ((charRep << 6) | (charRep << 7));
|
||||
*destPointer2 |= ((charRep << 6) | (charRep << 7));
|
||||
*destPointer3 |= ((charRep << 6) | (charRep << 7));
|
||||
}
|
||||
|
||||
if (currentByte < font->normal.fontCharEntry[i].byteWidth) {
|
||||
srcPointer = &font->normal.font[font->normal.header.rowLength * row + font->normal.fontCharEntry[i].index + currentByte];
|
||||
charRep = *srcPointer;
|
||||
*destPointer1 |= charRep | (charRep >> 1) | (charRep >> 2);
|
||||
*destPointer2 |= charRep | (charRep >> 1) | (charRep >> 2);
|
||||
*destPointer3 |= charRep | (charRep >> 1) | (charRep >> 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "Hollow out" character to prevent overdraw
|
||||
for (row = 0; row < font->normal.header.charHeight; row++) {
|
||||
for (currentByte = 0; currentByte < font->outline.fontCharEntry[i].byteWidth; currentByte++) {
|
||||
destPointer2 = &font->outline.font[font->outline.header.rowLength * (row + 1) + font->outline.fontCharEntry[i].index + currentByte];
|
||||
if (currentByte > 0) {
|
||||
// Get last two columns from previous byte
|
||||
srcPointer = &font->normal.font[font->normal.header.rowLength * row + font->normal.fontCharEntry[i].index + (currentByte - 1)];
|
||||
*destPointer2 &= ((*srcPointer << 7) ^ 0xFFU);
|
||||
}
|
||||
|
||||
if (currentByte < font->normal.fontCharEntry[i].byteWidth) {
|
||||
srcPointer = &font->normal.font[font->normal.header.rowLength * row + font->normal.fontCharEntry[i].index + currentByte];
|
||||
*destPointer2 &= ((*srcPointer >> 1) ^ 0xFFU);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SJISFont::SJISFont(SagaEngine *vm) : Font(vm), _font(0) {
|
||||
_font = Graphics::FontSJIS::createFont(vm->getPlatform());
|
||||
assert(_font);
|
||||
}
|
||||
|
||||
SJISFont::~SJISFont() {
|
||||
delete _font;
|
||||
}
|
||||
|
||||
int SJISFont::getStringWidth(FontId fontId, const char *text, size_t count, FontEffectFlags flags) {
|
||||
int res = 0;
|
||||
for (uint16 c = fetchChar(text); c; c = fetchChar(text))
|
||||
res += _font->getCharWidth(c);
|
||||
return res;
|
||||
}
|
||||
|
||||
int SJISFont::getHeight(FontId fontId) {
|
||||
return _font->getFontHeight();
|
||||
}
|
||||
|
||||
void SJISFont::draw(FontId fontId, const char *text, size_t count, const Common::Point &point, int color, int effectColor, FontEffectFlags flags) {
|
||||
|
||||
}
|
||||
|
||||
uint16 SJISFont::fetchChar(const char *&s) const {
|
||||
uint16 ch = (uint8)*s++;
|
||||
|
||||
if (ch <= 0x7F || (ch >= 0xA1 && ch <= 0xDF))
|
||||
return ch;
|
||||
|
||||
ch |= (uint8)(*s++) << 8;
|
||||
return ch;
|
||||
}
|
||||
|
||||
} // End of namespace Saga
|
||||
|
@ -28,6 +28,10 @@
|
||||
#include "common/list.h"
|
||||
#include "saga/gfx.h"
|
||||
|
||||
namespace Graphics {
|
||||
class FontSJIS;
|
||||
}
|
||||
|
||||
namespace Saga {
|
||||
|
||||
#define FONT_SHOWUNDEFINED 1 // Define to draw undefined characters * as ?'s
|
||||
@ -139,58 +143,71 @@ struct FontData {
|
||||
};
|
||||
|
||||
class Font {
|
||||
public:
|
||||
Font(SagaEngine *vm);
|
||||
~Font();
|
||||
public:
|
||||
Font(SagaEngine *vm) : _vm(vm) {}
|
||||
virtual ~Font() {}
|
||||
|
||||
int getStringWidth(KnownFont font, const char *text, size_t count, FontEffectFlags flags) {
|
||||
return getStringWidth(knownFont2FontIdx(font), text, count, flags);
|
||||
}
|
||||
|
||||
int getHeight(KnownFont font) {
|
||||
return getHeight(knownFont2FontIdx(font));
|
||||
}
|
||||
|
||||
int getHeight(KnownFont font, const char *text, int width, FontEffectFlags flags) {
|
||||
return getHeight(knownFont2FontIdx(font), text, width, flags);
|
||||
}
|
||||
|
||||
void textDraw(KnownFont font, const char *string, const Common::Point &point, int color, int effectColor, FontEffectFlags flags) {
|
||||
textDraw(knownFont2FontIdx(font), string, point, color, effectColor, flags);
|
||||
}
|
||||
|
||||
void textDrawRect(KnownFont font, const char *text, const Common::Rect &rect, int color, int effectColor, FontEffectFlags flags) {
|
||||
textDrawRect(knownFont2FontIdx(font), text, rect, color, effectColor, flags);
|
||||
}
|
||||
|
||||
virtual void setFontMapping(int) {}
|
||||
|
||||
protected:
|
||||
enum FontId {
|
||||
kSmallFont,
|
||||
kMediumFont,
|
||||
kBigFont,
|
||||
kIHNMUnknown,
|
||||
kIHNMFont8,
|
||||
kIHNMUnknown2,
|
||||
kIHNMMainFont
|
||||
};
|
||||
|
||||
SagaEngine *_vm;
|
||||
|
||||
private:
|
||||
FontId knownFont2FontIdx(KnownFont font);
|
||||
int getHeight(FontId fontId, const char *text, int width, FontEffectFlags flags);
|
||||
void textDrawRect(FontId fontId, const char *text, const Common::Rect &rect, int color, int effectColor, FontEffectFlags flags);
|
||||
void textDraw(FontId fontId, const char *string, const Common::Point &point, int color, int effectColor, FontEffectFlags flags);
|
||||
|
||||
virtual int translateChar(int charId) = 0;
|
||||
virtual int getStringWidth(FontId fontId, const char *text, size_t count, FontEffectFlags flags) = 0;
|
||||
virtual int getHeight(FontId fontId) = 0;
|
||||
virtual bool valid(FontId) = 0;
|
||||
virtual void draw(FontId fontId, const char *text, size_t count, const Common::Point &point, int color, int effectColor, FontEffectFlags flags) = 0;
|
||||
};
|
||||
|
||||
class DefaultFont : public Font {
|
||||
public:
|
||||
DefaultFont(SagaEngine *vm);
|
||||
~DefaultFont() override;
|
||||
|
||||
void setFontMapping(int mapping) {
|
||||
_fontMapping = mapping;
|
||||
}
|
||||
|
||||
private:
|
||||
enum FontId {
|
||||
kSmallFont,
|
||||
kMediumFont,
|
||||
kBigFont,
|
||||
kIHNMUnknown,
|
||||
kIHNMFont8,
|
||||
kIHNMUnknown2,
|
||||
kIHNMMainFont
|
||||
};
|
||||
|
||||
Font::FontId knownFont2FontIdx(KnownFont font);
|
||||
int translateChar(int charId);
|
||||
|
||||
int getStringWidth(FontId fontId, const char *text, size_t count, FontEffectFlags flags);
|
||||
int getHeight(FontId fontId, const char *text, int width, FontEffectFlags flags);
|
||||
void textDrawRect(FontId fontId, const char *text, const Common::Rect &rect, int color, int effectColor, FontEffectFlags flags);
|
||||
void textDraw(FontId fontId, const char *string, const Common::Point &point, int color, int effectColor, FontEffectFlags flags);
|
||||
|
||||
void loadFont(FontData *font, uint32 fontResourceId);
|
||||
void createOutline(FontData *font);
|
||||
void draw(FontId fontId, const char *text, size_t count, const Common::Point &point, int color, int effectColor, FontEffectFlags flags);
|
||||
void outFont(const FontStyle &drawFont, const char *text, size_t count, const Common::Point &point, int color, FontEffectFlags flags);
|
||||
|
||||
FontData *getFont(FontId fontId) {
|
||||
validate(fontId);
|
||||
return &_fonts[fontId];
|
||||
}
|
||||
|
||||
int getHeight(FontId fontId) {
|
||||
int translateChar(int charId) override;
|
||||
int getStringWidth(FontId fontId, const char *text, size_t count, FontEffectFlags flags) override;
|
||||
int getHeight(FontId fontId) override {
|
||||
return getFont(fontId)->normal.header.charHeight;
|
||||
}
|
||||
|
||||
@ -199,9 +216,21 @@ class Font {
|
||||
error("Font::validate: Invalid font id");
|
||||
}
|
||||
}
|
||||
bool valid(FontId fontId) {
|
||||
|
||||
bool valid(FontId fontId) override {
|
||||
return (uint(fontId) < _fonts.size());
|
||||
}
|
||||
|
||||
FontData *getFont(FontId fontId) {
|
||||
validate(fontId);
|
||||
return &_fonts[fontId];
|
||||
}
|
||||
|
||||
void draw(FontId fontId, const char *text, size_t count, const Common::Point &point, int color, int effectColor, FontEffectFlags flags) override;
|
||||
void outFont(const FontStyle &drawFont, const char *text, size_t count, const Common::Point &point, int color, FontEffectFlags flags);
|
||||
void loadFont(FontData *font, uint32 fontResourceId);
|
||||
void createOutline(FontData *font);
|
||||
|
||||
int getByteLen(int numBits) const {
|
||||
int byteLength = numBits / 8;
|
||||
|
||||
@ -213,11 +242,27 @@ class Font {
|
||||
}
|
||||
|
||||
static const int _charMap[128];
|
||||
SagaEngine *_vm;
|
||||
|
||||
int _fontMapping;
|
||||
|
||||
Common::Array<FontData> _fonts;
|
||||
int _fontMapping;
|
||||
};
|
||||
|
||||
class SJISFont : public Font {
|
||||
public:
|
||||
SJISFont(SagaEngine *vm);
|
||||
~SJISFont() override;
|
||||
|
||||
private:
|
||||
int translateChar(int charId) override { return charId; }
|
||||
int getStringWidth(FontId fontId, const char *text, size_t count, FontEffectFlags flags) override;
|
||||
int getHeight(FontId fontId) override;
|
||||
bool valid(FontId fontId) override { return fontId != kBigFont; }
|
||||
|
||||
void draw(FontId fontId, const char *text, size_t count, const Common::Point &point, int color, int effectColor, FontEffectFlags flags) override;
|
||||
|
||||
uint16 fetchChar(const char *&s) const;
|
||||
|
||||
Graphics::FontSJIS *_font;
|
||||
};
|
||||
|
||||
} // End of namespace Saga
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
namespace Saga {
|
||||
|
||||
const int Font::_charMap[128] = {
|
||||
const int DefaultFont::_charMap[128] = {
|
||||
// Characters 0 - 127 are mapped directly to ISO 8859-1
|
||||
199, // 128 LATIN CAPITAL LETTER C WITH CEDILLA
|
||||
252, // 129 LATIN SMALL LETTER U WITH DIAERESIS
|
||||
|
@ -254,7 +254,10 @@ Common::Error SagaEngine::run() {
|
||||
_events = new Events(this);
|
||||
|
||||
if (!isSaga2()) {
|
||||
_font = new Font(this);
|
||||
if (getLanguage() == Common::JA_JPN)
|
||||
_font = new SJISFont(this);
|
||||
else
|
||||
_font = new DefaultFont(this);
|
||||
_sprite = new Sprite(this);
|
||||
_script = new SAGA1Script(this);
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user