[Scummvm-cvs-logs] SF.net SVN: scummvm:[42811] tools/trunk

lordhoto at users.sourceforge.net lordhoto at users.sourceforge.net
Sun Jul 26 16:15:58 CEST 2009


Revision: 42811
          http://scummvm.svn.sourceforge.net/scummvm/?rev=42811&view=rev
Author:   lordhoto
Date:     2009-07-26 14:15:58 +0000 (Sun, 26 Jul 2009)

Log Message:
-----------
Initial commit of the tool to create a SJIS compatible font for ScummVM. It is not enabled by default in the Makefile yet and it lacks documentation for the user for now.

Modified Paths:
--------------
    tools/trunk/Makefile

Added Paths:
-----------
    tools/trunk/create_sjisfnt.cpp

Modified: tools/trunk/Makefile
===================================================================
--- tools/trunk/Makefile	2009-07-26 13:50:57 UTC (rev 42810)
+++ tools/trunk/Makefile	2009-07-26 14:15:58 UTC (rev 42811)
@@ -208,6 +208,9 @@
 extract_zak_c64$(EXEEXT): extract_zak_c64.o util.o
 	$(CXX) $(LDFLAGS) -o $@ $+
 
+create_sjisfnt$(EXEEXT): create_sjisfnt.o util.o
+	$(CXX) $(LDFLAGS) `freetype-config --libs` -o $@ $+
+
 tools_gui$(EXEEXT): tools_gui.o
 	$(CXX) $(LDFLAGS) -o $@ $+ `wx-config --libs`
 
