[Scummvm-cvs-logs] SF.net SVN: scummvm: [32257] scummvm/trunk/engines/cine

sev at users.sourceforge.net sev at users.sourceforge.net
Sun May 25 00:11:41 CEST 2008


Revision: 32257
          http://scummvm.svn.sourceforge.net/scummvm/?rev=32257&view=rev
Author:   sev
Date:     2008-05-24 15:11:41 -0700 (Sat, 24 May 2008)

Log Message:
-----------
Patch #1969189: "CinE renderer rewrite"

Modified Paths:
--------------
    scummvm/trunk/engines/cine/anim.cpp
    scummvm/trunk/engines/cine/bg.cpp
    scummvm/trunk/engines/cine/bg.h
    scummvm/trunk/engines/cine/bg_list.cpp
    scummvm/trunk/engines/cine/bg_list.h
    scummvm/trunk/engines/cine/cine.cpp
    scummvm/trunk/engines/cine/gfx.cpp
    scummvm/trunk/engines/cine/gfx.h
    scummvm/trunk/engines/cine/main_loop.cpp
    scummvm/trunk/engines/cine/object.cpp
    scummvm/trunk/engines/cine/pal.cpp
    scummvm/trunk/engines/cine/pal.h
    scummvm/trunk/engines/cine/prc.cpp
    scummvm/trunk/engines/cine/rel.cpp
    scummvm/trunk/engines/cine/script.h
    scummvm/trunk/engines/cine/script_fw.cpp
    scummvm/trunk/engines/cine/script_os.cpp
    scummvm/trunk/engines/cine/texte.cpp
    scummvm/trunk/engines/cine/texte.h
    scummvm/trunk/engines/cine/various.cpp
    scummvm/trunk/engines/cine/various.h
    scummvm/trunk/engines/cine/xref.txt

