 Index: base/gameDetector.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/base/gameDetector.cpp,v
retrieving revision 1.99
diff -u -r1.99 gameDetector.cpp
--- base/gameDetector.cpp	10 Jan 2005 22:05:34 -0000	1.99
+++ base/gameDetector.cpp	12 Feb 2005 14:15:29 -0000
@@ -96,6 +96,7 @@
 	"  --native-mt32            True Roland MT-32 (disable GM emulation)\n"
 	"  --output-rate=RATE       Select output sample rate in Hz (e.g. 22050)\n"
 	"  --aspect-ratio           Enable aspect ratio correction\n"
+	"  --render-mode=MODE       Enable additional render modes (cga, ega, herc)\n"
 	"\n"
 #if !defined(DISABLE_SKY) || !defined(DISABLE_QUEEN)
 	"  --alt-intro              Use alternative intro for CD versions of Beneath a\n"
@@ -122,6 +123,7 @@
 	ConfMan.registerDefault("fullscreen", false);
 	ConfMan.registerDefault("aspect_ratio", false);
 	ConfMan.registerDefault("gfx_mode", "normal");
+	ConfMan.registerDefault("render_mode", "default");
 
 	// Sound & Music
 	ConfMan.registerDefault("music_volume", 192);
@@ -478,6 +480,14 @@
 				ConfMan.set("aspect_ratio", cmdValue, kTransientDomain);
 			END_OPTION
 
+			DO_LONG_OPTION("render-mode")
+				int renderMode = Common::parseRenderMode(option);
+				if (renderMode == Common::kRenderDefault)
+					goto ShowHelpAndExit;
+
+				ConfMan.set("render_mode", option, kTransientDomain);
+			END_OPTION
+
 			DO_LONG_OPTION("savepath")
 				// TODO: Verify whether the path is valid
 				ConfMan.set("savepath", option, kTransientDomain);

Index: common/util.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/common/util.cpp,v
retrieving revision 1.47
diff -u -r1.47 util.cpp
--- common/util.cpp	1 Jan 2005 16:08:50 -0000	1.47
+++ common/util.cpp	12 Feb 2005 14:15:38 -0000
@@ -219,5 +219,47 @@
 }
 
 
+#pragma mark -
+
+
+const RenderModeDescription g_renderModes[] = {
+	{"herc", "Hercules", kRenderHerc},
+	{"cga", "CGA", kRenderCGA},
+	{"ega", "EGA", kRenderEGA},
+	{0, 0, kRenderDefault}
+};
+
+RenderMode parseRenderMode(const String &str) {
+	if (str.isEmpty())
+		return kRenderDefault;
+
+	const char *s = str.c_str();
+	const RenderModeDescription *l = g_renderModes;
+	for (; l->code; ++l) {
+		if (!scumm_stricmp(l->code, s))
+			return l->id;
+	}
+
+	return kRenderDefault;
+}
+
+const char *getRenderModeCode(RenderMode id) {
+	const RenderModeDescription *l = g_renderModes;
+	for (; l->code; ++l) {
+		if (l->id == id)
+			return l->code;
+	}
+	return 0;
+}
+
+const char *getRenderModeDescription(RenderMode id) {
+	const RenderModeDescription *l = g_renderModes;
+	for (; l->code; ++l) {
+		if (l->id == id)
+			return l->description;
+	}
+	return 0;
+}
+
 
 }	// End of namespace Common
Index: common/util.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/common/util.h,v
retrieving revision 1.46
diff -u -r1.46 util.h
--- common/util.h	1 Jan 2005 16:08:50 -0000	1.46
+++ common/util.h	12 Feb 2005 14:15:38 -0000
@@ -147,12 +147,37 @@
 
 extern const PlatformDescription g_platforms[];
 
-
 /** Convert a string containing a platform name into a Platform enum value. */
 extern Platform parsePlatform(const String &str);
 extern const char *getPlatformCode(Platform id);
 extern const char *getPlatformDescription(Platform id);
 
+/** 
+ * List of render modes. It specifies which original graphics mode
+ * to use. Some targets used postprocessing dithering routines for
+ * reducing color depth of final image which let it to be rendered on
+ * such low-level adapters as CGA or Hercules.
+ */
+enum RenderMode {
+	kRenderDefault = -1,
+	kRenderEGA = 0,
+	kRenderCGA = 1,
+	kRenderHerc = 2
+};
+
+struct RenderModeDescription {
+	const char *code;
+	const char *description;
+	Common::RenderMode id;
+};
+
+extern const RenderModeDescription g_renderModes[];
+
+/** Convert a string containing a render mode name into a RenderingMode enum value. */
+extern RenderMode parseRenderMode(const String &str);
+extern const char *getRenderModeCode(RenderMode id);
+extern const char *getRenderModeDescription(RenderMode id);
+
 }	// End of namespace Common
 
 
