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

lordhoto at users.sourceforge.net lordhoto at users.sourceforge.net
Tue Sep 22 19:51:06 CEST 2009


Revision: 44263
          http://scummvm.svn.sourceforge.net/scummvm/?rev=44263&view=rev
Author:   lordhoto
Date:     2009-09-22 17:51:06 +0000 (Tue, 22 Sep 2009)

Log Message:
-----------
Implement menu stack to support all menu color effects, specific to the Amiga version of the game.

Modified Paths:
--------------
    scummvm/trunk/engines/cine/gfx.cpp
    scummvm/trunk/engines/cine/gfx.h
    scummvm/trunk/engines/cine/various.cpp

Modified: scummvm/trunk/engines/cine/gfx.cpp
===================================================================
--- scummvm/trunk/engines/cine/gfx.cpp	2009-09-22 17:10:08 UTC (rev 44262)
+++ scummvm/trunk/engines/cine/gfx.cpp	2009-09-22 17:51:06 UTC (rev 44263)
@@ -92,7 +92,7 @@
  */
 FWRenderer::FWRenderer() : _background(NULL), _backupPal(), _cmd(""),
 	_cmdY(0), _messageBg(0), _backBuffer(new byte[_screenSize]),
-	_screenBackUp(0), _activePal(), _changePal(0), _showCollisionPage(false) {
+	_activePal(), _changePal(0), _showCollisionPage(false) {
 
 	assert(_backBuffer);
 
@@ -105,7 +105,6 @@
 FWRenderer::~FWRenderer() {
 	delete[] _background;
 	delete[] _backBuffer;
-	delete[] _screenBackUp;
 }
 
 bool FWRenderer::initialize() {
@@ -273,7 +272,7 @@
 			ty += 9;
 			if (color >= 0) {
 				if (isAmiga)
-					drawTransparentBox(x, ty, width, 4);
+					drawTransparentBox(x, ty, width, 9);
 				else
 					drawPlainBox(x, ty, width, 9, color);
 			}
@@ -367,17 +366,13 @@
 	boxRect.clip(screenRect);
 
 	byte *dest = _backBuffer + boxRect.top * 320 + boxRect.left;
-	const byte *src = _screenBackUp + boxRect.top * 320 + boxRect.left;
 	const int lineAdd = 320 - boxRect.width();
 	for (int i = 0; i < boxRect.height(); ++i) {
-		for (int j = 0; j < boxRect.width(); ++j) {
-			if (*src < 16)
-				*dest++ = *src++ + 16;
-			else
-				*dest++ = *src++;
+		for (int j = 0; j < boxRect.width(); ++j, ++dest) {
+			if (*dest < 16)
+				*dest += 16;
 		}
 		dest += lineAdd;
-		src += lineAdd;
 	}
 }
 
@@ -564,6 +559,10 @@
 		refreshPalette();
 	}
 
+	const int menus = _menuStack.size();
+	for (int i = 0; i < menus; ++i)
+		_menuStack[i]->drawMenu(*this, (i == menus - 1));
+
 	blit();
 }
 
@@ -793,87 +792,117 @@
 	refreshPalette();
 }
 
