GRAPHICS: Cleanup SJIS font code a bit.

This commit is contained in:
Johannes Schickel 2011-07-01 04:13:37 +02:00
parent 173db53e4b
commit c047f871d6
2 changed files with 184 additions and 143 deletions

View file

@ -58,6 +58,43 @@ void FontSJIS::drawChar(Graphics::Surface &dst, uint16 ch, int x, int y, uint32
drawChar(dst.getBasePtr(x, y), ch, dst.pitch, dst.format.bytesPerPixel, c1, c2, dst.w - x, dst.h - y); drawChar(dst.getBasePtr(x, y), ch, dst.pitch, dst.format.bytesPerPixel, c1, c2, dst.w - x, dst.h - y);
} }
FontSJISBase::FontSJISBase() : _drawMode(kDefaultMode), _flippedMode(false) {
}
void FontSJISBase::setDrawingMode(DrawingMode mode) {
_drawMode = mode;
}
void FontSJISBase::toggleFlippedMode(bool enable) {
_flippedMode = enable;
}
uint FontSJISBase::getFontHeight() const {
switch (_drawMode) {
case kOutlineMode:
return 18;
case kDefaultMode:
return 16;
default:
return 17;
}
}
uint FontSJISBase::getMaxFontWidth() const {
switch (_drawMode) {
case kOutlineMode:
return 18;
case kDefaultMode:
return 16;
default:
return 17;
}
}
template<typename Color> template<typename Color>
void FontSJISBase::blitCharacter(const uint8 *glyph, const int w, const int h, uint8 *dst, int pitch, Color c) const { void FontSJISBase::blitCharacter(const uint8 *glyph, const int w, const int h, uint8 *dst, int pitch, Color c) const {
for (int y = 0; y < h; ++y) { for (int y = 0; y < h; ++y) {
@ -131,6 +168,9 @@ const uint8 *FontSJISBase::flipCharacter(const uint8 *glyph, const int w) const
0x0F, 0x8F, 0x4F, 0xC7, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x97, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF 0x0F, 0x8F, 0x4F, 0xC7, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x97, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
}; };
// TODO: This code looks like it will only work with 16 pixel wide
// characters we should really take care that we only call it on these
// or we fix this to support a generic width.
for (int i = 0; i < w; i++) { for (int i = 0; i < w; i++) {
_tempGlyph[i] = flipData[glyph[(w * 2 - 1) - i]]; _tempGlyph[i] = flipData[glyph[(w * 2 - 1) - i]];
_tempGlyph[(w * 2 - 1) - i] = flipData[glyph[i]]; _tempGlyph[(w * 2 - 1) - i] = flipData[glyph[i]];
@ -146,8 +186,8 @@ void FontSJISBase::drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1,
int outlineExtraWidth = 2, outlineExtraHeight = 2; int outlineExtraWidth = 2, outlineExtraHeight = 2;
int outlineXOffset = 0, outlineYOffset = 0; int outlineXOffset = 0, outlineYOffset = 0;
if (is8x16(ch)) { if (isASCII(ch)) {
glyphSource = getCharData8x16(ch); glyphSource = getCharData(ch);
width = 8; width = 8;
height = 16; height = 16;
} else { } else {
@ -177,6 +217,9 @@ void FontSJISBase::drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1,
} }
#ifndef DISABLE_FLIPPED_MODE #ifndef DISABLE_FLIPPED_MODE
// TODO: This code inside flopCharater looks like it will only work with
// 16 pixel wide characters we should really take care that we only call
// it on these or we fix it to support a generic width.
if (_flippedMode) if (_flippedMode)
glyphSource = flipCharacter(glyphSource, width); glyphSource = flipCharacter(glyphSource, width);
#endif #endif
@ -221,13 +264,13 @@ void FontSJISBase::drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1,
} }
uint FontSJISBase::getCharWidth(uint16 ch) const { uint FontSJISBase::getCharWidth(uint16 ch) const {
if (is8x16(ch)) if (isASCII(ch))
return (_drawMode == kOutlineMode) ? 10 : (_drawMode == kDefaultMode ? 8 : 9); return (_drawMode == kOutlineMode) ? 10 : (_drawMode == kDefaultMode ? 8 : 9);
else else
return getMaxFontWidth(); return getMaxFontWidth();
} }
bool FontSJISBase::is8x16(uint16 ch) const { bool FontSJISBase::isASCII(uint16 ch) const {
if (ch >= 0xFF) if (ch >= 0xFF)
return false; return false;
else if (ch <= 0x7F || (ch >= 0xA1 && ch <= 0xDF)) else if (ch <= 0x7F || (ch >= 0xA1 && ch <= 0xDF))
@ -253,105 +296,112 @@ bool FontTowns::loadData() {
} }
const uint8 *FontTowns::getCharData(uint16 ch) const { const uint8 *FontTowns::getCharData(uint16 ch) const {
uint8 f = ch & 0xFF; if (ch < kFont8x16Chars) {
uint8 s = ch >> 8; return _fontData8x16 + ch * 16;
} else {
uint8 f = ch & 0xFF;
uint8 s = ch >> 8;
// copied from scumm\charset.cpp // copied from scumm\charset.cpp
enum { enum {
KANA = 0, KANA = 0,
KANJI = 1, KANJI = 1,
EKANJI = 2 EKANJI = 2
}; };
int base = s - ((s + 1) % 32); int base = s - ((s + 1) % 32);
int c = 0, p = 0, chunk_f = 0, chunk = 0, cr = 0, kanjiType = KANA; int c = 0, p = 0, chunk_f = 0, chunk = 0, cr = 0, kanjiType = KANA;
if (f >= 0x81 && f <= 0x84) kanjiType = KANA; if (f >= 0x81 && f <= 0x84) kanjiType = KANA;
if (f >= 0x88 && f <= 0x9f) kanjiType = KANJI; if (f >= 0x88 && f <= 0x9f) kanjiType = KANJI;
if (f >= 0xe0 && f <= 0xea) kanjiType = EKANJI; if (f >= 0xe0 && f <= 0xea) kanjiType = EKANJI;
if ((f > 0xe8 || (f == 0xe8 && base >= 0x9f)) || (f > 0x90 || (f == 0x90 && base >= 0x9f))) { if ((f > 0xe8 || (f == 0xe8 && base >= 0x9f)) || (f > 0x90 || (f == 0x90 && base >= 0x9f))) {
c = 48; //correction c = 48; //correction
p = -8; //correction p = -8; //correction
}
if (kanjiType == KANA) {//Kana
chunk_f = (f - 0x81) * 2;
} else if (kanjiType == KANJI) {//Standard Kanji
p += f - 0x88;
chunk_f = c + 2 * p;
} else if (kanjiType == EKANJI) {//Enhanced Kanji
p += f - 0xe0;
chunk_f = c + 2 * p;
}
// Base corrections
if (base == 0x7f && s == 0x7f)
base -= 0x20;
if (base == 0x9f && s == 0xbe)
base += 0x20;
if (base == 0xbf && s == 0xde)
base += 0x20;
//if (base == 0x7f && s == 0x9e)
// base += 0x20;
switch (base) {
case 0x3f:
cr = 0; //3f
if (kanjiType == KANA) chunk = 1;
else if (kanjiType == KANJI) chunk = 31;
else if (kanjiType == EKANJI) chunk = 111;
break;
case 0x5f:
cr = 0; //5f
if (kanjiType == KANA) chunk = 17;
else if (kanjiType == KANJI) chunk = 47;
else if (kanjiType == EKANJI) chunk = 127;
break;
case 0x7f:
cr = -1; //80
if (kanjiType == KANA) chunk = 9;
else if (kanjiType == KANJI) chunk = 63;
else if (kanjiType == EKANJI) chunk = 143;
break;
case 0x9f:
cr = 1; //9e
if (kanjiType == KANA) chunk = 2;
else if (kanjiType == KANJI) chunk = 32;
else if (kanjiType == EKANJI) chunk = 112;
break;
case 0xbf:
cr = 1; //be
if (kanjiType == KANA) chunk = 18;
else if (kanjiType == KANJI) chunk = 48;
else if (kanjiType == EKANJI) chunk = 128;
break;
case 0xdf:
cr = 1; //de
if (kanjiType == KANA) chunk = 10;
else if (kanjiType == KANJI) chunk = 64;
else if (kanjiType == EKANJI) chunk = 144;
break;
default:
debug(4, "Invalid Char! f %x s %x base %x c %d p %d", f, s, base, c, p);
}
debug(6, "Kanji: %c%c f 0x%x s 0x%x base 0x%x c %d p %d chunk %d cr %d index %d", f, s, f, s, base, c, p, chunk, cr, ((chunk_f + chunk) * 32 + (s - base)) + cr);
const int chunkNum = (((chunk_f + chunk) * 32 + (s - base)) + cr);
if (chunkNum < 0 || chunkNum >= kFont16x16Chars)
return 0;
else
return _fontData16x16 + chunkNum * 32;
} }
if (kanjiType == KANA) {//Kana
chunk_f = (f - 0x81) * 2;
} else if (kanjiType == KANJI) {//Standard Kanji
p += f - 0x88;
chunk_f = c + 2 * p;
} else if (kanjiType == EKANJI) {//Enhanced Kanji
p += f - 0xe0;
chunk_f = c + 2 * p;
}
// Base corrections
if (base == 0x7f && s == 0x7f)
base -= 0x20;
if (base == 0x9f && s == 0xbe)
base += 0x20;
if (base == 0xbf && s == 0xde)
base += 0x20;
//if (base == 0x7f && s == 0x9e)
// base += 0x20;
switch (base) {
case 0x3f:
cr = 0; //3f
if (kanjiType == KANA) chunk = 1;
else if (kanjiType == KANJI) chunk = 31;
else if (kanjiType == EKANJI) chunk = 111;
break;
case 0x5f:
cr = 0; //5f
if (kanjiType == KANA) chunk = 17;
else if (kanjiType == KANJI) chunk = 47;
else if (kanjiType == EKANJI) chunk = 127;
break;
case 0x7f:
cr = -1; //80
if (kanjiType == KANA) chunk = 9;
else if (kanjiType == KANJI) chunk = 63;
else if (kanjiType == EKANJI) chunk = 143;
break;
case 0x9f:
cr = 1; //9e
if (kanjiType == KANA) chunk = 2;
else if (kanjiType == KANJI) chunk = 32;
else if (kanjiType == EKANJI) chunk = 112;
break;
case 0xbf:
cr = 1; //be
if (kanjiType == KANA) chunk = 18;
else if (kanjiType == KANJI) chunk = 48;
else if (kanjiType == EKANJI) chunk = 128;
break;
case 0xdf:
cr = 1; //de
if (kanjiType == KANA) chunk = 10;
else if (kanjiType == KANJI) chunk = 64;
else if (kanjiType == EKANJI) chunk = 144;
break;
default:
debug(4, "Invalid Char! f %x s %x base %x c %d p %d", f, s, base, c, p);
}
debug(6, "Kanji: %c%c f 0x%x s 0x%x base 0x%x c %d p %d chunk %d cr %d index %d", f, s, f, s, base, c, p, chunk, cr, ((chunk_f + chunk) * 32 + (s - base)) + cr);
const int chunkNum = (((chunk_f + chunk) * 32 + (s - base)) + cr);
if (chunkNum < 0 || chunkNum >= kFont16x16Chars)
return 0;
else
return _fontData16x16 + chunkNum * 32;
}
const uint8 *FontTowns::getCharData8x16(uint16 c) const {
if (c >= kFont8x16Chars)
return 0;
return _fontData8x16 + c * 16;
} }
// ScummVM SJIS font // ScummVM SJIS font
FontSjisSVM::FontSjisSVM()
: _fontData16x16(0), _fontData16x16Size(0), _fontData8x16(0), _fontData8x16Size(0) {
}
FontSjisSVM::~FontSjisSVM() {
delete[] _fontData16x16;
delete[] _fontData8x16;
}
bool FontSjisSVM::loadData() { bool FontSjisSVM::loadData() {
Common::SeekableReadStream *data = SearchMan.createReadStreamForMember("SJIS.FNT"); Common::SeekableReadStream *data = SearchMan.createReadStreamForMember("SJIS.FNT");
if (!data) if (!data)
@ -393,46 +443,40 @@ const uint8 *FontSjisSVM::getCharData(uint16 c) const {
const uint8 fB = c & 0xFF; const uint8 fB = c & 0xFF;
const uint8 sB = c >> 8; const uint8 sB = c >> 8;
// We only allow 2 byte SJIS characters. if (isASCII(c)) {
if (fB <= 0x80 || fB >= 0xF0 || (fB >= 0xA0 && fB <= 0xDF) || sB == 0x7F) int index = fB;
return 0;
int base = fB; // half-width katakana
base -= 0x81; if (fB >= 0xA1 && fB <= 0xDF)
if (base >= 0x5F) index -= 0x21;
base -= 0x40;
int index = sB; const uint offset = index * 16;
index -= 0x40; assert(offset <= _fontData8x16Size);
if (index >= 0x3F) return _fontData8x16 + offset;
--index; } else {
// We only allow 2 byte SJIS characters.
if (fB <= 0x80 || fB >= 0xF0 || (fB >= 0xA0 && fB <= 0xDF) || sB == 0x7F)
return 0;
// Another check if the passed character was an int base = fB;
// correctly encoded SJIS character. base -= 0x81;
if (index < 0 || index >= 0xBC || base < 0) if (base >= 0x5F)
return 0; base -= 0x40;
const uint offset = (base * 0xBC + index) * 32; int index = sB;
assert(offset + 16 <= _fontData16x16Size); index -= 0x40;
return _fontData16x16 + offset; if (index >= 0x3F)
} --index;
const uint8 *FontSjisSVM::getCharData8x16(uint16 c) const { // Another check if the passed character was an
const uint8 fB = c & 0xFF; // correctly encoded SJIS character.
const uint8 sB = c >> 8; if (index < 0 || index >= 0xBC || base < 0)
return 0;
if (!is8x16(c) || sB) const uint offset = (base * 0xBC + index) * 32;
return 0; assert(offset + 16 <= _fontData16x16Size);
return _fontData16x16 + offset;
int index = fB; }
// half-width katakana
if (fB >= 0xA1 && fB <= 0xDF)
index -= 0x21;
const uint offset = index * 16;
assert(offset <= _fontData8x16Size);
return _fontData8x16 + offset;
} }
} // End of namespace Graphics } // End of namespace Graphics

View file

@ -134,19 +134,19 @@ public:
*/ */
class FontSJISBase : public FontSJIS { class FontSJISBase : public FontSJIS {
public: public:
FontSJISBase() : _drawMode(kDefaultMode), _flippedMode(false) {} FontSJISBase();
void setDrawingMode(DrawingMode mode) { _drawMode = mode; } virtual void setDrawingMode(DrawingMode mode);
void toggleFlippedMode(bool enable) { _flippedMode = enable; } virtual void toggleFlippedMode(bool enable);
uint getFontHeight() const { return (_drawMode == kOutlineMode) ? 18 : (_drawMode == kDefaultMode ? 16 : 17); } virtual uint getFontHeight() const;
uint getMaxFontWidth() const { return (_drawMode == kOutlineMode) ? 18 : (_drawMode == kDefaultMode ? 16 : 17); } virtual uint getMaxFontWidth() const;
uint getCharWidth(uint16 ch) const; virtual uint getCharWidth(uint16 ch) const;
void drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, uint32 c2, int maxW = -1, int maxH = -1) const; virtual void drawChar(void *dst, uint16 ch, int pitch, int bpp, uint32 c1, uint32 c2, int maxW = -1, int maxH = -1) const;
private: private:
template<typename Color> template<typename Color>
void blitCharacter(const uint8 *glyph, const int w, const int h, uint8 *dst, int pitch, Color c) const; void blitCharacter(const uint8 *glyph, const int w, const int h, uint8 *dst, int pitch, Color c) const;
@ -162,10 +162,9 @@ protected:
DrawingMode _drawMode; DrawingMode _drawMode;
bool _flippedMode; bool _flippedMode;
bool is8x16(uint16 ch) const; bool isASCII(uint16 ch) const;
virtual const uint8 *getCharData(uint16 c) const = 0; virtual const uint8 *getCharData(uint16 c) const = 0;
virtual const uint8 *getCharData8x16(uint16 c) const = 0;
}; };
/** /**
@ -188,8 +187,7 @@ private:
uint8 _fontData16x16[kFont16x16Chars * 32]; uint8 _fontData16x16[kFont16x16Chars * 32];
uint8 _fontData8x16[kFont8x16Chars * 32]; uint8 _fontData8x16[kFont8x16Chars * 32];
const uint8 *getCharData(uint16 c) const; virtual const uint8 *getCharData(uint16 c) const;
const uint8 *getCharData8x16(uint16 c) const;
}; };
/** /**
@ -197,8 +195,8 @@ private:
*/ */
class FontSjisSVM : public FontSJISBase { class FontSjisSVM : public FontSJISBase {
public: public:
FontSjisSVM() : _fontData16x16(0), _fontData16x16Size(0), _fontData8x16(0), _fontData8x16Size(0) {} FontSjisSVM();
~FontSjisSVM() { delete[] _fontData16x16; delete[] _fontData8x16; } ~FontSjisSVM();
/** /**
* Load the font data from "SJIS.FNT". * Load the font data from "SJIS.FNT".
@ -211,8 +209,7 @@ private:
uint8 *_fontData8x16; uint8 *_fontData8x16;
uint _fontData8x16Size; uint _fontData8x16Size;
const uint8 *getCharData(uint16 c) const; virtual const uint8 *getCharData(uint16 c) const;
const uint8 *getCharData8x16(uint16 c) const;
}; };
// TODO: Consider adding support for PC98 ROM // TODO: Consider adding support for PC98 ROM