Index: engines/scumm/smush/smush_font.cpp
===================================================================
--- engines/scumm/smush/smush_font.cpp	(revision 25268)
+++ engines/scumm/smush/smush_font.cpp	(working copy)
@@ -74,7 +74,7 @@
 		for (int j = 0; j < h; j++) {
 			for (int i = 0; i < w; i++) {
 				int8 value = *src++;
-				if (value)
+				if (value != kDefaultTransparentColor)
 					dst[i] = value;
 			}
 			dst += dst_width;
@@ -89,7 +89,7 @@
 						dst[i] = 0xFF;
 					} else if (value == -31) {
 						dst[i] = 0;
-					} else if (value) {
+					} else if (value != kSmush44TransparentColor) {
 						dst[i] = value;
 					}
 				}
@@ -101,7 +101,7 @@
 					int8 value = *src++;
 					if (value == 1) {
 						dst[i] = color;
-					} else if (value) {
+					} else if (value != kDefaultTransparentColor) {
 						dst[i] = 0;
 					}
 				}
Index: engines/scumm/charset.cpp
===================================================================
--- engines/scumm/charset.cpp	(revision 25268)
+++ engines/scumm/charset.cpp	(working copy)
@@ -1655,13 +1655,9 @@
 	if (chr == '@')
 		return;
 
-	shadow.left = _left - 1;
-	shadow.top = _top - 1;
+	shadow.left = _left;
+	shadow.top = _top;
 
-	// Note that the character is drawn with a shadow, so it is slightly
-	// larger than the advertised dimensions. See drawShadowChar() for
-	// details.
-
 	if (_firstChar) {
 		_str.left = (shadow.left >= 0) ? shadow.left : 0;
 		_str.top = (shadow.top >= 0) ? shadow.top : 0;
@@ -1676,8 +1672,8 @@
 	if (chr >= 256 && _vm->_useCJKMode)
 		width = _vm->_2byteWidth;
 
-	shadow.right = _left + width + 2;
-	shadow.bottom = _top + height + 2;
+	shadow.right = _left + width;
+	shadow.bottom = _top + height;
 
 	Graphics::Surface s;
 	if (!ignoreCharsetMask) {
@@ -1695,7 +1691,10 @@
 		drawTop -= _vm->_screenTop;
 	}
 
-	_current->drawShadowChar(s, chr, _left, drawTop, _color, _curId != 3);
+	if (chr >= 256 && _vm->_useCJKMode)
+		_current->draw2byte(s, chr, _left, drawTop, _color);
+	else
+		_current->drawChar(s, (byte)chr, _left, drawTop, _color);
 	_vm->markRectAsDirty(kMainVirtScreen, shadow);
 
 	if (_str.left > _left)
Index: engines/scumm/nut_renderer.cpp
===================================================================
--- engines/scumm/nut_renderer.cpp	(revision 25268)
+++ engines/scumm/nut_renderer.cpp	(working copy)
@@ -27,73 +27,22 @@
 
 namespace Scumm {
 
-NutRenderer::NutRenderer(ScummEngine *vm, const char *filename, bool bitmap) :
+NutRenderer::NutRenderer(ScummEngine *vm, const char *filename, bool compress) :
 	_vm(vm),
-	_bitmapFont(bitmap),
 	_numChars(0),
 	_decodedData(0) {
 	memset(_chars, 0, sizeof(_chars));
-	loadFont(filename);
+	loadFont(filename, compress);
 }
 
 NutRenderer::~NutRenderer() {
 	delete [] _decodedData;
 }
 
-void NutRenderer::codec1(byte *dst, const byte *src, int width, int height, int pitch) {
-	byte val, code;
-	int32 length;
-	int h = height, size_line;
+void smush_decode_codec1(byte *dst, const byte *src, int left, int top, int width, int height, int pitch);
 
-	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 (_bitmapFont) {
-					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 (_bitmapFont) {
-						if (val)
-							*dst |= bit;
-						bit >>= 1;
-						if (!bit) {
-							bit = 0x80;
-							dst++;
-						}
-					} else {
-						if (val)
-							*dst = val;
-						dst++;
-					}
-				}
-			}
-		}
-		dst = dstPtrNext;
-	}
+void NutRenderer::codec1(byte *dst, const byte *src, int width, int height, int pitch) {
+	smush_decode_codec1(dst, src, 0, 0, width, height, pitch);
 }
 
 void NutRenderer::codec21(byte *dst, const byte *src, int width, int height, int pitch) {
@@ -102,21 +51,9 @@
 		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;
-			if (_bitmapFont) {
-				for (i = 0; i < offs; i++) {
-					bit >>= 1;
-					if (!bit) {
-						bit = 0x80;
-						dst++;
-					}
-				}
-			} else {
-				dst += offs;
-			}
+			dst += offs;
 			len -= offs;
 			if (len <= 0) {
 				break;
@@ -130,20 +67,11 @@
 			//  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
-			if (_bitmapFont) {
-				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;
+			for (int i = 0; i < w; i++) {
+				_paletteMap[src[i]] = 1;
 			}
+			memcpy(dst, src, w);
+			dst += w;
 			src += w;
 		} while (len > 0);
 		dst = dstPtrNext;
@@ -151,7 +79,7 @@
 	}
 }
 