-void FWRenderer::prepareMenu() {
-	if (g_cine->getPlatform() != Common::kPlatformAmiga)
-		return;
+/*! \brief Fade to black
+ * \bug Operation Stealth sometimes seems to fade to black using
+ * transformPalette resulting in double fadeout
+ */
+void FWRenderer::fadeToBlack() {
+	assert(_activePal.isValid() && !_activePal.empty());
 
-	if (!_screenBackUp) {
-		_screenBackUp = new uint8[_screenSize];
-		assert(_screenBackUp);
+	for (int i = 0; i < 8; i++) {
+		// Fade out the whole palette by 1/7th
+		// (Operation Stealth used 36 / 252, which is 1 / 7. Future Wars used 1 / 7 directly).
+		_activePal.saturatedAddNormalizedGray(_activePal, 0, _activePal.colorCount() - 1, -1, 7);
+
+		refreshPalette();
+		g_system->updateScreen();
+		g_system->delayMillis(50);
 	}
-	memcpy(_screenBackUp, _backBuffer, _screenSize);
 }
 
-void FWRenderer::discardMenu() {
-	delete[] _screenBackUp;
-	_screenBackUp = 0;
+// Menu implementation
+
+void FWRenderer::pushMenu(Menu *menu) {
+	_menuStack.push(menu);
 }
 
-/*! \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;
+Menu *FWRenderer::popMenu() {
+	if (_menuStack.empty())
+		return 0;
 
-	if (x + width > 319) {
-		x = 319 - width;
-	}
+	Menu *menu = _menuStack.top();
+	_menuStack.pop();
+	return menu;
+}
 
-	if (y + th > 199) {
-		y = 199 - th;
+void FWRenderer::clearMenuStack() {
+	Menu *menu = 0;
+	while ((menu = popMenu()) != 0)
+		delete menu;
+}
+
+SelectionMenu::SelectionMenu(Common::Point p, int width, Common::StringList elements)
+	: Menu(kSelectionMenu), _pos(p), _width(width), _elements(elements), _selection(-1) {
+}
+
+void SelectionMenu::setSelection(int selection) {
+	if (selection >= getElementCount() || selection < -1) {
+		warning("Invalid selection %d", selection);
+		selection = -1;
 	}
 
+	_selection = selection;
+}
+
+void SelectionMenu::drawMenu(FWRenderer &r, bool top) {
+	const int height = getElementCount() * 9 + 10;
+	int x = _pos.x;
+	int y = _pos.y;
+
+	if (x + _width > 319)
+		x = 319 - _width;
+
+	if (y + height > 199)
+		y = 199 - height;
+
 	const bool isAmiga = (g_cine->getPlatform() == Common::kPlatformAmiga);
 
-	if (isAmiga)
-		drawTransparentBox(x, y, width, 4);
-	else
-		drawPlainBox(x, y, width, 4, _messageBg);
+	if (isAmiga) {
+		r.drawTransparentBox(x, y, _width, height);
+		r.drawDoubleBorder(x, y, _width, height, 18);
+	} else {
+		r.drawPlainBox(x, y, _width, height, r._messageBg);
+		r.drawDoubleBorder(x, y, _width, height, 2);
+	}
 
-	ty = y + 4;
+	int lineY = y + 4;
+	int charX;
 
-	for (i = 0; i < height; i++, ty += 9) {
-		if (isAmiga) {
-			// The original Amiga version is using a different highlight color here,
-			// but with our current code it is not possible to change the text color
-			// thus we can not use it, since otherwise the text wouldn't be visible
-			// anymore.
-			if ((int)i == selected)
-				drawPlainBox(x, ty, width, 9, 0/*2*/);
-			else
-				drawTransparentBox(x, ty, width, 9);
-		} else {
-			drawPlainBox(x, ty, width, 9, (int)i == selected ? 0 : _messageBg);
+	const int elemCount = getElementCount();
+	for (int i = 0; i < elemCount; ++i, lineY += 9) {
+		charX = x + 4;
+
+		if (i == _selection) {
+			if (isAmiga) {
+				// The original Amiga version is using a different highlight color here,
+				// but with our current code it is not possible to change the text color,
+				// thus we can not use the Amiga's color, since otherwise the text
+				// wouldn't be visible anymore.
+				r.drawPlainBox(charX, lineY, _width - 8, FONT_HEIGHT, top ? r._messageBg/*2*/ : 18);
+			} else {
+				r.drawPlainBox(charX, lineY, _width - 8, 9, r._messageBg);
+			}
 		}
-		tx = x + 4;
 
-		for (j = 0; items[i][j]; j++) {
-			tx = drawChar(items[i][j], tx, ty);
-		}
+		const int size = _elements[i].size();
+		for (int j = 0; j < size; ++j)
+			charX = r.drawChar(_elements[i][j], charX, lineY);
 	}
+}
 
-	if (isAmiga)
-		drawTransparentBox(x, ty, width, 4);
-	else
-		drawPlainBox(x, ty, width, 4, _messageBg);
-	drawDoubleBorder(x, y, width, ty - y + 4, isAmiga ? 18 : 2);
+TextInputMenu::TextInputMenu(Common::Point p, int width, const char *info)
+	: Menu(kTextInputMenu), _pos(p), _width(width), _info(info), _input(), _cursor(0) {
 }
 
-/*! \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) {
+void TextInputMenu::setInput(const char *input, int cursor) {
+	_input = input;
+	_cursor = cursor;
+}
+
+void TextInputMenu::drawMenu(FWRenderer &r, bool top) {
+	const int x = _pos.x;
+	const int y = _pos.y;
+
 	int i, tx, ty, tw;
 	int line = 0, words = 0, cw = 0;
 	int space = 0, extraSpace = 0;
@@ -881,20 +910,22 @@
 	const bool isAmiga = (g_cine->getPlatform() == Common::kPlatformAmiga);
 
 	if (isAmiga)
-		drawTransparentBox(x, y, width, 4);
+		r.drawTransparentBox(x, y, _width, 4);
 	else
-		drawPlainBox(x, y, width, 4, _messageBg);
+		r.drawPlainBox(x, y, _width, 4, r._messageBg);
 	tx = x + 4;
-	ty = info[0] ? y - 5 : y + 4;
-	tw = width - 8;
+	ty = _info[0] ? y - 5 : y + 4;
+	tw = _width - 8;
 
+	const int infoSize = _info.size();
+
 	// input box info message
-	for (i = 0; info[i]; i++, line--) {
+	for (i = 0; i < infoSize; i++, line--) {
 		// fit line of text
 		if (!line) {
-			line = fitLine(info + i, tw, words, cw);
+			line = fitLine(_info.c_str() + i, tw, words, cw);
 
-			if ( info[i + line] != '\0' && words) {
+			if (i + line < infoSize && words) {
 				space = (tw - cw) / words;
 				extraSpace = (tw - cw) % words;
 			} else {
@@ -904,72 +935,57 @@
 
 			ty += 9;
 			if (isAmiga)
-				drawTransparentBox(x, ty, width, 9);
+				r.drawTransparentBox(x, ty, _width, 9);
 			else
-				drawPlainBox(x, ty, width, 9, _messageBg);
+				r.drawPlainBox(x, ty, _width, 9, r._messageBg);
 			tx = x + 4;
 		}
 
 		// draw characters
-		if (info[i] == ' ') {
+		if (_info[i] == ' ') {
 			tx += space + extraSpace;
 
 			if (extraSpace) {
 				extraSpace = 0;
 			}
 		} else {
-			tx = drawChar(info[i], tx, ty);
+			tx = r.drawChar(_info[i], tx, ty);
 		}
 	}
 
 	// input area background
 	ty += 9;
 	if (isAmiga)
-		drawTransparentBox(x, ty, width, 9);
+		r.drawTransparentBox(x, ty, _width, 9);
 	else
-		drawPlainBox(x, ty, width, 9, _messageBg);
-	drawPlainBox(x + 16, ty - 1, width - 32, 9, 0);
+		r.drawPlainBox(x, ty, _width, 9, r._messageBg);
+	r.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);
+	const int inputSize = _input.size();
+	for (i = 0; i < inputSize; i++) {
+		tx = r.drawChar(_input[i], tx, ty);
 
-		if (cursor == i + 2) {
-			drawLine(tx, ty - 1, 1, 9, 2);
+		if (_cursor == i + 2) {
+			r.drawLine(tx, ty - 1, 1, 9, 2);
 		}
 	}
 
-	if (!input[0] || cursor == 1) {
-		drawLine(x + 20, ty - 1, 1, 9, 2);
+	if (_input.empty() || _cursor == 1) {
+		r.drawLine(x + 20, ty - 1, 1, 9, 2);
 	}
 
 	ty += 9;
 	if (isAmiga)
-		drawTransparentBox(x, ty, width, 4);
+		r.drawTransparentBox(x, ty, _width, 4);
 	else
-		drawPlainBox(x, ty, width, 4, _messageBg);
-	drawDoubleBorder(x, y, width, ty - y + 4, isAmiga ? 18 : 2);
+		r.drawPlainBox(x, ty, _width, 4, r._messageBg);
+	r.drawDoubleBorder(x, y, _width, ty - y + 4, isAmiga ? 18 : 2);
 }
 
-/*! \brief Fade to black
- * \bug Operation Stealth sometimes seems to fade to black using
- * transformPalette resulting in double fadeout
- */
-void FWRenderer::fadeToBlack() {
-	assert(_activePal.isValid() && !_activePal.empty());
+// -------------------
 
-	for (int i = 0; i < 8; i++) {
-		// Fade out the whole palette by 1/7th
-		// (Operation Stealth used 36 / 252, which is 1 / 7. Future Wars used 1 / 7 directly).
-		_activePal.saturatedAddNormalizedGray(_activePal, 0, _activePal.colorCount() - 1, -1, 7);
-
-		refreshPalette();
-		g_system->updateScreen();
-		g_system->delayMillis(50);
-	}
-}
-
 /*! \brief Initialize Operation Stealth renderer
  */
 OSRenderer::OSRenderer() : FWRenderer(), _bgTable(), _currentBg(0), _scrollBg(0),

Modified: scummvm/trunk/engines/cine/gfx.h
===================================================================
--- scummvm/trunk/engines/cine/gfx.h	2009-09-22 17:10:08 UTC (rev 44262)
+++ scummvm/trunk/engines/cine/gfx.h	2009-09-22 17:51:06 UTC (rev 44263)
@@ -27,6 +27,8 @@
 #define CINE_GFX_H
 
 #include "common/noncopyable.h"
+#include "common/rect.h"
+#include "common/stack.h"
 #include "cine/object.h"
 
 namespace Cine {
@@ -61,13 +63,66 @@
 	}
 };
 