@@ -217,6 +220,9 @@
 clean:
 	rm -f *.o utils/*.o $(TARGETS)
 
+create_sjisfnt.o: create_sjisfnt.cpp util.h
+	$(CXX) $(CXXFLAGS) $(CPPFLAGS) `freetype-config --cflags` -c create_sjisfnt.cpp -o create_sjisfnt.o
+
 tools_gui.o: tools_gui.cpp tools_gui.h
 	$(CXX) $(CXXFLAGS) $(CPPFLAGS) `wx-config --cxxflags` -c tools_gui.cpp -o tools_gui.o
 

Added: tools/trunk/create_sjisfnt.cpp
===================================================================
--- tools/trunk/create_sjisfnt.cpp	                        (rev 0)
+++ tools/trunk/create_sjisfnt.cpp	2009-07-26 14:15:58 UTC (rev 42811)
@@ -0,0 +1,376 @@
+/* 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include <iconv.h>
+#include <vector>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#include "util.h"
+#include <cstdio>
+#include <cstdlib>
+
+namespace {
+
+int mapSJIStoChunk(uint8 fB, uint8 sB);
+
+bool initSJIStoUTF32Conversion();
+void deinitSJIStoUTF32Conversion();
+uint32 convertSJIStoUTF32(uint8 fB, uint8 sB);
+
+bool initFreeType(const char *font);
+void deinitFreeType();
+
+struct Glyph {
+	uint8 fB, sB;
+
+	int xOffset;
+	int yOffset;
+	int height;
+	int width;
+
+	int pitch;
+	uint8 *plainData;
+};
+
+bool drawGlyph16x16(uint32 unicode, Glyph &glyph);
+
+} // end of anonymous namespace
+
+int main(int argc, char *argv[]) {
+	if (argc < 2 || argc > 3) {
+		std::printf("Usage:\n\t%s <input ttf font> [outfile]\n", argv[0]);
+		return -1;
+	}
+
+	const char *font = argv[1];
+	const char *out = 0;
+	if (argc == 3)
+		out = argv[2];
+	else
+		out = "sjis.fnt";
+
+	if (!initSJIStoUTF32Conversion()) {
+		error("Could not initialize conversion from SJIS to UTF-32.");
+		return -1;
+	}
+
+	atexit(deinitSJIStoUTF32Conversion);
+
+	if (!initFreeType(font)) {
+		error("Could not initialize FreeType library.");
+		return -1;
+	}
+
+	atexit(deinitFreeType);
+
+	std::vector<Glyph> glyphs;
+	int chars = 0;
+
+	for (uint8 fB = 0x81; fB <= 0xEF; ++fB) {
+		if (fB >= 0xA0 && fB <= 0xDF)
+			continue;
+
+		for (uint8 sB = 0x40; sB <= 0xFC; ++sB) {
+			if (sB == 0x7F)
+				continue;
+
+			++chars;
+
+			uint32 utf32 = convertSJIStoUTF32(fB, sB);
+			if (utf32 == (uint32)-1) {
+				// For now we disable that warning, since iconv will fail for all reserved,
+				// that means unused, valid SJIS character codes.
+				//
+				// It might be useful to enable that warning again to detect problems with
+				// iconv though. An example for such an iconv problem is the 
+				// "FULLWIDTH APOSTROPHE", which iconv refuses to convert to UTF-32.
+				//warning("Conversion error on: %.2X %.02X", fB, sB);
+				continue;
+			}
+
+			Glyph data;
+			data.fB = fB;
+			data.sB = sB;
+			if (!drawGlyph16x16(utf32, data)) {
+				warning("Could not render glyph: %.2X %.2X", fB, sB);
+				continue;
+			}
+
+			glyphs.push_back(data);
+		}
+	}
+
+	// Calculate the base line for the font. The possible range is [0, 15].
+	int baseLine = 15;
+	for (std::vector<Glyph>::const_iterator i = glyphs.begin(); i != glyphs.end(); ++i) {
+		int bL = 16 + (i->yOffset - i->height);
+
+		if (bL < baseLine)
+			baseLine = bL;
+	}
+	
+	// Check whether we have an character which does not fit in 16x16
+	for (std::vector<Glyph>::const_iterator i = glyphs.begin(); i != glyphs.end(); ++i) {
+		if (baseLine - i->yOffset < 0 || baseLine - i->yOffset + i->height > 16 ||
+			i->xOffset > 15 || i->xOffset + i->width > 16) {
+
+			for (std::vector<Glyph>::iterator j = glyphs.begin(); j != glyphs.end(); ++j)
+				delete[] i->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);
+		}
+	}
+
+	const int sjisDataSize = chars * 32;
+	uint8 *sjisFontData = new uint8[sjisDataSize];
+
+	if (!sjisFontData) {
+		for (std::vector<Glyph>::iterator i = glyphs.begin(); i != glyphs.end(); ++i)
+			delete[] i->plainData;
+		error("Out of memory");
+	}
+
+	memset(sjisFontData, 0, sjisDataSize);
+
+	for (std::vector<Glyph>::const_iterator i = glyphs.begin(); i != glyphs.end(); ++i) {
+		int chunk = mapSJIStoChunk(i->fB, i->sB);
+
+		if (chunk != -1) {
+			uint8 *dst = sjisFontData + chunk * 32;
+			const uint8 *src = i->plainData;
+
+			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;
+			}
+		}
+	}
+
+	for (std::vector<Glyph>::iterator i = glyphs.begin(); i != glyphs.end(); ++i)
+		delete[] i->plainData;
+	glyphs.clear();
+
+	FILE *sjisFont = std::fopen(out, "wb");
+	if (sjisFont) {
+		// Write our magic bytes
+		writeUint32BE(sjisFont, MKID_BE('SCVM'));
+		writeUint32BE(sjisFont, MKID_BE('SJIS'));
+
+		// Write version
+		writeUint32BE(sjisFont, 0x00000001);
+
+		// Write character count
+		writeUint16BE(sjisFont, chars);
+
+		std::fwrite(sjisFontData, 1, sjisDataSize, sjisFont);
+		std::fflush(sjisFont);
+
+		if (std::ferror(sjisFont)) {
+			delete[] sjisFontData;
+			std::fclose(sjisFont);
+			error("Error while writing to font file: '%s'", out);
+		}
+
+		std::fclose(sjisFont);
+	} else {
+		delete[] sjisFontData;
+		error("Could not open file '%s' for writing", out);
+	}
+
+	delete[] sjisFontData;
+	return 0;
+}
+
+namespace {
+
+int mapSJIStoChunk(uint8 fB, uint8 sB) {
+	// We only allow 2 byte SJIS characters.
+	if (fB <= 0x80 || fB >= 0xF0 || (fB >= 0xA0 && fB <= 0xDF) || sB == 0x7F)
+		return -1;
+
+	int base = fB;
+	base -= 0x81;
+	if (base >= 0x5F)
+		base -= 0x40;
+
+	int index = sB;
+	index -= 0x40;
+	if (index >= 0x3F)
+		--index;
+
+	return (base * 0xBC + index);
+}
+
+iconv_t confSetup = (iconv_t)-1;
+
+bool initSJIStoUTF32Conversion() {
+	// We initialize a SJIS to native endian UTF-32 conversion
+	// over here.
+	confSetup = iconv_open("UTF-32", "SJIS");
+	return (confSetup != (iconv_t)-1);
+}
+
+void deinitSJIStoUTF32Conversion() {
+	iconv_close(confSetup);
+}
+
+uint32 convertSJIStoUTF32(uint8 fB, uint8 sB) {
+	// For some reason iconv will refuse "0x81 0xAD" as valid
+	// SJIS sequence, even though it is "FULLWIDTH APOSTROPHE",
+	// thus we will short circuit iconv and convert it ourself
+	// here.
+	if (fB == 0x81 && sB == 0xAD)
+		return 0x0000FF07;
+
+	char inBuf[3];
+
+	inBuf[0] = fB;
+	inBuf[1] = sB;
+	inBuf[2] = 0;
+
+	char outBuf[3 * sizeof(uint32)];
+	memset(outBuf, 0, sizeof(outBuf));
+
+	size_t inBufSize = sizeof(inBuf);
+	size_t outBufSize = sizeof(outBuf);
+	char *inBufWrap = inBuf;
+	char *outBufWrap = outBuf;
+
+	if (iconv(confSetup, &inBufWrap, &inBufSize, &outBufWrap, &outBufSize) == (size_t)-1)
+		return (uint32)-1;
+
+	uint32 ret = *(uint32 *)outBuf;
+
+	// It might happen that iconv will add a "ZERO WIDTH NO-BREAK SPACE"
+	// before a character, we filter that out over here.
+	if (ret == 0x0000FEFF)
+		ret = *(uint32 *)(outBuf + 4);
+	
+	return ret;
+}
+
+FT_Library ft = NULL;
+FT_Face sjisFont = NULL;
+
+bool initFreeType(const char *font) {
+	FT_Error err = FT_Init_FreeType(&ft);
+	if (err) {
+		warning("Could not initialize FreeType2 library.");
+		return false;
+	}
+
+	err = FT_New_Face(ft, font, 0, &sjisFont);
+	if (err) {
+		warning("Could not load font '%s'", font);
+		return false;
+	}
+
+	err = FT_Set_Pixel_Sizes(sjisFont, 16, 16);
+	if (err) {
+		warning("Could not initialize font for 16x16 outout.");
+		return false;
+	}
+
+	err = FT_Select_Charmap(sjisFont, FT_ENCODING_UNICODE);
+	if (err) {
+		warning("Could not select unicode charmap.");
+		return false;
+	}
+
+	return true;
+}
+
+void deinitFreeType() {
+	FT_Done_Face(sjisFont);
+	FT_Done_FreeType(ft);
+}
+
+bool drawGlyph16x16(uint32 unicode, Glyph &glyph) {
+	uint32 index = FT_Get_Char_Index(sjisFont, unicode);
+	if (!index)
+		return false;
+
+	FT_Error err = FT_Load_Glyph(sjisFont, index, FT_LOAD_MONOCHROME);
+	if (err)
+		return false;
+
+	err = FT_Render_Glyph(sjisFont->glyph, FT_RENDER_MODE_MONO);
+	if (err)
+		return false;
+
+	const FT_Bitmap &bitmap = sjisFont->glyph->bitmap;
+
+	glyph.yOffset = sjisFont->glyph->bitmap_top;
+	glyph.xOffset = sjisFont->glyph->bitmap_left;
+	glyph.height = bitmap.rows;
+	glyph.width = bitmap.width;
+	glyph.pitch = bitmap.pitch;
+	glyph.plainData = 0;
+
+	if (glyph.height) {
+		glyph.plainData = new uint8[glyph.height * abs(glyph.pitch)];
+		if (!glyph.plainData)
+			return false;
+
+		const uint8 *src = bitmap.buffer;
+		uint8 *dst = glyph.plainData;
+
+		if (glyph.pitch < 0)
+			dst += (glyph.height - 1) * (-glyph.pitch);
+
+		for (int i = 0; i < bitmap.rows; ++i) {
+			memcpy(dst, src, glyph.pitch);
+			src += bitmap.pitch;
+			dst += glyph.pitch;
+		}
+	}
+
+	return true;
+}
+
+} // end of anonymous namespace
+


Property changes on: tools/trunk/create_sjisfnt.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native


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