Modified: scummvm/trunk/engines/cine/anim.cpp
===================================================================
--- scummvm/trunk/engines/cine/anim.cpp	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/anim.cpp	2008-05-24 22:11:41 UTC (rev 32257)
@@ -53,6 +53,7 @@
 
 static const AnimDataEntry transparencyData[] = {
 	{"ALPHA", 0xF},
+	{"TITRE", 0xF},
 	{"TITRE2", 0xF},
 	{"ET", 0xC},
 	{"L311", 0x3},

Modified: scummvm/trunk/engines/cine/bg.cpp
===================================================================
--- scummvm/trunk/engines/cine/bg.cpp	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/bg.cpp	2008-05-24 22:11:41 UTC (rev 32257)
@@ -37,7 +37,7 @@
 byte *additionalBgTable[9];
 byte currentAdditionalBgIdx = 0, currentAdditionalBgIdx2 = 0;
 
-byte loadCt(const char *ctName) {
+byte loadCtFW(const char *ctName) {
 	uint16 header[32];
 	byte *ptr, *dataPtr;
 
@@ -46,79 +46,62 @@
 
 	ptr = dataPtr = readBundleFile(findFileInBundle(ctName));
 
-	if (g_cine->getGameType() == Cine::GType_OS) {
-		uint16 bpp = READ_BE_UINT16(ptr); ptr += 2;
-		if (bpp == 8) {
-			ctColorMode = 1;
-			memcpy(newPalette, ptr, 256 * 3);
-			ptr += 3 * 256;
-			memcpy(page3Raw, ptr, 320 * 200);
-		} else {
-			ctColorMode = 0;
-			for (int i = 0; i < 16; i++) {
-				tempPalette[i] = READ_BE_UINT16(ptr);
-				ptr += 2;
-			}
+	loadRelatedPalette(ctName);
 
-			gfxResetRawPage(page3Raw);
-			gfxConvertSpriteToRaw(page3Raw, ptr, 160, 200);
-		}
-	} else {
-		loadRelatedPalette(ctName);
+	assert(strstr(ctName, ".NEO"));
 
-		assert(strstr(ctName, ".NEO"));
+	Common::MemoryReadStream readS(ptr, 32);
 
-		Common::MemoryReadStream readS(ptr, 32);
-
-		for (int i = 0; i < 16; i++) {
-			header[i] = readS.readUint16BE();
-		}
-
-		gfxConvertSpriteToRaw(page3Raw, ptr + 0x80, 160, 200);
+	for (int i = 0; i < 16; i++) {
+		header[i] = readS.readUint16BE();
 	}
 
+	gfxConvertSpriteToRaw(page3Raw, ptr + 0x80, 160, 200);
+
 	free(dataPtr);
 	return 0;
 }
 
-void loadBgHigh(const char *currentPtr) {
-	memcpy(newPalette, currentPtr, 256 * 3);
-	currentPtr += 256 * 3;
+byte loadCtOS(const char *ctName) {
+	byte *ptr, *dataPtr;
 
-	memcpy(page2Raw, currentPtr, 320 * 200);
+	if (currentCtName != ctName)
+		strcpy(currentCtName, ctName);
 
-	newColorMode = 2;
-	bgColorMode = 1;
+	ptr = dataPtr = readBundleFile(findFileInBundle(ctName));
 
+	uint16 bpp = READ_BE_UINT16(ptr);
+	ptr += 2;
+
+	if (bpp == 8) {
+		memcpy(page3Raw, ptr + 256 * 3, 320 * 200);
+		renderer->loadCt256(ptr, ctName);
+	} else {
+		gfxConvertSpriteToRaw(page3Raw, ptr + 32, 160, 200);
+		renderer->loadCt16(ptr, ctName);
+	}
+
+	free(dataPtr);
+	return 0;
 }
 
 byte loadBg(const char *bgName) {
 	byte *ptr, *dataPtr;
 
-	if (currentBgName[0] != bgName)
-		strcpy(currentBgName[0], bgName);
-
 	byte fileIdx = findFileInBundle(bgName);
 	ptr = dataPtr = readBundleFile(fileIdx);
 
-	uint16 bpp = READ_BE_UINT16(ptr); ptr += 2;
+	uint16 bpp = READ_BE_UINT16(ptr);
+	ptr += 2;
+
 	if (bpp == 8) {
-		loadBgHigh((const char *)ptr);
+		renderer->loadBg256(ptr, bgName);
 	} else {
-		newColorMode = 1;
-		bgColorMode = 0;
-
-		for (int i = 0; i < 16; i++) {
-			tempPalette[i] = READ_BE_UINT16(ptr);
-			ptr += 2;
-		}
-
 		if (g_cine->getGameType() == Cine::GType_FW) {
 			loadRelatedPalette(bgName);
 		}
 
-		gfxResetRawPage(page2Raw);
-		gfxConvertSpriteToRaw(page2Raw, ptr, 160, 200);
+		renderer->loadBg16(ptr, bgName);
 	}
 	free(dataPtr);
 	return 0;
@@ -127,28 +110,15 @@
 void addBackground(const char *bgName, uint16 bgIdx) {
 	byte *ptr, *dataPtr;
 
-	strcpy(currentBgName[bgIdx], bgName);
-
 	byte fileIdx = findFileInBundle(bgName);
 	ptr = dataPtr = readBundleFile(fileIdx);
 
-	additionalBgTable[bgIdx] = (byte *) malloc(320 * 200);
-
 	uint16 bpp = READ_BE_UINT16(ptr); ptr += 2;
 
 	if (bpp == 8) {
-		bgColorMode = 1;
-		memcpy(newPalette, ptr, 256 * 3);
-		ptr += 3 * 256;
-		memcpy(additionalBgTable[bgIdx], ptr, 320 * 200);
+		renderer->loadBg256(ptr, bgName, bgIdx);
 	} else {
-		bgColorMode = 0;
-		for (int i = 0; i < 16; i++) {
-			tempPalette[i] = READ_BE_UINT16(ptr);
-			ptr += 2;
-		}
-
-		gfxConvertSpriteToRaw(additionalBgTable[bgIdx], ptr, 160, 200);
+		renderer->loadBg16(ptr, bgName, bgIdx);
 	}
 	free(dataPtr);
 }

Modified: scummvm/trunk/engines/cine/bg.h
===================================================================
--- scummvm/trunk/engines/cine/bg.h	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/bg.h	2008-05-24 22:11:41 UTC (rev 32257)
@@ -27,21 +27,10 @@
 #define CINE_BG_H
 
 namespace Cine {
-struct bgData {
-	byte *data;
-	byte colorMode;
-	byte *highPalette;
-	uint16 *lowPalette;
-};
-
 byte loadBg(const char *bgName);
-byte loadCt(const char *bgName);
+byte loadCtFW(const char *bgName);
+byte loadCtOS(const char *bgName);
 
-//extern bgData additionalBgTable[9];
-extern byte *additionalBgTable[9];
-extern byte currentAdditionalBgIdx;
-extern byte currentAdditionalBgIdx2;
-
 void addBackground(const char *bgName, uint16 bgIdx);
 
 extern uint16 bgVar0;

Modified: scummvm/trunk/engines/cine/bg_list.cpp
===================================================================
--- scummvm/trunk/engines/cine/bg_list.cpp	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/bg_list.cpp	2008-05-24 22:11:41 UTC (rev 32257)
@@ -40,62 +40,20 @@
 
 /*! \brief Add masked sprite to the background
  * \param objIdx Sprite description
- * \param addList Add sprite to incrust list if true
- * \todo Fix incrust objects on CT background. Always drawing incrust elements
- * on CT background breaks game zones
  */
-void addToBGList(int16 objIdx, bool addList) {
-	int16 x = objectTable[objIdx].x;
-	int16 y = objectTable[objIdx].y;
-	int16 width = animDataTable[objectTable[objIdx].frame]._var1;
-	int16 height = animDataTable[objectTable[objIdx].frame]._height;
-	const byte *data = animDataTable[objectTable[objIdx].frame].data();
-	const byte *mask = animDataTable[objectTable[objIdx].frame].mask();
-//	int16 part = objectTable[objIdx].part;
+void addToBGList(int16 objIdx) {
+	renderer->incrustSprite(objectTable[objIdx]);
 
-	// Operation Stealth may switch among multiple backgrounds
-	if (g_cine->getGameType() == GType_OS) {
-		for (int i = 0; i < 8; i++) {
-			if (additionalBgTable[i]) {
-				drawSpriteRaw2(data, objectTable[objIdx].part, width, height, additionalBgTable[i], x, y);
-			}
-		}
-	} else {
-		drawSpriteRaw(data, mask, width, height, page2Raw, x, y);
-	}
-
-	if (addList)
-		createBgIncrustListElement(objIdx, 0);
+	createBgIncrustListElement(objIdx, 0);
 }
 
 /*! \brief Add filled sprite to the background
  * \param objIdx Sprite description
- * \param addList Add sprite to incrust list if true
- * \todo Fix incrust objects on CT background. Always drawing incrust elements
- * on CT background breaks game zones
  */
-void addSpriteFilledToBGList(int16 objIdx, bool addList) {
-	int16 x = objectTable[objIdx].x;
-	int16 y = objectTable[objIdx].y;
-	int16 width = animDataTable[objectTable[objIdx].frame]._realWidth;
-	int16 height = animDataTable[objectTable[objIdx].frame]._height;
-	const byte *data = animDataTable[objectTable[objIdx].frame].data();
+void addSpriteFilledToBGList(int16 objIdx) {
+	renderer->incrustMask(objectTable[objIdx]);
 
-	if (data) {
-		// Operation Stealth may switch among multiple backgrounds
-		if (g_cine->getGameType() == GType_OS) {
-			for (int i = 0; i < 8; i++) {
-				if (additionalBgTable[i]) {
-					gfxFillSprite(data, width, height, additionalBgTable[i], x, y);
-				}
-			}
-		} else {
-			gfxFillSprite(data, width, height, page2Raw, x, y);
-		}
-	}
-
-	if (addList)
-		createBgIncrustListElement(objIdx, 1);
+	createBgIncrustListElement(objIdx, 1);
 }
 
 /*! \brief Add new element to incrust list
@@ -115,7 +73,7 @@
 	bgIncrustList.push_back(tmp);
 }
 
-/*! \brief Reset var8 (probably something related to bgIncrustList
+/*! \brief Reset var8 (probably something related to bgIncrustList)
  */
 void resetBgIncrustList(void) {
 	var8 = 0;
@@ -142,9 +100,9 @@
 		bgIncrustList.push_back(tmp);
 
 		if (tmp.param == 0) {
-			addToBGList(tmp.objIdx, false);
+			renderer->incrustSprite(objectTable[tmp.objIdx]);
 		} else {
-			addSpriteFilledToBGList(tmp.objIdx, false);
+			renderer->incrustMask(objectTable[tmp.objIdx]);
 		}
 	}
 }

Modified: scummvm/trunk/engines/cine/bg_list.h
===================================================================
--- scummvm/trunk/engines/cine/bg_list.h	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/bg_list.h	2008-05-24 22:11:41 UTC (rev 32257)
@@ -46,8 +46,8 @@
 extern Common::List<BGIncrust> bgIncrustList;
 extern uint32 var8;
 
-void addToBGList(int16 objIdx, bool addList = true);
-void addSpriteFilledToBGList(int16 idx, bool addList = true);
+void addToBGList(int16 objIdx);
+void addSpriteFilledToBGList(int16 idx);
 
 void createBgIncrustListElement(int16 objIdx, int16 param);
 void resetBgIncrustList(void);

Modified: scummvm/trunk/engines/cine/cine.cpp
===================================================================
--- scummvm/trunk/engines/cine/cine.cpp	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/cine.cpp	2008-05-24 22:11:41 UTC (rev 32257)
@@ -95,7 +95,9 @@
 int CineEngine::go() {
 	CursorMan.showMouse(true);
 	mainLoop(1);
-	gfxDestroy();
+
+	delete renderer;
+	delete[] page3Raw;
 	delete g_sound;
 	return 0;
 }
@@ -105,8 +107,14 @@
 	setupOpcodes();
 
 	initLanguage(g_cine->getLanguage());
-	gfxInit();
 
+	if (g_cine->getGameType() == Cine::GType_OS) {
+		renderer = new OSRenderer;
+	} else {
+		renderer = new FWRenderer;
+	}
+
+	page3Raw = new byte[320 * 200];
 	textDataPtr = (byte *)malloc(8000);
 
 	partBuffer = (PartBuffer *)malloc(NUM_MAX_PARTDATA * sizeof(PartBuffer));

Modified: scummvm/trunk/engines/cine/gfx.cpp
===================================================================
--- scummvm/trunk/engines/cine/gfx.cpp	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/gfx.cpp	2008-05-24 22:11:41 UTC (rev 32257)
@@ -27,6 +27,7 @@
 #include "cine/bg.h"
 #include "cine/bg_list.h"
 #include "cine/various.h"
+#include "cine/pal.h"
 
 #include "common/endian.h"
 #include "common/system.h"
@@ -35,18 +36,8 @@
 
 namespace Cine {
 
-uint16 c_palette[256];
-byte colorMode256 = 0;
-byte palette256[256 * 3];
-byte newPalette[256 * 3];
-byte newColorMode = 0;
-byte ctColorMode = 0;
-byte bgColorMode = 0;
-
-byte *screenBuffer;
-byte *page1Raw;
-byte *page2Raw;
 byte *page3Raw;
+FWRenderer *renderer = NULL;
 
 static const byte mouseCursorNormal[] = {
 	0x00, 0x00, 0x40, 0x00, 0x60, 0x00, 0x70, 0x00,
@@ -96,30 +87,1191 @@
 	0xff, 0xff, 0xff, 0xff
 };
 
-void gfxInit() {
-	screenBuffer = (byte *)malloc(320 * 200);
-	page1Raw = (byte *)malloc(320 * 200);
-	page2Raw = (byte *)malloc(320 * 200);
-	page3Raw = (byte *)malloc(320 * 200);
-	if (!screenBuffer || !page1Raw || !page2Raw || !page3Raw) {
-		error("Unable to allocate offscreen buffers");
+/*! \brief Initialize renderer
+ */
+FWRenderer::FWRenderer() : _background(NULL), _palette(NULL), _cmd(""),
+	_cmdY(0), _messageBg(0), _backBuffer(new byte[_screenSize]),
+	_activeLowPal(NULL), _changePal(0) {
+
+	assert(_backBuffer);
+
+	memset(_backBuffer, 0, _screenSize);
+	memset(_bgName, 0, sizeof (_bgName));
+}
+
+/* \brief Destroy renderer
+ */
+FWRenderer::~FWRenderer() {
+	delete[] _background;
+	delete[] _palette;
+	delete[] _backBuffer;
+	delete[] _activeLowPal;
+}
+
+/* \brief Reset renderer state
+ */
+void FWRenderer::clear() {
+	delete[] _background;
+	delete[] _palette;
+	delete[] _activeLowPal;
+
+	_background = NULL;
+	_palette = NULL;
+	_activeLowPal = NULL;
+
+	memset(_backBuffer, 0, _screenSize);
+
+	_cmd = "";
+	_cmdY = 0;
+	_messageBg = 0;
+	_changePal = 0;
+}
+
+/*! \brief Draw 1bpp sprite using selected color
+ * \param obj Object info
+ * \param fillColor Sprite color
+ */
+void FWRenderer::fillSprite(const objectStruct &obj, uint8 color) {
+	const byte *data = animDataTable[obj.frame].data();
+	int x, y, width, height;
+
+	x = obj.x;
+	y = obj.y;
+	width = animDataTable[obj.frame]._realWidth;
+	height = animDataTable[obj.frame]._height;
+
+	gfxFillSprite(data, width, height, _backBuffer, x, y, color);
+}
+
+/*! \brief Draw 1bpp sprite using selected color on background
+ * \param obj Object info
+ * \param fillColor Sprite color
+ */
+void FWRenderer::incrustMask(const objectStruct &obj, uint8 color) {
+	const byte *data = animDataTable[obj.frame].data();
+	int x, y, width, height;
+
+	x = obj.x;
+	y = obj.y;
+	width = animDataTable[obj.frame]._realWidth;
+	height = animDataTable[obj.frame]._height;
+
+	gfxFillSprite(data, width, height, _background, x, y, color);
+}
+
+/*! \brief Draw color sprite using with external mask
+ * \param obj Object info
+ * \param mask External mask
+ */
+void FWRenderer::drawMaskedSprite(const objectStruct &obj, const byte *mask) {
+	const byte *data = animDataTable[obj.frame].data();
+	int x, y, width, height;
+
+	x = obj.x;
+	y = obj.y;
+	width = animDataTable[obj.frame]._realWidth;
+	height = animDataTable[obj.frame]._height;
+
+	assert(mask);
+
+	drawSpriteRaw(data, mask, width, height, _backBuffer, x, y);
+}
+
+/*! \brief Draw color sprite
+ * \param obj Object info
+ */
+void FWRenderer::drawSprite(const objectStruct &obj) {
+	const byte *mask = animDataTable[obj.frame].mask();
+	drawMaskedSprite(obj, mask);
+}
+
+/*! \brief Draw color sprite on background
+ * \param obj Object info
+ */
+void FWRenderer::incrustSprite(const objectStruct &obj) {
+	const byte *data = animDataTable[obj.frame].data();
+	const byte *mask = animDataTable[obj.frame].mask();
+	int x, y, width, height;
+
+	x = obj.x;
+	y = obj.y;
+	width = animDataTable[obj.frame]._realWidth;
+	height = animDataTable[obj.frame]._height;
+
+	assert(mask);
+
+	drawSpriteRaw(data, mask, width, height, _background, x, y);
+}
+
+/*! \brief Draw command box on screen
+ */
+void FWRenderer::drawCommand() {
+	unsigned int i;
+	int x = 10, y = _cmdY;
+
+	drawPlainBox(x, y, 301, 11, 0);
+	drawBorder(x - 1, y - 1, 302, 12, 2);
+
+	x += 2;
+	y += 2;
+
+	for (i = 0; i < _cmd.size(); i++) {
+		x = drawChar(_cmd[i], x, y);
 	}
-	memset(page1Raw, 0, 320 * 200);
-	memset(page2Raw, 0, 320 * 200);
-	memset(page3Raw, 0, 320 * 200);
+}
 
-	memset(additionalBgTable, 0, sizeof(additionalBgTable));
-	additionalBgTable[0] = page2Raw;
-	additionalBgTable[8] = page3Raw;
+/*! \brief Draw message in a box
+ * \param str Message to draw
+ * \param x Top left message box corner coordinate
+ * \param y Top left message box corner coordinate
+ * \param width Message box width
+ * \param color Message box background color
+ */
+void FWRenderer::drawMessage(const char *str, int x, int y, int width, byte color) {
+	int i, tx, ty, tw;
+	int line = 0, words = 0, cw = 0;
+	int space = 0, extraSpace = 0;
+
+	drawPlainBox(x, y, width, 4, color);
+	tx = x + 4;
+	ty = str[0] ? y - 5 : y + 4;
+	tw = width - 8;
+
+	for (i = 0; str[i]; i++, line--) {
+		// Fit line of text into textbox
+		if (!line) {
+			while (str[i] == ' ') i++;
+			line = fitLine(str + i, tw, words, cw);
+
+			if ( str[i + line] != '\0' && str[i + line] != 0x7C && words) {
+				space = (tw - cw) / words;
+				extraSpace = (tw - cw) % words;
+			} else {
+				space = 5;
+				extraSpace = 0;
+			}
+
+			ty += 9;
+			drawPlainBox(x, ty, width, 9, color);
+			tx = x + 4;
+		}
+
+		// draw characters
+		if (str[i] == ' ') {
+			tx += space + extraSpace;
+
+			if (extraSpace) {
+				extraSpace = 0;
+			}
+		} else {
+			tx = drawChar(str[i], tx, ty);
+		}
+	}
+
+	ty += 9;
+	drawPlainBox(x, ty, width, 4, color);
+	drawDoubleBorder(x, y, width, ty - y + 4, 2);
 }
 
-void gfxDestroy() {
-	free(screenBuffer);
-	free(page1Raw);
-	free(page2Raw);
-	free(page3Raw);
+/*! \brief Draw rectangle on screen
+ * \param x Top left corner coordinate
+ * \param y Top left corner coordinate
+ * \param width Rectangle width
+ * \param height Rectangle height
+ * \param color Fill color
+ */
+void FWRenderer::drawPlainBox(int x, int y, int width, int height, byte color) {
+	int i;
+	byte *dest = _backBuffer + y * 320 + x;
+
+	if (width < 0) {
+		x += width;
+		width = -width;
+	}
+
+	if (height < 0) {
+		y += height;
+		height = -height;
+	}
+
+	for (i = 0; i < height; i++) {
+		memset(dest + i * 320, color, width);
+	}
 }
 
+/*! \brief Draw empty rectangle
+ * \param x Top left corner coordinate
+ * \param y Top left corner coordinate
+ * \param width Rectangle width
+ * \param height Rectangle height
+ * \param color Line color
+ */
+void FWRenderer::drawBorder(int x, int y, int width, int height, byte color) {
+	drawLine(x, y, width, 1, color);
+	drawLine(x, y + height, width, 1, color);
+	drawLine(x, y, 1, height, color);
+	drawLine(x + width, y, 1, height + 1, color);
+}
+
+/*! \brief Draw empty 2 color rectangle (inner line color is black)
+ * \param x Top left corner coordinate
+ * \param y Top left corner coordinate
+ * \param width Rectangle width
+ * \param height Rectangle height
+ * \param color Outter line color
+ */
+void FWRenderer::drawDoubleBorder(int x, int y, int width, int height, byte color) {
+	drawBorder(x + 1, y + 1, width - 2, height - 2, 0);
+	drawBorder(x, y, width, height, color);
+}
+
+/*! \brief Draw text character on screen
+ * \param character Character to draw
+ * \param x Character coordinate
+ * \param y Character coordinate
+ */
+int FWRenderer::drawChar(char character, int x, int y) {
+	int width, idx;
+
+	if (character == ' ') {
+		x += 5;
+	} else if ((width = fontParamTable[character].characterWidth)) {
+		idx = fontParamTable[character].characterIdx;
+		drawSpriteRaw(textTable[idx][0], textTable[idx][1], 16, 8, _backBuffer, x, y);
+		x += width + 1;
+	}
+
+	return x;
+}
+
+/*! \brief Draw Line
+ * \param x Line end coordinate
+ * \param y Line end coordinate
+ * \param width Horizontal line length
+ * \param height Vertical line length
+ * \param color Line color
+ * \note Either width or height must be equal to 1
+ */
+void FWRenderer::drawLine(int x, int y, int width, int height, byte color) {
+	// this line is a special case of rectangle ;-)
+	drawPlainBox(x, y, width, height, color);
+}
+
+/*! \brief Hide invisible parts of the sprite
+ * \param[in,out] mask Mask to be updated
+ * \param it Overlay info from overlayList
+ */
+void FWRenderer::remaskSprite(byte *mask, Common::List<overlay>::iterator it) {
+	AnimData &sprite = animDataTable[objectTable[it->objIdx].frame];
+	int x, y, width, height, idx;
+	int mx, my, mw, mh;
+
+	x = objectTable[it->objIdx].x;
+	y = objectTable[it->objIdx].y;
+	width = sprite._realWidth;
+	height = sprite._height;
+
+	for (++it; it != overlayList.end(); ++it) {
+		if (it->type != 5) {
+			continue;
+		}
+
+		idx = ABS(objectTable[it->objIdx].frame);
+		mx = objectTable[it->objIdx].x;
+		my = objectTable[it->objIdx].y;
+		mw = animDataTable[idx]._realWidth;
+		mh = animDataTable[idx]._height;
+
+		gfxUpdateSpriteMask(mask, x, y, width, height, animDataTable[idx].data(), mx, my, mw, mh);
+	}
+}
+
+/*! \brief Draw background to backbuffer
+ */
+void FWRenderer::drawBackground() {
+	assert(_background);
+	memcpy(_backBuffer, _background, _screenSize);
+}
+
+/*! \brief Draw one overlay
+ * \param it Overlay info
+ */
+void FWRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
+	int idx, len, width;
+	objectStruct *obj;
+	AnimData *sprite;
+	byte *mask;
+
+	switch (it->type) {
+	// color sprite
+	case 0:
+		sprite = animDataTable + objectTable[it->objIdx].frame;
+		len = sprite->_realWidth * sprite->_height;
+		mask = new byte[len];
+		memcpy(mask, sprite->mask(), len);
+		remaskSprite(mask, it);
+		drawMaskedSprite(objectTable[it->objIdx], mask);
+		delete[] mask;
+		break;
+
+	// game message
+	case 2:
+		if (it->objIdx >= messageTable.size()) {
+			return;
+		}
+
+		_messageLen += messageTable[it->objIdx].size();
+		drawMessage(messageTable[it->objIdx].c_str(), it->x, it->y, it->width, it->color);
+		break;
+
+	// action failure message
+	case 3:
+		idx = it->objIdx * 4 + g_cine->_rnd.getRandomNumber(3);
+		len = strlen(failureMessages[idx]);
+		_messageLen += len;
+		width = 6 * len + 20;
+		width = width > 300 ? 300 : width;
+
+		drawMessage(failureMessages[idx], (320 - width) / 2, 80, width, 4);
+		break;
+
+	// bitmap
+	case 4:
+		assert(it->objIdx < NUM_MAX_OBJECT);
+		obj = objectTable + it->objIdx;
+
+		if (obj->frame < 0) {
+			return;
+		}
+
+		if (!animDataTable[obj->frame].data()) {
+			return;
+		}
+
+		fillSprite(*obj);
+		break;
+	}
+}
+
+/*! \brief Draw overlays
+ */
+void FWRenderer::drawOverlays() {
+	Common::List<overlay>::iterator it;
+
+	for (it = overlayList.begin(); it != overlayList.end(); ++it) {
+		renderOverlay(it);
+	}
+}
+
+/*! \brief Draw another frame
+ */
+void FWRenderer::drawFrame() {
+	drawBackground();
+	drawOverlays();
+
+	if (!_cmd.empty()) {
+		drawCommand();
+	}
+
+	if (_changePal) {
+		refreshPalette();
+	}
+
+	blit();
+}
+
+/*! \brief Update screen
+ */
+void FWRenderer::blit() {
+	g_system->copyRectToScreen(_backBuffer, 320, 0, 0, 320, 200);
+}
+
+/*! \brief Set player command string
+ * \param cmd New command string
+ */
+void FWRenderer::setCommand(const char *cmd) {
+	_cmd = cmd;
+}
+
+/*! \brief Refresh current palette
+ */
+void FWRenderer::refreshPalette() {
+	int i;
+	byte pal[16*4];
+
+	assert(_activeLowPal);
+
+	for (i = 0; i < 16; i++) {
+		// This seems to match the output from DOSbox.
+		pal[i * 4 + 2] = ((_activeLowPal[i] & 0x00f) >> 0) * 32;
+		pal[i * 4 + 1] = ((_activeLowPal[i] & 0x0f0) >> 4) * 32;
+		pal[i * 4 + 0] = ((_activeLowPal[i] & 0xf00) >> 8) * 32;
+		pal[i * 4 + 3] = 0;
+	}
+
+	g_system->setPalette(pal, 0, 16);
+	_changePal = 0;
+}
+
+/*! \brief Load palette of current background
+ */
+void FWRenderer::reloadPalette() {
+	assert(_palette);
+
+	if (!_activeLowPal) {
+		_activeLowPal = new uint16[_lowPalSize];
+	}
+
+	assert(_activeLowPal);
+
+	memcpy(_activeLowPal, _palette, _lowPalSize * sizeof (uint16));
+	_changePal = 1;
+}
+
+/*! \brief Load background into renderer
+ * \param bg Raw background data
+ */
+void FWRenderer::loadBg16(const byte *bg, const char *name) {
+	int i;
+
+	if (!_background) {
+		_background = new byte[_screenSize];
+	}
+
+	if (!_palette) {
+		_palette = new uint16[_lowPalSize];
+	}
+
+	assert(_background && _palette);
+
+	strcpy(_bgName, name);
+
+	for (i = 0; i < _lowPalSize; i++, bg += 2) {
+		_palette[i] = READ_BE_UINT16(bg);
+	}
+
+	gfxConvertSpriteToRaw(_background, bg, 160, 200);
+}
+
+/*! \brief Placeholder for Operation Stealth implementation
+ */
+void FWRenderer::loadBg16(const byte *bg, const char *name, unsigned int idx) {
+	error("Future Wars renderer doesn't support multiple backgrounds");
+}
+
+/*! \brief Placeholder for Operation Stealth implementation
+ */
+void FWRenderer::loadCt16(const byte *ct, const char *name) {
+	error("Future Wars renderer doesn't support multiple backgrounds");
+}
+
+/*! \brief Placeholder for Operation Stealth implementation
+ */
+void FWRenderer::loadBg256(const byte *bg, const char *name) {
+	error("Future Wars renderer doesn't support 256 color mode");
+}
+
+/*! \brief Placeholder for Operation Stealth implementation
+ */
+void FWRenderer::loadBg256(const byte *bg, const char *name, unsigned int idx) {
+	error("Future Wars renderer doesn't support multiple backgrounds");
+}
+
+/*! \brief Placeholder for Operation Stealth implementation
+ */
+void FWRenderer::loadCt256(const byte *ct, const char *name) {
+	error("Future Wars renderer doesn't support multiple backgrounds");
+}
+
+/*! \brief Placeholder for Operation Stealth implementation
+ */
+void FWRenderer::selectBg(unsigned int idx) {
+	error("Future Wars renderer doesn't support multiple backgrounds");
+}
+
+/*! \brief Placeholder for Operation Stealth implementation
+ */
+void FWRenderer::selectScrollBg(unsigned int idx) {
+	error("Future Wars renderer doesn't support multiple backgrounds");
+}
+
+/*! \brief Placeholder for Operation Stealth implementation
+ */
+void FWRenderer::setScroll(unsigned int shift) {
+	error("Future Wars renderer doesn't support multiple backgrounds");
+}
+
+/*! \brief Placeholder for Operation Stealth implementation
+ */
+void FWRenderer::removeBg(unsigned int idx) {
+	error("Future Wars renderer doesn't support multiple backgrounds");
+}
+
+void FWRenderer::saveBg(Common::OutSaveFile &fHandle) {
+	fHandle.write(_bgName, 13);
+}
+
+/*! \brief Restore active and backup palette from save
+ * \param fHandle Savefile open for reading
+ */
+void FWRenderer::restorePalette(Common::InSaveFile &fHandle) {
+	int i;
+
+	if (!_palette) {
+		_palette = new uint16[_lowPalSize];
+	}
+
+	if (!_activeLowPal) {
+		_activeLowPal = new uint16[_lowPalSize];
+	}
+
+	assert(_palette && _activeLowPal);
+
+	for (i = 0; i < _lowPalSize; i++) {
+		_activeLowPal[i] = fHandle.readUint16BE();
+	}
+
+	for (i = 0; i < _lowPalSize; i++) {
+		_palette[i] = fHandle.readUint16BE();
+	}
+
+	_changePal = 1;
+}
+
+/*! \brief Write active and backup palette to save
+ * \param fHandle Savefile open for writing
+ */
+void FWRenderer::savePalette(Common::OutSaveFile &fHandle) {
+	int i;
+
+	assert(_palette && _activeLowPal);
+
+	for (i = 0; i < _lowPalSize; i++) {
+		fHandle.writeUint16BE(_activeLowPal[i]);
+	}
+
+	for (i = 0; i < _lowPalSize; i++) {
+		fHandle.writeUint16BE(_palette[i]);
+	}
+}
+
+/*! \brief Rotate active palette
+ * \param a First color to rotate
+ * \param b Last color to rotate
+ * \param c Possibly rotation step, must be equal to 1 at the moment
+ */
+void FWRenderer::rotatePalette(int a, int b, int c) {
+	palRotate(_activeLowPal, a, b, c);
+	refreshPalette();
+}
+
+/*! \brief Copy part of backup palette to active palette and transform
+ * \param first First color to transform
+ * \param last Last color to transform
+ * \param r Red channel transformation
+ * \param g Green channel transformation
+ * \param b Blue channel transformation
+ */
+void FWRenderer::transformPalette(int first, int last, int r, int g, int b) {
+	if (!_activeLowPal) {
+		_activeLowPal = new uint16[_lowPalSize];
+		memset(_activeLowPal, 0, _lowPalSize * sizeof (uint16));
+	}
+
+	transformPaletteRange(_activeLowPal, _palette, first, last, r, g, b);
+	refreshPalette();
+}
+
+/*! \brief Draw menu box, one item per line with possible highlight
+ * \param items Menu items
+ * \param height Item count
+ * \param x Top left menu corner coordinate
+ * \param y Top left menu corner coordinate
+ * \param width Menu box width
+ * \param selected Index of highlighted item (no highlight if less than 0)
+ */
+void FWRenderer::drawMenu(const CommandeType *items, unsigned int height, int x, int y, int width, int selected) {
+	int tx, ty, th = height * 9 + 10;
+	unsigned int i, j;
+
+	if (x + width > 319) {
+		x = 319 - width;
+	}
+
+	if (y + th > 199) {
+		y = 199 - th;
+	}
+
+	drawPlainBox(x, y, width, 4, _messageBg);
+
+	ty = y + 4;
+
+	for (i = 0; i < height; i++, ty += 9) {
+		drawPlainBox(x, ty, width, 9, (int)i == selected ? 0 : _messageBg);
+		tx = x + 4;
+
+		for (j = 0; items[i][j]; j++) {
+			tx = drawChar(items[i][j], tx, ty);
+		}
+	}
+
+	drawPlainBox(x, ty, width, 4, _messageBg);
+	drawDoubleBorder(x, y, width, ty - y + 4, 2);
+}
+
+/*! \brief Draw text input box
+ * \param info Input box message
+ * \param input Text entered in the input area
+ * \param cursor Cursor position in the input area
+ * \param x Top left input box corner coordinate
+ * \param y Top left input box corner coordinate
+ * \param width Input box width
+ */
+void FWRenderer::drawInputBox(const char *info, const char *input, int cursor, int x, int y, int width) {
+	int i, tx, ty, tw;
+	int line = 0, words = 0, cw = 0;
+	int space = 0, extraSpace = 0;
+
+	drawPlainBox(x, y, width, 4, _messageBg);
+	tx = x + 4;
+	ty = info[0] ? y - 5 : y + 4;
+	tw = width - 8;
+
+	// input box info message
+	for (i = 0; info[i]; i++, line--) {
+		// fit line of text
+		if (!line) {
+			line = fitLine(info + i, tw, words, cw);
+
+			if ( info[i + line] != '\0' && words) {
+				space = (tw - cw) / words;
+				extraSpace = (tw - cw) % words;
+			} else {
+				space = 5;
+				extraSpace = 0;
+			}
+
+			ty += 9;
+			drawPlainBox(x, ty, width, 9, _messageBg);
+			tx = x + 4;
+		}
+
+		// draw characters
+		if (info[i] == ' ') {
+			tx += space + extraSpace;
+
+			if (extraSpace) {
+				extraSpace = 0;
+			}
+		} else {
+			tx = drawChar(info[i], tx, ty);
+		}
+	}
+
+	// input area background
+	ty += 9;
+	drawPlainBox(x, ty, width, 9, _messageBg);
+	drawPlainBox(x + 16, ty - 1, width - 32, 9, 0);
+	tx = x + 20;
+
+	// text in input area
+	for (i = 0; input[i]; i++) {
+		tx = drawChar(input[i], tx, ty);
+
+		if (cursor == i + 2) {
+			drawLine(tx, ty - 1, 1, 9, 2);
+		}
+	}
+
+	if (!input[0] || cursor == 1) {
+		drawLine(x + 20, ty - 1, 1, 9, 2);
+	}
+
+	ty += 9;
+	drawPlainBox(x, ty, width, 4, _messageBg);
+	drawDoubleBorder(x, y, width, ty - y + 4, 2);
+}
+
+/*! \brief Fade to black
+ */
+void FWRenderer::fadeToBlack() {
+	assert(_activeLowPal);
+
+	for (int i = 0; i < 8; i++) {
+		for (int j = 0; j < 16; j++) {
+			_activeLowPal[j] = transformColor(_activeLowPal[j], -1, -1, -1);
+		}
+
+		refreshPalette();
+		g_system->updateScreen();
+		g_system->delayMillis(50);
+	}
+}
+
+/*! \brief Initialize Operation Stealth renderer
+ */
+OSRenderer::OSRenderer() : _activeHiPal(NULL), _currentBg(0), _scrollBg(0),
+	_bgShift(0) {
+
+	int i;
+	for (i = 0; i < 9; i++) {
+		_bgTable[i].bg = NULL;
+		_bgTable[i].lowPal = NULL;
+		_bgTable[i].hiPal = NULL;
+		memset(_bgTable[i].name, 0, sizeof (_bgTable[i].name));
+	}
+}
+
+/*! \brief Destroy Operation Stealth renderer
+ */
+OSRenderer::~OSRenderer() {
+	delete[] _activeHiPal;
+
+	for (int i = 0; i < 9; i++) {
+		delete[] _bgTable[i].bg;
+		delete[] _bgTable[i].lowPal;
+		delete[] _bgTable[i].hiPal;
+	}
+}
+
+/*! \brief Reset Operation Stealth renderer state
+ */
+void OSRenderer::clear() {
+	delete[] _activeHiPal;
+	_activeHiPal = NULL;
+
+	for (int i = 0; i < 9; i++) {
+		delete[] _bgTable[i].bg;
+		delete[] _bgTable[i].lowPal;
+		delete[] _bgTable[i].hiPal;
+
+		_bgTable[i].bg = NULL;
+		_bgTable[i].lowPal = NULL;
+		_bgTable[i].hiPal = NULL;
+		memset(_bgTable[i].name, 0, sizeof (_bgTable[i].name));
+	}
+
+	_currentBg = 0;
+	_scrollBg = 0;
+	_bgShift = 0;
+
+	FWRenderer::clear();
+}
+
+/*! \brief Draw 1bpp sprite using selected color on backgrounds
+ * \param obj Object info
+ * \param fillColor Sprite color
+ */
+void OSRenderer::incrustMask(const objectStruct &obj, uint8 color) {
+	const byte *data = animDataTable[obj.frame].data();
+	int x, y, width, height, i;
+
+	x = obj.x;
+	y = obj.y;
+	width = animDataTable[obj.frame]._realWidth;
+	height = animDataTable[obj.frame]._height;
+
+	for (i = 0; i < 8; i++) {
+		if (!_bgTable[i].bg) {
+			continue;
+		}
+
+		gfxFillSprite(data, width, height, _bgTable[i].bg, x, y, color);
+	}
+}
+
+/*! \brief Draw color sprite
+ * \param obj Object info
+ */
+void OSRenderer::drawSprite(const objectStruct &obj) {
+	const byte *data = animDataTable[obj.frame].data();
+	int x, y, width, height, transColor;
+
+	x = obj.x;
+	y = obj.y;
+	transColor = obj.part;
+	width = animDataTable[obj.frame]._realWidth;
+	height = animDataTable[obj.frame]._height;
+
+	drawSpriteRaw2(data, transColor, width, height, _backBuffer, x, y);
+}
+
+/*! \brief Draw color sprite
+ * \param obj Object info
+ */
+void OSRenderer::incrustSprite(const objectStruct &obj) {
+	const byte *data = animDataTable[obj.frame].data();
+	int x, y, width, height, transColor, i;
+
+	x = obj.x;
+	y = obj.y;
+	transColor = obj.part;
+	width = animDataTable[obj.frame]._realWidth;
+	height = animDataTable[obj.frame]._height;
+
+	for (i = 0; i < 8; i++) {
+		if (!_bgTable[i].bg) {
+			continue;
+		}
+
+		drawSpriteRaw2(data, transColor, width, height, _bgTable[i].bg, x, y);
+	}
+}
+
+/*! \brief Draw text character on screen
+ * \param character Character to draw
+ * \param x Character coordinate
+ * \param y Character coordinate
+ */
+int OSRenderer::drawChar(char character, int x, int y) {
+	int width, idx;
+
+	if (character == ' ') {
+		x += 5;
+	} else if ((width = fontParamTable[character].characterWidth)) {
+		idx = fontParamTable[character].characterIdx;
+		drawSpriteRaw2(textTable[idx][0], 0, 16, 8, _backBuffer, x, y);
+		x += width + 1;
+	}
+
+	return x;
+}
+
+/*! \brief Draw background to backbuffer
+ */
+void OSRenderer::drawBackground() {
+	byte *main;
+
+	main = _bgTable[_currentBg].bg;
+	assert(main);
+
+	if (!_bgShift) {
+		memcpy(_backBuffer, main, _screenSize);
+	} else {
+		byte *scroll = _bgTable[_scrollBg].bg;
+		int mainShift = _bgShift * _screenWidth;
+		int mainSize = _screenSize - mainShift;
+
+		assert(scroll);
+
+		memcpy(_backBuffer, main + mainShift, mainSize);
+		memcpy(_backBuffer + mainSize, scroll, mainShift);
+	}
+}
+
+/*! \brief Draw one overlay
+ * \param it Overlay info
+ */
+void OSRenderer::renderOverlay(const Common::List<overlay>::iterator &it) {
+	int len;
+	objectStruct *obj;
+	AnimData *sprite;
+	byte *mask;
+
+	switch (it->type) {
+	// color sprite
+	case 0:
+		sprite = animDataTable + objectTable[it->objIdx].frame;
+		len = sprite->_realWidth * sprite->_height;
+		mask = new byte[len];
+		generateMask(sprite->data(), mask, len, objectTable[it->objIdx].part);
+		remaskSprite(mask, it);
+		drawMaskedSprite(objectTable[it->objIdx], mask);
+		delete[] mask;
+		break;
+
+	// masked background
+	case 20:
+		assert(it->objIdx < NUM_MAX_OBJECT);
+		obj = objectTable + it->objIdx;
+		sprite = animDataTable + obj->frame;
+
+		if (obj->frame < 0 || it->x > 8 || !_bgTable[it->x].bg || sprite->_bpp != 1) {
+			break;
+		}
+
+		maskBgOverlay(_bgTable[it->x].bg, sprite->data(), sprite->_realWidth, sprite->_height, _backBuffer, obj->x, obj->y);
+		break;
+
+	// something else
+	default:
+		FWRenderer::renderOverlay(it);
+		break;
+	}
+}
+
+/*! \brief Refresh current palette
+ */
+void OSRenderer::refreshPalette() {
+	if (!_activeHiPal) {
+		FWRenderer::refreshPalette();
+		return;
+	}
+
+	int i;
+	byte pal[256*4];
+
+	for (i = 0; i < 256; i++) {
+		pal[i * 4 + 0] = _activeHiPal[i * 3 + 0];
+		pal[i * 4 + 1] = _activeHiPal[i * 3 + 1];
+		pal[i * 4 + 2] = _activeHiPal[i * 3 + 2];
+		pal[i * 4 + 3] = 0;
+	}
+
+	g_system->setPalette(pal, 0, 256);
+	_changePal = 0;
+}
+
+/*! \brief Load palette of current background
+ */
+void OSRenderer::reloadPalette() {
+	// selected background in plane takeoff scene has swapped colors 12
+	// and 14, shift background has it right
+	palBg *bg = _bgShift ? &_bgTable[_scrollBg] : &_bgTable[_currentBg];
+
+	assert(bg->lowPal || bg->hiPal);
+
+	if (bg->lowPal) {
+		if (!_activeLowPal) {
+			_activeLowPal = new uint16[_lowPalSize];
+		}
+
+		assert(_activeLowPal);
+
+		delete[] _activeHiPal;
+		_activeHiPal = NULL;
+
+		memcpy(_activeLowPal, bg->lowPal, _lowPalSize * sizeof (uint16));
+	} else {
+		if (!_activeHiPal) {
+			_activeHiPal = new byte[_hiPalSize];
+		}
+
+		assert(_activeHiPal);
+
+		delete[] _activeLowPal;
+		_activeLowPal = NULL;
+
+		memcpy(_activeHiPal, bg->hiPal, _hiPalSize);
+	}
+	_changePal = 1;
+}
+
+/*! \brief Rotate active palette
+ * \param a First color to rotate
+ * \param b Last color to rotate
+ * \param c Possibly rotation step, must be equal to 1 at the moment
+ */
+void OSRenderer::rotatePalette(int a, int b, int c) {
+	if (_activeLowPal) {
+		FWRenderer::rotatePalette(a, b, c);
+		return;
+	}
+
+	palRotate(_activeHiPal, a, b, c);
+	refreshPalette();
+}
+
+/*! \brief Copy part of backup palette to active palette and transform
+ * \param first First color to transform
+ * \param last Last color to transform
+ * \param r Red channel transformation
+ * \param g Green channel transformation
+ * \param b Blue channel transformation
+ */
+void OSRenderer::transformPalette(int first, int last, int r, int g, int b) {
+	palBg *bg = _bgShift ? &_bgTable[_scrollBg] : &_bgTable[_currentBg];
+
+	if (!bg->lowPal) {
+		if (!_activeHiPal) {
+			_activeHiPal = new byte[_hiPalSize];
+			memset(_activeHiPal, 0, _hiPalSize);
+		}
+
+		delete[] _activeLowPal;
+		_activeLowPal = NULL;
+
+		transformPaletteRange(_activeHiPal, bg->hiPal, first, last, r, g, b);
+	} else {
+		if (!_activeLowPal) {
+			_activeLowPal = new uint16[_lowPalSize];
+			memset(_activeLowPal, 0, _lowPalSize * sizeof (uint16));
+		}
+
+		delete[] _activeHiPal;
+		_activeHiPal = NULL;
+
+		transformPaletteRange(_activeLowPal, bg->lowPal, first, last, r, g, b);
+	}
+
+	refreshPalette();
+}
+
+/*! \brief Load 16 color background into renderer
+ * \param bg Raw background data
+ * \param name Background filename
+ */
+void OSRenderer::loadBg16(const byte *bg, const char *name) {
+	loadBg16(bg, name, 0);
+}
+
+/*! \brief Load 16 color background into renderer
+ * \param bg Raw background data
+ * \param name Background filename
+ * \param pos Background index
+ */
+void OSRenderer::loadBg16(const byte *bg, const char *name, unsigned int idx) {
+	int i;
+	assert(idx < 9);
+
+	if (!_bgTable[idx].bg) {
+		_bgTable[idx].bg = new byte[_screenSize];
+	}
+
+	if (!_bgTable[idx].lowPal) {
+		_bgTable[idx].lowPal = new uint16[_lowPalSize];
+	}
+
+	assert(_bgTable[idx].bg && _bgTable[idx].lowPal);
+
+	delete[] _bgTable[idx].hiPal;
+	_bgTable[idx].hiPal = NULL;
+
+	strcpy(_bgTable[idx].name, name);
+
+	for (i = 0; i < _lowPalSize; i++, bg += 2) {
+		_bgTable[idx].lowPal[i] = READ_BE_UINT16(bg);
+	}
+
+	gfxConvertSpriteToRaw(_bgTable[idx].bg, bg, 160, 200);
+}
+
+/*! \brief Load 16 color CT data as background into renderer
+ * \param ct Raw CT data
+ * \param name Background filename
+ */
+void OSRenderer::loadCt16(const byte *ct, const char *name) {
+	loadBg16(ct, name, 8);
+}
+
+/*! \brief Load 256 color background into renderer
+ * \param bg Raw background data
+ * \param name Background filename
+ */
+void OSRenderer::loadBg256(const byte *bg, const char *name) {
+	loadBg256(bg, name, 0);
+}
+
+/*! \brief Load 256 color background into renderer
+ * \param bg Raw background data
+ * \param name Background filename
+ * \param pos Background index
+ */
+void OSRenderer::loadBg256(const byte *bg, const char *name, unsigned int idx) {
+	assert(idx < 9);
+
+	if (!_bgTable[idx].bg) {
+		_bgTable[idx].bg = new byte[_screenSize];
+	}
+
+	if (!_bgTable[idx].hiPal) {
+		_bgTable[idx].hiPal = new byte[_hiPalSize];
+	}
+
+	assert(_bgTable[idx].bg && _bgTable[idx].hiPal);
+
+	delete[] _bgTable[idx].lowPal;
+	_bgTable[idx].lowPal = NULL;
+
+	strcpy(_bgTable[idx].name, name);
+	memcpy(_bgTable[idx].hiPal, bg, _hiPalSize);
+	memcpy(_bgTable[idx].bg, bg + _hiPalSize, _screenSize);
+}
+
+/*! \brief Load 256 color CT data as background into renderer
+ * \param ct Raw CT data
+ * \param name Background filename
+ */
+void OSRenderer::loadCt256(const byte *ct, const char *name) {
+	loadBg256(ct, name, 8);
+}
+
+/*! \brief Select active background and load its palette
+ * \param idx Background index
+ */
+void OSRenderer::selectBg(unsigned int idx) {
+	assert(idx < 9 && _bgTable[idx].bg);
+	assert(_bgTable[idx].lowPal || _bgTable[idx].hiPal);
+
+	_currentBg = idx;
+	reloadPalette();
+}
+
+/*! \brief Select scroll background
+ * \param idx Scroll background index
+ */
+void OSRenderer::selectScrollBg(unsigned int idx) {
+	assert(idx < 9);
+
+	if (_bgTable[idx].bg) {
+		_scrollBg = idx;
+	}
+	reloadPalette();
+}
+
+/*! \brief Set background scroll
+ * \param shift Background scroll in pixels
+ */
+void OSRenderer::setScroll(unsigned int shift) {
+	assert(shift <= 200);
+
+	_bgShift = shift;
+}
+
+/*! \brief Unload background from renderer
+ * \param idx Background to unload
+ */
+void OSRenderer::removeBg(unsigned int idx) {
+	assert(idx > 0 && idx < 9);
+
+	if (_currentBg == idx) {
+		_currentBg = 0;
+	}
+
+	if (_scrollBg == idx) {
+		_scrollBg = 0;
+	}
+
+	delete[] _bgTable[idx].bg;
+	delete[] _bgTable[idx].lowPal;
+	delete[] _bgTable[idx].hiPal;
+	_bgTable[idx].bg = NULL;
+	_bgTable[idx].lowPal = NULL;
+	_bgTable[idx].hiPal = NULL;
+	memset(_bgTable[idx].name, 0, sizeof (_bgTable[idx].name));
+}
+
+/*! \brief Fade to black
+ * \bug Operation Stealth sometimes seems to fade to black using
+ * transformPalette resulting in double fadeout
+ */
+void OSRenderer::fadeToBlack() {
+	if (!_activeHiPal) {
+		FWRenderer::fadeToBlack();
+		return;
+	}
+
+	for (int i = 0; i < 8; i++) {
+		for (int j = 0; j < _hiPalSize; j++) {
+			_activeHiPal[j] = CLIP(_activeHiPal[j] - 32, 0, 255);
+		}
+
+		refreshPalette();
+		g_system->updateScreen();
+		g_system->delayMillis(50);
+	}
+}
+
 void setMouseCursor(int cursor) {
 	static int currentMouseCursor = -1;
 	assert(cursor >= 0 && cursor < 3);
@@ -147,21 +1299,6 @@
 	}
 }
 
-static uint16 transformColor(uint16 baseColor, int8 r, int8 g, int8 b) {
-	int8 oriR = CLIP( (baseColor & 0x007)       + r, 0, 7);
-	int8 oriG = CLIP(((baseColor & 0x070) >> 4) + g, 0, 7);
-	int8 oriB = CLIP(((baseColor & 0x700) >> 8) + b, 0, 7);
-
-	return oriR | (oriG << 4) | (oriB << 8);
-}
-
-void transformPaletteRange(byte startColor, byte stopColor, int8 r, int8 g, int8 b) {
-	for (byte i = startColor; i <= stopColor; i++) {
-		c_palette[i] = transformColor(tempPalette[i], b, g, r);
-	}
-	//gfxFlipPage(page2);
-}
-
 void gfxFillSprite(const byte *spritePtr, uint16 width, uint16 height, byte *page, int16 x, int16 y, uint8 fillColor) {
 	int16 i, j;
 
@@ -170,17 +1307,12 @@
 		destPtr += i * 320;
 
 		for (j = 0; j < width; j++) {
-			if (x + j >= 0 && x + j < 320 && i + y >= 0
-			    && i + y < 200) {
-				if (!*(spritePtr++)) {
-					*(destPtr++) = fillColor;
-				} else {
-					destPtr++;
-				}
-			} else {
-				destPtr++;
-				spritePtr++;
+			if (x + j >= 0 && x + j < 320 && i + y >= 0 && i + y < 200 && !*spritePtr) {
+				*destPtr = fillColor;
 			}
+
+			destPtr++;
+			spritePtr++;
 		}
 	}
 }
@@ -360,53 +1492,7 @@
 	}
 }
 
-void gfxCopyRawPage(byte *source, byte *dest) {
-	memcpy(dest, source, 320 * 200);
-}
-
-void gfxFlipRawPage(byte *frontBuffer) {
-	byte *page = frontBuffer;
-	int x, y, i;
-	byte *pixels = (byte *) screenBuffer;
-	byte c;
-	byte pal[256 * 4];
-
-	for (y = 0; y < 200; y++) {
-		for (x = 0; x < 320; x++) {
-			c = *(page++);
-
-			if (!colorMode256) {
-				c = c & 15;
-			}
-
-			pixels[x + 0 + y * 320] = c;
-		}
-	}
-
-	if (colorMode256) {
-		for (i = 0; i < 256; i++) {
-			pal[i * 4 + 0] = palette256[i * 3 + 0];
-			pal[i * 4 + 1] = palette256[i * 3 + 1];
-			pal[i * 4 + 2] = palette256[i * 3 + 2];
-			pal[i * 4 + 3] = 0;
-		}
-		g_system->setPalette(pal, 0, 256);
-	} else {
-		for (i = 0; i < 16; i++) {
-			// This seems to match the output from DOSbox.
-			pal[i * 4 + 2] = ((c_palette[i] & 0x00f) >> 0) * 32;
-			pal[i * 4 + 1] = ((c_palette[i] & 0x0f0) >> 4) * 32;
-			pal[i * 4 + 0] = ((c_palette[i] & 0xf00) >> 8) * 32;
-			pal[i * 4 + 3] = 0;
-		}
-		g_system->setPalette(pal, 0, 16);
-	}
-
-	g_system->copyRectToScreen(screenBuffer, 320, 0, 0, 320, 200);
-}
-
-void drawSpriteRaw(const byte *spritePtr, const byte *maskPtr, int16 width, int16 height,
-				   byte *page, int16 x, int16 y) {
+void drawSpriteRaw(const byte *spritePtr, const byte *maskPtr, int16 width, int16 height, byte *page, int16 x, int16 y) {
 	int16 i, j;
 
 	// FIXME: Is it a bug if maskPtr == NULL?
@@ -417,9 +1503,8 @@
 		byte *destPtr = page + x + y * 320;
 		destPtr += i * 320;
 
-		for (j = 0; j < width * 8; j++) {
-			if (((g_cine->getGameType() == Cine::GType_FW && (!maskPtr || !(*maskPtr))) || (g_cine->getGameType() == Cine::GType_OS)) && (x + j >= 0
-					&& x + j < 320 && i + y >= 0 && i + y < 200)) {
+		for (j = 0; j < width; j++) {
+			if ((!maskPtr || !(*maskPtr)) && x + j >= 0 && x + j < 320 && i + y >= 0 && i + y < 200) {
 				*(destPtr++) = *(spritePtr++);
 			} else {
 				destPtr++;
@@ -432,21 +1517,19 @@
 	}
 }
 
-void drawSpriteRaw2(const byte *spritePtr, byte transColor, int16 width, int16 height,
-					byte *page, int16 x, int16 y) {
+void drawSpriteRaw2(const byte *spritePtr, byte transColor, int16 width, int16 height, byte *page, int16 x, int16 y) {
 	int16 i, j;
 
 	for (i = 0; i < height; i++) {
 		byte *destPtr = page + x + y * 320;
 		destPtr += i * 320;
 
-		for (j = 0; j < width * 8; j++) {
-			if ((*(spritePtr) != transColor) && (x + j >= 0 && x + j < 320 && i + y >= 0 && i + y < 200)) {
-				*(destPtr++) = *(spritePtr++);
-			} else {
-				destPtr++;
-				spritePtr++;
+		for (j = 0; j < width; j++) {
+			if ((*spritePtr != transColor) && (x + j >= 0 && x + j < 320 && i + y >= 0 && i + y < 200)) {
+				*destPtr = *spritePtr;
 			}
+			destPtr++;
+			spritePtr++;
 		}
 	}
 }
@@ -499,93 +1582,4 @@
 	}
 }
 
-/*! \todo Fix rendering to prevent fadein artifacts
- */
-void fadeFromBlack() {
-	int i, j;
-	int r, g, b, tr, tg, tb;
-	if (newColorMode == 2) {
-		colorMode256 = 1;
-		memset(palette256, 0, 256*3);
-	} else if (newColorMode == 1) {
-		colorMode256 = 0;
-		memset(c_palette, 0, 16 * sizeof(uint16));
-	}
-
-	for (i = 0; i < 8; i++ ) {
-		gfxFlipRawPage(page1Raw);
-		g_system->updateScreen();
-		g_system->delayMillis(50);
-
-		if (colorMode256) {
-			for (j = 0; j < 256*3; j++) {
-				r = palette256[j] + (newPalette[j] + 7) / 8;
-				palette256[j] = CLIP(r, 0, (int)newPalette[j]);
-			}
-		} else {
-			for (j = 0; j < 16; j++) {
-				r = c_palette[j] & 0xf;
-				g = (c_palette[j] & 0xf0) >> 4;
-				b = (c_palette[j] & 0xf00) >> 8;
-
-				tr = tempPalette[j] & 0xf;
-				tg = (tempPalette[j] & 0xf0) >> 4;
-				tb = (tempPalette[j] & 0xf00) >> 8;
-
-				r = CLIP(r + (tr + 7) / 8, 0, tr);
-				g = CLIP(g + (tg + 7) / 8, 0, tg);
-				b = CLIP(b + (tb + 7) / 8, 0, tb);
-
-				c_palette[j] = r | (g << 4) | (b << 8);
-			}
-
-		}
-	}
-
-	if (colorMode256) {
-		memcpy(palette256, newPalette, 256*3);
-	} else {
-		memcpy(c_palette, tempPalette, sizeof(uint16) * 16);
-	}
-}
-
-void fadeToBlack() {
-	for (int i = 0; i < 8; i++) {
-		if (colorMode256) {
-			for (int j = 0; j < 256*3; j++) {
-				palette256[j] = CLIP(palette256[j] - 32, 0, 255);
-			}
-		} else {
-			for (int j = 0; j < 16; j++) {
-				c_palette[j] = transformColor(c_palette[j], -1, -1, -1);
-			}
-		}
-		gfxFlipRawPage(page1Raw);
-		g_system->updateScreen();
-		g_system->delayMillis(50);
-	}
-}
-
-void blitRawScreen(byte *frontBuffer) {
-	gfxFlipRawPage(frontBuffer);
-}
-
-void flip(void) {
-	blitRawScreen(page1Raw);
-	if (fadeRequired) {
-		if (newColorMode == 3) {
-			newColorMode = ctColorMode + 1;
-		}
-
-		if (newColorMode == 2) {
-			colorMode256 = 1;
-			memcpy(palette256, newPalette, 256*3);
-		} else {
-			colorMode256 = 0;
-			memcpy(c_palette, tempPalette, sizeof(uint16) * 16);
-		}
-		fadeRequired = false;
-	}
-}
-
 } // End of namespace Cine

Modified: scummvm/trunk/engines/cine/gfx.h
===================================================================
--- scummvm/trunk/engines/cine/gfx.h	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/gfx.h	2008-05-24 22:11:41 UTC (rev 32257)
@@ -26,24 +26,158 @@
 #ifndef CINE_GFX_H
 #define CINE_GFX_H
 
+#include "common/noncopyable.h"
+#include "cine/object.h"
+
 namespace Cine {
 
+/*! \brief Background with palette
+ */
+struct palBg {
+	byte *bg; ///< Background data
+	byte *hiPal; ///< 256 color palette
+	uint16 *lowPal; ///< 16 color palette
+	char name[15]; ///< Background filename
+};
+
+/*! \brief Future Wars renderer
+ *
+ * Screen backbuffer is not cleared between frames, you can draw menus etc.
+ * without calling drawFrame() all the time
+ */
+class FWRenderer : public Common::NonCopyable {
+private:
+	byte *_background; ///< Current background
+	char _bgName[13]; ///< Background filename
+	uint16 *_palette; ///< 16 color backup palette
+
+	Common::String _cmd; ///< Player command string
+
+protected:
+	static const int _screenSize = 320 * 200; ///< Screen size
+	static const int _screenWidth = 320; ///< Screen width
+	static const int _screenHeight = 200; ///< Screen height
+	static const int _lowPalSize = 16; ///< 16 color palette size
+
+	byte *_backBuffer; ///< Screen backbuffer
+	uint16 *_activeLowPal; ///< Active 16 color palette
+	int _changePal; ///< Load active palette to video backend on next frame
+
+	void fillSprite(const objectStruct &obj, uint8 color = 0);
+	void drawMaskedSprite(const objectStruct &obj, const byte *mask);
+	virtual void drawSprite(const objectStruct &obj);
+
+	void drawCommand();
+	void drawMessage(const char *str, int x, int y, int width, byte color);
+	void drawPlainBox(int x, int y, int width, int height, byte color);
+	void drawBorder(int x, int y, int width, int height, byte color);
+	void drawDoubleBorder(int x, int y, int width, int height, byte color);
+	virtual int drawChar(char character, int x, int y);
+	void drawLine(int x, int y, int width, int height, byte color);
+	void remaskSprite(byte *mask, Common::List<overlay>::iterator it);
+	virtual void drawBackground();
+
+	virtual void renderOverlay(const Common::List<overlay>::iterator &it);
+	void drawOverlays();
+
+public:
+	uint16 _messageBg; ///< Message box background color
+	uint16 _cmdY; ///< Player command string position on screen
+
+	FWRenderer();
+	virtual ~FWRenderer();
+
+	/*! \brief Test if renderer is ready to draw */
+	virtual bool ready() { return _background != NULL; }
+
+	virtual void clear();
+
+	void drawFrame();
+	void blit();
+	void setCommand(const char *cmd);
+
+	virtual void incrustMask(const objectStruct &obj, uint8 color = 0);
+	virtual void incrustSprite(const objectStruct &obj);
+
+	virtual void loadBg16(const byte *bg, const char *name);
+	virtual void loadBg16(const byte *bg, const char *name, unsigned int idx);
+	virtual void loadCt16(const byte *ct, const char *name);
+	virtual void loadBg256(const byte *bg, const char *name);
+	virtual void loadBg256(const byte *bg, const char *name, unsigned int idx);
+	virtual void loadCt256(const byte *ct, const char *name);
+	virtual void selectBg(unsigned int idx);
+	virtual void selectScrollBg(unsigned int idx);
+	virtual void setScroll(unsigned int shift);
+	virtual void removeBg(unsigned int idx);
+	void saveBg(Common::OutSaveFile &fHandle);
+
+	virtual void refreshPalette();
+	virtual void reloadPalette();
+	void restorePalette(Common::InSaveFile &fHandle);
+	void savePalette(Common::OutSaveFile &fHandle);
+	virtual void rotatePalette(int a, int b, int c);
+	virtual void transformPalette(int first, int last, int r, int g, int b);
+
+	void drawMenu(const CommandeType *items, unsigned int height, int x, int y, int width, int selected);
+	void drawInputBox(const char *info, const char *input, int cursor, int x, int y, int width);
+
+	virtual void fadeToBlack();
+};
+
+/*! \brief Operation Stealth renderer
+ */
+class OSRenderer : public FWRenderer {
+private:
+	palBg _bgTable[9]; ///< Table of backgrounds loaded into renderer
+	byte *_activeHiPal; ///< Active 256 color palette
+	unsigned int _currentBg; ///< Current background
+	unsigned int _scrollBg; ///< Current scroll background
+	unsigned int _bgShift; ///< Background shift
+
+protected:
+	static const int _hiPalSize = 256 * 3; ///< 256 color palette size
+
+	void drawSprite(const objectStruct &obj);
+	int drawChar(char character, int x, int y);
+	void drawBackground();
+	void renderOverlay(const Common::List<overlay>::iterator &it);
+
+public:
+	OSRenderer();
+	~OSRenderer();
+
+	/*! \brief Test if renderer is ready to draw */
+	bool ready() { return _bgTable[_currentBg].bg != NULL; }
+
+	void clear();
+
+	void incrustMask(const objectStruct &obj, uint8 color = 0);
+	void incrustSprite(const objectStruct &obj);
+
+	void loadBg16(const byte *bg, const char *name);
+	void loadBg16(const byte *bg, const char *name, unsigned int idx);
+	void loadCt16(const byte *ct, const char *name);
+	void loadBg256(const byte *bg, const char *name);
+	void loadBg256(const byte *bg, const char *name, unsigned int idx);
+	void loadCt256(const byte *ct, const char *name);
+	void selectBg(unsigned int idx);
+	void selectScrollBg(unsigned int idx);
+	void setScroll(unsigned int shift);
+	void removeBg(unsigned int idx);
+
+	void refreshPalette();
+	void reloadPalette();
+	void rotatePalette(int a, int b, int c);
+	void transformPalette(int first, int last, int r, int g, int b);
+
+	void fadeToBlack();
+};
+
 void gfxDrawSprite(byte *src4, uint16 sw, uint16 sh, byte *dst4, int16 sx, int16 sy);
 
-extern byte *page1Raw;
-extern byte *page2Raw;
 extern byte *page3Raw;
+extern FWRenderer *renderer;
 
-extern uint16 c_palette[256];
-extern byte colorMode256;
-extern byte palette256[256 * 3];
-extern byte newPalette[256 * 3];
-extern byte newColorMode;
-extern byte ctColorMode;
-extern byte bgColorMode;
-
-void gfxInit();
-void gfxDestroy();
 void setMouseCursor(int cursor);
 void gfxCopyPage(byte *source, byte *dest);
 

Modified: scummvm/trunk/engines/cine/main_loop.cpp
===================================================================
--- scummvm/trunk/engines/cine/main_loop.cpp	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/main_loop.cpp	2008-05-24 22:11:41 UTC (rev 32257)
@@ -182,14 +182,12 @@
 void CineEngine::mainLoop(int bootScriptIdx) {
 	bool playerAction;
 	uint16 quitFlag;
-	uint16 i;
 	byte di;
 	uint16 mouseButton;
 
 	quitFlag = 0;
 
 	if (_preLoad == false) {
-		resetSeqList();
 		resetBgIncrustList();
 
 		setTextWindow(0, 0, 20, 200);
@@ -223,17 +221,10 @@
 			globalVars[VAR_LOW_MEMORY] = 0; // set to 1 to disable some animations, sounds etc.
 		}
 
-		for (i = 0; i < 16; i++) {
-			c_palette[i] = 0;
-		}
-
-		_paletteNeedUpdate = true;
-
 		strcpy(newPrcName, "");
 		strcpy(newRelName, "");
 		strcpy(newObjectName, "");
 		strcpy(newMsgName, "");
-		strcpy(currentBgName[0], "");
 		strcpy(currentCtName, "");
 		strcpy(currentPartName, "");
 
@@ -257,8 +248,9 @@
 			setMouseCursor(MOUSE_CURSOR_CROSS);
 		}
 
-		drawOverlays();
-		flip();
+		if (renderer->ready()) {
+			renderer->drawFrame();
+		}
 
 		if (waitForPlayerClick) {
 			playerAction = false;
@@ -289,6 +281,8 @@
 			} while (mouseButton != 0);
 
 			waitForPlayerClick = 0;
+
+			removeMessages();
 		}
 
 		if (checkForPendingDataLoadSwitch) {

Modified: scummvm/trunk/engines/cine/object.cpp
===================================================================
--- scummvm/trunk/engines/cine/object.cpp	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/object.cpp	2008-05-24 22:11:41 UTC (rev 32257)
@@ -236,6 +236,10 @@
 	return compareResult;
 }
 
+/*! \bug In Operation Stealth, if you try to go downstairs to the sea in the
+ * location between bank and hotel, getObjectParam is called with paramIdx 16
+ * and crashes
+ */
 int16 getObjectParam(uint16 objIdx, uint16 paramIdx) {
 	assert(objIdx <= NUM_MAX_OBJECT);
 

Modified: scummvm/trunk/engines/cine/pal.cpp
===================================================================
--- scummvm/trunk/engines/cine/pal.cpp	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/pal.cpp	2008-05-24 22:11:41 UTC (rev 32257)
@@ -28,8 +28,6 @@
 
 namespace Cine {
 
-uint16 tempPalette[256];
-
 uint16 palEntriesCount;
 
 PalEntry *palPtr = NULL;
@@ -113,4 +111,64 @@
 	}
 }
 
+void palRotate(uint16 *pal, byte a, byte b, byte c) {
+	assert(pal);
+
+	if (c == 1) {
+		uint16 currentColor = pal[b];
+
+		for (int i = b; i > a; i--) {
+			pal[i] = pal[i - 1];
+		}
+
+		pal[a] = currentColor;
+	}
+}
+
+void palRotate(byte *pal, byte a, byte b, byte c) {
+	assert(pal);
+
+	if (c == 1) {
+		byte currentR = pal[3 * b + 0];
+		byte currentG = pal[3 * b + 1];
+		byte currentB = pal[3 * b + 2];
+
+		for (int i = b; i > a; i--) {
+			pal[3 * i + 0] = pal[3 * (i - 1) + 0];
+			pal[3 * i + 1] = pal[3 * (i - 1) + 1];
+			pal[3 * i + 2] = pal[3 * (i - 1) + 2];
+		}
+
+		pal[3 * a + 0] = currentR;
+		pal[3 * a + 1] = currentG;
+		pal[3 * a + 2] = currentB;
+	}
+}
+
+uint16 transformColor(uint16 baseColor, int r, int g, int b) {
+	int8 oriR = CLIP( (baseColor & 0x007)       + b, 0, 7);
+	int8 oriG = CLIP(((baseColor & 0x070) >> 4) + g, 0, 7);
+	int8 oriB = CLIP(((baseColor & 0x700) >> 8) + r, 0, 7);
+
+	return oriR | (oriG << 4) | (oriB << 8);
+}
+
+void transformPaletteRange(uint16 *dstPal, uint16 *srcPal, int startColor, int stopColor, int r, int g, int b) {
+	assert(srcPal && dstPal);
+
+	for (int i = startColor; i <= stopColor; i++) {
+		dstPal[i] = transformColor(srcPal[i], r, g, b);
+	}
+}
+
+void transformPaletteRange(byte *dstPal, byte *srcPal, int startColor, int stopColor, int r, int g, int b) {
+	assert(srcPal && dstPal);
+
+	for (int i = startColor; i <= stopColor; i++) {
+		dstPal[3 * i + 0] = CLIP(srcPal[3 * i + 0] + r * 32, 0, 255);
+		dstPal[3 * i + 1] = CLIP(srcPal[3 * i + 1] + g * 32, 0, 255);
+		dstPal[3 * i + 2] = CLIP(srcPal[3 * i + 2] + b * 32, 0, 255);
+	}
+}
+
 } // End of namespace Cine

Modified: scummvm/trunk/engines/cine/pal.h
===================================================================
--- scummvm/trunk/engines/cine/pal.h	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/pal.h	2008-05-24 22:11:41 UTC (rev 32257)
@@ -36,10 +36,14 @@
 
 void loadPal(const char *fileName);
 
-extern uint16 tempPalette[256];
-
 void loadRelatedPalette(const char *fileName);
 
+void palRotate(uint16 *pal, byte a, byte b, byte c);
+void palRotate(byte *pal, byte a, byte b, byte c);
+uint16 transformColor(uint16 baseColor, int r, int g, int b);
+void transformPaletteRange(uint16 *srcPal, uint16 *dstPal, int startColor, int stopColor, int r, int g, int b);
+void transformPaletteRange(byte *srcPal, byte *dstPal, int startColor, int stopColor, int r, int g, int b);
+
 } // End of namespace Cine
 
 #endif

Modified: scummvm/trunk/engines/cine/prc.cpp
===================================================================
--- scummvm/trunk/engines/cine/prc.cpp	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/prc.cpp	2008-05-24 22:11:41 UTC (rev 32257)
@@ -98,10 +98,10 @@
 		char buffer[256];
 
 		for (s = 0; s < numScripts; s++) {
-			if (scriptTable[s].size) {
+			if (scriptTable[s]->_size) {
 				sprintf(buffer, "%s_%03d.txt", pPrcName, s);
 
-				decompileScript(scriptTable[s].ptr, scriptTable[s].stack, scriptTable[s].size, s);
+				decompileScript((const byte *)scriptTable[s]->getString(0), scriptTable[s]->_size, s);
 				dumpScript(buffer);
 			}
 		}

Modified: scummvm/trunk/engines/cine/rel.cpp
===================================================================
--- scummvm/trunk/engines/cine/rel.cpp	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/rel.cpp	2008-05-24 22:11:41 UTC (rev 32257)
@@ -81,10 +81,10 @@
 		char buffer[256];
 
 		for (s = 0; s < numEntry; s++) {
-			if (relTable[s].size) {
+			if (relTable[s]->_size) {
 				sprintf(buffer, "%s_%03d.txt", pRelName, s);
 
-				decompileScript(relTable[s].data, NULL, relTable[s].size, s);
+				decompileScript((const byte *)relTable[s]->getString(0), relTable[s]->_size, s);
 				dumpScript(buffer);
 			}
 		}

Modified: scummvm/trunk/engines/cine/script.h
===================================================================
--- scummvm/trunk/engines/cine/script.h	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/script.h	2008-05-24 22:11:41 UTC (rev 32257)
@@ -230,6 +230,7 @@
 	int o1_unloadMask5();
 
 	// pointers to member functions in C++ suck...
+	int o2_loadCt();
 	int o2_loadPart();
 	int o2_addSeqListElement();
 	int o2_removeSeq();
@@ -362,7 +363,7 @@
 
 void setupOpcodes();
 
-void decompileScript(byte *scriptPtr, int16 *stackPtr, uint16 scriptSize, uint16 scriptIdx);
+void decompileScript(const byte *scriptPtr, uint16 scriptSize, uint16 scriptIdx);
 void dumpScript(char *dumpName);
 
 #define OP_loadPart                     0x3F

Modified: scummvm/trunk/engines/cine/script_fw.cpp
===================================================================
--- scummvm/trunk/engines/cine/script_fw.cpp	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/script_fw.cpp	2008-05-24 22:11:41 UTC (rev 32257)
@@ -41,11 +41,6 @@
 ScriptVars globalVars(NUM_MAX_VAR);
 
 uint16 compareVars(int16 a, int16 b);
-void palRotate(byte a, byte b, byte c);
-void removeSeq(uint16 param1, uint16 param2, uint16 param3);
-uint16 isSeqRunning(uint16 param1, uint16 param2, uint16 param3);
-void addGfxElementA0(int16 param1, int16 param2);
-void removeGfxElementA0(int16 idx, int16 param);
 
 const Opcode FWScript::_opcodeTable[] = {
 	/* 00 */
@@ -1299,7 +1294,7 @@
 	const char *param = getNextString();
 
 	debugC(5, kCineDebugScript, "Line: %d: loadCt(\"%s\")", _line, param);
-	loadCt(param);
+	loadCtFW(param);
 	return 0;
 }
 
@@ -1355,31 +1350,29 @@
 	debugC(5, kCineDebugScript, "Line: %d: request fadein", _line);
 	// TODO: use real code
 
-	drawOverlays();
-	fadeRequired = true;
-	flip();
-
 //	fadeFromBlack();
+
+	renderer->reloadPalette();
 	return 0;
 }
 
 int FWScript::o1_fadeToBlack() {
 	debugC(5, kCineDebugScript, "Line: %d: request fadeout", _line);
 
-	fadeToBlack();
+	renderer->fadeToBlack();
 	return 0;
 }
 
 int FWScript::o1_transformPaletteRange() {
 	byte startColor = getNextByte();
 	byte numColor = getNextByte();
-	uint16 r = getNextWord();
-	uint16 g = getNextWord();
-	uint16 b = getNextWord();
+	int16 r = getNextWord();
+	int16 g = getNextWord();
+	int16 b = getNextWord();
 
 	debugC(5, kCineDebugScript, "Line: %d: transformPaletteRange(from:%d,numIdx:%d,r:%d,g:%d,b:%d)", _line, startColor, numColor, r, g, b);
 
-	transformPaletteRange(startColor, numColor, r, g, b);
+	renderer->transformPalette(startColor, numColor, r, g, b);
 	return 0;
 }
 
@@ -1387,7 +1380,8 @@
 	byte param = getNextByte();
 
 	debugC(5, kCineDebugScript, "Line: %d: setDefaultMenuColor2(%d)", _line, param);
-	defaultMenuBoxColor2 = param;
+
+	renderer->_messageBg = param;
 	return 0;
 }
 
@@ -1397,7 +1391,8 @@
 	byte c = getNextByte();
 
 	debugC(5, kCineDebugScript, "Line: %d: palRotate(%d,%d,%d)", _line, a, b, c);
-	palRotate(a, b, c);
+
+	renderer->rotatePalette(a, b, c);
 	return 0;
 }
 
@@ -1475,11 +1470,7 @@
 
 		debugC(5, kCineDebugScript, "Line: %d: compare globalVars[%d] and %d", _line, varIdx, value);
 
-		if (varIdx == 255 && (g_cine->getGameType() == Cine::GType_FW)) {	// TODO: fix
-			_compare = 1;
-		} else {
-			_compare = compareVars(_globalVars[varIdx], value);
-		}
+		_compare = compareVars(_globalVars[varIdx], value);
 	}
 
 	return 0;
@@ -1558,7 +1549,8 @@
 	byte param = getNextByte();
 
 	debugC(5, kCineDebugScript, "Line: %d: setDefaultMenuColor(%d)", _line, param);
-	defaultMenuBoxColor = param;
+
+	renderer->_cmdY = param;
 	return 0;
 }
 
@@ -1728,18 +1720,6 @@
 
 //-----------------------------------------------------------------------
 
-void palRotate(byte a, byte b, byte c) {
-	if (c == 1) {
-		uint16 currentColor = c_palette[b];
-
-		for (int16 i = b; i > a; i--) {
-			c_palette[i] = c_palette[i - 1];
-		}
-
-		c_palette[a] = currentColor;
-	}
-}
-
 void addScriptToList0(uint16 idx) {
 	ScriptPtr tmp(scriptInfo->create(*scriptTable[idx], idx));
 	assert(tmp);
@@ -1863,14 +1843,13 @@
 	}
 }
 
-void decompileScript(byte *scriptPtr, int16 *stackPtr, uint16 scriptSize, uint16 scriptIdx) {
+void decompileScript(const byte *scriptPtr, uint16 scriptSize, uint16 scriptIdx) {
 	char lineBuffer[256];
-	byte *localScriptPtr = scriptPtr;
+	const byte *localScriptPtr = scriptPtr;
 	uint16 exitScript;
 	uint32 position = 0;
 
 	assert(scriptPtr);
-	// assert(stackPtr);
 
 	exitScript = 0;
 
@@ -2292,7 +2271,7 @@
 					sprintf(lineBuffer, "loadPart(%s)\n", localScriptPtr + position);
 				}
 
-				position += strlen((char *)localScriptPtr + position) + 1;
+				position += strlen((const char *)localScriptPtr + position) + 1;
 				break;
 			}
 		case 0x40:
@@ -2309,7 +2288,7 @@
 
 				sprintf(lineBuffer, "loadPrc(%d,%s)\n", param, localScriptPtr + position);
 
-				position += strlen((char *)localScriptPtr + position) + 1;
+				position += strlen((const char *)localScriptPtr + position) + 1;
 				break;
 			}
 		case OP_requestCheckPendingDataLoad:	// nop
@@ -2461,7 +2440,7 @@
 			{
 				sprintf(lineBuffer, "comment: %s\n", localScriptPtr + position);
 
-				position += strlen((char *)localScriptPtr + position);
+				position += strlen((const char *)localScriptPtr + position);
 				break;
 			}
 		case 0x5A:
@@ -2540,7 +2519,7 @@
 			{
 				sprintf(lineBuffer, "loadDat(%s)\n", localScriptPtr + position);
 
-				position += strlen((char *)localScriptPtr + position) + 1;
+				position += strlen((const char *)localScriptPtr + position) + 1;
 				break;
 			}
 		case 0x6E:	// nop
@@ -2801,7 +2780,7 @@
 
 				sprintf(lineBuffer, "ADDBG(%d,%s)\n", param1, localScriptPtr + position);
 
-				position += strlen((char *)localScriptPtr + position);
+				position += strlen((const char *)localScriptPtr + position);
 
 				break;
 			}
@@ -2825,7 +2804,7 @@
 
 				sprintf(lineBuffer, "loadABS(%d,%s)\n", param1, localScriptPtr + position);
 
-				position += strlen((char *)localScriptPtr + position);
+				position += strlen((const char *)localScriptPtr + position);
 
 				break;
 			}

Modified: scummvm/trunk/engines/cine/script_os.cpp
===================================================================
--- scummvm/trunk/engines/cine/script_os.cpp	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/script_os.cpp	2008-05-24 22:11:41 UTC (rev 32257)
@@ -116,7 +116,7 @@
 	{ &FWScript::o1_loadAnim, "s" },
 	/* 3C */
 	{ &FWScript::o1_loadBg, "s" },
-	{ &FWScript::o1_loadCt, "s" },
+	{ &FWScript::o2_loadCt, "s" },
 	{ 0, 0 },
 	{ &FWScript::o2_loadPart, "s" },
 	/* 40 */
@@ -365,6 +365,14 @@
 // OPERATION STEALTH opcodes
 // ------------------------------------------------------------------------
 
+int FWScript::o2_loadCt() {
+	const char *param = getNextString();
+
+	debugC(5, kCineDebugScript, "Line: %d: loadCt(\"%s\")", _line, param);
+	loadCtOS(param);
+	return 0;
+}
+
 int FWScript::o2_loadPart() {
 	const char *param = getNextString();
 
@@ -615,20 +623,7 @@
 
 	debugC(5, kCineDebugScript, "Line: %d: removeBackground(%d)", _line, param);
 
-	if (additionalBgTable[param]) {
-		free(additionalBgTable[param]);
-		additionalBgTable[param] = NULL;
-	}
-
-	if (currentAdditionalBgIdx == param) {
-		currentAdditionalBgIdx = 0;
-	}
-
-	if (currentAdditionalBgIdx2 == param) {
-		currentAdditionalBgIdx2 = 0;
-	}
-
-	strcpy(currentBgName[param], "");
+	renderer->removeBg(param);
 	return 0;
 }
 
@@ -644,22 +639,11 @@
 int FWScript::o2_loadBg() {
 	byte param = getNextByte();
 
-	assert(param <= 8);
+	assert(param < 9);
 
 	debugC(5, kCineDebugScript, "Line: %d: useBg(%d)", _line, param);
 
-	if (additionalBgTable[param]) {
-		currentAdditionalBgIdx = param;
-		if (param == 8) {
-			newColorMode = 3;
-		} else {
-			newColorMode = bgColorMode + 1;
-		}
-		//if (_screenNeedFadeOut == 0) {
-		//	adBgVar1 = 1;
-		//}
-		fadeRequired = true;
-	}
+	renderer->selectBg(param);
 	return 0;
 }
 
@@ -699,13 +683,11 @@
 int FWScript::o2_useBgScroll() {
 	byte param = getNextByte();
 
-	assert(param <= 8);
+	assert(param < 9);
 
 	debugC(5, kCineDebugScript, "Line: %d: useBgScroll(%d)", _line, param);
 
-	if (additionalBgTable[param]) {
-		currentAdditionalBgIdx2 = param;
-	}
+	renderer->selectScrollBg(param);
 	return 0;
 }
 
@@ -716,12 +698,12 @@
 		byte param2 = getNextByte();
 
 		debugC(5, kCineDebugScript, "Line: %d: additionalBgVScroll = var[%d]", _line, param2);
-		additionalBgVScroll = _localVars[param2];
+		renderer->setScroll(_localVars[param2]);
 	} else {
 		uint16 param2 = getNextWord();
 
 		debugC(5, kCineDebugScript, "Line: %d: additionalBgVScroll = %d", _line, param2);
-		additionalBgVScroll = param2;
+		renderer->setScroll(param2);
 	}
 	return 0;
 }