+class FWRenderer;
+
+class Menu {
+public:
+	enum Type {
+		kSelectionMenu,
+		kTextInputMenu
+	};
+
+	Menu(Type t) : _type(t) {}
+	virtual ~Menu() {}
+
+	Type getType() const { return _type; }
+
+	virtual void drawMenu(FWRenderer &r, bool top) = 0;
+private:
+	const Type _type;
+};
+
+class SelectionMenu : public Menu {
+public:
+	SelectionMenu(Common::Point p, int width, Common::StringList elements);
+
+	int getElementCount() const { return _elements.size(); }
+
+	void setSelection(int selection);
+
+	void drawMenu(FWRenderer &r, bool top);
+private:
+	const Common::Point _pos;
+	const int _width;
+	const Common::StringList _elements;
+
+	int _selection;
+};
+
+class TextInputMenu : public Menu {
+public:
+	TextInputMenu(Common::Point p, int width, const char *info);
+
+	void setInput(const char *input, int cursor);
+
+	void drawMenu(FWRenderer &r, bool top);
+private:
+	const Common::Point _pos;
+	const int _width;
+	const Common::String _info;
+
+	Common::String _input;
+	int _cursor;
+};
+
 /*! \brief Future Wars renderer
  *
- * Screen backbuffer is not cleared between frames, you can draw menus etc.
- * without calling drawFrame() all the time
+ * Screen backbuffer is not cleared between frames.
  */
 class FWRenderer : public Common::NonCopyable {
-protected:
+	// TODO: Consider getting rid of this
+	friend class SelectionMenu;
+	friend class TextInputMenu;
 private:
 	byte *_background; ///< Current background
 	char _bgName[13]; ///< Background filename
@@ -80,9 +135,9 @@
 	static const int _screenHeight = 200; ///< Screen height
 
 	byte *_backBuffer; ///< Screen backbuffer
-	byte *_screenBackUp; ///< Screen backbuffer's backup for the transparent menu code in the Amiga version
 	Cine::Palette _backupPal; ///< The backup color palette
 	Cine::Palette _activePal; ///< The active color palette
+	Common::Stack<Menu *> _menuStack; ///< All displayed menus
 	int _changePal; ///< Load active palette to video backend on next frame
 	bool _showCollisionPage; ///< Should we show the collision page instead of the back buffer? Used for debugging.
 
@@ -104,6 +159,7 @@
 	virtual void renderOverlay(const Common::List<overlay>::iterator &it);
 	void drawOverlays();
 
+	void blit();
 public:
 	uint16 _messageBg; ///< Message box background color
 	uint16 _cmdY; ///< Player command string position on screen
@@ -119,7 +175,6 @@
 	virtual void clear();
 
 	void drawFrame();
-	void blit();
 	void setCommand(Common::String cmd);
 
 	virtual void incrustMask(const ObjectStruct &obj, uint8 color = 0);
@@ -144,12 +199,10 @@
 	virtual void rotatePalette(int a, int b, int c);
 	virtual void transformPalette(int first, int last, int r, int g, int b);
 
-	void prepareMenu();
-	void discardMenu();
+	void pushMenu(Menu *menu);
+	Menu *popMenu();
+	void clearMenuStack();
 
-	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();
 	void showCollisionPage(bool state);
 };