-void NutRenderer::loadFont(const char *filename) {
+void NutRenderer::loadFont(const char *filename, bool compress) {
 	ScummFile file;
 	_vm->openFile(file, filename);
 	if (!file.isOpen()) {
@@ -181,28 +109,27 @@
 
 	uint32 offset = 0;
 	uint32 decodedLength = 0;
-	for (int l = 0; l < _numChars; l++) {
+	int l;
+	
+	_paletteMap = new byte[256];
+	for (l = 0; l < 256; l++) {
+		_paletteMap[l] = 0;
+	}
+
+	for (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);
-		}
+		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.
+	debug(1, "NutRenderer::loadFont('%s') - decodedLength = %d", filename, decodedLength);
 
 	_decodedData = new byte[decodedLength];
-	memset(_decodedData, 0, decodedLength);
-
 	byte *decodedPtr = _decodedData;
 
 	offset = 0;
-	for (int l = 0; l < _numChars; l++) {
+	for (l = 0; l < _numChars; l++) {
 		offset += READ_BE_UINT32(dataSrc + offset + 4) + 8;
 		if (READ_BE_UINT32(dataSrc + offset) != MKID_BE('FRME')) {
 			error("NutRenderer::loadFont(%s) there is no FRME chunk %d (offset %x)", filename, l, offset);
@@ -220,31 +147,109 @@
 		_chars[l].height = READ_LE_UINT16(dataSrc + offset + 16);
 		_chars[l].src = decodedPtr;
 
-		int pitch;
+		decodedPtr += (_chars[l].width * _chars[l].height);
 
-		if (_bitmapFont) {
-			pitch = (_chars[l].width + 7) / 8;
+		// 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 a default color first.
+		if (codec == 44) {
+			memset(_chars[l].src, kSmush44TransparentColor, _chars[l].width * _chars[l].height);
+			_paletteMap[kSmush44TransparentColor] = 1;
+			_chars[l].transparency = kSmush44TransparentColor;
 		} else {
-			pitch = _chars[l].width;
+			memset(_chars[l].src, kDefaultTransparentColor, _chars[l].width * _chars[l].height);
+			_paletteMap[kDefaultTransparentColor] = 1;
+			_chars[l].transparency = kDefaultTransparentColor;
 		}
 
-		decodedPtr += (pitch * _chars[l].height);
-
 		const uint8 *fobjptr = dataSrc + offset + 22;
 		switch (codec) {
 		case 1:
-			codec1(_chars[l].src, fobjptr, _chars[l].width, _chars[l].height, pitch);
+			codec1(_chars[l].src, fobjptr, _chars[l].width, _chars[l].height, _chars[l].width);
 			break;
 		case 21:
 		case 44:
-			codec21(_chars[l].src, fobjptr, _chars[l].width, _chars[l].height, pitch);
+			codec21(_chars[l].src, fobjptr, _chars[l].width, _chars[l].height, _chars[l].width);
 			break;
 		default:
 			error("NutRenderer::loadFont: unknown codec: %d", codec);
 		}
 	}
 
+	if (compress) {
+		int numColors = 0;
+		for (l = 0; l < 256; l++) {
+			if (_paletteMap[l]) {
+				if (numColors < ARRAYSIZE(_palette)) {
+					_paletteMap[l] = numColors;
+					_palette[numColors] = l;
+				}
+				numColors++;
+			}
+		}
+
+		// Now _palette contains all the used colors, and _paletteMap
+		// maps the real color to the palette index.
+
+		if (numColors <= 2)
+			_bpp = 1;
+		else if (numColors <= 4)
+			_bpp = 2;
+		else if (numColors <= 16)
+			_bpp = 4;
+		else
+			_bpp = 8;
+
+		if (_bpp < 8) {
+			int compressedLength = 0;
+			for (l = 0; l < 256; l++) {
+				compressedLength += (((_bpp * _chars[l].width + 7) / 8) * _chars[l].height);
+			}
+
+			debug(1, "NutRenderer::loadFont('%s') - compressedLength = %d (%d bpp)", filename, compressedLength, _bpp);
+
+			byte *compressedData = new byte[compressedLength];
+			memset(compressedData, 0, compressedLength);
+
+			offset = 0;
+
+			for (l = 0; l < 256; l++) {
+				byte *src = _chars[l].src;
+				byte *dst = compressedData + offset;
+				int srcPitch = _chars[l].width;
+				int dstPitch = (_bpp * _chars[l].width + 7) / 8;
+
+				for (int h = 0; h < _chars[l].height; h++) {
+					byte bit = 0x80;
+					byte *nextDst = dst + dstPitch;
+					for (int w = 0; w < srcPitch; w++) {
+						byte color = _paletteMap[src[w]];
+						for (int i = 0; i < _bpp; i++) {
+							if (color & (1 << i))
+								*dst |= bit;
+							bit >>= 1;
+						}
+						if (!bit) {
+							bit = 0x80;
+							dst++;
+						}
+					}
+					src += srcPitch;
+					dst = nextDst;
+				}
+				_chars[l].src = compressedData + offset;
+				offset += (dstPitch * _chars[l].height);
+			}
+
+			delete [] _decodedData;
+			_decodedData = compressedData;
+		} else
+			_bpp = 8;
+			
+	}
+
 	delete [] dataSrc;
+	delete [] _paletteMap;
 }
 
 int NutRenderer::getCharWidth(byte c) const {
@@ -267,43 +272,7 @@
 	return _chars[c].height;
 }
 
-void NutRenderer::drawShadowChar(const Graphics::Surface &s, int c, int x, int y, byte color, bool showShadow) {
-
-	// We draw the character a total of 7 times: 6 times shifted and in black
-	// for the shadow, and once in the right color and position. This way we
-	// achieve the exact look as the original CMI had.
-	// However, this is not how the original engine handled it. Char glyphs
-	// were compressed with codec 44. In the decoding routine, transparent
-	// pixels are skipped. Other pixels are just filled with the decoded color
-	// which can be equal to 0 (==shadow), 1 (==char color) or another value
-	// (255, 224) which is just copied as-is in the destination buffer.
-
-	static const int offsetX[7] = { -1,  0, 1, 0, 1, 2, 0 };
-	static const int offsetY[7] = {  0, -1, 0, 1, 2, 1, 0 };
-	const int cTable[7] = { 0, 0, 0, 0, 0, 0, color };
-	int i = 0;
-
-	if (!showShadow)
-		i = 6;
-
-	for (; i < 7; i++) {
-		x += offsetX[i];
-		y += offsetY[i];
-		color = cTable[i];
-
-		if (c >= 256 && _vm->_useCJKMode)
-			draw2byte(s, c, x, y, color);
-		else
-			drawChar(s, (byte)c, x, y, color);
-
-		x -= offsetX[i];
-		y -= offsetY[i];
-	}
-}
-
 void NutRenderer::drawFrame(byte *dst, int c, int x, int 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;
@@ -340,14 +309,8 @@
 	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;
-	int srcPitch;
+	int srcPitch = (_bpp * _chars[c].width + 7) / 8;
 
-	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;
 
@@ -361,16 +324,45 @@
 	}
 
 	for (int ty = minY; ty < height; ty++) {
-		int tx;
+		for (int tx = minX; tx < width; tx++) {
+			byte val;
 
-		for (tx = minX; tx < width; tx++) {
-			if (_bitmapFont) {
-				if (src[tx / 8] & (0x80 >> (tx % 8))) {
-					dst[tx] = color;
+			if (_bpp < 8) {
+				int offset;
+				byte bit;
+
+				switch (_bpp) {
+				case 1:
+					offset = tx / 8;
+					bit = 0x80 >> (tx % 8);
+					break;
+				case 2:
+					offset = tx / 4;
+					bit = 0x80 >> (2 * (tx % 4));
+					break;
+				default:
+					offset = tx / 2;
+					bit = 0x80 >> (4 * (tx % 2));
+					break;
 				}
+
+				val = 0;
+
+				for (int i = 0; i < _bpp; i++) {
+					if (src[offset] & (bit >> i))
+						val |= (1 << i);
+				}
+
+				val = _palette[val];
 			} else {
-				if (src[tx] != 0) {
+				val = src[tx];
+			}
+
+			if (val != _chars[c].transparency) {
+				if (val == 1) {
 					dst[tx] = color;
+				} else {
+					dst[tx] = val;
 				}
 			}
 		}
Index: engines/scumm/nut_renderer.h
===================================================================
--- engines/scumm/nut_renderer.h	(revision 25268)
+++ engines/scumm/nut_renderer.h	(working copy)
@@ -31,31 +31,38 @@
 
 class NutRenderer {
 protected:
+
+	enum {
+		kDefaultTransparentColor = 0,
+		kSmush44TransparentColor = 2
+	};
+
 	ScummEngine *_vm;
-	bool _bitmapFont;
 	int _numChars;
 	byte *_decodedData;
+	byte *_paletteMap;
+	byte _bpp;
+	byte _palette[16];
 	struct {
 		uint16 width;
 		uint16 height;
 		byte *src;
+		byte transparency;
 	} _chars[256];
 
 	void codec1(byte *dst, const byte *src, int width, int height, int pitch);
 	void codec21(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);
+	void loadFont(const char *filename, bool compress);
 
-	void loadFont(const char *filename);
-
 public:
-	NutRenderer(ScummEngine *vm, const char *filename, bool bitmap);
+	NutRenderer(ScummEngine *vm, const char *filename, bool compress);
 	virtual ~NutRenderer();
 	int getNumChars() const { return _numChars; }
 
 	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);
+	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);
 
 	int getCharWidth(byte c) const;
 	int getCharHeight(byte c) const;