Modified: scummvm/trunk/engines/cine/texte.cpp
===================================================================
--- scummvm/trunk/engines/cine/texte.cpp	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/texte.cpp	2008-05-24 22:11:41 UTC (rev 32257)
@@ -611,65 +611,49 @@
 	fontParamTable = 0;
 }
 
-uint16 computeMessageLength(const byte *ptr, uint16 width, uint16 *numWords, uint16 *messageWidth, uint16 *lineResult) {
-	const byte *localPtr = ptr;
+/*! \brief Fit a substring of text into one line of fixed width text box
+ * \param str Text to fit
+ * \param maxWidth Text box width
+ * \param[out] words Number of words that fit
+ * \param[out] width Total width of nonblank characters that fit
+ * \return Length of substring which fits
+ */
+int fitLine(const char *str, int maxWidth, int &words, int &width) {
+	int i, bkpWords = 0, bkpWidth = 0, bkpLen = 0;
+	int charWidth = 0, fullWidth = 0;
 
-	uint16 var_2 = 0;
-	uint16 localLineResult = 0;
-	uint16 var_6 = 0;
-	uint16 var_8 = 0;
-	uint16 localMessageWidth = 0;
-	uint16 var_16 = 0;
-	uint16 finished = 0;
-	uint16 si = 0;
-	uint16 di = 0;
+	words = 0;
+	width = 0;
 
-	while (!finished) {
-		byte character = *(localPtr++);
-
-		if (character == ' ') {
-			var_8 = var_16;
-			var_6 = localMessageWidth;
-			localLineResult = si;
-			var_2 = di;
-
-			if (si + 5 < width) {
-				var_16++;
-				si += 5;
-			} else {
-				finished = 1;
-			}
-		} else if (character == 0x7C || character == 0) {
-			finished = 1;
-			si = 0;
+	for (i = 0; str[i]; i++) {
+		if (str[i] == 0x7C) {
+			i++;
+			break;
+		} else if (str[i] == ' ') {
+			charWidth = 5;
+			bkpWords = words++;
+			bkpWidth = width;
+			bkpLen = i + 1;
 		} else {
-			if (fontParamTable[character].characterWidth) {
-				uint16 var_C = fontParamTable[character].characterWidth + 1;
+			charWidth = fontParamTable[str[i]].characterWidth + 1;
+			width += charWidth;
+		}
 
-				if (si + var_C < width) {
-					si += var_C;
-					localMessageWidth += var_C;
-				} else {
-					finished = 1;
-
-					if (localLineResult) {
-						var_16 = var_8;
-						localMessageWidth = var_6;
-						si = localLineResult;
-						di = var_2;
-					}
-				}
-			}
+		if (!charWidth) {
+			continue;
 		}
 
-		di++;
+		if (fullWidth + charWidth < maxWidth) {
+			fullWidth += charWidth;
+		} else if (fullWidth) {
+			words = bkpWords;
+			width = bkpWidth;
+			i = bkpLen;
+			break;
+		}
 	}
 
-	*numWords = var_16;
-	*messageWidth = localMessageWidth;
-	*lineResult = si;
-
-	return di;
+	return i;
 }
 
 } // End of namespace Cine

Modified: scummvm/trunk/engines/cine/texte.h
===================================================================
--- scummvm/trunk/engines/cine/texte.h	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/texte.h	2008-05-24 22:11:41 UTC (rev 32257)
@@ -56,7 +56,7 @@
 void loadPoldatDat(const char *fname);
 void freePoldatDat(void);
 
-uint16 computeMessageLength(const byte *ptr, uint16 width, uint16 *numWords, uint16 *messageWidth, uint16 *lineResult);
+int fitLine(const char *ptr, int maxWidth, int &words, int &width);
 
 } // End of namespace Cine
 

Modified: scummvm/trunk/engines/cine/various.cpp
===================================================================
--- scummvm/trunk/engines/cine/various.cpp	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/various.cpp	2008-05-24 22:11:41 UTC (rev 32257)
@@ -87,7 +87,6 @@
 char newRelName[20];
 char newObjectName[20];
 char newMsgName[20];
-char currentBgName[8][15];
 char currentCtName[15];
 char currentPartName[15];
 char currentDatName[30];
@@ -96,8 +95,6 @@
 
 byte isInPause = 0;
 
-uint16 defaultMenuBoxColor;
-
 byte inputVar1 = 0;
 uint16 inputVar2 = 0, inputVar3 = 0;
 
@@ -114,7 +111,6 @@
 int16 objListTab[20];
 
 uint16 exitEngine;
-uint16 defaultMenuBoxColor2;
 uint16 zoneData[NUM_MAX_ZONE];
 
 
@@ -140,6 +136,7 @@
 	tmp.type = 3;
 
 	overlayList.push_back(tmp);
+	waitForPlayerClick = 1;
 }
 
 int16 getRelEntryForObject(uint16 param1, uint16 param2, SelectedObjStruct *pSelectedObject) {
@@ -393,11 +390,14 @@
 	return broken;
 }
 
