[Scummvm-cvs-logs] SF.net SVN: scummvm:[55120] scummvm/trunk/graphics

mthreepwood at users.sourceforge.net mthreepwood at users.sourceforge.net
Tue Jan 4 21:39:27 CET 2011


Revision: 55120
          http://scummvm.svn.sourceforge.net/scummvm/?rev=55120&view=rev
Author:   mthreepwood
Date:     2011-01-04 20:39:27 +0000 (Tue, 04 Jan 2011)

Log Message:
-----------
GRAPHICS: Add support for Windows FON/FNT fonts

As required by Hugo and Mohawk.

Modified Paths:
--------------
    scummvm/trunk/graphics/module.mk

Added Paths:
-----------
    scummvm/trunk/graphics/fonts/winfont.cpp
    scummvm/trunk/graphics/fonts/winfont.h

Added: scummvm/trunk/graphics/fonts/winfont.cpp
===================================================================
--- scummvm/trunk/graphics/fonts/winfont.cpp	                        (rev 0)
+++ scummvm/trunk/graphics/fonts/winfont.cpp	2011-01-04 20:39:27 UTC (rev 55120)
@@ -0,0 +1,299 @@
+/* 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 "common/file.h"
+#include "common/ne_exe.h"
+#include "common/str.h"
+#include "graphics/fonts/winfont.h"
+
+namespace Graphics {
+
+WinFont::WinFont() {
+	_glyphs = 0;
+	close();
+}
+
+WinFont::~WinFont() {
+	close();
+}
+
+void WinFont::close() {
+	_pixHeight = 0;
+	_ascent = 0;
+	_maxWidth = 0;
+	_firstChar = 0;
+	_lastChar = 0;
+	_defaultChar = 0;
+	_glyphCount = 0;
+	delete[] _glyphs;
+	_glyphs = 0;
+}
+
+// Reads a null-terminated string
+static Common::String readString(Common::SeekableReadStream &stream) {
+	Common::String string;
+
+	char c = stream.readByte();
+	while (c && stream.pos() < stream.size()) {
+		string += c;
+		c = stream.readByte();
+	}
+
+	return string;
+}
+
+static WinFontDirEntry readDirEntry(Common::SeekableReadStream &stream) {
+	WinFontDirEntry entry;
+
+	stream.skip(68); // Useless
+	entry.points = stream.readUint16LE();
+	stream.skip(43); // Useless (for now, maybe not in the future)
+	readString(stream);
+	entry.faceName = readString(stream);
+
+	return entry;
+}
+
+bool WinFont::loadFromFON(const Common::String &fileName, const WinFontDirEntry &dirEntry) {
+	// TODO: PE libraries (If it's used anywhere by a ScummVM game)
+
+	Common::NEResources exe;
+
+	if (!exe.loadFromEXE(fileName))
+		return false;
+
+	// Let's pull out the font directory
+	Common::SeekableReadStream *fontDirectory = exe.getResource(Common::kNEFontDir, Common::String("FONTDIR"));
+	if (!fontDirectory) {
+		warning("No font directory in '%s'", fileName.c_str());
+		return false;
+	}
+
+	uint16 numFonts = fontDirectory->readUint16LE();
+
+	// Probably not possible, so this is really  sanity check
+	if (numFonts == 0) {
+		warning("No fonts in '%s'", fileName.c_str());
+		return false;
+	}
+
+	// Scour the directory for our matching name
+	int fontId = -1;
+	for (uint16 i = 0; i < numFonts; i++) {
+		uint16 id = fontDirectory->readUint16LE();
+
+		if (dirEntry.faceName.empty()) {
+			// Use the first name when empty
+			fontId = id;
+			break;
+		}
+
+		WinFontDirEntry entry = readDirEntry(*fontDirectory);
+
+		if (dirEntry.faceName.equalsIgnoreCase(entry.faceName) && dirEntry.points == entry.points) {
+			// Match!
+			fontId = id;
+			break;
+		}
+	}
+
+	delete fontDirectory;
+
+	// Couldn't match the face name
+	if (fontId < 0) {
+		warning("Could not find face '%s' in '%s'", dirEntry.faceName.c_str(), fileName.c_str());
+		return false;
+	}
+
+	// Actually go get our font now...
+	Common::SeekableReadStream *fontStream = exe.getResource(Common::kNEFont, fontId);
+	if (!fontStream) {
+		warning("Could not find font %d in %s", fontId, fileName.c_str());
+		return false;
+	}
+
+	bool ok = loadFromFNT(*fontStream);
+	delete fontStream;
+	return ok;
+}
+
+bool WinFont::loadFromFNT(const Common::String &fileName) {
+	Common::File file;
+
+	return file.open(fileName) && loadFromFNT(file);
+}
+
+char WinFont::indexToCharacter(uint16 index) const {
+	// Use a space for the sentinel value
+	if (index == _glyphCount - 1)
+		return ' ';
+
+	return index + _firstChar;
+}
+
+uint16 WinFont::characterToIndex(byte character) const {
+	// Go to the default character if we didn't find a mapping
+	if (character < _firstChar || character > _lastChar)
+		character = _defaultChar;
+
+	return character - _firstChar;
+}
+
+int WinFont::getCharWidth(byte chr) const {
+	return _glyphs[characterToIndex(chr)].charWidth;
+}
+
+bool WinFont::loadFromFNT(Common::SeekableReadStream &stream) {
+	uint16 version = stream.readUint16LE();
+
+	// We'll accept Win2 and Win3 fonts
+	if (version != 0x200 && version != 0x300) {
+		if (version == 0x100) {
+			// TODO: Hugo1 has a font with this
+			// Even FreeType won't accept this font!
+			warning("Windows 1.0 font? Specs please");
+		} else
+			warning("Bad FNT version %04x", version);
+
+		return false;
+	}
+
+	/* uint32 size = */ stream.readUint32LE();
+	stream.skip(60); // Copyright info
+	uint16 fontType = stream.readUint16LE();
+	/* uint16 points = */ stream.readUint16LE();
+	/* uint16 vertRes = */ stream.readUint16LE();
+	/* uint16 horizRes = */ stream.readUint16LE();
+	_ascent = stream.readUint16LE();
+	/* uint16 internalLeading = */ stream.readUint16LE();
+	/* uint16 externalLeading = */ stream.readUint16LE();
+	/* byte italic = */ stream.readByte();
+	/* byte underline = */ stream.readByte();
+	/* byte strikeOut = */ stream.readByte();
+	/* uint16 weight = */ stream.readUint16LE();
+	/* byte charSet = */ stream.readByte();
+	uint16 pixWidth = stream.readUint16LE();
+	_pixHeight = stream.readUint16LE();
+	/* byte pitchAndFamily = */ stream.readByte();
+	/* uint16 avgWidth = */ stream.readUint16LE();
+	_maxWidth = stream.readUint16LE();
+	_firstChar = stream.readByte();
+	_lastChar = stream.readByte();
+	_defaultChar = stream.readByte();
+	/* byte breakChar = */ stream.readByte();
+	/* uint16 widthBytes = */ stream.readUint16LE();
+	/* uint32 device = */ stream.readUint32LE();
+	/* uint32 face = */ stream.readUint32LE();
+	/* uint32 bitsPointer = */ stream.readUint32LE();
+	/* uint32 bitsOffset = */ stream.readUint32LE();
+	/* byte reserved = */ stream.readByte();
+
+	if (version == 0x300) {
+		// For Windows 3.0, Microsoft added 6 new fields. All of which are
+		// guaranteed to be 0. Which leads to the question: Why add these at all?
+
+		/* uint32 flags = */ stream.readUint32LE();
+		/* uint16 aSpace = */ stream.readUint16LE();
+		/* uint16 bSpace = */ stream.readUint16LE();
+		/* uint16 cSpace = */ stream.readUint16LE();
+		/* uint32 colorPointer = */ stream.readUint32LE();
+		stream.skip(16); // Reserved
+	}
+
+	// Begin loading in the glyphs
+	_glyphCount = (_lastChar - _firstChar) + 2;
+	_glyphs = new GlyphEntry[_glyphCount];
+
+	for (uint16 i = 0; i < _glyphCount; i++) {
+		_glyphs[i].charWidth = stream.readUint16LE();
+
+		// Use the default if present
+		if (pixWidth)
+			_glyphs[i].charWidth = pixWidth;
+
+		_glyphs[i].offset = (version == 0x300) ? stream.readUint32LE() : stream.readUint16LE();
+	}
+
+	// TODO: Currently only raster fonts are supported!
+	if (fontType & 1) {
+		warning("Vector FNT files not supported yet");
+		return false;
+	}
+
+	// Read in the bitmaps for the raster images
+	for (uint16 i = 0; i < _glyphCount - 1; i++) {
+		stream.seek(_glyphs[i].offset);
+
+		_glyphs[i].bitmap = new byte[_pixHeight * _glyphs[i].charWidth];
+
+		// Calculate the amount of columns
+		byte colCount = (_glyphs[i].charWidth + 7) / 8;
+
+		for (uint16 j = 0; j < colCount; j++) {
+			for (uint16 k = 0; k < _pixHeight; k++) {
+				byte x = stream.readByte();
+				uint offset = j * 8 + k * _glyphs[i].charWidth;
+
+				for (byte l = 0; l < 8 && j * 8 + l < _glyphs[i].charWidth; l++)
+					_glyphs[i].bitmap[offset + l] = (x & (1 << (7 - l))) ? 1 : 0;
+			}
+		}
+
+#if 0
+		// Debug print
+		debug("Character %02x '%c' at %08x", indexToCharacter(i), indexToCharacter(i), _glyphs[i].offset);
+		for (uint16 j = 0; j < _pixHeight; j++) {
+			for (uint16 k = 0; k < _glyphs[i].charWidth; k++)
+				debugN("%c", _glyphs[i].bitmap[k + j * _glyphs[i].charWidth] ? 'X' : ' ');
+
+			debugN("\n");
+		}
+#endif
+	}
+
+	return true;
+}
+
+void WinFont::drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const {
+	assert(dst);
+	assert(dst->bytesPerPixel == 1 || dst->bytesPerPixel == 2 || dst->bytesPerPixel == 4);
+	assert(_glyphs);
+
+	GlyphEntry &glyph = _glyphs[characterToIndex(chr)];
+
+	for (uint16 i = 0; i < _pixHeight; i++) {
+		for (uint16 j = 0; j < glyph.charWidth; j++) {
+			if (glyph.bitmap[j + i * glyph.charWidth]) {
+				if (dst->bytesPerPixel == 1)
+					*((byte *)dst->getBasePtr(x + j, y + i)) = color;
+				else if (dst->bytesPerPixel == 2)
+					*((uint16 *)dst->getBasePtr(x + j, y + i)) = color;
+				else if (dst->bytesPerPixel == 4)
+					*((uint32 *)dst->getBasePtr(x + j, y + i)) = color;
+			}
+		}
+	}
+}
+
+} // End of namespace Graphics


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