Index: gui/options.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/gui/options.cpp,v
retrieving revision 1.68
diff -u -r1.68 options.cpp
--- gui/options.cpp	27 Jan 2005 21:35:14 -0000	1.68
+++ gui/options.cpp	12 Feb 2005 14:15:38 -0000
@@ -75,7 +75,7 @@
 	: Dialog(x, y, w, h),
 	_domain(domain),
 	_enableGraphicSettings(false),
-	_gfxPopUp(0), _fullscreenCheckbox(0), _aspectCheckbox(0),
+	_gfxPopUp(0), _renderModePopUp(0), _fullscreenCheckbox(0), _aspectCheckbox(0),
 	_enableAudioSettings(false),
 	_multiMidiCheckbox(0), _mt32Checkbox(0), _subCheckbox(0),
 	_enableVolumeSettings(false),
@@ -108,6 +108,19 @@
 			}
 		}
 
+		_renderModePopUp->setSelected(0);
+
+		if (ConfMan.hasKey("render_mode", _domain)) {
+			const Common::RenderModeDescription *p = Common::g_renderModes;
+			const Common::RenderMode renderMode = Common::parseRenderMode(ConfMan.get("render_mode", _domain));
+			int sel = 0;
+			for (int i = 0; p->code; ++p, ++i) {
+				if (renderMode == p->id)
+					sel = i + 2;
+			}
+			_renderModePopUp->setSelected(sel);
+		}
+
 #ifndef _WIN32_WCE
 		// Fullscreen setting
 		_fullscreenCheckbox->setState(ConfMan.getBool("fullscreen", _domain));
@@ -167,10 +180,14 @@
 
 				if ((int32)_gfxPopUp->getSelectedTag() >= 0)
 					ConfMan.set("gfx_mode", _gfxPopUp->getSelectedString(), _domain);
+
+				if ((int32)_renderModePopUp->getSelectedTag() >= 0)
+					ConfMan.set("render_mode", _renderModePopUp->getSelectedString(), _domain);
 			} else {
 				ConfMan.removeKey("fullscreen", _domain);
 				ConfMan.removeKey("aspect_ratio", _domain);
 				ConfMan.removeKey("gfx_mode", _domain);
+				ConfMan.removeKey("render_mode", _domain);
 			}
 		}
 
@@ -240,6 +257,7 @@
 	_enableGraphicSettings = enabled;
 
 	_gfxPopUp->setEnabled(enabled);
+	_renderModePopUp->setEnabled(enabled);
 #ifndef _WIN32_WCE
 	_fullscreenCheckbox->setEnabled(enabled);
 	_aspectCheckbox->setEnabled(enabled);
@@ -282,6 +300,16 @@
 		gm++;
 	}
 
+	// RenderMode popup
+	_renderModePopUp = new PopUpWidget(boss, x-5, yoffset, w+5, kLineHeight, "Render mode: ", 100);
+	yoffset += 16;
+	_renderModePopUp->appendEntry("<default>");
+	_renderModePopUp->appendEntry("");
+	const Common::RenderModeDescription *rm = Common::g_renderModes;
+	for (; rm->code; ++rm) {
+		_renderModePopUp->appendEntry(rm->description, rm->id);
+	}
+
 	// Fullscreen checkbox
 	_fullscreenCheckbox = new CheckboxWidget(boss, x, yoffset, w, 16, "Fullscreen mode");
 	yoffset += 16;
Index: gui/options.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/gui/options.h,v
retrieving revision 1.24
diff -u -r1.24 options.h
--- gui/options.h	10 Jan 2005 20:53:16 -0000	1.24
+++ gui/options.h	12 Feb 2005 14:15:38 -0000
@@ -71,6 +71,7 @@
 	PopUpWidget *_gfxPopUp;
 	CheckboxWidget *_fullscreenCheckbox;
 	CheckboxWidget *_aspectCheckbox;
+	PopUpWidget *_renderModePopUp;
 
 	//
 	// Audio controls