+/*! \todo Implement Operation Stealth loading, this is obviously Future Wars only
+ */
 bool CineEngine::makeLoad(char *saveName) {
 	int16 i;
 	int16 size;
 	bool broken;
 	Common::InSaveFile *fHandle;
+	char bgName[13];
 
 	fHandle = g_saveFileMan->openForLoading(saveName);
 
@@ -440,7 +440,6 @@
 	strcpy(newRelName, "");
 	strcpy(newObjectName, "");
 	strcpy(newMsgName, "");
-	strcpy(currentBgName[0], "");
 	strcpy(currentCtName, "");
 
 	allowPlayerInput = 0;
@@ -455,9 +454,7 @@
 
 	fadeRequired = false;
 
-	for (i = 0; i < 16; i++) {
-		c_palette[i] = 0;
-	}
+	renderer->clear();
 
 	checkForPendingDataLoadSwitch = 0;
 
@@ -473,7 +470,7 @@
 	fHandle->read(currentPrcName, 13);
 	fHandle->read(currentRelName, 13);
 	fHandle->read(currentMsgName, 13);
-	fHandle->read(currentBgName[0], 13);
+	fHandle->read(bgName, 13);
 	fHandle->read(currentCtName, 13);
 
 	checkDataDisk(currentDisk);
@@ -490,12 +487,12 @@
 		loadRel(currentRelName);
 	}
 
