[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