Index: scumm/actor.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/actor.cpp,v
retrieving revision 1.319
diff -u -r1.319 actor.cpp
--- scumm/actor.cpp	1 Jan 2005 16:09:12 -0000	1.319
+++ scumm/actor.cpp	12 Feb 2005 14:15:50 -0000
@@ -1400,6 +1400,12 @@
 	} else if (_vm->_features & GF_OLD_BUNDLE) {
 		for (i = 0; i < 16; i++)
 			palette[i] = i;
+
+		// Make stuff more visible on CGA. Based on disassembly
+		if (_vm->_features & GF_16COLOR && _vm->_renderMode == Common::kRenderCGA) {
+			palette[6] = 5;
+			palette[7] = 15;
+		}
 	} else {
 		for (i = 0; i < 32; i++)
 			palette[i] = 0xFF;
Index: scumm/charset.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/charset.cpp,v
retrieving revision 2.124
diff -u -r2.124 charset.cpp
--- scumm/charset.cpp	1 Jan 2005 16:09:13 -0000	2.124
+++ scumm/charset.cpp	12 Feb 2005 14:15:50 -0000
@@ -1269,7 +1269,22 @@
 	if (chr == '@')
 		return;
 
+	// Based on disassembly
 	_vm->_charsetColorMap[1] = _color;
+	if (_vm->_features & GF_16COLOR && _vm->_renderMode == Common::kRenderCGA) {
+		static byte CGAtextColorMap[16] = {0,  3, 3, 3, 5, 5, 5,  15, 
+										   15, 3, 3, 3, 5, 5, 15, 15};
+		_color = CGAtextColorMap[_color & 0x0f];
+		is2byte = 0;
+	}
+
+	if (_vm->_features & GF_16COLOR && _vm->_renderMode == Common::kRenderHerc) {
+		static byte HercTextColorMap[16] = {0, 15,  2, 15, 15,  5, 15,  15, 
+										   8, 15, 15, 15, 15, 15, 15, 15};
+		_color = HercTextColorMap[_color & 0x0f];
+		is2byte = 0;
+	}
+
 
 	int type = *_fontPtr;
 	if (is2byte) {
Index: scumm/gfx.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/gfx.cpp,v
retrieving revision 2.387
diff -u -r2.387 gfx.cpp
--- scumm/gfx.cpp	2 Feb 2005 00:30:50 -0000	2.387
+++ scumm/gfx.cpp	12 Feb 2005 14:15:57 -0000
@@ -508,11 +508,47 @@
 		dst += _vm->_screenWidth;
 		text += _textSurface.pitch;
 	}
-	
+
+	if (_vm->_features & GF_16COLOR && _vm->_renderMode == Common::kRenderCGA)
+		ditherCGA(_compositeBuf + x + y * _vm->_screenWidth, _vm->_screenWidth, x, y, width, height);
+
 	// Finally blit the whole thing to the screen
 	_vm->_system->copyRectToScreen(_compositeBuf + x + y * _vm->_screenWidth, _vm->_screenWidth, x, y, width, height);
 }
 
+// CGA
+// indy3 loom maniac monkey1 zak
+//
+// Herc
+// maniac monkey1 zak
+//
+// EGA
+// monkey2 loom maniac monkey1 atlantis indy3 zak loomcd
+
+// CGA dithers 4x4 square with direct substitutes
+// Odd lines have colors swapped, so there will be checkered patterns.
+// But apparently there is a mistake for 10th color.
+void Gdi::ditherCGA(byte *dst, int dstPitch, int x, int y, int width, int height) const {
+	byte *ptr;
+	int idx1, idx2;
+	static byte cgaDither[2][2][16] = {
+		{{0, 1, 0, 1, 2, 2, 0, 0, 3, 1, 3, 1, 3, 2, 1, 3},
+		 {0, 0, 1, 1, 0, 2, 2, 3, 0, 3, 1, 1, 3, 3, 1, 3}},
+		{{0, 0, 1, 1, 0, 2, 2, 3, 0, 3, 1, 1, 3, 3, 1, 3},
+		 {0, 1, 0, 1, 2, 2, 0, 0, 3, 1, 1, 1, 3, 2, 1, 3}}};
+
+	for (int y1 = 0; y1 <  height; y1++) {
+		ptr = dst + y1 * dstPitch;
+
+		idx1 = (y + y1) % 2;
+		for (int x1 = 0; x1 < width; x1++) {
+			idx2 = (x + x1) % 2;
+			*ptr++ = cgaDither[idx1][idx2][*ptr & 0xF];
+		}
+	}
+}
+
+
 #pragma mark -
 #pragma mark --- Background buffers & charset mask ---
 #pragma mark -