-	if (strlen(currentBgName[0])) {
-		loadBg(currentBgName[0]);
+	if (strlen(bgName)) {
+		loadBg(bgName);
 	}
 
 	if (strlen(currentCtName)) {
-		loadCt(currentCtName);
+		loadCtFW(currentCtName);
 	}
 
 	fHandle->readUint16BE();
@@ -511,14 +508,8 @@
 		objectTable[i].part = fHandle->readUint16BE();
 	}
 
-	for (i = 0; i < 16; i++) {
-		c_palette[i] = fHandle->readUint16BE();
-	}
+	renderer->restorePalette(*fHandle);
 
-	for (i = 0; i < 16; i++) {
-		tempPalette[i] = fHandle->readUint16BE();
-	}
-
 	globalVars.load(*fHandle, NUM_MAX_VAR - 1);
 
 	for (i = 0; i < 16; i++) {
@@ -530,8 +521,10 @@
 	}
 
 	fHandle->read(commandBuffer, 0x50);
+	renderer->setCommand(commandBuffer);
 
-	defaultMenuBoxColor = fHandle->readUint16BE();
+	renderer->_cmdY = fHandle->readUint16BE();
+
 	bgVar0 = fHandle->readUint16BE();
 	allowPlayerInput = fHandle->readUint16BE();
 	playerCommand = fHandle->readSint16BE();
