[Scummvm-cvs-logs] SF.net SVN: scummvm:[44482] tools/trunk/create_sjisfnt.cpp
lordhoto at users.sourceforge.net
lordhoto at users.sourceforge.net
Wed Sep 30 15:05:53 CEST 2009
Revision: 44482
http://scummvm.svn.sourceforge.net/scummvm/?rev=44482&view=rev
Author: lordhoto
Date: 2009-09-30 13:05:53 +0000 (Wed, 30 Sep 2009)
Log Message:
-----------
- Adapt create_sjisfnt to also include ASCII and half-width katakana in the font (as 8x16 glyphs, as the PC98 font rom does).
- Increase sjis.fnt version to 2
Modified Paths:
--------------
tools/trunk/create_sjisfnt.cpp
Modified: tools/trunk/create_sjisfnt.cpp
===================================================================
--- tools/trunk/create_sjisfnt.cpp 2009-09-30 12:17:38 UTC (rev 44481)
+++ tools/trunk/create_sjisfnt.cpp 2009-09-30 13:05:53 UTC (rev 44482)
@@ -35,6 +35,9 @@
namespace {
+bool isASCII(uint8 fB);
+
+int mapASCIItoChunk(uint8 fB);
int mapSJIStoChunk(uint8 fB, uint8 sB);
bool initSJIStoUTF32Conversion();
@@ -62,6 +65,9 @@
bool drawGlyph(uint8 fB, uint8 sB, Glyph &glyph);
bool drawGlyph(uint32 unicode, Glyph &glyph);
+void convertChar8x16(uint8 *dst, const Glyph &g);
+void convertChar16x16(uint8 *dst, const Glyph &g);
+
typedef std::list<Glyph> GlyphList;
void freeGlyphlist(GlyphList &list) {
for (GlyphList::iterator i = list.begin(); i != list.end(); ++i)
@@ -99,18 +105,43 @@
std::atexit(deinitFreeType);
GlyphList glyphs;
+ int chars8x16 = 0;
int chars16x16 = 0;
+ // FIXME: It seems some ttf fonts will only render invalid data,
+ // when FreeType2 is asked to provide 8x16 glyphs. "sazanami-mincho.ttf"
+ // is such a case. When we will render them in the default 16x16 setting
+ // all ASCII chars will be rendered correctly and still fit within 8x16.
+ // Some fonts might require special setup as 8x16 though.
+ // We should try to find some proper way of detecting and handling this.
+
+ // ASCII chars will be rendererd as 8x16
+ //if (!setGlyphSize(8, 16))
+ // return -1;
+
+ for (uint8 fB = 0x00; fB <= 0xDF; ++fB) {
+ if (mapASCIItoChunk(fB) == -1)
+ continue;
+
+ ++chars8x16;
+
+ Glyph data;
+ if (drawGlyph(fB, 0, data))
+ glyphs.push_back(data);
+ }
+
// The two byte SJIS chars will be rendered as 16x16
- if (!setGlyphSize(16, 16))
+ if (!setGlyphSize(16, 16)) {
+ freeGlyphlist(glyphs);
return -1;
+ }
for (uint8 fB = 0x81; fB <= 0xEF; ++fB) {
- if (fB >= 0xA0 && fB <= 0xDF)
+ if (mapSJIStoChunk(fB, 0x40) == -1)
continue;
for (uint8 sB = 0x40; sB <= 0xFC; ++sB) {
- if (sB == 0x7F)
+ if (mapSJIStoChunk(fB, sB) == -1)
continue;
++chars16x16;
@@ -121,65 +152,77 @@
}
}
+ // Post process all chars, so that xOffset is at least 0
+ int minXOffset = 0;
+ for (GlyphList::const_iterator i = glyphs.begin(); i != glyphs.end(); ++i)
+ minXOffset = std::min(minXOffset, i->xOffset);
+
+ minXOffset = std::abs(minXOffset);
+
+ for (GlyphList::iterator i = glyphs.begin(); i != glyphs.end(); ++i)
+ i->xOffset += minXOffset;
+
// Calculate the base line for the font. The possible range is [0, 15].
- int baseLine = 15;
+ // TODO: This logic might need some more tinkering, it's pretty hacky right now.
+ int baseLine = 0;
for (GlyphList::const_iterator i = glyphs.begin(); i != glyphs.end(); ++i) {
- int bL = 16 + (i->yOffset - i->height);
+ int bL = 0;
- if (bL < baseLine)
- baseLine = bL;
+ // Try to center the glyph vertically
+ if (i->height + i->yOffset <= 16)
+ bL = i->yOffset + (16 - (i->height + i->yOffset)) / 2;
+
+ bL = std::min(bL, 15);
+
+ baseLine = std::max(baseLine, bL);
}
-
- // Check whether we have an character which does not fit in 16x16
+
+ // Check whether we have an character which does not fit within the boundaries6
for (GlyphList::const_iterator i = glyphs.begin(); i != glyphs.end(); ++i) {
- if (!checkGlyphSize(*i, baseLine, 16, 16)) {
+ if (i->pitch == 0)
+ continue;
+
+ if ((isASCII(i->fB) && !checkGlyphSize(*i, baseLine, 8, 16)) ||
+ (!isASCII(i->fB) && !checkGlyphSize(*i, baseLine, 16, 16))) {
for (GlyphList::iterator j = glyphs.begin(); j != glyphs.end(); ++j)
- delete[] i->plainData;
+ delete[] j->plainData;
- error("Could not fit glyph for %.2X %.2X top: %d bottom: %d, left: %d right: %d", i->fB, i->sB,
- baseLine - i->yOffset, baseLine - i->yOffset + i->height, i->xOffset, i->xOffset + i->width);
+ error("Could not fit glyph for %.2X %.2X top: %d bottom: %d, left: %d right: %d, xOffset: %d, yOffset: %d, width: %d, height: %d, baseLine: %d",
+ i->fB, i->sB, baseLine - i->yOffset, baseLine - i->yOffset + i->height, i->xOffset, i->xOffset + i->width,
+ i->xOffset, i->yOffset, i->width, i->height, baseLine);
}
}
- const int sjisDataSize = chars16x16 * 32;
- uint8 *sjisFontData = new uint8[sjisDataSize];
+ const int sjis8x16DataSize = chars8x16 * 16;
+ uint8 *sjis8x16FontData = new uint8[sjis8x16DataSize];
- if (!sjisFontData) {
+ const int sjis16x16DataSize = chars16x16 * 32;
+ uint8 *sjis16x16FontData = new uint8[sjis16x16DataSize];
+
+ if (!sjis16x16FontData) {
freeGlyphlist(glyphs);
error("Out of memory");
}
- memset(sjisFontData, 0, sjisDataSize);
+ memset(sjis8x16FontData, 0, sjis8x16DataSize);
+ memset(sjis16x16FontData, 0, sjis16x16DataSize);
for (GlyphList::const_iterator i = glyphs.begin(); i != glyphs.end(); ++i) {
- int chunk = mapSJIStoChunk(i->fB, i->sB);
+ if (isASCII(i->fB)) {
+ int chunk = mapASCIItoChunk(i->fB);
- if (chunk != -1) {
- uint8 *dst = sjisFontData + chunk * 32;
- const uint8 *src = i->plainData;
+ if (chunk != -1) {
+ uint8 *dst = sjis8x16FontData + chunk * 16;
+ dst += (baseLine - i->yOffset);
+ convertChar8x16(dst, *i);
+ }
+ } else {
+ int chunk = mapSJIStoChunk(i->fB, i->sB);
- dst += (baseLine - i->yOffset) * 2;
-
- for (int y = 0; y < i->height; ++y) {
- uint16 mask = 1 << (15 - i->xOffset);
-
- const uint8 *curSrc = src;
-
- uint16 line = 0;
- uint8 d = 0;
- for (int x = 0; x < i->width; ++x) {
- if (x == 0 || x == 8)
- d = *curSrc++;
-
- if (d & 0x80)
- line |= mask;
-
- d <<= 1;
- mask >>= 1;
- }
-
- WRITE_BE_UINT16(dst, line); dst += 2;
- src += i->pitch;
+ if (chunk != -1) {
+ uint8 *dst = sjis16x16FontData + chunk * 32;
+ dst += (baseLine - i->yOffset) * 2;
+ convertChar16x16(dst, *i);
}
}
}
@@ -193,32 +236,53 @@
writeUint32BE(sjisFont, MKID_BE('SJIS'));
// Write version
- writeUint32BE(sjisFont, 0x00000001);
+ writeUint32BE(sjisFont, 0x00000002);
// Write character count
writeUint16BE(sjisFont, chars16x16);
+ writeUint16BE(sjisFont, chars8x16);
- std::fwrite(sjisFontData, 1, sjisDataSize, sjisFont);
+ std::fwrite(sjis16x16FontData, 1, sjis16x16DataSize, sjisFont);
+ std::fwrite(sjis8x16FontData, 1, sjis8x16DataSize, sjisFont);
std::fflush(sjisFont);
if (std::ferror(sjisFont)) {
- delete[] sjisFontData;
+ delete[] sjis8x16FontData;
+ delete[] sjis16x16FontData;
std::fclose(sjisFont);
error("Error while writing to font file: '%s'", out);
}
std::fclose(sjisFont);
} else {
- delete[] sjisFontData;
+ delete[] sjis8x16FontData;
+ delete[] sjis16x16FontData;
error("Could not open file '%s' for writing", out);
}
- delete[] sjisFontData;
+ delete[] sjis8x16FontData;
+ delete[] sjis16x16FontData;
return 0;
}
namespace {
+bool isASCII(uint8 fB) {
+ return (mapASCIItoChunk(fB) != -1);
+}
+
+int mapASCIItoChunk(uint8 fB) {
+ // ASCII chars
+ if (fB <= 0x7F)
+ return fB;
+
+ // half-width katakana
+ if (fB >= 0xA1 && fB <= 0xDF)
+ return fB - 0x21;
+
+ return -1;
+}
+
int mapSJIStoChunk(uint8 fB, uint8 sB) {
// We only allow 2 byte SJIS characters.
if (fB <= 0x80 || fB >= 0xF0 || (fB >= 0xA0 && fB <= 0xDF) || sB == 0x7F)
@@ -257,6 +321,12 @@
// here.
if (fB == 0x81 && sB == 0xAD)
return 0x0000FF07;
+ // SJIS uses "YEN SIGN" instead of "REVERSE SOLIDUS"
+ else if (fB == 0x5C && sB == 0x00)
+ return 0x000000A5;
+ // SJIS uses "OVERLINE" instead of "TILDE"
+ else if (fB == 0x7E && sB == 0x00)
+ return 0x0000203E;
char inBuf[3];
@@ -329,8 +399,8 @@
}
bool checkGlyphSize(const Glyph &g, const int baseLine, const int maxW, const int maxH) {
- if (baseLine - g.yOffset < 0 || baseLine - g.yOffset + g.height > maxH ||
- g.xOffset > (maxW - 1) || g.xOffset + g.width > maxW)
+ if (baseLine - g.yOffset < 0 || baseLine - g.yOffset + g.height > (maxH + 1) ||
+ g.xOffset > (maxW - 1) || g.xOffset + g.width > (maxW + 1))
return false;
return true;
}
@@ -392,7 +462,7 @@
dst += (glyph.height - 1) * (-glyph.pitch);
for (int i = 0; i < bitmap.rows; ++i) {
- memcpy(dst, src, glyph.pitch);
+ memcpy(dst, src, std::abs(glyph.pitch));
src += bitmap.pitch;
dst += glyph.pitch;
}
@@ -403,5 +473,61 @@
return true;
}
+// TODO: merge these two
+
+void convertChar8x16(uint8 *dst, const Glyph &g) {
+ const uint8 *src = g.plainData;
+
+ assert(g.width + g.xOffset <= 8);
+
+ for (int y = 0; y < g.height; ++y) {
+ uint8 mask = 1 << (7 - g.xOffset);
+
+ const uint8 *curSrc = src;
+
+ uint8 line = 0;
+ uint8 d = 0;
+ for (int x = 0; x < g.width; ++x) {
+ if (x == 0)
+ d = *curSrc++;
+
+ if (d & 0x80)
+ line |= mask;
+
+ d <<= 1;
+ mask >>= 1;
+ }
+
+ *dst++ = line;
+ src += g.pitch;
+ }
+}
+
+void convertChar16x16(uint8 *dst, const Glyph &g) {
+ const uint8 *src = g.plainData;
+
+ for (int y = 0; y < g.height; ++y) {
+ uint16 mask = 1 << (15 - g.xOffset);
+
+ const uint8 *curSrc = src;
+
+ uint16 line = 0;
+ uint8 d = 0;
+ for (int x = 0; x < g.width; ++x) {
+ if (x == 0 || x == 8)
+ d = *curSrc++;
+
+ if (d & 0x80)
+ line |= mask;
+
+ d <<= 1;
+ mask >>= 1;
+ }
+
+ WRITE_BE_UINT16(dst, line); dst += 2;
+ src += g.pitch;
+ }
+}
+
} // end of anonymous namespace
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
More information about the Scummvm-git-logs
mailing list