Index: scumm/gfx.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/gfx.h,v
retrieving revision 1.99
diff -u -r1.99 gfx.h
--- scumm/gfx.h	11 Jan 2005 13:25:01 -0000	1.99
+++ scumm/gfx.h	12 Feb 2005 14:16:03 -0000
@@ -256,7 +256,8 @@
 	/* Misc */
 	void drawStripToScreen(VirtScreen *vs, int x, int w, int t, int b);
 	void updateDirtyScreen(VirtScreen *vs);
-	
+	void ditherCGA(byte *dst, int dstPitch, int x, int y, int width, int height) const;
+
 	byte *getMaskBuffer(int x, int y, int z);
 	
 	int getZPlanes(const byte *smap_ptr, const byte *zplane_list[9], bool bmapImage) const;
Index: scumm/palette.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/palette.cpp,v
retrieving revision 2.22
diff -u -r2.22 palette.cpp
--- scumm/palette.cpp	1 Jan 2005 16:09:14 -0000	2.22
+++ scumm/palette.cpp	12 Feb 2005 14:16:03 -0000
@@ -48,6 +48,18 @@
 	setPalColor(15, 255, 255, 255);
 }
 
+void ScummEngine::setupCGAPalette() {
+	setPalColor( 0,   0,   0,   0);
+	setPalColor( 1,   0, 168, 168);
+	setPalColor( 2, 168,   0, 168);
+	setPalColor( 3, 168, 168, 168);
+
+	// Setup cursor palette
+	setPalColor( 7, 170, 170, 170);
+	setPalColor( 8,  85,  85,  85);
+	setPalColor(15, 255, 255, 255);
+}
+
 void ScummEngine::setupEGAPalette() {
 	setPalColor( 0,   0,   0,   0);
 	setPalColor( 1,   0,   0, 170);
Index: scumm/scumm.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/scumm.cpp,v
retrieving revision 1.322
diff -u -r1.322 scumm.cpp
--- scumm/scumm.cpp	11 Feb 2005 13:29:15 -0000	1.322
+++ scumm/scumm.cpp	12 Feb 2005 14:16:14 -0000
@@ -981,6 +981,10 @@
 	}
 	_confirmExit = ConfMan.getBool("confirm_exit");
 
+	if (ConfMan.hasKey("render_mode")) {
+		_renderMode = Common::parseRenderMode(ConfMan.get("render_mode").c_str());
+	}
+
 	_hexdumpScripts = false;
 	_showStack = false;
 
@@ -1252,6 +1256,8 @@
 			_shadowPalette[i] = i;
 		if ((_features & GF_AMIGA) || (_features & GF_ATARI_ST))
 			setupAmigaPalette();
+		else if (_renderMode == Common::kRenderCGA)
+			setupCGAPalette();
 		else
 			setupEGAPalette();
 	}
Index: scumm/scumm.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/scumm.h,v
retrieving revision 1.531
diff -u -r1.531 scumm.h
--- scumm/scumm.h	11 Feb 2005 03:45:10 -0000	1.531
+++ scumm/scumm.h	12 Feb 2005 14:16:14 -0000
@@ -870,6 +870,8 @@
 	int _screenStartStrip, _screenEndStrip;
 	int _screenTop;
 
+	Common::RenderMode _renderMode;
+
 protected:
 	ColorCycle _colorCycle[16];	// Palette cycles
 
@@ -932,6 +934,7 @@
 
 	const byte *getPalettePtr(int palindex, int room);
 	void setupAmigaPalette();
+	void setupCGAPalette();
 	void setupEGAPalette();
 	void setupV1ManiacPalette();
 	void setupV1ZakPalette();
Index: scumm/vars.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/scumm/vars.cpp,v
retrieving revision 1.113
diff -u -r1.113 vars.cpp
--- scumm/vars.cpp	1 Jan 2005 16:09:16 -0000	1.113
+++ scumm/vars.cpp	12 Feb 2005 14:16:19 -0000
@@ -553,6 +553,8 @@
 			VAR(VAR_VIDEOMODE) = 50;
 		else if (_gameId == GID_MONKEY2 && (_features & GF_AMIGA))
 			VAR(VAR_VIDEOMODE) = 82;
+		else if (_features & GF_16COLOR && _renderMode == Common::kRenderCGA)
+			VAR(VAR_VIDEOMODE) = 4;
 		else
 			VAR(VAR_VIDEOMODE) = 19;
 		if (_gameId == GID_LOOM && _features & GF_OLD_BUNDLE) {