@@ -542,8 +535,9 @@
 	var3 = fHandle->readUint16BE();
 	var2 = fHandle->readUint16BE();
 	commandVar2 = fHandle->readSint16BE();
-	defaultMenuBoxColor2 = fHandle->readUint16BE();
 
+	renderer->_messageBg = fHandle->readUint16BE();
+
 	fHandle->readUint16BE();
 	fHandle->readUint16BE();
 
@@ -615,7 +609,7 @@
 	fHandle->write(currentPrcName, 13);
 	fHandle->write(currentRelName, 13);
 	fHandle->write(currentMsgName, 13);
-	fHandle->write(currentBgName[0], 13);
+	renderer->saveBg(*fHandle);
 	fHandle->write(currentCtName, 13);
 
 	fHandle->writeUint16BE(0xFF);
@@ -631,14 +625,8 @@
 		fHandle->writeUint16BE(objectTable[i].part);
 	}
 
-	for (i = 0; i < 16; i++) {
-		fHandle->writeUint16BE(c_palette[i]);
-	}
+	renderer->savePalette(*fHandle);
 
-	for (i = 0; i < 16; i++) {
-		fHandle->writeUint16BE(tempPalette[i]);
-	}
-
 	globalVars.save(*fHandle, NUM_MAX_VAR - 1);
 
 	for (i = 0; i < 16; i++) {
@@ -651,7 +639,8 @@
 
 	fHandle->write(commandBuffer, 0x50);
 
-	fHandle->writeUint16BE(defaultMenuBoxColor);
+	fHandle->writeUint16BE(renderer->_cmdY);
+
 	fHandle->writeUint16BE(bgVar0);
 	fHandle->writeUint16BE(allowPlayerInput);
 	fHandle->writeUint16BE(playerCommand);
@@ -662,8 +651,9 @@
 	fHandle->writeUint16BE(var3);
 	fHandle->writeUint16BE(var2);
 	fHandle->writeUint16BE(commandVar2);
-	fHandle->writeUint16BE(defaultMenuBoxColor2);
 
+	fHandle->writeUint16BE(renderer->_messageBg);
+
 	fHandle->writeUint16BE(0xFF);
 	fHandle->writeUint16BE(0x1E);
 
@@ -864,26 +854,6 @@
 	}
 }
 
-int drawChar(byte character, int16 x, int16 y) {
-	if (character == ' ') {
-		x += 5;
-	} else {
-		byte characterWidth = fontParamTable[character].characterWidth;
-
-		if (characterWidth) {
-			byte characterIdx = fontParamTable[character].characterIdx;
-			if (g_cine->getGameType() == Cine::GType_OS) {
-				drawSpriteRaw2(textTable[characterIdx][0], 0, 2, 8, page1Raw, x, y);
-			} else {
-				drawSpriteRaw(textTable[characterIdx][0], textTable[characterIdx][1], 2, 8, page1Raw, x, y);
-			}
-			x += characterWidth + 1;
-		}
-	}
-
-	return x;
-}
-
 void drawMessageBox(int16 x, int16 y, int16 width, int16 currentY, int16 offset, int16 color, byte* page) {
 	gfxDrawLine(x + offset, y + offset, x + width - offset, y + offset, color, page);	// top
 	gfxDrawLine(x + offset, currentY + 4 - offset, x + width - offset, currentY + 4 - offset, color, page);	// bottom
@@ -896,49 +866,6 @@
 	drawMessageBox(x, y, width, currentY, 0, color, page);
 }
 
-void makeTextEntry(const CommandeType commandList[], uint16 height, uint16 X, uint16 Y, uint16 width) {
-	byte color = 2;
-	byte color2 = defaultMenuBoxColor2;
-	int16 paramY = (height * 9) + 10;
-	int16 currentX, currentY;
-	int16 i;
-	uint16 j;
-	byte currentChar;
-
-	if (X + width > 319) {
-		X = 319 - width;
-	}
-
-	if (Y + paramY > 199) {
-		Y = 199 - paramY;
-	}
-
-	hideMouse();
-	blitRawScreen(page1Raw);
-
-	gfxDrawPlainBoxRaw(X, Y, X + width, Y + 4, color2, page1Raw);
-
-	currentX = X + 4;
-	currentY = Y + 4;
-
-	for (i = 0; i < height; i++) {
-		gfxDrawPlainBoxRaw(X, currentY, X + width, currentY + 9, color2, page1Raw);
-		currentX = X + 4;
-
-		for (j = 0; j < strlen(commandList[i]); j++) {
-			currentChar = commandList[i][j];
-			currentX = drawChar(currentChar, currentX, currentY);
-		}
-
-		currentY += 9;
-	}
-
-	gfxDrawPlainBoxRaw(X, currentY, X + width, currentY + 4, color2, page1Raw);	// bottom part
-	drawDoubleMessageBox(X, Y, width, currentY, color, page1Raw);
-
-	blitRawScreen(page1Raw);
-}
-
 void processInventory(int16 x, int16 y) {
 	int16 listSize = buildObjectListCommand(-2);
 	uint16 button;
@@ -946,7 +873,8 @@
 	if (!listSize)
 		return;
 
-	makeTextEntry(objectListCommand, listSize, x, y, 140);
+	renderer->drawMenu(objectListCommand, listSize, x, y, 140, -1);
+	renderer->blit();
 
 	do {
 		manageEvents();
@@ -1085,7 +1013,7 @@
 	}
 
 	if (!disableSystemMenu) {
-		isDrawCommandEnabled = 1;
+		renderer->setCommand(commandBuffer);
 	}
 }
 
@@ -1094,13 +1022,8 @@
 uint16 menuVar4 = 0;
 uint16 menuVar5 = 0;
 