Modified: scummvm/trunk/engines/cine/various.cpp
===================================================================
--- scummvm/trunk/engines/cine/various.cpp	2009-09-22 17:10:08 UTC (rev 44262)
+++ scummvm/trunk/engines/cine/various.cpp	2009-09-22 17:51:06 UTC (rev 44263)
@@ -492,10 +492,15 @@
 	if (!listSize)
 		return;
 
-	renderer->prepareMenu();
-	renderer->drawMenu(objectListCommand, listSize, x, y, menuWidth, -1);
-	renderer->blit();
-	renderer->discardMenu();
+	Common::StringList list;
+	for (int i = 0; i < listSize; ++i)
+		list.push_back(objectListCommand[i]);
+	SelectionMenu *menu = new SelectionMenu(Common::Point(x, y), menuWidth, list);
+	renderer->pushMenu(menu);
+	renderer->drawFrame();
+	renderer->popMenu();
+	delete menu;
+	menu = 0;
 
 	do {
 		manageEvents();
@@ -676,6 +681,7 @@
 	int16 var_14;
 	int16 currentSelection, oldSelection;
 	int16 var_4;
+	SelectionMenu *menu;
 
 	if (disableSystemMenu)
 		return -1;
@@ -690,9 +696,12 @@
 		Y = 199 - paramY;
 	}
 