Added: scummvm/trunk/graphics/fonts/winfont.h
===================================================================
--- scummvm/trunk/graphics/fonts/winfont.h	                        (rev 0)
+++ scummvm/trunk/graphics/fonts/winfont.h	2011-01-04 20:39:27 UTC (rev 55120)
@@ -0,0 +1,96 @@
+/* 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$
+ */
+
+#ifndef GRAPHICS_WINFONT_H
+#define GRAPHICS_WINFONT_H
+
+#include "graphics/font.h"
+
+namespace Common {
+	class SeekableReadStream;
+	class String;
+}
+
+namespace Graphics {
+
+struct WinFontDirEntry {
+	WinFontDirEntry() {}
+	WinFontDirEntry(const Common::String &name, uint16 p) : faceName(name), points(p) {}
+
+	// This is really just a simple identifier to match a directory entry with
+	// If need-be, we can add other things to check such as italics and strikethrough, etc.
+	Common::String faceName;
+	uint16 points;
+};
+
+class WinFont : public Font {
+public:
+	WinFont();
+	~WinFont();
+
+	/**
+	 * Open a font with a name in an FON file.
+	 *
+	 * If dirEntry is not given, the first font in the FONTDIR will be loaded
+	 */
+	bool loadFromFON(const Common::String &fileName, const WinFontDirEntry &dirEntry = WinFontDirEntry());
+
+	/** Open a font from an FNT file */
+	bool loadFromFNT(const Common::String &fileName);
+
+	/** Close this font */
+	void close();
+
+	// Font API
+	int getFontHeight() const { return _ascent; }
+	int getMaxCharWidth() const { return _maxWidth; }
+	int getCharWidth(byte chr) const;
+	void drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const;
+
+private:
+	bool loadFromFNT(Common::SeekableReadStream &stream);
+	char indexToCharacter(uint16 index) const;
+	uint16 characterToIndex(byte character) const;
+
+	uint16 _pixHeight;
+	uint16 _ascent;
+	uint16 _maxWidth;
+	byte _firstChar;
+	byte _lastChar;
+	byte _defaultChar;
+
+	uint16 _glyphCount;
+	struct GlyphEntry {
+		GlyphEntry() { bitmap = 0; }
+		~GlyphEntry() { delete[] bitmap; }
+
+		uint16 charWidth;
+		uint32 offset;
+		byte *bitmap;
+	} *_glyphs;	
+};
+
+} // End of namespace Graphics
+
+#endif


Property changes on: scummvm/trunk/graphics/fonts/winfont.h
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Modified: scummvm/trunk/graphics/module.mk
===================================================================
--- scummvm/trunk/graphics/module.mk	2011-01-04 19:46:18 UTC (rev 55119)
+++ scummvm/trunk/graphics/module.mk	2011-01-04 20:39:27 UTC (rev 55120)
@@ -10,6 +10,7 @@
 	fonts/newfont_big.o \
 	fonts/newfont.o \
 	fonts/scummfont.o \
+	fonts/winfont.o \
 	iff.o \
 	imagedec.o \
 	jpeg.o \


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