[Scummvm-cvs-logs] SF.net SVN: scummvm: [25155] scummvm/trunk/engines/scumm

eriktorbjorn at users.sourceforge.net eriktorbjorn at users.sourceforge.net
Sun Jan 21 18:14:54 CET 2007


Revision: 25155
          http://scummvm.svn.sourceforge.net/scummvm/?rev=25155&view=rev
Author:   eriktorbjorn
Date:     2007-01-21 09:14:53 -0800 (Sun, 21 Jan 2007)

Log Message:
-----------
Applied my own patch #1635584 (after discussing with Fingolfin) to reduce the
memory usage and number of allocations made by the NUT font renderer.

Modified Paths:
--------------
    scummvm/trunk/engines/scumm/charset.cpp
    scummvm/trunk/engines/scumm/insane/insane.cpp
    scummvm/trunk/engines/scumm/nut_renderer.cpp
    scummvm/trunk/engines/scumm/nut_renderer.h
    scummvm/trunk/engines/scumm/smush/smush_player.cpp

Modified: scummvm/trunk/engines/scumm/charset.cpp
===================================================================
--- scummvm/trunk/engines/scumm/charset.cpp	2007-01-21 16:57:13 UTC (rev 25154)
+++ scummvm/trunk/engines/scumm/charset.cpp	2007-01-21 17:14:53 UTC (rev 25155)
@@ -1609,7 +1609,7 @@
 			break;
 		sprintf(fontname, "font%d.nut", i);
 		_fr[i] = new NutRenderer(_vm);
-		if (!(_fr[i]->loadFont(fontname))) {
+		if (!(_fr[i]->loadFont(fontname, true))) {
 			delete _fr[i];
 			_fr[i] = NULL;
 		}

Modified: scummvm/trunk/engines/scumm/insane/insane.cpp
===================================================================
--- scummvm/trunk/engines/scumm/insane/insane.cpp	2007-01-21 16:57:13 UTC (rev 25154)
+++ scummvm/trunk/engines/scumm/insane/insane.cpp	2007-01-21 17:14:53 UTC (rev 25155)
@@ -66,15 +66,15 @@
 		readFileToMem("minedriv.flu", &_smush_minedrivFlu);
 		readFileToMem("minefite.flu", &_smush_minefiteFlu);
 		_smush_bensgoggNut = new NutRenderer(_vm);
-		_smush_bensgoggNut->loadFont("bensgogg.nut");
+		_smush_bensgoggNut->loadFont("bensgogg.nut", false);
 		_smush_bencutNut = new NutRenderer(_vm);
-		_smush_bencutNut->loadFont("bencut.nut");
+		_smush_bencutNut->loadFont("bencut.nut", false);
 	}
 
 	_smush_iconsNut = new NutRenderer(_vm);
-	_smush_iconsNut->loadFont("icons.nut");
+	_smush_iconsNut->loadFont("icons.nut", false);
 	_smush_icons2Nut = new NutRenderer(_vm);