-int16 makeMenuChoice(const CommandeType commandList[], uint16 height, uint16 X, uint16 Y,
-    uint16 width, bool recheckValue) {
-	byte color = 2;
-	byte color2 = defaultMenuBoxColor2;
+int16 makeMenuChoice(const CommandeType commandList[], uint16 height, uint16 X, uint16 Y, uint16 width, bool recheckValue) {
 	int16 paramY;
-	int16 currentX, currentY;
-	int16 i;
 	uint16 button;
 	int16 var_A;
 	int16 di;
@@ -1110,7 +1033,6 @@
 	int16 var_14;
 	int16 currentSelection, oldSelection;
 	int16 var_4;
-	byte currentChar;
 
 	if (disableSystemMenu)
 		return -1;
@@ -1125,31 +1047,9 @@
 		Y = 199 - paramY;
 	}
 
-	hideMouse();
-	blitRawScreen(page1Raw);
+	renderer->drawMenu(commandList, height, X, Y, width, -1);
+	renderer->blit();
 
-	gfxDrawPlainBoxRaw(X, Y, X + width, Y + 4, color2, page1Raw);
-
-	currentX = X + 4;
-	currentY = Y + 4;
-
-	for (i = 0; i < height; i++) {
-		gfxDrawPlainBoxRaw(X, currentY, X + width, currentY + 9, color2, page1Raw);
-		currentX = X + 4;
-
-		for (j = 0; j < strlen(commandList[i]); j++) {
-			currentChar = commandList[i][j];
-			currentX = drawChar(currentChar, currentX, currentY);
-		}
-
-		currentY += 9;
-	}
-
-	gfxDrawPlainBoxRaw(X, currentY, X + width, currentY + 4, color2, page1Raw);	// bottom part
-	drawDoubleMessageBox(X, Y, width, currentY, color, page1Raw);
-
-	blitRawScreen(page1Raw);
-
 	do {
 		manageEvents();
 		getMouseData(mouseUpdateStatus, &button, &dummyU16, &dummyU16);
@@ -1160,16 +1060,10 @@
 	currentSelection = 0;
 
 	di = currentSelection * 9 + Y + 4;
-	gfxDrawPlainBoxRaw(X + 2, di - 1, X + width - 2, di + 7, 0, page1Raw);	// draw black box behind selection
-	currentX = X + 4;
 
-	for (j = 0; j < strlen(commandList[currentSelection]); j++) {
-		currentChar = commandList[currentSelection][j];
-		currentX = drawChar(currentChar, currentX, di);
-	}
+	renderer->drawMenu(commandList, height, X, Y, width, currentSelection);
+	renderer->blit();
 
-	blitRawScreen(page1Raw);
-
 	manageEvents();
 	getMouseData(mouseUpdateStatus, &button, (uint16 *)&mouseX, (uint16 *)&mouseY);
 
@@ -1219,30 +1113,11 @@
 				hideMouse();
 			}
 
-			di = oldSelection * 9 + Y + 4;
-
-			gfxDrawPlainBoxRaw(X + 2, di - 1, X + width - 2, di + 7, color2, page1Raw);	// restore color
-
-			currentX = X + 4;
-
-			for (j = 0; j < strlen(commandList[oldSelection]); j++) {
-				currentChar = commandList[oldSelection][j];
-				currentX = drawChar(currentChar, currentX, di);
-			}
-
 			di = currentSelection * 9 + Y + 4;
 
-			gfxDrawPlainBoxRaw(X + 2, di - 1, X + width - 2, di + 7, 0, page1Raw);	// black new
+			renderer->drawMenu(commandList, height, X, Y, width, currentSelection);
+			renderer->blit();
 
-			currentX = X + 4;
-
-			for (j = 0; j < strlen(commandList[currentSelection]); j++) {
-				currentChar = commandList[currentSelection][j];
-				currentX = drawChar(currentChar, currentX, di);
-			}
-
-			blitRawScreen(page1Raw);
-
 //			if (needMouseSave) {
 //				gfxRedrawMouseCursor();
 //			}
@@ -1271,38 +1146,6 @@
 	return currentSelection;
 }
 
-void drawMenuBox(char *command, int16 x, int16 y) {
-	byte j;
-	byte lColor = 2;
-
-	hideMouse();
-
-	gfxDrawPlainBoxRaw(x, y, x + 300, y + 10, 0, page2Raw);
-
-	drawMessageBox(x, y, 300, y + 6, -1, lColor, page2Raw);
-
-	x += 2;
-	y += 2;
-
-	for (j = 0; j < strlen(command); j++) {
-		byte currentChar = command[j];
-
-		if (currentChar == ' ') {
-			x += 5;
-		} else {
-			byte characterWidth = fontParamTable[currentChar].characterWidth;
-
-			if (characterWidth) {
-				byte characterIdx = fontParamTable[currentChar].characterIdx;
-				drawSpriteRaw(textTable[characterIdx][0], textTable[characterIdx][1], 2, 8, page2Raw, x, y);
-				x += characterWidth + 1;
-			}
-		}
-	}
-
-//	gfxRedrawMouseCursor();
-}
-
 void makeActionMenu(void) {
 	uint16 mouseButton;
 	uint16 mouseX;
@@ -1342,11 +1185,6 @@
 	}
 
 	if (allowPlayerInput) {
-		if (isDrawCommandEnabled) {
-			drawMenuBox(commandBuffer, 10, defaultMenuBoxColor);
-			isDrawCommandEnabled = 0;
-		}
-
 		getMouseData(mouseUpdateStatus, &mouseButton, &mouseX, &mouseY);
 
 		while (mouseButton && currentEntry < 200) {
@@ -1393,7 +1231,6 @@
 						if (choiceResultTable[playerCommand] == commandVar1) {
 							int16 relEntry;
 
-							drawMenuBox(commandBuffer, 10, defaultMenuBoxColor);
 							SelectedObjStruct obj;
 							obj.idx = commandVar3[0];
 							obj.param = commandVar3[1];
@@ -1410,41 +1247,40 @@
 
 							commandVar1 = 0;
 							strcpy(commandBuffer, "");
+							renderer->setCommand("");
 						}
 					} else {
 						globalVars[VAR_MOUSE_X_POS] = mouseX;
 						globalVars[VAR_MOUSE_Y_POS] = mouseY;
 					}
 				}