-	renderer->prepareMenu();
-	renderer->drawMenu(commandList, height, X, Y, width, -1);
-	renderer->blit();
+	Common::StringList list;
+	for (uint16 i = 0; i < height; ++i)
+		list.push_back(commandList[i]);
+	menu = new SelectionMenu(Common::Point(X, Y), width, list);
+	renderer->pushMenu(menu);
+	renderer->drawFrame();
 
 	do {
 		manageEvents();
@@ -705,8 +714,8 @@
 
 	di = currentSelection * 9 + Y + 4;
 
-	renderer->drawMenu(commandList, height, X, Y, width, currentSelection);
-	renderer->blit();
+	menu->setSelection(currentSelection);
+	renderer->drawFrame();
 
 	manageEvents();
 	getMouseData(mouseUpdateStatus, &button, (uint16 *)&mouseX, (uint16 *)&mouseY);
@@ -759,8 +768,8 @@
 
 			di = currentSelection * 9 + Y + 4;
 
-			renderer->drawMenu(commandList, height, X, Y, width, currentSelection);
-			renderer->blit();
+			menu->setSelection(currentSelection);
+			renderer->drawFrame();
 
 //			if (needMouseSave) {
 //				gfxRedrawMouseCursor();
@@ -769,8 +778,6 @@
 
 	} while (!var_A && !g_cine->shouldQuit());
 
-	renderer->discardMenu();
-
 	assert(!needMouseSave);
 
 	var_4 = button;
@@ -1096,6 +1103,8 @@
 		}
 	}
 
+	renderer->clearMenuStack();
+
 	// Update Operation Stealth specific global variables.
 	// This fixes swimming at the bottom of the ocean after
 	// having been thrown into it with the girl.
@@ -1607,12 +1616,13 @@
 	int inputLength = strlen(inputString);
 	int inputPos = inputLength + 1;
 
-	renderer->prepareMenu();
+	TextInputMenu *inputBox = new TextInputMenu(Common::Point(x - 16, y), width + 32, messagePtr);
+	renderer->pushMenu(inputBox);
 
 	while (!quit) {
 		if (redraw) {
-			renderer->drawInputBox(messagePtr, inputString, inputPos, x - 16, y, width + 32);
-			renderer->blit();
+			inputBox->setInput(inputString, inputPos);
+			renderer->drawFrame();
 			redraw = false;
 		}
 
@@ -1691,7 +1701,8 @@
 		}
 	}
 
-	renderer->discardMenu();
+	renderer->popMenu();
+	delete inputBox;
 
 	if (quit == 2)
 		return false;


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