-	_smush_icons2Nut->loadFont("icons2.nut");
+	_smush_icons2Nut->loadFont("icons2.nut", false);
 }
 
 Insane::~Insane(void) {

Modified: scummvm/trunk/engines/scumm/nut_renderer.cpp
===================================================================
--- scummvm/trunk/engines/scumm/nut_renderer.cpp	2007-01-21 16:57:13 UTC (rev 25154)
+++ scummvm/trunk/engines/scumm/nut_renderer.cpp	2007-01-21 17:14:53 UTC (rev 25155)
@@ -30,26 +30,92 @@
 NutRenderer::NutRenderer(ScummEngine *vm) :
 	_vm(vm),
 	_loaded(false),
-	_numChars(0) {
+	_numChars(0),
+	_decodedData(0) {
 	memset(_chars, 0, sizeof(_chars));
 }
 
 NutRenderer::~NutRenderer() {
-	for (int i = 0; i < _numChars; i++) {
-		delete []_chars[i].src;
+	delete [] _decodedData;
+}
+
+void NutRenderer::codec1(bool bitmap, byte *dst, const byte *src, int width, int height, int pitch) {
+	byte val, code;
+	int32 length;
+	int h = height, size_line;
+
+	for (h = 0; h < height; h++) {
+		size_line = READ_LE_UINT16(src);
+		src += 2;
+		byte bit = 0x80;
+		byte *dstPtrNext = dst + pitch;
+		while (size_line > 0) {
+			code = *src++;
+			size_line--;
+			length = (code >> 1) + 1;
+			if (code & 1) {
+				val = *src++;
+				size_line--;
+				if (bitmap) {
+					for (int i = 0; i < length; i++) {
+						if (val)
+							*dst |= bit;
+						bit >>= 1;
+						if (!bit) {
+							bit = 0x80;
+							dst++;
+						}
+					}
+				} else {
+					if (val)
+						memset(dst, val, length);
+					dst += length;
+				}
+			} else {
+				size_line -= length;
+				while (length--) {
+					val = *src++;
+					if (bitmap) {
+						if (val)
+							*dst |= bit;
+						bit >>= 1;
+						if (!bit) {
+							bit = 0x80;
+							dst++;
+						}
+					} else {
+						if (val)
+							*dst = val;
+						dst++;
+					}
+				}
+			}
+		}
+		dst = dstPtrNext;
 	}
 }
 
-void smush_decode_codec1(byte *dst, const byte *src, int left, int top, int width, int height, int pitch);
-
-static void smush_decode_codec21(byte *dst, const byte *src, int width, int height, int pitch) {
+void NutRenderer::codec21(bool bitmap, byte *dst, const byte *src, int width, int height, int pitch) {
 	while (height--) {
-		uint8 *dstPtrNext = dst + pitch;
-		const uint8 *srcPtrNext = src + 2 + READ_LE_UINT16(src); src += 2;
+		byte *dstPtrNext = dst + pitch;
+		const byte *srcPtrNext = src + 2 + READ_LE_UINT16(src);
+		src += 2;
 		int len = width;
+		byte bit = 0x80;
 		do {
+			int i;
 			int offs = READ_LE_UINT16(src); src += 2;
-			dst += offs;
+			if (bitmap) {
+				for (i = 0; i < offs; i++) {
+					bit >>= 1;
+					if (!bit) {
+						bit = 0x80;
+						dst++;
+					}
+				}
+			} else {
+				dst += offs;
+			}
 			len -= offs;
 			if (len <= 0) {
 				break;
@@ -63,18 +129,34 @@
 			//  src bytes equal to 255 are replaced by 0 in dst
 			//  src bytes equal to 1 are replaced by a color passed as an argument in the original function
 			//  other src bytes values are copied as-is
-			memcpy(dst, src, w); dst += w; src += w;
+			if (bitmap) {
+				for (i = 0; i < w; i++) {
+					if (src[i])
+						*dst |= bit;
+					bit >>= 1;
+					if (!bit) {
+						bit = 0x80;
+						dst++;
+					}
+				}
+			} else {
+				memcpy(dst, src, w);
+				dst += w;
+			}
+			src += w;
 		} while (len > 0);
 		dst = dstPtrNext;
 		src = srcPtrNext;
 	}
 }
 
-bool NutRenderer::loadFont(const char *filename) {
+bool NutRenderer::loadFont(const char *filename, bool bitmap) {
 	if (_loaded) {
 		debug(0, "NutRenderer::loadFont() Font already loaded, ok, loading...");
 	}
 
+	_bitmapFont = bitmap;
+
 	ScummFile file;
 	_vm->openFile(file, filename);
 	if (!file.isOpen()) {
@@ -89,7 +171,7 @@
 	}
 
 	uint32 length = file.readUint32BE();
-	byte *dataSrc = (byte *)malloc(length);
+	byte *dataSrc = new byte[length];
 	file.read(dataSrc, length);
 	file.close();
 
@@ -99,10 +181,37 @@
 		return false;
 	}
 
+	// We pre-decode the font, which may seem wasteful at first. Actually,
+	// the memory needed for just the decoded glyphs is smaller than the
+	// whole of the undecoded font file.
+
 	_numChars = READ_LE_UINT16(dataSrc + 10);
 	assert(_numChars <= ARRAYSIZE(_chars));
+
 	uint32 offset = 0;
+	uint32 decodedLength = 0;
 	for (int l = 0; l < _numChars; l++) {
+		offset += READ_BE_UINT32(dataSrc + offset + 4) + 16;
+		int width = READ_LE_UINT16(dataSrc + offset + 14);
+		int height = READ_LE_UINT16(dataSrc + offset + 16);
+		if (_bitmapFont) {
+			decodedLength += (((width + 7) / 8) * height);
+		} else {
+			decodedLength += (width * height);
+		}
+	}
+
+	// If characters have transparency, then bytes just get skipped and
+	// so there may appear some garbage. That's why we have to fill it
+	// with zeroes first.
+
+	_decodedData = new byte[decodedLength];
+	memset(_decodedData, 0, decodedLength);
+
+	byte *decodedPtr = _decodedData;
+
+	offset = 0;
+	for (int l = 0; l < _numChars; l++) {
 		offset += READ_BE_UINT32(dataSrc + offset + 4) + 8;
 		if (READ_BE_UINT32(dataSrc + offset) != 'FRME') {
 			error("NutRenderer::loadFont(%s) there is no FRME chunk %d (offset %x)", filename, l, offset);
@@ -114,32 +223,37 @@
 			break;
 		}
 		int codec = READ_LE_UINT16(dataSrc + offset + 8);
-		_chars[l].xoffs = READ_LE_UINT16(dataSrc + offset + 10);
-		_chars[l].yoffs = READ_LE_UINT16(dataSrc + offset + 12);
+		// _chars[l].xoffs = READ_LE_UINT16(dataSrc + offset + 10);
+		// _chars[l].yoffs = READ_LE_UINT16(dataSrc + offset + 12);
 		_chars[l].width = READ_LE_UINT16(dataSrc + offset + 14);
 		_chars[l].height = READ_LE_UINT16(dataSrc + offset + 16);
-		const int srcSize = _chars[l].width * _chars[l].height;
-		_chars[l].src = new byte[srcSize];
-		// If characters have transparency, then bytes just get skipped and
-		// so there may appear some garbage. That's why we have to fill it
-		// with zeroes first.
-		memset(_chars[l].src, 0, srcSize);
+		_chars[l].src = decodedPtr;
 
+		int pitch;
+
+		if (_bitmapFont) {
+			pitch = (_chars[l].width + 7) / 8;
+		} else {
+			pitch = _chars[l].width;
+		}
+
+		decodedPtr += (pitch * _chars[l].height);
+
 		const uint8 *fobjptr = dataSrc + offset + 22;
 		switch (codec) {
 		case 1:
-			smush_decode_codec1(_chars[l].src, fobjptr, 0, 0, _chars[l].width, _chars[l].height, _chars[l].width);
+			codec1(_bitmapFont, _chars[l].src, fobjptr, _chars[l].width, _chars[l].height, pitch);
 			break;
 		case 21:
 		case 44:
-			smush_decode_codec21(_chars[l].src, fobjptr, _chars[l].width, _chars[l].height, _chars[l].width);
+			codec21(_bitmapFont, _chars[l].src, fobjptr, _chars[l].width, _chars[l].height, pitch);
 			break;
 		default:
 			error("NutRenderer::loadFont: unknown codec: %d", codec);
 		}
 	}
 
-	free(dataSrc);
+	delete [] dataSrc;
 	_loaded = true;
 	return true;
 }
@@ -210,8 +324,10 @@
 }
 
 void NutRenderer::drawFrame(byte *dst, int c, int x, int y) {
-	const int width = MIN(_chars[c].width, _vm->_screenWidth - x);
-	const int height = MIN(_chars[c].height, _vm->_screenHeight - y);
+	assert(!_bitmapFont);
+
+	const int width = MIN((int)_chars[c].width, _vm->_screenWidth - x);
+	const int height = MIN((int)_chars[c].height, _vm->_screenHeight - y);
 	const byte *src = _chars[c].src;
 	const int srcPitch = _chars[c].width;
 	byte bits = 0;
@@ -243,11 +359,17 @@
 
 void NutRenderer::drawChar(const Graphics::Surface &s, byte c, int x, int y, byte color) {
 	byte *dst = (byte *)s.pixels + y * s.pitch + x;
-	const int width = MIN(_chars[c].width, s.w - x);
-	const int height = MIN(_chars[c].height, s.h - y);
+	const int width = MIN((int)_chars[c].width, s.w - x);
+	const int height = MIN((int)_chars[c].height, s.h - y);
 	const byte *src = _chars[c].src;
-	const int srcPitch = _chars[c].width;
+	int srcPitch;
 
+	if (_bitmapFont) {
+		srcPitch = (_chars[c].width + 7) / 8;
+	} else {
+		srcPitch = _chars[c].width;
+	}
+
 	const int minX = x < 0 ? -x : 0;
 	const int minY = y < 0 ? -y : 0;
 
@@ -261,9 +383,17 @@
 	}
 
 	for (int ty = minY; ty < height; ty++) {
-		for (int tx = minX; tx < width; tx++) {
-			if (src[tx] != 0) {
-				dst[tx] = color;
+		int tx;
+
+		for (tx = minX; tx < width; tx++) {
+			if (_bitmapFont) {
+				if (src[tx / 8] & (0x80 >> (tx % 8))) {
+					dst[tx] = color;
+				}
+			} else {
+				if (src[tx] != 0) {
+					dst[tx] = color;
+				}
 			}
 		}
 		src += srcPitch;

Modified: scummvm/trunk/engines/scumm/nut_renderer.h
===================================================================
--- scummvm/trunk/engines/scumm/nut_renderer.h	2007-01-21 16:57:13 UTC (rev 25154)
+++ scummvm/trunk/engines/scumm/nut_renderer.h	2007-01-21 17:14:53 UTC (rev 25155)
@@ -33,15 +33,18 @@
 protected:
 	ScummEngine *_vm;
 	bool _loaded;
+	bool _bitmapFont;
 	int _numChars;
+	byte *_decodedData;
 	struct {
-		int xoffs;
-		int yoffs;
-		int width;
-		int height;
+		uint16 width;
+		uint16 height;
 		byte *src;
 	} _chars[256];
 
+	static void codec1(bool bitmap, byte *dst, const byte *src, int width, int height, int pitch);
+	static void codec21(bool bitmap, byte *dst, const byte *src, int width, int height, int pitch);
+
 	void drawChar(const Graphics::Surface &s, byte c, int x, int y, byte color);
 	void draw2byte(const Graphics::Surface &s, int c, int x, int y, byte color);
 
@@ -50,7 +53,7 @@
 	virtual ~NutRenderer();
 	int getNumChars() const { return _numChars; }
 
-	bool loadFont(const char *filename);
+	bool loadFont(const char *filename, bool bitmap);
 
 	void drawFrame(byte *dst, int c, int x, int y);
 	void drawShadowChar(const Graphics::Surface &s, int c, int x, int y, byte color, bool showShadow);

Modified: scummvm/trunk/engines/scumm/smush/smush_player.cpp
===================================================================
--- scummvm/trunk/engines/scumm/smush/smush_player.cpp	2007-01-21 16:57:13 UTC (rev 25154)
+++ scummvm/trunk/engines/scumm/smush/smush_player.cpp	2007-01-21 17:14:53 UTC (rev 25155)
@@ -1042,17 +1042,17 @@
 			_sf[1] = new SmushFont(_vm, true, false);
 			_sf[2] = new SmushFont(_vm, true, false);
 			_sf[3] = new SmushFont(_vm, true, false);
-			_sf[0]->loadFont("scummfnt.nut");
-			_sf[1]->loadFont("techfnt.nut");
-			_sf[2]->loadFont("titlfnt.nut");
-			_sf[3]->loadFont("specfnt.nut");
+			_sf[0]->loadFont("scummfnt.nut", false);
+			_sf[1]->loadFont("techfnt.nut", false);
+			_sf[2]->loadFont("titlfnt.nut", false);
+			_sf[3]->loadFont("specfnt.nut", false);
 		}
 	} else if (_vm->_game.id == GID_DIG) {
 		if (!(_vm->_game.features & GF_DEMO)) {
 			for (i = 0; i < 4; i++) {
 				sprintf(file_font, "font%d.nut", i);
 				_sf[i] = new SmushFont(_vm, i != 0, false);
-				_sf[i]->loadFont(file_font);
+				_sf[i]->loadFont(file_font, false);
 			}
 		}
 	} else if (_vm->_game.id == GID_CMI) {
@@ -1061,7 +1061,7 @@
 				break;
 			sprintf(file_font, "font%d.nut", i);
 			_sf[i] = new SmushFont(_vm, false, true);
-			_sf[i]->loadFont(file_font);
+			_sf[i]->loadFont(file_font, false);
 		}
 	} else {
 		error("SmushPlayer::setupAnim() Unknown font setup for game");


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