+			} else if (mouseButton & 2) {
+				if (mouseButton & 1) {
+					g_cine->makeSystemMenu();
+				}
+
+				makeActionMenu();
+				makeCommandLine();
 			} else {
-				if (mouseButton & 2) {
-					if (mouseButton & 1) {
-						g_cine->makeSystemMenu();
-					}
+				int16 objIdx;
 
-					makeActionMenu();
-					makeCommandLine();
-				} else {
-					int16 objIdx;
+				objIdx = getObjectUnderCursor(mouseX, mouseY);
 
-					objIdx = getObjectUnderCursor(mouseX, mouseY);
+				if (commandVar2 != objIdx) {
+					if (objIdx != -1) {
+						char command[256];
 
-					if (commandVar2 != objIdx) {
-						if (objIdx != -1) {
-							char command[256];
+						strcpy(command, commandBuffer);
+						strcat(command, " ");
+						strcat(command, objectTable[objIdx].name);
 
-							strcpy(command, commandBuffer);
-							strcat(command, " ");
-							strcat(command, objectTable[objIdx].name);
-
-							drawMenuBox(command, 10, defaultMenuBoxColor);
-						} else {
-							isDrawCommandEnabled = 1;
-						}
+						renderer->setCommand(command);
+					} else {
+						isDrawCommandEnabled = 1;
 					}
-
-					commandVar2 = objIdx;
 				}
+
+				commandVar2 = objIdx;
 			}
 		} else {
 			if (mouseButton & 2) {
@@ -1653,257 +1489,9 @@
 	free(msk);
 }
 
-int16 additionalBgVScroll = 0;
-
-void backupOverlayPage(void) {
-	byte *scrollBg;
-	byte *bgPage = additionalBgTable[currentAdditionalBgIdx];
-
-	if (bgPage) {
-		if (!additionalBgVScroll) {
-			memcpy(page1Raw, bgPage, 320 * 200);
-		} else {
-			scrollBg = additionalBgTable[currentAdditionalBgIdx2];
-
-			for (int16 i = additionalBgVScroll; i < 200 + additionalBgVScroll; i++) {
-				if (i > 200) {
-					memcpy(page1Raw + (i - additionalBgVScroll) * 320, scrollBg + (i - 200) * 320, 320);
-				} else {
-					memcpy(page1Raw + (i - additionalBgVScroll) * 320, bgPage + (i-1) * 320, 320);
-				}
-			}
-		}
-	}
-}
-
-void drawMessage(const char *messagePtr, int16 x, int16 y, int16 width, int16 color) {
-	byte color2 = 2;
-	byte endOfMessageReached = 0;
-	int16 localX, localY, localWidth;
-	uint16 messageLength = 0, numWords = 0, messageWidth = 0;
-	uint16 lineResult, fullLineWidth;
-	uint16 interWordSize, interWordSizeRemain;
-	const char *endOfMessagePtr;
-	byte currentChar; //, characterWidth;
-
-	gfxDrawPlainBoxRaw(x, y, x + width, y + 4, color, page1Raw);
-
-	localX = x + 4;
-	localY = y + 4;
-	localWidth = width - 8;
-
-	do {
-		messageLength = 0;
-
-		while (messagePtr[messageLength] == ' ') {
-			messageLength++;
-		}
-
-		messagePtr += messageLength;
-
-		messageLength = computeMessageLength((const byte *)messagePtr, localWidth, &numWords, &messageWidth, &lineResult);
-
-		endOfMessagePtr = messagePtr + messageLength;
-
-		if (lineResult) {
-			fullLineWidth = localWidth - messageWidth;
-
-			if (numWords) {
-				interWordSize = fullLineWidth / numWords;
-				interWordSizeRemain = fullLineWidth % numWords;
-			} else {
-				interWordSize = 5;
-				interWordSizeRemain = 0;
-			}
-		} else {
-			interWordSize = 5;
-			interWordSizeRemain = 0;
-		}
-
-		gfxDrawPlainBoxRaw(x, localY, x + width, localY + 9, color, page1Raw);
-
-		do {
-			currentChar = *(messagePtr++);
-
-			if (currentChar == 0) {
-				endOfMessageReached = 1;
-			} else if (currentChar == ' ') {
-				localX += interWordSizeRemain + interWordSize;
-
-				if (interWordSizeRemain)
-					interWordSizeRemain = 0;
-			} else {
-				localX = drawChar(currentChar, localX, localY);
-			}
-		} while ((messagePtr < endOfMessagePtr) && !endOfMessageReached);
-
-		localX = x + 4;
-		localY += 9;
-	} while (!endOfMessageReached);
-
-	gfxDrawPlainBoxRaw(x, localY, x + width, localY + 4, color, page1Raw);
-
-	drawDoubleMessageBox(x, y, width, localY, color2, page1Raw);
-}
-
-void drawDialogueMessage(byte msgIdx, int16 x, int16 y, int16 width, int16 color) {
-	if (msgIdx >= messageTable.size()) {
-//		removeOverlay(msgIdx, 2);
-		return;
-	}
-
-	_messageLen += messageTable[msgIdx].size();
-	drawMessage(messageTable[msgIdx].c_str(), x, y, width, color);
-
-	// this invalidates the iterator in drawOverlays()
-//	removeOverlay(msgIdx, 2);
-}
-
-void drawFailureMessage(byte cmd) {
-	byte msgIdx = cmd * 4 + g_cine->_rnd.getRandomNumber(3);
-
-	const char *messagePtr = failureMessages[msgIdx];
-	int len = strlen(messagePtr);
-
-	_messageLen += len;
-
-	int16 width = 6 * len + 20;
-
-	if (width > 300)
-		width = 300;
-
-	int16 x = (320 - width) / 2;
-	int16 y = 80;
-	int16 color = 4;
-
-	drawMessage(messagePtr, x, y, width, color);
-
-	// this invalidates the iterator in drawOverlays()
-//	removeOverlay(cmd, 3);
-}
-
-void drawOverlays(void) {
-	uint16 width, height;
-	AnimData *pPart;
-	int16 x, y;
-	objectStruct *objPtr;
-	byte messageIdx;
+void removeMessages() {
 	Common::List<overlay>::iterator it;
 
-	backupOverlayPage();
-
-	_messageLen = 0;
-
-	for (it = overlayList.begin(); it != overlayList.end(); ++it) {
-		switch (it->type) {
-		case 0: // sprite
-			assert(it->objIdx < NUM_MAX_OBJECT);
-
-			objPtr = &objectTable[it->objIdx];
-			x = objPtr->x;
-			y = objPtr->y;
-
-			if (objPtr->frame < 0) {
-				continue;
-			}
-
-			pPart = &animDataTable[objPtr->frame];
-			width = pPart->_realWidth;
-			height = pPart->_height;
-
-			if (!pPart->data()) {
-				continue;
-			}
-
-			// drawSprite ignores masks of Operation Stealth sprites
-			drawSprite(it, pPart->data(), pPart->mask(), width, height, page1Raw, x, y);
-			break;
-
-		case 2:	// text
-			// gfxWaitVSync();
-			// hideMouse();
-
-			messageIdx = it->objIdx;
-			x = it->x;
-			y = it->y;
-			width = it->width;
-			height = it->color;
-
-			blitRawScreen(page1Raw);
-
-			drawDialogueMessage(messageIdx, x, y, width, height);
-
-			// blitScreen(page0, NULL);
-			// gfxRedrawMouseCursor();
-
-			waitForPlayerClick = 1;
-
-			break;
-
-		case 3:
-			// gfxWaitSync()
-			// hideMouse();
-
-			blitRawScreen(page1Raw);
-
-			drawFailureMessage(it->objIdx);
-
-			// blitScreen(page0, NULL);
-			// gfxRedrawMouseCursor();
-
-			waitForPlayerClick = 1;
-
-			break;
-
-		case 4:
-			assert(it->objIdx < NUM_MAX_OBJECT);
-
-			objPtr = &objectTable[it->objIdx];
-			x = objPtr->x;
-			y = objPtr->y;
-
-			if (objPtr->frame < 0) {
-				continue;
-			}
-
-			assert(objPtr->frame < NUM_MAX_ANIMDATA);
-
-			pPart = &animDataTable[objPtr->frame];
-
-			width = pPart->_realWidth;
-			height = pPart->_height;
-
-			if (!pPart->data()) {
-				continue;
-			}
-
-			gfxFillSprite(pPart->data(), width, height, page1Raw, x, y);
-			break;
-
-		case 20:
-			assert(it->objIdx < NUM_MAX_OBJECT);
-
-			objPtr = &objectTable[it->objIdx];
-			x = objPtr->x;
-			y = objPtr->y;
-			var5 = it->x;
-
-			if (objPtr->frame < 0 || var5 > 8 || !additionalBgTable[var5] || animDataTable[objPtr->frame]._bpp != 1) {
-				continue;
-			}
-
-			width = animDataTable[objPtr->frame]._realWidth;
-			height = animDataTable[objPtr->frame]._height;
-
-			if (!animDataTable[objPtr->frame].data()) {
-				continue;
-			}
-
-			maskBgOverlay(additionalBgTable[var5], animDataTable[objPtr->frame].data(), width, height, page1Raw, x, y);
-			break;
-		}
-	}
-
 	for (it = overlayList.begin(); it != overlayList.end(); ) {
 		if (it->type == 2 || it->type == 3) {
 			it = overlayList.erase(it);
@@ -1978,115 +1566,96 @@
 	tmp.color = param5;
 
 	overlayList.push_back(tmp);
+	waitForPlayerClick = 1;
 }
 
-SeqListElement seqList;
+Common::List<SeqListElement> seqList;
 
 void removeSeq(uint16 param1, uint16 param2, uint16 param3) {
-	SeqListElement *currentHead = &seqList;
-	SeqListElement *tempHead = currentHead;
+	Common::List<SeqListElement>::iterator it;
 
-	while (currentHead && (currentHead->var6 != param1 || currentHead->var4 != param2 || currentHead->varE != param3)) {
-		tempHead = currentHead;
-		currentHead = tempHead->next;
+	for (it = seqList.begin(); it != seqList.end(); ++it) {
+		if (it->objIdx == param1 && it->var4 == param2 && it->varE == param3) {
+			it->var4 = -1;
+			break;
+		}
 	}
-
-	if (currentHead && currentHead->var6 == param1 && currentHead->var4 == param2 && currentHead->varE == param3) {
-		currentHead->var4 = -1;
-	}
 }
 
 uint16 isSeqRunning(uint16 param1, uint16 param2, uint16 param3) {
-	SeqListElement *currentHead = &seqList;
-	SeqListElement *tempHead = currentHead;
+	Common::List<SeqListElement>::iterator it;
 
-	while (currentHead && (currentHead->var6 != param1 || currentHead->var4 != param2 || currentHead->varE != param3)) {
-		tempHead = currentHead;
-		currentHead = tempHead->next;
+	for (it = seqList.begin(); it != seqList.end(); ++it) {
+		if (it->objIdx == param1 && it->var4 == param2 && it->varE == param3) {
+			return 1;
+		}
 	}
 
-	if (currentHead && currentHead->var6 == param1 && currentHead->var4 == param2 && currentHead->varE == param3) {
-		return 1;
-	}
-
 	return 0;
 }
 
-void addSeqListElement(int16 param0, int16 param1, int16 param2, int16 param3, int16 param4, int16 param5, int16 param6, int16 param7, int16 param8) {
-	SeqListElement *currentHead = &seqList;
-	SeqListElement *tempHead = currentHead;
-	SeqListElement *newElement;
+void addSeqListElement(uint16 objIdx, int16 param1, int16 param2, int16 frame, int16 param4, int16 param5, int16 param6, int16 param7, int16 param8) {
+	Common::List<SeqListElement>::iterator it;
+	SeqListElement tmp;
 
-	currentHead = tempHead->next;
+	for (it = seqList.begin(); it != seqList.end() && it->varE < param7; ++it) ;
 
-	while (currentHead && currentHead->varE < param7) {
-		tempHead = currentHead;
-		currentHead = tempHead->next;
-	}
+	tmp.objIdx = objIdx;
+	tmp.var4 = param1;
+	tmp.var8 = param2;
+	tmp.frame = frame;
+	tmp.varC = param4;
+	tmp.var14 = 0;
+	tmp.var16 = 0;
+	tmp.var18 = param5;
+	tmp.var1A = param6;
+	tmp.varE = param7;
+	tmp.var10 = param8;
+	tmp.var12 = param8;
+	tmp.var1C = 0;
+	tmp.var1E = 0;
 
-	newElement = new SeqListElement;
-
-	newElement->next = tempHead->next;
-	tempHead->next = newElement;
-
-	newElement->var6 = param0;
-	newElement->var4 = param1;
-	newElement->var8 = param2;
-	newElement->varA = param3;
-	newElement->varC = param4;
-	newElement->var14 = 0;
-	newElement->var16 = 0;
-	newElement->var18 = param5;
-	newElement->var1A = param6;
-	newElement->varE = param7;
-	newElement->var10 = param8;
-	newElement->var12 = param8;
-	newElement->var1C = 0;
-	newElement->var1E = 0;
+	seqList.insert(it, tmp);
 }
 
-void resetSeqList() {
-	seqList.next = NULL;
-}
-
-void computeMove1(SeqListElement *element, int16 x, int16 y, int16 param1,
+void computeMove1(SeqListElement &element, int16 x, int16 y, int16 param1,
     int16 param2, int16 x2, int16 y2) {
-	element->var16 = 0;
-	element->var14 = 0;
+	element.var16 = 0;
+	element.var14 = 0;
 
 	if (y2) {
 		if (y - param2 > y2) {
-			element->var16 = 2;
+			element.var16 = 2;
 		}
 
 		if (y + param2 < y2) {
-			element->var16 = 1;
+			element.var16 = 1;
 		}
 	}
 
 	if (x2) {
 		if (x - param1 > x2) {
-			element->var14 = 2;
+			element.var14 = 2;
 		}
 
 		if (x + param1 < x2) {
-			element->var14 = 1;
+			element.var14 = 1;
 		}
 	}
 }
 
-uint16 computeMove2(SeqListElement *element) {
+uint16 computeMove2(SeqListElement &element) {
 	int16 returnVar = 0;
 
-	if (element->var16 == 1) {
+	if (element.var16 == 1) {
 		returnVar = 4;
-	} else if (element->var16 == 2) {
+	} else if (element.var16 == 2) {
 		returnVar = 3;
 	}
 
-	if (element->var14 == 1) {
+	if (element.var14 == 1) {
 		returnVar = 1;
-	} else if (element->var14 == 2) {
+	} else if (element.var14 == 2) {
 		returnVar = 2;
 	}
 
@@ -2165,14 +1734,13 @@
 #endif
 }
 
-uint16 addAni(uint16 param1, uint16 param2, const byte *ptr, SeqListElement *element, uint16 param3, int16 *param4) {
+uint16 addAni(uint16 param1, uint16 objIdx, const byte *ptr, SeqListElement &element, uint16 param3, int16 *param4) {
 	const byte *currentPtr = ptr;
 	const byte *ptrData;
 	const byte *ptr2;
 	int16 di;
 
 	assert(ptr);
-	assert(element);
 	assert(param4);
 
 	dummyU16 = READ_BE_UINT16((currentPtr + param1 * 2) + 8);
@@ -2181,25 +1749,25 @@
 
 	assert(*ptrData);
 
-	di = (objectTable[param2].costume + 1) % (*ptrData);
+	di = (objectTable[objIdx].costume + 1) % (*ptrData);
 	ptr2 = (ptrData + (di * 8)) + 1;
 
-	if ((checkCollision(param2, ptr2[0], ptr2[1], ptr2[2], ptr[0]) & 1)) {
+	if ((checkCollision(objIdx, ptr2[0], ptr2[1], ptr2[2], ptr[0]) & 1)) {
 		return 0;
 	}
 
-	objectTable[param2].x += (int8)ptr2[4];
-	objectTable[param2].y += (int8)ptr2[5];
-	objectTable[param2].mask += (int8)ptr2[6];
+	objectTable[objIdx].x += (int8)ptr2[4];
+	objectTable[objIdx].y += (int8)ptr2[5];
+	objectTable[objIdx].mask += (int8)ptr2[6];
 
-	if (objectTable[param2].frame) {
-		resetGfxEntityEntry(param2);
+	if (objectTable[objIdx].frame) {
+		resetGfxEntityEntry(objIdx);
 	}
 
-	objectTable[param2].frame = ptr2[7] + element->var8;
+	objectTable[objIdx].frame = ptr2[7] + element.var8;
 
-	if (param3 || !element->var14) {
-		objectTable[param2].costume = di;
+	if (param3 || !element.var14) {
+		objectTable[objIdx].costume = di;
 	} else {
 		*param4 = di;
 	}
@@ -2207,86 +1775,86 @@
 	return 1;
 }
 
-void processSeqListElement(SeqListElement *element) {
-	int16 x = objectTable[element->var6].x;
-	int16 y = objectTable[element->var6].y;
-	const byte *ptr1 = animDataTable[element->varA].data();
+void processSeqListElement(SeqListElement &element) {
+	int16 x = objectTable[element.objIdx].x;
+	int16 y = objectTable[element.objIdx].y;
+	const byte *ptr1 = animDataTable[element.frame].data();
 	int16 var_10;
 	int16 var_4;
 	int16 var_2;
 
-	if (element->var12 < element->var10) {
-		element->var12++;
+	if (element.var12 < element.var10) {
+		element.var12++;
 		return;
 	}
 
-	element->var12 = 0;
+	element.var12 = 0;
 
 	if (ptr1) {
 		uint16 param1 = ptr1[1];
 		uint16 param2 = ptr1[2];
 
-		if (element->varC != 255) {
+		if (element.varC != 255) {
 			// FIXME: Why is this here? Fingolfin gets lots of these
 			// in his copy of Operation Stealth (value 0 or 236) under
 			// Mac OS X. Maybe it's a endian issue? At least the graphics
 			// in the copy protection screen are partially messed up.
-			warning("processSeqListElement: varC = %d", element->varC);
+			warning("processSeqListElement: varC = %d", element.varC);
 		}
 
 		if (globalVars[VAR_MOUSE_X_POS] || globalVars[VAR_MOUSE_Y_POS]) {
 			computeMove1(element, ptr1[4] + x, ptr1[5] + y, param1, param2, globalVars[VAR_MOUSE_X_POS], globalVars[VAR_MOUSE_Y_POS]);
 		} else {
-			element->var16 = 0;
-			element->var14 = 0;
+			element.var16 = 0;
+			element.var14 = 0;
 		}
 
 		var_10 = computeMove2(element);
 
 		if (var_10) {
-			element->var1C = var_10;
-			element->var1E = var_10;
+			element.var1C = var_10;
+			element.var1E = var_10;
 		}
 
 		var_4 = -1;
 
-		if ((element->var16 == 1
-			&& !addAni(3, element->var6, ptr1, element, 0, &var_4)) || (element->var16 == 2	&& !addAni(2, element->var6, ptr1, element, 0,
+		if ((element.var16 == 1
+			&& !addAni(3, element.objIdx, ptr1, element, 0, &var_4)) || (element.var16 == 2	&& !addAni(2, element.objIdx, ptr1, element, 0,
 			    &var_4))) {
-			if (element->varC == 255) {
+			if (element.varC == 255) {
 				globalVars[VAR_MOUSE_Y_POS] = 0;
 			}
 		}
 
-		if ((element->var14 == 1
-			&& !addAni(0, element->var6, ptr1, element, 1, &var_2))) {
-			if (element->varC == 255) {
+		if ((element.var14 == 1
+			&& !addAni(0, element.objIdx, ptr1, element, 1, &var_2))) {
+			if (element.varC == 255) {
 				globalVars[VAR_MOUSE_X_POS] = 0;
 
 				if (var_4 != -1) {
-					objectTable[element->var6].costume = var_4;
+					objectTable[element.objIdx].costume = var_4;
 				}
 			}
 		}
 
-		if ((element->var14 == 2 && !addAni(1, element->var6, ptr1, element, 1, &var_2))) {
-			if (element->varC == 255) {
+		if ((element.var14 == 2 && !addAni(1, element.objIdx, ptr1, element, 1, &var_2))) {
+			if (element.varC == 255) {
 				globalVars[VAR_MOUSE_X_POS] = 0;
 
 				if (var_4 != -1) {
-					objectTable[element->var6].costume = var_4;
+					objectTable[element.objIdx].costume = var_4;
 				}
 			}
 		}
 
-		if (element->var16 + element->var14) {
-			if (element->var1C) {
-				if (element->var1E) {
-					objectTable[element->var6].costume = 0;
-					element->var1E = 0;
+		if (element.var16 + element.var14) {
+			if (element.var1C) {
+				if (element.var1E) {
+					objectTable[element.objIdx].costume = 0;
+					element.var1E = 0;
 				}
 
-				addAni(element->var1C + 3, element->var6, ptr1, element, 1, (int16 *) & var2);
+				addAni(element.var1C + 3, element.objIdx, ptr1, element, 1, (int16 *) & var2);
 
 			}
 		}
@@ -2295,119 +1863,28 @@
 }
 
 void processSeqList(void) {
-	SeqListElement *currentHead = &seqList;
-	SeqListElement *tempHead = currentHead;
+	Common::List<SeqListElement>::iterator it;
 
-	currentHead = tempHead->next;
-
-	while (currentHead) {
-		if (currentHead->var4 != -1) {
-			processSeqListElement(currentHead);
+	for (it = seqList.begin(); it != seqList.end(); ++it) {
+		if (it->var4 == -1) {
+			continue;
 		}
 
-		tempHead = currentHead;
-		currentHead = tempHead->next;
+		processSeqListElement(*it);
 	}
 }
 
 
 bool makeTextEntryMenu(const char *messagePtr, char *inputString, int stringMaxLength, int y) {
-	int16 color = 2;
-	byte color2 = defaultMenuBoxColor2;
-	byte endOfMessageReached = 0;
-	int16 localX, localY, localWidth;
-	int margins = 16;
 	int len = strlen(messagePtr);
 	int16 width = 6 * len + 20;
-	uint16 messageLength = 0, numWords = 0, messageWidth = 0;
-	uint16 lineResult, fullLineWidth;
-	uint16 interWordSize, interWordSizeRemain;
-	const char *endOfMessagePtr;
-	byte currentChar, characterWidth;
 
 	width = CLIP((int)width, 180, 250);
 
 	int16 x = (320 - width) / 2;
 
-	gfxDrawPlainBoxRaw(x - margins, y, x + width + margins, y + 4, color2, page1Raw);
-
-	localX = x + 4;
-	localY = y + 4;
-	localWidth = width;
-
 	getKeyData(); // clear input key
 
-	do {
-		messageLength = 0;
-
-		while (messagePtr[messageLength] == ' ') {
-			messageLength++;
-		}
-
-		messagePtr += messageLength;
-
-		messageLength = computeMessageLength((const byte *)messagePtr, localWidth, &numWords, &messageWidth, &lineResult);
-
-		endOfMessagePtr = messagePtr + messageLength;
-
-		if (lineResult) {
-			fullLineWidth = localWidth - messageWidth;
-
-			if (numWords) {
-				interWordSize = fullLineWidth / numWords;
-				interWordSizeRemain = fullLineWidth % numWords;
-			} else {
-				interWordSize = 5;
-				interWordSizeRemain = 0;
-			}
-		} else {
-			interWordSize = 5;
-			interWordSizeRemain = 0;
-		}
-
-		gfxDrawPlainBoxRaw(x - margins, localY, x + width + margins, localY + 9, color2, page1Raw);
-
-		do {
-			currentChar = *(messagePtr++);
-
-			if (currentChar == 0) {
-				endOfMessageReached = 1;
-			} else if (currentChar == ' ') {
-				localX += interWordSizeRemain + interWordSize;
-
-				if (interWordSizeRemain)
-					interWordSizeRemain = 0;
-			} else {
-				characterWidth = fontParamTable[currentChar].characterWidth;
-
-				if (characterWidth) {
-					byte characterIdx = fontParamTable[currentChar].characterIdx;
-					drawSpriteRaw(textTable[characterIdx][0], textTable[characterIdx][1], 2, 8, page1Raw, localX, localY);
-					localX += characterWidth + 1;
-				}
-			}
-		} while ((messagePtr < endOfMessagePtr) && !endOfMessageReached);
-
-		localX = x + 4;
-		localY += 9;
-	} while (!endOfMessageReached);
-
-	// Input string
-	gfxDrawPlainBoxRaw(x - margins, localY, x + width + margins, localY + 9, color2, page1Raw);
-	localY += 9;
-
-	x -= margins;
-	width += margins * 2;
-
-	gfxDrawPlainBoxRaw(x, localY, x + width, localY + 4, color2, page1Raw);
-
-	drawDoubleMessageBox(x, y, width, localY, color, page1Raw);
-
-	x += margins;
-	width -= margins * 2;
-	localY -= 9;
-
-
 	int quit = 0;
 	bool redraw = true;
 	CommandeType tempString;
@@ -2416,24 +1893,8 @@
 
 	while (!quit) {
 		if (redraw) {
-			gfxDrawPlainBoxRaw(x, localY - 1, x + width, localY + 8, 0, page1Raw);
-
-			int currentX = x + 4;
-
-			for (uint j = 0; j < strlen(inputString); j++) {
-				currentChar = inputString[j];
-				currentX = drawChar(currentChar, currentX, localY);
-
-				// draw cursor here
-				if (inputPos == (int)(j + 2))
-					gfxDrawLine(currentX, localY - 1, currentX, localY + 8, color, page1Raw);
-
-			}
-
-			if (strlen(inputString) == 0 || inputPos == 1) // cursor wasn't yet drawn
-				gfxDrawLine(x + 4, localY - 1, x + 4, localY + 8, color, page1Raw);
-
-			blitRawScreen(page1Raw);
+			renderer->drawInputBox(messagePtr, inputString, inputPos, x - 16, y, width + 32);
+			renderer->blit();
 			redraw = false;
 		}
 

Modified: scummvm/trunk/engines/cine/various.h
===================================================================
--- scummvm/trunk/engines/cine/various.h	2008-05-24 21:23:06 UTC (rev 32256)
+++ scummvm/trunk/engines/cine/various.h	2008-05-24 22:11:41 UTC (rev 32257)
@@ -43,11 +43,10 @@
 extern bool inMenu;
 
 struct SeqListElement {
-	struct SeqListElement *next;
 	int16 var4;
-	int16 var6;
+	uint16 objIdx;
 	int16 var8;
-	int16 varA;
+	int16 frame;
 	int16 varC;
 	int16 varE;
 	int16 var10;
@@ -60,7 +59,7 @@
 	int16 var1E;
 };
 
-extern SeqListElement seqList;
+extern Common::List<SeqListElement> seqList;
 
 extern uint16 var2;
 extern uint16 var3;
@@ -97,7 +96,6 @@
 extern char newObjectName[20];
 extern char newMsgName[20];
 
-extern char currentBgName[8][15];
 extern char currentCtName[15];
 extern char currentPartName[15];
 
@@ -130,20 +128,16 @@
 	int16 param;
 };
 
-extern uint16 defaultMenuBoxColor;
-extern uint16 defaultMenuBoxColor2;
-
 #define NUM_MAX_ZONE 16
 extern uint16 zoneData[NUM_MAX_ZONE];
 
 void addMessage(byte param1, int16 param2, int16 param3, int16 param4, int16 param5);
 
-extern int16 additionalBgVScroll;
+void removeMessages();
 
 void removeSeq(uint16 param1, uint16 param2, uint16 param3);
 uint16 isSeqRunning(uint16 param1, uint16 param2, uint16 param3);

@@ Diff output truncated at 100000 characters. @@

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