Example #1
0
TestExitStatus EventTests::mouseEvents() {

	Testsuite::clearScreen();
	Common::String info = "Testing Mouse events.\n "
	"Any movement/click generated by L/R/M mouse buttons or the mouse wheel should be detected.\n"
	"Press X to exit";

	if (Testsuite::handleInteractiveInput(info, "OK", "Skip", kOptionRight)) {
		Testsuite::logPrintf("Info! Skipping test : keyboard events\n");
		return kTestSkipped;
	}

	Common::EventManager *eventMan = g_system->getEventManager();

	Common::Point pt(0, 30);
	Common::Rect rectInfo = Testsuite::writeOnScreen("Generate mouse events make L/R/M button clicks, move wheel", pt);
	pt.y += 15;
	Testsuite::writeOnScreen("Press X to exit", pt);
	pt.y = 70;
	Common::Rect rectLB = Testsuite::writeOnScreen("Left-button click : Not tested", pt);
	pt.y += 15;
	Common::Rect rectRB = Testsuite::writeOnScreen("Right-button click : Not tested", pt);
	pt.y += 15;
	Common::Rect rectMB = Testsuite::writeOnScreen("Middle-button click : Not tested", pt);
	pt.y += 15;
	Common::Rect rectWheel = Testsuite::writeOnScreen("Wheel Movements : Not tested", pt);


	// Init Mouse Palette
	GFXtests::initMousePalette();
	Common::Rect finishZone = drawFinishZone();

	bool quitLoop = false;
	TestExitStatus passed = kTestPassed;
	// handle all mouse events
	Common::Event event;
	while (!quitLoop) {
		// Show mouse
		CursorMan.showMouse(true);
		g_system->updateScreen();

		while (eventMan->pollEvent(event)) {
			// Quit if explicitly requested
			if (Engine::shouldQuit()) {
				return passed;
			}
			switch (event.type) {
			case Common::EVENT_MOUSEMOVE:
				// Movements havee already been tested in GFX
				break;
			case Common::EVENT_LBUTTONDOWN:
				Testsuite::clearScreen(rectInfo);
				Testsuite::writeOnScreen("Mouse left-button pressed", Common::Point(rectInfo.left, rectInfo.top));
				break;
			case Common::EVENT_RBUTTONDOWN:
				Testsuite::clearScreen(rectInfo);
				Testsuite::writeOnScreen("Mouse right-button pressed", Common::Point(rectInfo.left, rectInfo.top));
				break;
			case Common::EVENT_WHEELDOWN:
				Testsuite::clearScreen(rectInfo);
				Testsuite::writeOnScreen("Mouse wheel moved down", Common::Point(rectInfo.left, rectInfo.top));
				Testsuite::writeOnScreen("Wheel Movements : Done!", Common::Point(rectWheel.left, rectWheel.top));
				break;
			case Common::EVENT_MBUTTONDOWN:
				Testsuite::clearScreen(rectInfo);
				Testsuite::writeOnScreen("Mouse middle-button pressed ", Common::Point(rectInfo.left, rectInfo.top));
				break;
			case Common::EVENT_LBUTTONUP:
				Testsuite::clearScreen(rectInfo);
				if (finishZone.contains(eventMan->getMousePos())) {
					quitLoop = true;
				}
				Testsuite::writeOnScreen("Mouse left-button released", Common::Point(rectInfo.left, rectInfo.top));
				Testsuite::writeOnScreen("Left-button clicks : Done!", Common::Point(rectLB.left, rectLB.top));
				break;
			case Common::EVENT_RBUTTONUP:
				Testsuite::clearScreen(rectInfo);
				Testsuite::writeOnScreen("Mouse right-button released", Common::Point(rectInfo.left, rectInfo.top));
				Testsuite::writeOnScreen("Right-button clicks : Done!", Common::Point(rectRB.left, rectRB.top));
				break;
			case Common::EVENT_WHEELUP:
				Testsuite::clearScreen(rectInfo);
				Testsuite::writeOnScreen("Mouse wheel moved up", Common::Point(rectInfo.left, rectInfo.top));
				Testsuite::writeOnScreen("Wheel Movements : Done!", Common::Point(rectWheel.left, rectWheel.top));
				break;
			case Common::EVENT_MBUTTONUP:
				Testsuite::clearScreen(rectInfo);
				Testsuite::writeOnScreen("Mouse middle-button released ", Common::Point(rectInfo.left, rectInfo.top));
				Testsuite::writeOnScreen("Middle-button clicks : Done!", Common::Point(rectMB.left, rectMB.top));
				break;
			case Common::EVENT_KEYDOWN:
				if (event.kbd.keycode == Common::KEYCODE_x) {
					Testsuite::clearScreen(rectInfo);
					Testsuite::writeOnScreen("Exit requested", Common::Point(rectInfo.left, rectInfo.top));
					quitLoop = true;
				}
				break;
			default:
				break;
			}

		}
	}

	CursorMan.showMouse(false);

	// Verify results now!
	if (Testsuite::handleInteractiveInput("Were mouse clicks (L/R/M buttons) and wheel movements identfied ?", "Yes", "No", kOptionRight)) {
		Testsuite::logDetailedPrintf("Mouse clicks (L/R/M buttons) and wheel movements failed");
		passed = kTestFailed;
	}

	return passed;
}
Example #2
0
void ZVision::playVideo(Video::VideoDecoder &videoDecoder, const Common::Rect &destRect, bool skippable) {
	byte bytesPerPixel = videoDecoder.getPixelFormat().bytesPerPixel;

	uint16 origWidth = videoDecoder.getWidth();
	uint16 origHeight = videoDecoder.getHeight();

	uint scale = 1;
	// If destRect is empty, no specific scaling was requested. However, we may choose to do scaling anyway
	if (destRect.isEmpty()) {
		// Most videos are very small. Therefore we do a simple 2x scale
		if (origWidth * 2 <= 640 && origHeight * 2 <= 480) {
			scale = 2;
		}
	} else {
		// Assume bilinear scaling. AKA calculate the scale from just the width.
		// Also assume that the scaling is in integral intervals. AKA no 1.5x scaling
		// TODO: Test ^these^ assumptions
		scale = destRect.width() / origWidth;

		// TODO: Test if we need to support downscale.
	}

	uint16 pitch = origWidth * bytesPerPixel;

	uint16 finalWidth = origWidth * scale;
	uint16 finalHeight = origHeight * scale;

	byte *scaledVideoFrameBuffer;
	if (scale != 1) {
		scaledVideoFrameBuffer = new byte[finalWidth * finalHeight * bytesPerPixel];
	}

	uint16 x = ((WINDOW_WIDTH - finalWidth) / 2) + destRect.left;
	uint16 y = ((WINDOW_HEIGHT - finalHeight) / 2) + destRect.top;

	_clock.stop();
	videoDecoder.start();

	// Only continue while the video is still playing
	while (!shouldQuit() && !videoDecoder.endOfVideo() && videoDecoder.isPlaying()) {
		// Check for engine quit and video stop key presses
		while (!videoDecoder.endOfVideo() && videoDecoder.isPlaying() && _eventMan->pollEvent(_event)) {
			switch (_event.type) {
			case Common::EVENT_KEYDOWN:
				switch (_event.kbd.keycode) {
				case Common::KEYCODE_q:
					if (_event.kbd.hasFlags(Common::KBD_CTRL))
						quitGame();
					break;
				case Common::KEYCODE_SPACE:
					if (skippable) {
						videoDecoder.stop();
					}
					break;
				default:
					break;
				}
			default:
				break;
			}
		}

		if (videoDecoder.needsUpdate()) {
			const Graphics::Surface *frame = videoDecoder.decodeNextFrame();

			if (frame) {
				if (scale != 1) {
					scaleBuffer((const byte *)frame->getPixels(), scaledVideoFrameBuffer, origWidth, origHeight, bytesPerPixel, scale);
					_system->copyRectToScreen(scaledVideoFrameBuffer, pitch * 2, x, y, finalWidth, finalHeight);
				} else {
					_system->copyRectToScreen((const byte *)frame->getPixels(), pitch, x, y, finalWidth, finalHeight);
				}
			}
		}

		// Always update the screen so the mouse continues to render
		_system->updateScreen();

		_system->delayMillis(videoDecoder.getTimeToNextFrame());
	}

	_clock.start();

	if (scale != 1) {
		delete[] scaledVideoFrameBuffer;
	}
}
Example #3
0
void UISlots::draw(bool updateFlag, bool delFlag) {
	Scene &scene = _vm->_game->_scene;
	UserInterface &userInterface = scene._userInterface;
	DirtyArea *dirtyAreaPtr = nullptr;

	// Loop through setting up the dirty areas
	for (uint idx = 0; idx < size(); ++idx) {
		DirtyArea &dirtyArea = userInterface._dirtyAreas[idx];
		UISlot &slot = (*this)[idx];

		if (slot._flags >= IMG_STATIC) {
			dirtyArea._active = false;
		} else {
			dirtyArea.setUISlot(&slot);
			dirtyArea._textActive = true;
			if (slot._segmentId == IMG_SPINNING_OBJECT && slot._flags == IMG_FULL_UPDATE) {
				dirtyArea._active = false;
				dirtyAreaPtr = &dirtyArea;
			}
		}
	}

	userInterface._dirtyAreas.merge(1, userInterface._uiSlots.size());
	if (dirtyAreaPtr)
		dirtyAreaPtr->_active = true;

	// Copy parts of the user interface background that need to be erased
	for (uint idx = 0; idx < size(); ++idx) {
		DirtyArea &dirtyArea = userInterface._dirtyAreas[idx];
		UISlot &slot = (*this)[idx];

		if (dirtyArea._active && dirtyArea._bounds.width() > 0
				&& dirtyArea._bounds.height() > 0 && slot._flags > -20) {

			if (slot._flags >= IMG_ERASE) {
				// Merge area
				userInterface.mergeFrom(&userInterface._surface, dirtyArea._bounds,
					Common::Point(dirtyArea._bounds.left, dirtyArea._bounds.top));
			} else {
				// Copy area
				userInterface.blitFrom(userInterface._surface, dirtyArea._bounds,
					Common::Point(dirtyArea._bounds.left, dirtyArea._bounds.top));
			}
		}
	}

	for (uint idx = 0; idx < size(); ++idx) {
		DirtyArea &dirtyArea = userInterface._dirtyAreas[idx];
		UISlot &slot = (*this)[idx];

		int slotType = slot._flags;
		if (slotType >= IMG_STATIC) {
			dirtyArea.setUISlot(&slot);
			if (!updateFlag)
				slotType &= ~0x40;

			dirtyArea._textActive = slotType > 0;
			slot._flags &= 0x40;
		}
	}

	userInterface._dirtyAreas.merge(1, userInterface._uiSlots.size());

	for (uint idx = 0; idx < size(); ++idx) {
		DirtyArea *dirtyArea = &userInterface._dirtyAreas[idx];
		UISlot &slot = (*this)[idx];

		if (slot._flags >= IMG_STATIC && !(slot._flags & 0x40)) {
			if (!dirtyArea->_active) {
				do {
					dirtyArea = dirtyArea->_mergedArea;
				} while (!dirtyArea->_active);
			}

			if (dirtyArea->_textActive) {
				SpriteAsset *asset = scene._sprites[slot._spritesIndex];

				// Get the frame details
				int frameNumber = ABS(slot._frameNumber);
				bool flipped = slot._frameNumber < 0;

				if (slot._segmentId == IMG_SPINNING_OBJECT) {
					MSprite *sprite = asset->getFrame(frameNumber - 1);
					userInterface.transBlitFrom(*sprite, slot._position,
						sprite->getTransparencyIndex());
				} else {
					MSprite *sprite = asset->getFrame(frameNumber - 1);

					if (flipped) {
						MSurface *spr = sprite->flipHorizontal();
						userInterface.mergeFrom(spr, spr->getBounds(), slot._position,
							sprite->getTransparencyIndex());
						spr->free();
						delete spr;
					} else {
						userInterface.mergeFrom(sprite, sprite->getBounds(), slot._position,
							sprite->getTransparencyIndex());
					}
				}
			}
		}
	}

	// Mark areas of the screen surface for updating
	if (updateFlag) {
		for (uint idx = 0; idx < size(); ++idx) {
			DirtyArea &dirtyArea = userInterface._dirtyAreas[idx];

			if (dirtyArea._active && dirtyArea._textActive &&
				dirtyArea._bounds.width() > 0 && dirtyArea._bounds.height() > 0) {
				// Flag area of screen as needing update
				Common::Rect r = dirtyArea._bounds;
				r.translate(0, scene._interfaceY);
				//_vm->_screen->copyRectToScreen(r);
			}
		}
	}

	// Post-processing to remove slots no longer needed
	for (int idx = (int)size() - 1; idx >= 0; --idx) {
		UISlot &slot = (*this)[idx];

		if (slot._flags < IMG_STATIC) {
			if (delFlag || updateFlag)
				remove_at(idx);
			else if (slot._flags > -20)
				slot._flags -= 20;
		} else {
			if (updateFlag)
				slot._flags &= ~0x40;
			else
				slot._flags |= 0x40;
		}
	}
}
Example #4
0
void GfxControls32::kernelTexteditChange(reg_t controlObject) {
	SciEvent curEvent;
	uint16 maxChars = 40;	//readSelectorValue(_segMan, controlObject, SELECTOR(max));	// TODO
	reg_t textReference = readSelector(_segMan, controlObject, SELECTOR(text));
	GfxFont *font = _cache->getFont(readSelectorValue(_segMan, controlObject, SELECTOR(font)));
	Common::String text;
	uint16 textSize;
	bool textChanged = false;
	bool textAddChar = false;
	Common::Rect rect;

	if (textReference.isNull())
		error("kEditControl called on object that doesnt have a text reference");
	text = _segMan->getString(textReference);

	// TODO: Finish this
	warning("kEditText ('%s')", text.c_str());
	return;

	uint16 cursorPos = 0;
	//uint16 oldCursorPos = cursorPos;
	bool captureEvents = true;
	EventManager* eventMan = g_sci->getEventManager();

	while (captureEvents) {
		curEvent = g_sci->getEventManager()->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_PEEK);

		if (curEvent.type == SCI_EVENT_NONE) {
			eventMan->getSciEvent(SCI_EVENT_KEYBOARD);	// consume the event
		} else {
			textSize = text.size();

			switch (curEvent.type) {
			case SCI_EVENT_MOUSE_PRESS:
				// TODO: Implement mouse support for cursor change
				break;
			case SCI_EVENT_KEYBOARD:
				switch (curEvent.character) {
				case SCI_KEY_BACKSPACE:
					if (cursorPos > 0) {
						cursorPos--; text.deleteChar(cursorPos);
						textChanged = true;
					}
					eventMan->getSciEvent(SCI_EVENT_KEYBOARD);	// consume the event
					break;
				case SCI_KEY_DELETE:
					if (cursorPos < textSize) {
						text.deleteChar(cursorPos);
						textChanged = true;
					}
					eventMan->getSciEvent(SCI_EVENT_KEYBOARD);	// consume the event
					break;
				case SCI_KEY_HOME: // HOME
					cursorPos = 0; textChanged = true;
					eventMan->getSciEvent(SCI_EVENT_KEYBOARD);	// consume the event
					break;
				case SCI_KEY_END: // END
					cursorPos = textSize; textChanged = true;
					eventMan->getSciEvent(SCI_EVENT_KEYBOARD);	// consume the event
					break;
				case SCI_KEY_LEFT: // LEFT
					if (cursorPos > 0) {
						cursorPos--; textChanged = true;
					}
					eventMan->getSciEvent(SCI_EVENT_KEYBOARD);	// consume the event
					break;
				case SCI_KEY_RIGHT: // RIGHT
					if (cursorPos + 1 <= textSize) {
						cursorPos++; textChanged = true;
					}
					eventMan->getSciEvent(SCI_EVENT_KEYBOARD);	// consume the event
					break;
				case 3:	// returned in SCI1 late and newer when Control - C is pressed
					if (curEvent.modifiers & SCI_KEYMOD_CTRL) {
						// Control-C erases the whole line
						cursorPos = 0; text.clear();
						textChanged = true;
					}
					eventMan->getSciEvent(SCI_EVENT_KEYBOARD);	// consume the event
					break;
				case SCI_KEY_UP:
				case SCI_KEY_DOWN:
				case SCI_KEY_ENTER:
				case SCI_KEY_ESC:
				case SCI_KEY_TAB:
				case SCI_KEY_SHIFT_TAB:
					captureEvents = false;
					break;
				default:
					if ((curEvent.modifiers & SCI_KEYMOD_CTRL) && curEvent.character == 'c') {
						// Control-C in earlier SCI games (SCI0 - SCI1 middle)
						// Control-C erases the whole line
						cursorPos = 0; text.clear();
						textChanged = true;
					} else if (curEvent.character > 31 && curEvent.character < 256 && textSize < maxChars) {
						// insert pressed character
						textAddChar = true;
						textChanged = true;
					}
					eventMan->getSciEvent(SCI_EVENT_KEYBOARD);	// consume the event
					break;
				}
				break;
			}
		}

		if (textChanged) {
			rect = g_sci->_gfxCompare->getNSRect(controlObject);

			if (textAddChar) {
				const char *textPtr = text.c_str();

				// We check if we are really able to add the new char
				uint16 textWidth = 0;
				while (*textPtr)
					textWidth += font->getCharWidth((byte)*textPtr++);
				textWidth += font->getCharWidth(curEvent.character);

				// Does it fit?
				if (textWidth >= rect.width()) {
					return;
				}

				text.insertChar(curEvent.character, cursorPos++);

				// Note: the following checkAltInput call might make the text
				// too wide to fit, but SSCI fails to check that too.
			}

			reg_t hunkId = readSelector(_segMan, controlObject, SELECTOR(bitmap));
			Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(controlObject);
			//texteditCursorErase();	// TODO: Cursor

			// Write back string
			_segMan->strcpy(textReference, text.c_str());
			// Modify the buffer and show it
			_text->createTextBitmap(controlObject, 0, 0, hunkId);

			_text->drawTextBitmap(0, 0, nsRect, controlObject);
			//texteditCursorDraw(rect, text.c_str(), cursorPos);	// TODO: Cursor
			g_system->updateScreen();
		} else {
			// TODO: Cursor
			/*
			if (g_system->getMillis() >= _texteditBlinkTime) {
				_paint16->invertRect(_texteditCursorRect);
				_paint16->bitsShow(_texteditCursorRect);
				_texteditCursorVisible = !_texteditCursorVisible;
				texteditSetBlinkTime();
			}
			*/
		}

		textAddChar = false;
		textChanged = false;
		g_sci->sleep(10);
	}	// while
}
Example #5
0
// Draws a text in rect.
void GfxText16::Box(const char *text, uint16 languageSplitter, bool show, const Common::Rect &rect, TextAlignment alignment, GuiResourceId fontId) {
	int16 textWidth, maxTextWidth, textHeight, charCount;
	int16 offset = 0;
	int16 hline = 0;
	GuiResourceId previousFontId = GetFontId();
	int16 previousPenColor = _ports->_curPort->penClr;
	bool doubleByteMode = false;
	const char *curTextPos = text;
	const char *curTextLine = text;

	if (fontId != -1)
		SetFont(fontId);
	else
		fontId = previousFontId;

	// Reset reference code rects
	_codeRefRects.clear();
	_codeRefTempRect.left = _codeRefTempRect.top = -1;

	maxTextWidth = 0;
	while (*curTextPos) {
		// We need to check for Shift-JIS every line
		//  Police Quest 2 PC-9801 often draws English + Japanese text during the same call
		if (g_sci->getLanguage() == Common::JA_JPN) {
			if (SwitchToFont900OnSjis(curTextPos, languageSplitter))
				doubleByteMode = true;
		}

		charCount = GetLongest(curTextPos, rect.width(), fontId);
		if (charCount == 0)
			break;
		Width(curTextLine, 0, charCount, fontId, textWidth, textHeight, true);
		maxTextWidth = MAX<int16>(maxTextWidth, textWidth);
		switch (alignment) {
		case SCI_TEXT16_ALIGNMENT_RIGHT:
			offset = rect.width() - textWidth;
			break;
		case SCI_TEXT16_ALIGNMENT_CENTER:
			offset = (rect.width() - textWidth) / 2;
			break;
		case SCI_TEXT16_ALIGNMENT_LEFT:
			offset = 0;
			break;

		default:
			warning("Invalid alignment %d used in TextBox()", alignment);
		}
		_ports->moveTo(rect.left + offset, rect.top + hline);

		if (show) {
			Show(curTextLine, 0, charCount, fontId, previousPenColor);
		} else {
			Draw(curTextLine, 0, charCount, fontId, previousPenColor);
		}

		hline += textHeight;
		curTextLine = curTextPos;
	}
	SetFont(previousFontId);
	_ports->penColor(previousPenColor);

	if (doubleByteMode) {
		// Kanji is written by pc98 rom to screen directly. Because of
		// GetLongest() behavior (not cutting off the last char, that causes a
		// new line), results in the script thinking that the text would need
		// less space. The coordinate adjustment in fontsjis.cpp handles the
		// incorrect centering because of that and this code actually shows all
		// of the chars - if we don't do this, the scripts will only show most
		// of the chars, but the last few pixels won't get shown most of the
		// time.
		Common::Rect kanjiRect = rect;
		_ports->offsetRect(kanjiRect);
		kanjiRect.left &= 0xFFC;
		kanjiRect.right = kanjiRect.left + maxTextWidth;
		kanjiRect.bottom = kanjiRect.top + hline;
		kanjiRect.left *= 2; kanjiRect.right *= 2;
		kanjiRect.top *= 2; kanjiRect.bottom *= 2;
		_screen->copyDisplayRectToScreen(kanjiRect);
	}
}
void ShaderRenderer::draw2DText(const Common::String &text, const Common::Point &position) {
	OpenGLTexture *glFont = static_cast<OpenGLTexture *>(_font);

	// The font only has uppercase letters
	Common::String textToDraw = text;
	textToDraw.toUppercase();

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

	glDisable(GL_DEPTH_TEST);
	glDepthMask(GL_FALSE);

	if (_prevText != textToDraw || _prevTextPosition != position) {
		_prevText = textToDraw;
		_prevTextPosition = position;

		float x = position.x / _currentViewport.getWidth();
		float y = position.y / _currentViewport.getHeight();

		float *bufData = new float[16 * textToDraw.size()];
		float *cur = bufData;

		for (uint i = 0; i < textToDraw.size(); i++) {
			Common::Rect textureRect = getFontCharacterRect(textToDraw[i]);
			float w = textureRect.width() / _currentViewport.getWidth();
			float h = textureRect.height() / _currentViewport.getHeight();

			float cw = textureRect.width() / (float)glFont->internalWidth;
			float ch = textureRect.height() / (float)glFont->internalHeight;
			float cx = textureRect.left / (float)glFont->internalWidth;
			float cy = textureRect.top / (float)glFont->internalHeight;

			const float charData[] = {
				cx,      cy + ch, x,     y,    
				cx + cw, cy + ch, x + w, y,    
				cx + cw, cy,      x + w, y + h,
				cx,      cy,      x,     y + h,
			};

			memcpy(cur, charData, 16 * sizeof(float));
			cur += 16;

			x += (textureRect.width() - 3) / _currentViewport.getWidth();
		}

		glBindBuffer(GL_ARRAY_BUFFER, _textVBO);
		glBufferSubData(GL_ARRAY_BUFFER, 0, textToDraw.size() * 16 * sizeof(float), bufData);
		delete[] bufData;
	}

	_textShader->use();
	glBindTexture(GL_TEXTURE_2D, glFont->id);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _quadEBO);
	glDrawElements(GL_TRIANGLES, 6 * textToDraw.size(), GL_UNSIGNED_SHORT, 0);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

	glDisable(GL_BLEND);
	glEnable(GL_DEPTH_TEST);
	glDepthMask(GL_TRUE);
}
Example #7
0
reg_t GfxPaint16::kernelDisplay(const char *text, int argc, reg_t *argv) {
	reg_t displayArg;
	TextAlignment alignment = SCI_TEXT16_ALIGNMENT_LEFT;
	int16 colorPen = -1, colorBack = -1, width = -1, bRedraw = 1;
	bool doSaveUnder = false;
	Common::Rect rect;
	reg_t result = NULL_REG;

	// Make a "backup" of the port settings (required for some SCI0LATE and
	// SCI01+ only)
	Port oldPort = *_ports->getPort();

	// setting defaults
	_ports->penMode(0);
	_ports->penColor(0);
	_ports->textGreyedOutput(false);
	// processing codes in argv
	while (argc > 0) {
		displayArg = argv[0];
		if (displayArg.getSegment())
			displayArg.setOffset(0xFFFF);
		argc--; argv++;
		switch (displayArg.getOffset()) {
		case SCI_DISPLAY_MOVEPEN:
			_ports->moveTo(argv[0].toUint16(), argv[1].toUint16());
			argc -= 2; argv += 2;
			break;
		case SCI_DISPLAY_SETALIGNMENT:
			alignment = argv[0].toSint16();
			argc--; argv++;
			break;
		case SCI_DISPLAY_SETPENCOLOR:
			colorPen = argv[0].toUint16();
			_ports->penColor(colorPen);
			argc--; argv++;
			break;
		case SCI_DISPLAY_SETBACKGROUNDCOLOR:
			colorBack = argv[0].toUint16();
			argc--; argv++;
			break;
		case SCI_DISPLAY_SETGREYEDOUTPUT:
			_ports->textGreyedOutput(!argv[0].isNull());
			argc--; argv++;
			break;
		case SCI_DISPLAY_SETFONT:
			_text16->SetFont(argv[0].toUint16());
			argc--; argv++;
			break;
		case SCI_DISPLAY_WIDTH:
			width = argv[0].toUint16();
			argc--; argv++;
			break;
		case SCI_DISPLAY_SAVEUNDER:
			doSaveUnder = true;
			break;
		case SCI_DISPLAY_RESTOREUNDER:
			bitsGetRect(argv[0], &rect);
			rect.translate(-_ports->getPort()->left, -_ports->getPort()->top);
			bitsRestore(argv[0]);
			kernelGraphRedrawBox(rect);
			// finishing loop
			argc = 0;
			break;
		case SCI_DISPLAY_DONTSHOWBITS:
			bRedraw = 0;
			break;

		// The following three dummy calls are not supported by the Sierra SCI
		// interpreter, but are erroneously called in some game scripts.
		case SCI_DISPLAY_DUMMY1:	// Longbow demo (all rooms) and QFG1 EGA demo (room 11)
		case SCI_DISPLAY_DUMMY2:	// Longbow demo (all rooms)
		case SCI_DISPLAY_DUMMY3:	// QFG1 EGA demo (room 11) and PQ2 (room 23)
			if (!(g_sci->getGameId() == GID_LONGBOW && g_sci->isDemo()) &&
				!(g_sci->getGameId() == GID_QFG1    && g_sci->isDemo()) &&
				!(g_sci->getGameId() == GID_PQ2))
				error("Unknown kDisplay argument %d", displayArg.getOffset());

			if (displayArg.getOffset() == SCI_DISPLAY_DUMMY2) {
				if (!argc)
					error("No parameter left for kDisplay(115)");
				argc--; argv++;
			}
			break;
		default:
			SciTrackOriginReply originReply;
			SciWorkaroundSolution solution = trackOriginAndFindWorkaround(0, kDisplay_workarounds, &originReply);
			if (solution.type == WORKAROUND_NONE)
				error("Unknown kDisplay argument (%04x:%04x) from method %s::%s (script %d, localCall %x)",
						PRINT_REG(displayArg), originReply.objectName.c_str(), originReply.methodName.c_str(),
						originReply.scriptNr, originReply.localCallOffset);
			assert(solution.type == WORKAROUND_IGNORE);
			break;
		}
	}

	// now drawing the text
	_text16->Size(rect, text, -1, width);
	rect.moveTo(_ports->getPort()->curLeft, _ports->getPort()->curTop);
	// Note: This code has been found in SCI1 middle and newer games. It was
	// previously only for SCI1 late and newer, but the LSL1 interpreter contains
	// this code.
	if (getSciVersion() >= SCI_VERSION_1_MIDDLE) {
		int16 leftPos = rect.right <= _screen->getWidth() ? 0 : _screen->getWidth() - rect.right;
		int16 topPos = rect.bottom <= _screen->getHeight() ? 0 : _screen->getHeight() - rect.bottom;
		_ports->move(leftPos, topPos);
		rect.moveTo(_ports->getPort()->curLeft, _ports->getPort()->curTop);
	}

	if (doSaveUnder)
		result = bitsSave(rect, GFX_SCREEN_MASK_VISUAL);
	if (colorBack != -1)
		fillRect(rect, GFX_SCREEN_MASK_VISUAL, colorBack, 0, 0);
	_text16->Box(text, false, rect, alignment, -1);
	if (_screen->_picNotValid == 0 && bRedraw)
		bitsShow(rect);
	// restoring port and cursor pos
	Port *currport = _ports->getPort();
	uint16 tTop = currport->curTop;
	uint16 tLeft = currport->curLeft;
	if (!g_sci->_features->usesOldGfxFunctions()) {
		// Restore port settings for some SCI0LATE and SCI01+ only.
		//
		// The change actually happened inbetween .530 (hoyle1) and .566 (heros
		// quest). We don't have any detection for that currently, so we are
		// using oldGfxFunctions (.502). The only games that could get
		// regressions because of this are hoyle1, kq4 and funseeker. If there
		// are regressions, we should use interpreter version (which would
		// require exe version detection).
		//
		// If we restore the port for whole SCI0LATE, at least sq3old will get
		// an issue - font 0 will get used when scanning for planets instead of
		// font 600 - a setfont parameter is missing in one of the kDisplay
		// calls in script 19. I assume this is a script bug, because it was
		// added in sq3new.
		*currport = oldPort;
	}
	currport->curTop = tTop;
	currport->curLeft = tLeft;
	return result;
}
Example #8
0
void ThemeEngine::restoreBackground(Common::Rect r) {
	r.clip(_screen.w, _screen.h);
	_vectorRenderer->blitSurface(&_backBuffer, r);
}
Example #9
0
void DeathMenu::drawAllScores() {
	Surface numbers;
	numbers.getImageFromPICTFile("Images/Death Screens/Numbers.pict");

	Common::Rect scoreBounds;
	GameScoreType caldoriaTotal = 0;

	switch (_deathReason) {
	case kDeathCardBomb:
	case kDeathShotBySinclair:
	case kDeathSinclairShotDelegate:
	case kDeathNuclearExplosion:
	case kDeathGassedInNorad:
	case kDeathWokeUpNorad:
	case kDeathArrestedInNorad:
	case kDeathSubDestroyed:
	case kDeathRobotThroughNoradDoor:
	case kDeathRobotSubControlRoom:
	case kDeathWrongShuttleLock:
	case kDeathArrestedInMars:
	case kDeathRunOverByPod:
	case kDeathDidntGetOutOfWay:
	case kDeathReactorBurn:
	case kDeathDidntFindMarsBomb:
	case kDeathDidntDisarmMarsBomb:
	case kDeathNoMaskInMaze:
	case kDeathNoAirInMaze:
	case kDeathGroundByMazebot:
	case kDeathMissedOreBucket:
	case kDeathDidntLeaveBucket:
	case kDeathRanIntoCanyonWall:
	case kDeathRanIntoSpaceJunk:
	case kDeathDidntStopPoison:
	case kDeathArrestedInWSC:
	case kDeathHitByPlasma:
	case kDeathShotOnCatwalk:
	case kPlayerWonGame:
		caldoriaTotal += kMaxCaldoriaTSAScoreAfter;
		scoreBounds = Common::Rect(kDeathScreenScoreLeft, kDeathScreenScoreTop - kDeathScreenScoreSkipVert * 5,
				kDeathScreenScoreLeft + kDeathScreenScoreWidth, kDeathScreenScoreTop - kDeathScreenScoreSkipVert * 5 + kDeathScreenScoreHeight);
		drawScore(GameState.getGandhiScore(), kMaxGandhiScore, scoreBounds, &numbers);

		scoreBounds.translate(0, kDeathScreenScoreSkipVert);
		drawScore(GameState.getWSCScore(), kMaxWSCScore, scoreBounds, &numbers);

		scoreBounds.translate(0, kDeathScreenScoreSkipVert);
		drawScore(GameState.getNoradScore(), kMaxNoradScore, scoreBounds, &numbers);

		scoreBounds.translate(0, kDeathScreenScoreSkipVert);
		drawScore(GameState.getMarsScore(), kMaxMarsScore, scoreBounds, &numbers);
		// fall through
	case kDeathFallOffCliff:
	case kDeathEatenByDinosaur:
	case kDeathStranded:
	case kDeathShotByTSARobots:
		scoreBounds = Common::Rect(kDeathScreenScoreLeft, kDeathScreenScoreTop - kDeathScreenScoreSkipVert,
				kDeathScreenScoreLeft + kDeathScreenScoreWidth, kDeathScreenScoreTop - kDeathScreenScoreSkipVert + kDeathScreenScoreHeight);
		drawScore(GameState.getPrehistoricScore(), kMaxPrehistoricScore, scoreBounds, &numbers);
		// fall through
	case kDeathUncreatedInCaldoria:
	case kDeathUncreatedInTSA:
		scoreBounds = Common::Rect(kDeathScreenScoreLeft, kDeathScreenScoreTop, kDeathScreenScoreLeft + kDeathScreenScoreWidth,
				kDeathScreenScoreTop + kDeathScreenScoreHeight);
		caldoriaTotal += kMaxCaldoriaTSAScoreBefore;
		drawScore(GameState.getCaldoriaTSAScore(), caldoriaTotal, scoreBounds, &numbers);

		scoreBounds = Common::Rect(kDeathScreenScoreLeft, kDeathScreenScoreTop - kDeathScreenScoreSkipVert * 6,
				kDeathScreenScoreLeft + kDeathScreenScoreWidth, kDeathScreenScoreTop - kDeathScreenScoreSkipVert * 6 + kDeathScreenScoreHeight);

		drawScore(GameState.getTotalScore(), kMaxTotalScore, scoreBounds, &numbers);
		break;
	}
}
Example #10
0
Window *GfxPorts::addWindow(const Common::Rect &dims, const Common::Rect *restoreRect, const char *title, uint16 style, int16 priority, bool draw) {
	// Find an unused window/port id
	uint id = PORTS_FIRSTWINDOWID;
	while (id < _windowsById.size() && _windowsById[id]) {
		if (_windowsById[id]->counterTillFree) {
			// port that is already disposed, but not freed yet
			freeWindow((Window *)_windowsById[id]);
			_freeCounter--;
			break; // reuse the handle
			// we do this especially for sq4cd. it creates and disposes the
			//  inventory window all the time, but reuses old handles as well
			//  this worked somewhat under the original interpreter, because
			//  it put the new window where the old was.
		}
		++id;
	}
	if (id == _windowsById.size())
		_windowsById.push_back(0);
	assert(0 < id && id < 0xFFFF);

	Window *pwnd = new Window(id);
	Common::Rect r;

	if (!pwnd) {
		error("Can't open window");
		return 0;
	}

	_windowsById[id] = pwnd;

	// KQ1sci, KQ4, iceman, QfG2 always add windows to the back of the list.
	// KQ5CD checks style.
	// Hoyle3-demo also always adds to the back (#3036763).
	bool forceToBack = (getSciVersion() <= SCI_VERSION_1_EGA_ONLY) ||
	                   (g_sci->getGameId() == GID_HOYLE3 && g_sci->isDemo());

	if (!forceToBack && (style & SCI_WINDOWMGR_STYLE_TOPMOST))
		_windowList.push_front(pwnd);
	else
		_windowList.push_back(pwnd);
	openPort(pwnd);

	r = dims;
	// This looks fishy, but it's exactly what Sierra did. They removed last
	// bit of the left dimension in their interpreter. It seems Sierra did it
	// for EGA byte alignment (EGA uses 1 byte for 2 pixels) and left it in
	// their interpreter even in the newer VGA games.
	r.left = r.left & 0xFFFE;

	if (r.width() > _screen->getWidth()) {
		// We get invalid dimensions at least at the end of sq3 (script bug!).
		// Same happens very often in lsl5, sierra sci didnt fix it but it looked awful.
		// Also happens frequently in the demo of GK1.
		warning("Fixing too large window, left: %d, right: %d", dims.left, dims.right);
		r.left = 0;
		r.right = _screen->getWidth() - 1;
		if ((style != _styleUser) && !(style & SCI_WINDOWMGR_STYLE_NOFRAME))
			r.right--;
	}
	pwnd->rect = r;
	if (restoreRect)
		pwnd->restoreRect = *restoreRect;

	pwnd->wndStyle = style;
	pwnd->hSaved1 = pwnd->hSaved2 = NULL_REG;
	pwnd->bDrawn = false;
	if ((style & SCI_WINDOWMGR_STYLE_TRANSPARENT) == 0)
		pwnd->saveScreenMask = (priority == -1 ? GFX_SCREEN_MASK_VISUAL : GFX_SCREEN_MASK_VISUAL | GFX_SCREEN_MASK_PRIORITY);

	if (title && (style & SCI_WINDOWMGR_STYLE_TITLE)) {
		pwnd->title = title;
	}

	r = pwnd->rect;
	if ((style != _styleUser) && !(style & SCI_WINDOWMGR_STYLE_NOFRAME)) {
		r.grow(1);
		if (style & SCI_WINDOWMGR_STYLE_TITLE) {
			r.top -= 10;
			r.bottom++;
		}
	}

	pwnd->dims = r;

	// Clip window, if needed
	Common::Rect wmprect = _wmgrPort->rect;
	// Handle a special case for Dr. Brain 1 Mac. When hovering the mouse cursor
	// over the status line on top, the game scripts try to draw the game's icon
	// bar above the current port, by specifying a negative window top, so that
	// the end result will be drawn 10 pixels above the current port. This is a
	// hack by Sierra, and is only limited to user style windows. Normally, we
	// should not clip, same as what Sierra does. However, this will result in
	// having invalid rectangles with negative coordinates. For this reason, we
	// adjust the containing rectangle instead.
	if (pwnd->dims.top < 0 && g_sci->getPlatform() == Common::kPlatformMacintosh &&
		(style & SCI_WINDOWMGR_STYLE_USER) && _wmgrPort->top + pwnd->dims.top >= 0) {
		// Offset the final rect top by the requested pixels
		wmprect.top += pwnd->dims.top;
	}

	int16 oldtop = pwnd->dims.top;
	int16 oldleft = pwnd->dims.left;

	if (wmprect.top > pwnd->dims.top)
		pwnd->dims.moveTo(pwnd->dims.left, wmprect.top);

	if (wmprect.bottom < pwnd->dims.bottom)
		pwnd->dims.moveTo(pwnd->dims.left, wmprect.bottom - pwnd->dims.bottom + pwnd->dims.top);

	if (wmprect.right < pwnd->dims.right)
		pwnd->dims.moveTo(wmprect.right + pwnd->dims.left - pwnd->dims.right, pwnd->dims.top);

	if (wmprect.left > pwnd->dims.left)
		pwnd->dims.moveTo(wmprect.left, pwnd->dims.top);

	pwnd->rect.moveTo(pwnd->rect.left + pwnd->dims.left - oldleft, pwnd->rect.top + pwnd->dims.top - oldtop);

	if (restoreRect == 0)
		pwnd->restoreRect = pwnd->dims;

	if (pwnd->restoreRect.top < 0 && g_sci->getPlatform() == Common::kPlatformMacintosh &&
		(style & SCI_WINDOWMGR_STYLE_USER) && _wmgrPort->top + pwnd->restoreRect.top >= 0) {
		// Special case for Dr. Brain 1 Mac (check above), applied to the
		// restore rectangle.
		pwnd->restoreRect.moveTo(pwnd->restoreRect.left, wmprect.top);
	}

	if (draw)
		drawWindow(pwnd);
	setPort((Port *)pwnd);

	// All SCI0 games till kq4 .502 (not including) did not adjust against _wmgrPort, we set _wmgrPort->top to 0 in that case
	setOrigin(pwnd->rect.left, pwnd->rect.top + _wmgrPort->top);
	pwnd->rect.moveTo(0, 0);
	return pwnd;
}
Example #11
0
void GfxPorts::drawWindow(Window *pWnd) {
	if (pWnd->bDrawn)
		return;
	int16 wndStyle = pWnd->wndStyle;

	pWnd->bDrawn = true;
	Port *oldport = setPort(_wmgrPort);
	penColor(0);
	if ((wndStyle & SCI_WINDOWMGR_STYLE_TRANSPARENT) == 0) {
		pWnd->hSaved1 = _paint16->bitsSave(pWnd->restoreRect, GFX_SCREEN_MASK_VISUAL);
		if (pWnd->saveScreenMask & GFX_SCREEN_MASK_PRIORITY) {
			pWnd->hSaved2 = _paint16->bitsSave(pWnd->restoreRect, GFX_SCREEN_MASK_PRIORITY);
			if ((wndStyle & SCI_WINDOWMGR_STYLE_USER) == 0)
				_paint16->fillRect(pWnd->restoreRect, GFX_SCREEN_MASK_PRIORITY, 0, 15);
		}
	}

	// drawing frame,shadow and title
	if ((getSciVersion() >= SCI_VERSION_1_LATE) ? !(wndStyle & _styleUser) : wndStyle != _styleUser) {
		Common::Rect r = pWnd->dims;

		if (!(wndStyle & SCI_WINDOWMGR_STYLE_NOFRAME)) {
			r.top++;
			r.left++;
			_paint16->frameRect(r);// draw shadow
			r.translate(-1, -1);
			_paint16->frameRect(r);// draw actual window frame

			if (wndStyle & SCI_WINDOWMGR_STYLE_TITLE) {
				if (getSciVersion() <= SCI_VERSION_0_LATE) {
					// draw a black line between titlebar and actual window content for SCI0
					r.bottom = r.top + 10;
					_paint16->frameRect(r);
				}
				r.grow(-1);
				if (getSciVersion() <= SCI_VERSION_0_LATE)
					_paint16->fillRect(r, GFX_SCREEN_MASK_VISUAL, 8); // grey titlebar for SCI0
				else
					_paint16->fillRect(r, GFX_SCREEN_MASK_VISUAL, 0); // black titlebar for SCI01+
				if (!pWnd->title.empty()) {
					int16 oldcolor = getPort()->penClr;
					penColor(_screen->getColorWhite());
					_text16->Box(pWnd->title.c_str(), true, r, SCI_TEXT16_ALIGNMENT_CENTER, 0);
					penColor(oldcolor);
				}

				r.grow(+1);
				r.bottom = pWnd->dims.bottom - 1;
				r.top += 9;
			}

			r.grow(-1);
		}

		if (!(wndStyle & SCI_WINDOWMGR_STYLE_TRANSPARENT))
			_paint16->fillRect(r, GFX_SCREEN_MASK_VISUAL, pWnd->backClr);

		_paint16->bitsShow(pWnd->dims);
	}
	setPort(oldport);
}
Example #12
0
void PressureDoor::openInteraction() {
	if (_isUpperDoor) {
		_levelsMovie.initFromMovieFile("Images/Norad Alpha/Upper Levels Movie");
		_levelsMovie.moveElementTo(kNoradUpperLevelsLeft, kNoradUpperLevelsTop);
	} else {
		_levelsMovie.initFromMovieFile("Images/Norad Alpha/Lower Levels Movie");
		_levelsMovie.moveElementTo(kNoradLowerLevelsLeft, kNoradLowerLevelsTop);
	}

	_levelsScale = _levelsMovie.getScale();
	_levelsMovie.setDisplayOrder(kPressureLevelsOrder);
	_levelsMovie.startDisplaying();
	_levelsMovie.setSegment(kLevelsSplashStart * _levelsScale, kLevelsSplashStop * _levelsScale);
	_levelsMovie.setTime(kLevelsSplashStart * _levelsScale);
	_levelsMovie.redrawMovieWorld();
	_levelsMovie.show();

	_pressureCallBack.setNotification(&_pressureNotification);
	_pressureCallBack.initCallBack(&_levelsMovie, kCallBackAtExtremes);
	_pressureCallBack.setCallBackFlag(kSplashFinished);
	_pressureCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);

	_pressureNotification.notifyMe(this, kPressureNotificationFlags, kPressureNotificationFlags);

	if (_isUpperDoor) {
		_typeMovie.initFromMovieFile("Images/Norad Alpha/Upper Type Movie");
		_typeMovie.moveElementTo(kNoradUpperTypeLeft, kNoradUpperTypeTop);
	} else {
		_typeMovie.initFromMovieFile("Images/Norad Alpha/Lower Type Movie");
		_typeMovie.moveElementTo(kNoradLowerTypeLeft, kNoradLowerTypeTop);
	}

	_typeScale = _typeMovie.getScale();
	_typeMovie.setDisplayOrder(kPressureTypeOrder);
	_typeMovie.startDisplaying();
	_typeMovie.setTime(kDoorSealedTime * _typeScale);
	_typeMovie.redrawMovieWorld();

	SpriteFrame *frame = new SpriteFrame();
	if (_isUpperDoor)
		frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kLowerPressureUpOffPICTID);
	else
		frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kUpperPressureUpOffPICTID);
	_upButton.addFrame(frame, 0, 0);

	frame = new SpriteFrame();
	if (_isUpperDoor)
		frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kLowerPressureUpOnPICTID);
	else
		frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kUpperPressureUpOnPICTID);
	_upButton.addFrame(frame, 0, 0);

	_upButton.setCurrentFrameIndex(0);
	_upButton.setDisplayOrder(kPressureUpOrder);

	Common::Rect r;
	frame->getSurfaceBounds(r);
	if (_isUpperDoor)
		r.moveTo(kNoradUpperUpLeft, kNoradUpperUpTop);
	else
		r.moveTo(kNoradLowerUpLeft, kNoradLowerUpTop);

	_upButton.setBounds(r);
	_upButton.startDisplaying();
	_upButton.show();

	frame = new SpriteFrame();
	if (_isUpperDoor)
		frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kLowerPressureDownOffPICTID);
	else
		frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kUpperPressureDownOffPICTID);
	_downButton.addFrame(frame, 0, 0);

	frame = new SpriteFrame();
	if (_isUpperDoor)
		frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kLowerPressureDownOnPICTID);
	else
		frame->initFromPICTResource(((PegasusEngine *)g_engine)->_resFork, kUpperPressureDownOnPICTID);
	_downButton.addFrame(frame, 0, 0);

	_downButton.setCurrentFrameIndex(0);
	_downButton.setDisplayOrder(kPressureDownOrder);

	frame->getSurfaceBounds(r);
	if (_isUpperDoor)
		r.moveTo(kNoradUpperDownLeft, kNoradUpperDownTop);
	else
		r.moveTo(kNoradLowerDownLeft, kNoradLowerDownTop);

	_downButton.setBounds(r);
	_downButton.startDisplaying();
	_downButton.show();

	_utilityCallBack.setNotification(&_utilityNotification);
	_utilityCallBack.initCallBack(&_utilityTimer, kCallBackAtTime);
	_utilityNotification.notifyMe(this, kUtilityNotificationFlags, kUtilityNotificationFlags);
	_utilityTimer.setMasterTimeBase(getOwner()->getNavMovie());

	if (_playingAgainstRobot)
		_neighborhoodNotification->notifyMe(this, kExtraCompletedFlag | kDelayCompletedFlag |
				kSpotSoundCompletedFlag, kExtraCompletedFlag | kDelayCompletedFlag | kSpotSoundCompletedFlag);
	else
		_neighborhoodNotification->notifyMe(this, kDelayCompletedFlag | kSpotSoundCompletedFlag,
				kDelayCompletedFlag | kSpotSoundCompletedFlag);

	_gameState = kPlayingSplash;
}
Example #13
0
reg_t GfxText32::createTextBitmap(reg_t textObject, uint16 maxWidth, uint16 maxHeight) {
	reg_t stringObject = readSelector(_segMan, textObject, SELECTOR(text));

	// The object in the text selector of the item can be either a raw string
	// or a Str object. In the latter case, we need to access the object's data
	// selector to get the raw string.
	if (_segMan->isHeapObject(stringObject))
		stringObject = readSelector(_segMan, stringObject, SELECTOR(data));

	Common::String text = _segMan->getString(stringObject);
	// HACK: The character offsets of the up and down arrow buttons are off by one
	// in GK1, for some unknown reason. Fix them here.
	if (text.size() == 1 && (text[0] == 29 || text[0] == 30)) {
		text.setChar(text[0] + 1, 0);
	}
	GuiResourceId fontId = readSelectorValue(_segMan, textObject, SELECTOR(font));
	GfxFont *font = _cache->getFont(fontId);
	bool dimmed = readSelectorValue(_segMan, textObject, SELECTOR(dimmed));
	int16 alignment = readSelectorValue(_segMan, textObject, SELECTOR(mode));
	uint16 foreColor = readSelectorValue(_segMan, textObject, SELECTOR(fore));
	uint16 backColor = readSelectorValue(_segMan, textObject, SELECTOR(back));

	Common::Rect nsRect = g_sci->_gfxCompare->getNSRect(textObject);
	uint16 width = nsRect.width() + 1;
	uint16 height = nsRect.height() + 1;

	// Limit rectangle dimensions, if requested
	if (maxWidth > 0)
		width = maxWidth;
	if (maxHeight > 0)
		height = maxHeight;

	// Upscale the coordinates/width if the fonts are already upscaled
	if (_screen->fontIsUpscaled()) {
		width = width * _screen->getDisplayWidth() / _screen->getWidth();
		height = height * _screen->getDisplayHeight() / _screen->getHeight();
	}

	int entrySize = width * height + BITMAP_HEADER_SIZE;
	reg_t memoryId = _segMan->allocateHunkEntry("TextBitmap()", entrySize);
	writeSelector(_segMan, textObject, SELECTOR(bitmap), memoryId);
	byte *memoryPtr = _segMan->getHunkPointer(memoryId);
	memset(memoryPtr, backColor, entrySize);
	byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE;

	// Save totalWidth, totalHeight
	WRITE_LE_UINT16(memoryPtr, width);
	WRITE_LE_UINT16(memoryPtr + 2, height);

	int16 charCount = 0;
	uint16 curX = 0, curY = 0;
	const char *txt = text.c_str();
	int16 textWidth, textHeight, totalHeight = 0, offsetX = 0, offsetY = 0;
	uint16 start = 0;

	// Calculate total text height
	while (*txt) {
		charCount = GetLongest(txt, width, font);
		if (charCount == 0)
			break;

		Width(txt, 0, (int16)strlen(txt), fontId, textWidth, textHeight, true);

		totalHeight += textHeight;
		txt += charCount;
		while (*txt == ' ')
			txt++; // skip over breaking spaces
	}

	txt = text.c_str();

	// Draw text in buffer
	while (*txt) {
		charCount = GetLongest(txt, width, font);
		if (charCount == 0)
			break;
		Width(txt, start, charCount, fontId, textWidth, textHeight, true);

		switch (alignment) {
		case SCI_TEXT32_ALIGNMENT_RIGHT:
			offsetX = width - textWidth;
			break;
		case SCI_TEXT32_ALIGNMENT_CENTER:
			// Center text both horizontally and vertically
			offsetX = (width - textWidth) / 2;
			offsetY = (height - totalHeight) / 2;
			break;
		case SCI_TEXT32_ALIGNMENT_LEFT:
			offsetX = 0;
			break;

		default:
			warning("Invalid alignment %d used in TextBox()", alignment);
		}

		for (int i = 0; i < charCount; i++) {
			unsigned char curChar = txt[i];
			font->drawToBuffer(curChar, curY + offsetY, curX + offsetX, foreColor, dimmed, bitmap, width, height);
			curX += font->getCharWidth(curChar);
		}

		curX = 0;
		curY += font->getHeight();
		txt += charCount;
		while (*txt == ' ')
			txt++; // skip over breaking spaces
	}

	return memoryId;
}
Example #14
0
bool RenderObject::getObjectIntersection(RenderObjectPtr<RenderObject> pObject, Common::Rect &result) {
	result = pObject->getBbox();
	result.clip(_bbox);
	return result.isValidRect();
}
Example #15
0
void RenderManager::prepareBackground() {
	_backgroundDirtyRect.clip(_backgroundWidth, _backgroundHeight);
	RenderTable::RenderState state = _renderTable.getRenderState();

	if (state == RenderTable::PANORAMA) {
		// Calculate the visible portion of the background
		Common::Rect viewPort(_workingWidth, _workingHeight);
		viewPort.translate(-(_screenCenterX - _backgroundOffset), 0);
		Common::Rect drawRect = _backgroundDirtyRect;
		drawRect.clip(viewPort);

		// Render the visible portion
		if (!drawRect.isEmpty()) {
			blitSurfaceToSurface(_currentBackgroundImage, drawRect, _backgroundSurface, _screenCenterX - _backgroundOffset + drawRect.left, drawRect.top);
		}

		// Mark the dirty portion of the surface
		_backgroundSurfaceDirtyRect = _backgroundDirtyRect;
		_backgroundSurfaceDirtyRect.translate(_screenCenterX - _backgroundOffset, 0);

		// Panorama mode allows the user to spin in circles. Therefore, we need to render 
		// the portion of the image that wrapped to the other side of the screen
		if (_backgroundOffset < _screenCenterX) {
			viewPort.moveTo(-(_screenCenterX - (_backgroundOffset + _backgroundWidth)), 0);
			drawRect = _backgroundDirtyRect;
			drawRect.clip(viewPort);

			if (!drawRect.isEmpty())
				blitSurfaceToSurface(_currentBackgroundImage, drawRect, _backgroundSurface, _screenCenterX - (_backgroundOffset + _backgroundWidth) + drawRect.left, drawRect.top);

			Common::Rect tmp = _backgroundDirtyRect;
			tmp.translate(_screenCenterX - (_backgroundOffset + _backgroundWidth), 0);
			if (!tmp.isEmpty())
				_backgroundSurfaceDirtyRect.extend(tmp);

		} else if (_backgroundWidth - _backgroundOffset < _screenCenterX) {
			viewPort.moveTo(-(_screenCenterX + _backgroundWidth - _backgroundOffset), 0);
			drawRect = _backgroundDirtyRect;
			drawRect.clip(viewPort);

			if (!drawRect.isEmpty())
				blitSurfaceToSurface(_currentBackgroundImage, drawRect, _backgroundSurface, _screenCenterX + _backgroundWidth - _backgroundOffset + drawRect.left, drawRect.top);

			Common::Rect tmp = _backgroundDirtyRect;
			tmp.translate(_screenCenterX + _backgroundWidth - _backgroundOffset, 0);
			if (!tmp.isEmpty())
				_backgroundSurfaceDirtyRect.extend(tmp);

		}
	} else if (state == RenderTable::TILT) {
		// Tilt doesn't allow wrapping, so we just do a simple clip
		Common::Rect viewPort(_workingWidth, _workingHeight);
		viewPort.translate(0, -(_screenCenterY - _backgroundOffset));
		Common::Rect drawRect = _backgroundDirtyRect;
		drawRect.clip(viewPort);
		if (!drawRect.isEmpty())
			blitSurfaceToSurface(_currentBackgroundImage, drawRect, _backgroundSurface, drawRect.left, _screenCenterY - _backgroundOffset + drawRect.top);

		// Mark the dirty portion of the surface
		_backgroundSurfaceDirtyRect = _backgroundDirtyRect;
		_backgroundSurfaceDirtyRect.translate(0, _screenCenterY - _backgroundOffset);

	} else {
		if (!_backgroundDirtyRect.isEmpty())
			blitSurfaceToSurface(_currentBackgroundImage, _backgroundDirtyRect, _backgroundSurface, _backgroundDirtyRect.left, _backgroundDirtyRect.top);
		_backgroundSurfaceDirtyRect = _backgroundDirtyRect;
	}

	// Clear the dirty rect since everything is clean now
	_backgroundDirtyRect = Common::Rect();

	_backgroundSurfaceDirtyRect.clip(_workingWidth, _workingHeight);
}
Example #16
0
/**
 * This copies a rect to screen w/o scaling adjustment and is only meant to be
 * used on hires graphics used in upscaled hires mode.
 */
void GfxScreen::copyDisplayRectToScreen(const Common::Rect &rect) {
	if (!_upscaledHires)
		error("copyDisplayRectToScreen: not in upscaled hires mode");
	g_system->copyRectToScreen(_activeScreen + rect.top * _displayWidth + rect.left, _displayWidth, rect.left, rect.top, rect.width(), rect.height());
}
void ShaderRenderer::setupCameraPerspective(float pitch, float heading, float fov) {
	Renderer::setupCameraPerspective(pitch, heading, fov);

	Common::Rect frame = frameViewport();
	glViewport(frame.left, frame.top, frame.width(), frame.height());
}
Example #18
0
void GfxScreen::copyRectToScreen(const Common::Rect &rect, int16 x, int16 y) {
	if (!_upscaledHires)  {
		g_system->copyRectToScreen(_activeScreen + rect.top * _displayWidth + rect.left, _displayWidth, x, y, rect.width(), rect.height());
	} else {
		int rectHeight = _upscaledMapping[rect.bottom] - _upscaledMapping[rect.top];
		g_system->copyRectToScreen(_activeScreen + _upscaledMapping[rect.top] * _displayWidth + rect.left * 2, _displayWidth, x * 2, _upscaledMapping[y], rect.width() * 2, rectHeight);
	}
}
Example #19
0
void Slide::drawSlideElement(const Common::Rect &drawRect, const Common::Rect &oldBounds, DisplayElement *picture) {
	if (picture && drawRect.intersects(oldBounds)) {
		picture->moveElementTo(oldBounds.left, oldBounds.top);
		picture->draw(drawRect.findIntersectingRect(oldBounds));
	}
}
Example #20
0
bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, float zoomX, float zoomY, uint32 alpha, bool alphaDisable, TSpriteBlendMode blendMode, bool mirrorX, bool mirrorY, int offsetX, int offsetY) {
	BaseRenderOSystem *renderer = static_cast<BaseRenderOSystem *>(_gameRef->_renderer);

	if (!_loaded) {
		finishLoad();
	}

	if (renderer->_forceAlphaColor != 0) {
		alpha = renderer->_forceAlphaColor;
	}

	byte r = RGBCOLGetR(alpha);
	byte g = RGBCOLGetG(alpha);
	byte b = RGBCOLGetB(alpha);
	byte a = RGBCOLGetA(alpha);

	renderer->setAlphaMod(a);
	renderer->setColorMod(r, g, b);

#if 0 // These are kept for reference if BlendMode is reimplemented at some point.
	if (alphaDisable) {
		SDL_SetTextureBlendMode(_texture, SDL_BLENDMODE_NONE);
	} else {
		SDL_SetTextureBlendMode(_texture, SDL_BLENDMODE_BLEND);
	}
#endif
	// TODO: This _might_ miss the intended behaviour by 1 in each direction
	// But I think it fits the model used in Wintermute.
	Common::Rect srcRect;
	srcRect.left = rect->left;
	srcRect.top = rect->top;
	srcRect.setWidth(rect->right - rect->left);
	srcRect.setHeight(rect->bottom - rect->top);

	Common::Rect position;
	position.left = x + offsetX;
	position.top = y + offsetY;

	// Crop off-by-ones:
	if (position.left == -1) {
		position.left = 0; // TODO: Something is wrong
	}
	if (position.top == -1) {
		position.top = 0; // TODO: Something is wrong
	}

	position.setWidth((int16)((float)srcRect.width() * zoomX / 100.f));
	position.setHeight((int16)((float)srcRect.height() * zoomX / 100.f));

	renderer->modTargetRect(&position);

	/*  position.left += offsetX;
	    position.top += offsetY;*/

	// TODO: This actually requires us to have the SAME source-offsets every time,
	// But no checking is in place for that yet.

	// TODO: Optimize by not doing alpha-blits if we lack or disable alpha
	bool hasAlpha;
	if (_hasAlpha && !alphaDisable) {
		hasAlpha = true;
	} else {
		hasAlpha = false;
	}
	if (alphaDisable) {
		warning("BaseSurfaceOSystem::drawSprite - AlphaDisable ignored");
	}

	renderer->drawSurface(this, _surface, &srcRect, &position, mirrorX, mirrorY, !hasAlpha);

	return STATUS_OK;
}
Example #21
0
void Menu::renderSubmenu(MenuItem *menu) {
	Common::Rect *r = &menu->subbbox;

	if (r->width() == 0 || r->height() == 0)
		return;

	Design::drawFilledRect(&_gui->_screen, *r, kColorWhite, _gui->_patterns, kPatternSolid);
	Design::drawRect(&_gui->_screen, *r, 1, kColorBlack, _gui->_patterns, kPatternSolid);
	Design::drawVLine(&_gui->_screen, r->right + 1, r->top + 3, r->bottom + 1, 1, kColorBlack, _gui->_patterns, kPatternSolid);
	Design::drawHLine(&_gui->_screen, r->left + 3, r->right + 1, r->bottom + 1, 1, kColorBlack, _gui->_patterns, kPatternSolid);

	int x = r->left + kMenuDropdownPadding;
	int y = r->top + 1;
	for (uint i = 0; i < menu->subitems.size(); i++) {
		Common::String text(menu->subitems[i]->text);
		Common::String acceleratorText(getAcceleratorString(menu->subitems[i], ""));
		int accelX = r->right - 25;

		int color = kColorBlack;
		if (i == (uint)_activeSubItem && !text.empty() && menu->subitems[i]->enabled) {
			color = kColorWhite;
			Common::Rect trect(r->left, y - (_gui->_builtInFonts ? 1 : 0), r->right, y + _font->getFontHeight());

			Design::drawFilledRect(&_gui->_screen, trect, kColorBlack, _gui->_patterns, kPatternSolid);
		}

		if (!text.empty()) {
			Graphics::ManagedSurface *s = &_gui->_screen;
			int tx = x, ty = y;

			if (!menu->subitems[i]->enabled) {
				s = &_tempSurface;
				tx = 0;
				ty = 0;
				accelX -= x;

				_tempSurface.clear(kColorGreen);
			}

			_font->drawString(s, text, tx, ty, r->width(), color);

			if (!acceleratorText.empty())
				_font->drawString(s, acceleratorText, accelX, ty, r->width(), color);

			if (!menu->subitems[i]->enabled) {
				// I am lazy to extend drawString() with plotProc as a parameter, so
				// fake it here
				for (int ii = 0; ii < _tempSurface.h; ii++) {
					const byte *src = (const byte *)_tempSurface.getBasePtr(0, ii);
					byte *dst = (byte *)_gui->_screen.getBasePtr(x, y+ii);
					byte pat = _gui->_patterns[kPatternCheckers2 - 1][ii % 8];
					for (int j = 0; j < r->width(); j++) {
						if (*src != kColorGreen && (pat & (1 << (7 - (x + j) % 8))))
							*dst = *src;
						src++;
						dst++;
					}
				}
			}
		} else { // Delimiter
			Design::drawHLine(&_gui->_screen, r->left + 1, r->right - 1, y + kMenuDropdownItemHeight / 2, 1, kColorBlack, _gui->_patterns, kPatternStripes);
		}

		y += kMenuDropdownItemHeight;
	}

	g_system->copyRectToScreen(_gui->_screen.getBasePtr(r->left, r->top), _gui->_screen.pitch, r->left, r->top, r->width() + 3, r->height() + 3);
}
Example #22
0
void GfxFrameout::kernelFrameout() {
	if (g_sci->_robotDecoder->isVideoLoaded()) {
		bool skipVideo = false;
		RobotDecoder *videoDecoder = g_sci->_robotDecoder;
		uint16 x = videoDecoder->getPos().x;
		uint16 y = videoDecoder->getPos().y;

		if (videoDecoder->hasDirtyPalette())
			videoDecoder->setSystemPalette();

		while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) {
			if (videoDecoder->needsUpdate()) {
				const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
				if (frame) {
					g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);

					if (videoDecoder->hasDirtyPalette())
						videoDecoder->setSystemPalette();

					g_system->updateScreen();
				}
			}

			Common::Event event;
			while (g_system->getEventManager()->pollEvent(event)) {
				if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP)
					skipVideo = true;
			}

			g_system->delayMillis(10);
		}
		return;
	}

	_palette->palVaryUpdate();

	for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); it++) {
		reg_t planeObject = it->object;
		uint16 planeLastPriority = it->lastPriority;

		// Update priority here, sq6 sets it w/o UpdatePlane
		uint16 planePriority = it->priority = readSelectorValue(_segMan, planeObject, SELECTOR(priority));

		it->lastPriority = planePriority;
		if (planePriority == 0xffff) { // Plane currently not meant to be shown
			// If plane was shown before, delete plane rect
			if (planePriority != planeLastPriority)
				_paint32->fillRect(it->planeRect, 0);
			continue;
		}

		if (it->planeBack)
			_paint32->fillRect(it->planeRect, it->planeBack);

		GuiResourceId planeMainPictureId = it->pictureId;

		_coordAdjuster->pictureSetDisplayArea(it->planeRect);
		_palette->drewPicture(planeMainPictureId);

		FrameoutList itemList;

		// Copy screen items of the current frame to the list of items to be drawn
		for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) {
			reg_t itemPlane = readSelector(_segMan, (*listIterator)->object, SELECTOR(plane));
			if (planeObject == itemPlane) {
				kernelUpdateScreenItem((*listIterator)->object);	// TODO: Why is this necessary?
				itemList.push_back(*listIterator);
			}
		}

		for (PlanePictureList::iterator pictureIt = _planePictures.begin(); pictureIt != _planePictures.end(); pictureIt++) {
			if (pictureIt->object == planeObject) {
				GfxPicture *planePicture = pictureIt->picture;
				// Allocate memory for picture cels
				pictureIt->pictureCels = new FrameoutEntry[planePicture->getSci32celCount()];

				// Add following cels to the itemlist
				FrameoutEntry *picEntry = pictureIt->pictureCels;
				int planePictureCels = planePicture->getSci32celCount();
				for (int pictureCelNr = 0; pictureCelNr < planePictureCels; pictureCelNr++) {
					picEntry->celNo = pictureCelNr;
					picEntry->object = NULL_REG;
					picEntry->picture = planePicture;
					picEntry->y = planePicture->getSci32celY(pictureCelNr);
					picEntry->x = planePicture->getSci32celX(pictureCelNr);
					picEntry->picStartX = pictureIt->startX;

					picEntry->priority = planePicture->getSci32celPriority(pictureCelNr);

					itemList.push_back(picEntry);
					picEntry++;
				}
			}
		}

		// Now sort our itemlist
		Common::sort(itemList.begin(), itemList.end(), sortHelper);

//		warning("Plane %s", _segMan->getObjectName(planeObject));

		for (FrameoutList::iterator listIterator = itemList.begin(); listIterator != itemList.end(); listIterator++) {
			FrameoutEntry *itemEntry = *listIterator;

			if (itemEntry->object.isNull()) {
				// Picture cel data
				itemEntry->y = ((itemEntry->y * _screen->getHeight()) / scriptsRunningHeight);
				itemEntry->x = ((itemEntry->x * _screen->getWidth()) / scriptsRunningWidth);
				itemEntry->picStartX = ((itemEntry->picStartX * _screen->getWidth()) / scriptsRunningWidth);

				// Out of view
				int16 pictureCelStartX = itemEntry->picStartX + itemEntry->x;
				int16 pictureCelEndX = pictureCelStartX + itemEntry->picture->getSci32celWidth(itemEntry->celNo);
				int16 planeStartX = it->planeOffsetX;
				int16 planeEndX = planeStartX + it->planeRect.width();
				if (pictureCelEndX < planeStartX)
					continue;
				if (pictureCelStartX > planeEndX)
					continue;

				int16 pictureOffsetX = it->planeOffsetX;
				int16 pictureX = itemEntry->x;
				if ((it->planeOffsetX) || (itemEntry->picStartX)) {
					if (it->planeOffsetX <= itemEntry->picStartX) {
						pictureX += itemEntry->picStartX - it->planeOffsetX;
						pictureOffsetX = 0;
					} else {
						pictureOffsetX = it->planeOffsetX - itemEntry->picStartX;
					}
				}

				itemEntry->picture->drawSci32Vga(itemEntry->celNo, pictureX, itemEntry->y, pictureOffsetX, it->planePictureMirrored);
//				warning("picture cel %d %d", itemEntry->celNo, itemEntry->priority);

			} else if (itemEntry->viewId != 0xFFFF) {
				GfxView *view = _cache->getView(itemEntry->viewId);

//				warning("view %s %04x:%04x", _segMan->getObjectName(itemEntry->object), PRINT_REG(itemEntry->object));


				if (view->isSci2Hires()) {
					int16 dummyX = 0;
					_screen->adjustToUpscaledCoordinates(itemEntry->y, itemEntry->x);
					_screen->adjustToUpscaledCoordinates(itemEntry->z, dummyX);
				} else if (getSciVersion() == SCI_VERSION_2_1) {
					itemEntry->y = (itemEntry->y * _screen->getHeight()) / scriptsRunningHeight;
					itemEntry->x = (itemEntry->x * _screen->getWidth()) / scriptsRunningWidth;
					itemEntry->z = (itemEntry->z * _screen->getHeight()) / scriptsRunningHeight;
				}

				// Adjust according to current scroll position
				itemEntry->x -= it->planeOffsetX;

				uint16 useInsetRect = readSelectorValue(_segMan, itemEntry->object, SELECTOR(useInsetRect));
				if (useInsetRect) {
					itemEntry->celRect.top = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inTop));
					itemEntry->celRect.left = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inLeft));
					itemEntry->celRect.bottom = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inBottom)) + 1;
					itemEntry->celRect.right = readSelectorValue(_segMan, itemEntry->object, SELECTOR(inRight)) + 1;
					if (view->isSci2Hires()) {
						_screen->adjustToUpscaledCoordinates(itemEntry->celRect.top, itemEntry->celRect.left);
						_screen->adjustToUpscaledCoordinates(itemEntry->celRect.bottom, itemEntry->celRect.right);
					}
					itemEntry->celRect.translate(itemEntry->x, itemEntry->y);
					// TODO: maybe we should clip the cels rect with this, i'm not sure
					//  the only currently known usage is game menu of gk1
				} else {
					if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128))
						view->getCelRect(itemEntry->loopNo, itemEntry->celNo, itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->celRect);
					else
						view->getCelScaledRect(itemEntry->loopNo, itemEntry->celNo, itemEntry->x, itemEntry->y, itemEntry->z, itemEntry->scaleX, itemEntry->scaleY, itemEntry->celRect);

					Common::Rect nsRect = itemEntry->celRect;
					// Translate back to actual coordinate within scrollable plane
					nsRect.translate(it->planeOffsetX, 0);

					if (view->isSci2Hires()) {
						_screen->adjustBackUpscaledCoordinates(nsRect.top, nsRect.left);
						_screen->adjustBackUpscaledCoordinates(nsRect.bottom, nsRect.right);
					} else if (getSciVersion() == SCI_VERSION_2_1) {
						nsRect.top = (nsRect.top * scriptsRunningHeight) / _screen->getHeight();
						nsRect.left = (nsRect.left * scriptsRunningWidth) / _screen->getWidth();
						nsRect.bottom = (nsRect.bottom * scriptsRunningHeight) / _screen->getHeight();
						nsRect.right = (nsRect.right * scriptsRunningWidth) / _screen->getWidth();
					}

					writeSelectorValue(_segMan, itemEntry->object, SELECTOR(nsLeft), nsRect.left);
					writeSelectorValue(_segMan, itemEntry->object, SELECTOR(nsTop), nsRect.top);
					writeSelectorValue(_segMan, itemEntry->object, SELECTOR(nsRight), nsRect.right);
					writeSelectorValue(_segMan, itemEntry->object, SELECTOR(nsBottom), nsRect.bottom);
				}

				int16 screenHeight = _screen->getHeight();
				int16 screenWidth = _screen->getWidth();
				if (view->isSci2Hires()) {
					screenHeight = _screen->getDisplayHeight();
					screenWidth = _screen->getDisplayWidth();
				}

				if (itemEntry->celRect.bottom < 0 || itemEntry->celRect.top >= screenHeight)
					continue;

				if (itemEntry->celRect.right < 0 || itemEntry->celRect.left >= screenWidth)
					continue;

				Common::Rect clipRect, translatedClipRect;
				clipRect = itemEntry->celRect;
				if (view->isSci2Hires()) {
					clipRect.clip(it->upscaledPlaneClipRect);
					translatedClipRect = clipRect;
					translatedClipRect.translate(it->upscaledPlaneRect.left, it->upscaledPlaneRect.top);
				} else {
					clipRect.clip(it->planeClipRect);
					translatedClipRect = clipRect;
					translatedClipRect.translate(it->planeRect.left, it->planeRect.top);
				}

				if (!clipRect.isEmpty()) {
					if ((itemEntry->scaleX == 128) && (itemEntry->scaleY == 128))
						view->draw(itemEntry->celRect, clipRect, translatedClipRect, itemEntry->loopNo, itemEntry->celNo, 255, 0, view->isSci2Hires());
					else
						view->drawScaled(itemEntry->celRect, clipRect, translatedClipRect, itemEntry->loopNo, itemEntry->celNo, 255, itemEntry->scaleX, itemEntry->scaleY);
				}
			} else {
				// Most likely a text entry
				// This draws text the "SCI0-SCI11" way. In SCI2, text is prerendered in kCreateTextBitmap
				// TODO: rewrite this the "SCI2" way (i.e. implement the text buffer to draw inside kCreateTextBitmap)
				if (lookupSelector(_segMan, itemEntry->object, SELECTOR(text), NULL, NULL) == kSelectorVariable) {
					reg_t stringObject = readSelector(_segMan, itemEntry->object, SELECTOR(text));

					// The object in the text selector of the item can be either a raw string
					// or a Str object. In the latter case, we need to access the object's data
					// selector to get the raw string.
					if (_segMan->isHeapObject(stringObject))
						stringObject = readSelector(_segMan, stringObject, SELECTOR(data));

					Common::String text = _segMan->getString(stringObject);
					GfxFont *font = _cache->getFont(readSelectorValue(_segMan, itemEntry->object, SELECTOR(font)));
					bool dimmed = readSelectorValue(_segMan, itemEntry->object, SELECTOR(dimmed));
					uint16 foreColor = readSelectorValue(_segMan, itemEntry->object, SELECTOR(fore));

					itemEntry->y = ((itemEntry->y * _screen->getHeight()) / scriptsRunningHeight);
					itemEntry->x = ((itemEntry->x * _screen->getWidth()) / scriptsRunningWidth);

					uint16 startX = itemEntry->x + it->planeRect.left;
					uint16 curY = itemEntry->y + it->planeRect.top;
					const char *txt = text.c_str();
					// HACK. The plane sometimes doesn't contain the correct width. This
					// hack breaks the dialog options when speaking with Grace, but it's
					// the best we got up to now. This happens because of the unimplemented
					// kTextWidth function in SCI32.
					// TODO: Remove this once kTextWidth has been implemented.
					uint16 w = it->planeRect.width() >= 20 ? it->planeRect.width() : _screen->getWidth() - 10;
					int16 charCount;

					// Upscale the coordinates/width if the fonts are already upscaled
					if (_screen->fontIsUpscaled()) {
						startX = startX * _screen->getDisplayWidth() / _screen->getWidth();
						curY = curY * _screen->getDisplayHeight() / _screen->getHeight();
						w  = w * _screen->getDisplayWidth() / _screen->getWidth();
					}

					while (*txt) {
						charCount = GetLongest(txt, w, font);
						if (charCount == 0)
							break;

						uint16 curX = startX;

						for (int i = 0; i < charCount; i++) {
							unsigned char curChar = txt[i];
							font->draw(curChar, curY, curX, foreColor, dimmed);
							curX += font->getCharWidth(curChar);
						}

						curY += font->getHeight();
						txt += charCount;
						while (*txt == ' ')
							txt++; // skip over breaking spaces
					}

				}
			}
		}

		for (PlanePictureList::iterator pictureIt = _planePictures.begin(); pictureIt != _planePictures.end(); pictureIt++) {
			if (pictureIt->object == planeObject) {
				delete[] pictureIt->pictureCels;
				pictureIt->pictureCels = 0;
			}
		}
	}

	_screen->copyToScreen();

	g_sci->getEngineState()->_throttleTrigger = true;
}
Example #23
0
bool VideoManager::drawNextFrame(VideoEntryPtr videoEntry) {
	Video::VideoDecoder *video = videoEntry->_video;
	const Graphics::Surface *frame = video->decodeNextFrame();

	if (!frame || !videoEntry->isEnabled()) {
		return false;
	}

	Graphics::Surface *convertedFrame = nullptr;
	Graphics::PixelFormat pixelFormat = _vm->_system->getScreenFormat();

	if (frame->format != pixelFormat) {
		// We don't support downconverting to 8bpp without having
		// support in the codec. Set _enableDither if shows up.
		if (pixelFormat.bytesPerPixel == 1) {
			warning("Cannot convert high color video frame to 8bpp");
			return false;
		}

		// Convert to the current screen format
		convertedFrame = frame->convertTo(pixelFormat, video->getPalette());
		frame = convertedFrame;
	} else if (pixelFormat.bytesPerPixel == 1 && video->hasDirtyPalette()) {
		// Set the palette when running in 8bpp mode only
		// Don't do this for Myst, which has its own per-stack handling
		if (_vm->getGameType() != GType_MYST)
			_vm->_system->getPaletteManager()->setPalette(video->getPalette(), 0, 256);
	}

	// Clip the video to make sure it stays on the screen (Myst does this a few times)
	Common::Rect targetRect = Common::Rect(video->getWidth(), video->getHeight());
	targetRect.translate(videoEntry->getX(), videoEntry->getY());

	Common::Rect frameRect = Common::Rect(video->getWidth(), video->getHeight());

	if (targetRect.left < 0) {
		frameRect.left -= targetRect.left;
		targetRect.left = 0;
	}

	if (targetRect.top < 0) {
		frameRect.top -= targetRect.top;
		targetRect.top = 0;
	}

	if (targetRect.right > _vm->_system->getWidth()) {
		frameRect.right -= targetRect.right - _vm->_system->getWidth();
		targetRect.right = _vm->_system->getWidth();
	}

	if (targetRect.bottom > _vm->_system->getHeight()) {
		frameRect.bottom -= targetRect.bottom - _vm->_system->getHeight();
		targetRect.bottom = _vm->_system->getHeight();
	}

	_vm->_system->copyRectToScreen(frame->getBasePtr(frameRect.left, frameRect.top), frame->pitch,
	                               targetRect.left, targetRect.top, targetRect.width(), targetRect.height());

	// Delete 8bpp conversion surface
	if (convertedFrame) {
		convertedFrame->free();
		delete convertedFrame;
	}

	// We've drawn something to the screen, make sure we update it
	return true;
}
Example #24
0
bool AgiEngine::handleMouseClicks(uint16 &key) {
	// No mouse click? -> exit
	if (key != AGI_MOUSE_BUTTON_LEFT)
		return false;

	if (!cycleInnerLoopIsActive()) {
		// Only do this, when no inner loop is currently active
		Common::Rect displayLineRect = _gfx->getFontRectForDisplayScreen(0, 0, FONT_COLUMN_CHARACTERS, 1);
//		Common::Rect displayLineRect(_gfx->getDisplayScreenWidth(), _gfx->getDisplayFontHeight());

		if (displayLineRect.contains(_mouse.pos)) {
			// Mouse is inside first line of the screen
			if (getFlag(VM_FLAG_MENUS_ACCESSIBLE) && _menu->isAvailable()) {
				_menu->delayedExecuteViaMouse();
				key = 0; // eat event
				return true;
			}
		}

		if (_text->promptIsEnabled()) {
			// Prompt is currently enabled
			int16 promptRow = _text->promptRow_Get();

			displayLineRect.moveTo(0, promptRow * _gfx->getDisplayFontHeight());

			if (displayLineRect.contains(_mouse.pos)) {
				// and user clicked within the line of the prompt
				showPredictiveDialog();

				key = 0; // eat event
				return true;
			}
		}
	}

	if (cycleInnerLoopIsActive()) {
		// inner loop active, check what kind of loop it is. Then process / forward it
		switch (_game.cycleInnerLoopType) {
		case CYCLE_INNERLOOP_GETSTRING:
		case CYCLE_INNERLOOP_GETNUMBER: {
			// process in here
			int16 stringRow, stringColumn, stringMaxLen;

			_text->stringPos_Get(stringRow, stringColumn);
			stringMaxLen = _text->stringGetMaxLen();

			Common::Rect displayRect = _gfx->getFontRectForDisplayScreen(stringColumn, stringRow, stringMaxLen, 1);
			if (displayRect.contains(_mouse.pos)) {
				// user clicked inside the input space
				showPredictiveDialog();

				key = 0; // eat event
				return true;
			}
			break;
		}
		case CYCLE_INNERLOOP_INVENTORY:
			// TODO: forward
			break;

		case CYCLE_INNERLOOP_MENU_VIA_KEYBOARD:
			_menu->mouseEvent(key);
			key = 0; // eat event
			break;

		case CYCLE_INNERLOOP_SYSTEMUI_SELECTSAVEDGAMESLOT:
			// TODO: forward
			break;

		default:
			break;
		}
	}
	return false;
}
Example #25
0
void CUP_Player::copyRectToScreen(const Common::Rect &r) {
	const uint8 *src = _offscreenBuffer + r.top * _width + r.left;
	_system->copyRectToScreen(src, _width, r.left, r.top, r.width() + 1, r.height() + 1);
}
Example #26
0
uint16 PopupMenu::Show(int numEntries, const char *actions[]) {
	if (numEntries == 0) return 0xffff;
	LureEngine &engine = LureEngine::getReference();
	Events &e = Events::getReference();
	Mouse &mouse = Mouse::getReference();
	OSystem &system = *g_system;
	Screen &screen = Screen::getReference();
	Common::Rect r;
	bool isEGA = LureEngine::getReference().isEGA();
	byte bgColor = isEGA ? EGA_DIALOG_BG_COLOR : 0;
	byte textColor = isEGA ? EGA_DIALOG_TEXT_COLOR : VGA_DIALOG_TEXT_COLOR;
	byte whiteColor = isEGA ? EGA_DIALOG_WHITE_COLOR : VGA_DIALOG_WHITE_COLOR;


	const uint16 yMiddle = FULL_SCREEN_HEIGHT / 2;
#ifndef LURE_CLICKABLE_MENUS
	uint16 oldX = mouse.x();
	uint16 oldY = mouse.y();
	mouse.cursorOff();
	mouse.setPosition(FULL_SCREEN_WIDTH / 2, yMiddle);

	// Round up number of lines in dialog to next odd number
	uint16 numLines = (numEntries / 2) * 2 + 1;
	if (numLines > 5) numLines = 5;
#else
	mouse.pushCursorNum(CURSOR_ARROW);

	// In WinCE, the whole menu is shown and the items are click-selectable
	uint16 numLines = numEntries;
#endif

	// Figure out the character width
	uint16 numCols = 0;
	for (int ctr = 0; ctr < numEntries; ++ctr) {
		int len = strlen(actions[ctr]);
		if (len > numCols)
			numCols = len;
	}

	// Create the dialog surface
	Common::Point size;
	Surface::getDialogBounds(size, numCols, numLines, false);
	Surface *s = new Surface(size.x, size.y);
	s->createDialog(true);

	int selectedIndex = 0;
	bool refreshFlag = true;
	r.left = Surface::textX();
	r.right = s->width() - Surface::textX() + 1;
	r.top = Surface::textY();
	r.bottom = s->height() - Surface::textY() + 1;

	bool bailOut = false;

	while (!bailOut) {
		if (refreshFlag) {
			// Set up the contents of the menu
			s->fillRect(r, bgColor);

			for (int index = 0; index < numLines; ++index) {
#ifndef LURE_CLICKABLE_MENUS
				int actionIndex = selectedIndex - (numLines / 2) + index;
#else
				int actionIndex = index;
#endif
				if ((actionIndex >= 0) && (actionIndex < numEntries)) {
					s->writeString(Surface::textX(), Surface::textY() + index * FONT_HEIGHT,
						actions[actionIndex], true,
#ifndef LURE_CLICKABLE_MENUS
						(index == (numLines / 2)) ? whiteColor : textColor,
#else
						(index == selectedIndex) ? whiteColor : textColor,
#endif
						false);
				}
			}

			s->copyToScreen(0, yMiddle-(s->height() / 2));
			system.updateScreen();
			refreshFlag = false;
		}

		while (e.pollEvent()) {
			if (engine.shouldQuit()) {
				selectedIndex = 0xffff;
				bailOut = true;
				break;
			} else if (e.type() == Common::EVENT_WHEELUP) {
				// Scroll upwards
				if (selectedIndex > 0) {
					--selectedIndex;
					refreshFlag = true;
				}
			} else if (e.type() == Common::EVENT_WHEELDOWN) {
				// Scroll downwards
				if (selectedIndex < numEntries - 1) {
					++selectedIndex;
					refreshFlag = true;
				}
			} else if (e.type() == Common::EVENT_KEYDOWN) {
				uint16 keycode = e.event().kbd.keycode;

				if (((keycode == Common::KEYCODE_KP8) || (keycode == Common::KEYCODE_UP)) && (selectedIndex > 0)) {
					--selectedIndex;
					refreshFlag = true;
				} else if (((keycode == Common::KEYCODE_KP2) || (keycode == Common::KEYCODE_DOWN)) &&
						(selectedIndex < numEntries-1)) {
					++selectedIndex;
					refreshFlag = true;
				} else if ((keycode == Common::KEYCODE_RETURN) || (keycode == Common::KEYCODE_KP_ENTER)) {
					bailOut = true;
					break;
				} else if (keycode == Common::KEYCODE_ESCAPE) {
					selectedIndex = 0xffff;
					bailOut = true;
					break;
				}

#ifdef LURE_CLICKABLE_MENUS
			} else if (e.type() == Common::EVENT_LBUTTONDOWN || e.type() == Common::EVENT_MOUSEMOVE) {
				int16 x = mouse.x();
				int16 y = mouse.y() - yMiddle + (s->height() / 2);
				refreshFlag = true;

				if (r.contains(x, y)) {
					selectedIndex = (y - r.top) / FONT_HEIGHT;
					if (e.type() == Common::EVENT_LBUTTONDOWN)
						bailOut = true;
						break;
				}
#else
			} else if ((e.type() == Common::EVENT_LBUTTONDOWN) ||
					(e.type() == Common::EVENT_MBUTTONDOWN)) {
				//mouse.waitForRelease();
				bailOut = true;
				break;
#endif
			} else if (e.type() == Common::EVENT_RBUTTONDOWN) {
				mouse.waitForRelease();
				selectedIndex = 0xffff;
				bailOut = true;
				break;
			}
		}

		if (!bailOut) {
#ifndef LURE_CLICKABLE_MENUS
			// Warping the mouse to "neutral" even if the top/bottom menu
			// entry has been reached has both pros and cons. It makes the
			// menu behave a bit more sensibly, but it also makes it harder
			// to move the mouse pointer out of the ScummVM window.

			if (mouse.y() < yMiddle - POPMENU_CHANGE_SENSITIVITY) {
				if (selectedIndex > 0) {
					--selectedIndex;
					refreshFlag = true;
				}
				mouse.setPosition(FULL_SCREEN_WIDTH / 2, yMiddle);
			} else if (mouse.y() > yMiddle + POPMENU_CHANGE_SENSITIVITY) {
				if (selectedIndex < numEntries - 1) {
					++selectedIndex;
					refreshFlag = true;
				}
				mouse.setPosition(FULL_SCREEN_WIDTH / 2, yMiddle);
			}
#endif

			system.delayMillis(20);
		}
	}

	// bailOut
	delete s;

#ifndef LURE_CLICKABLE_MENUS
	mouse.setPosition(oldX, oldY);
	mouse.cursorOn();
#else
	mouse.popCursor();
#endif
	screen.update();
	return selectedIndex;
}
Example #27
0
void Surface::fillRect(const Common::Rect &r, uint8 color) {
	for (int yp = r.top; yp <= r.bottom; ++yp) {
		byte *const addr = _data->data() + (yp * _width) + r.left;
		memset(addr, color, r.width());
	}
}
Example #28
0
void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Common::Rect &_srcRect , Graphics::Surface &dst, int _x, int _y, uint32 colorkey) {
	Common::Rect srcRect = _srcRect;
	if (srcRect.isEmpty())
		srcRect = Common::Rect(src.w, src.h);
	srcRect.clip(src.w, src.h);
	Common::Rect dstRect = Common::Rect(-_x + srcRect.left , -_y + srcRect.top, -_x + srcRect.left + dst.w, -_y + srcRect.top + dst.h);
	srcRect.clip(dstRect);

	if (srcRect.isEmpty() || !srcRect.isValidRect())
		return;

	Graphics::Surface *srcAdapted = src.convertTo(dst.format);
	uint32 keycolor = colorkey & ((1 << (src.format.bytesPerPixel << 3)) - 1);

	// Copy srcRect from src surface to dst surface
	const byte *srcBuffer = (const byte *)srcAdapted->getBasePtr(srcRect.left, srcRect.top);

	int xx = _x;
	int yy = _y;

	if (xx < 0)
		xx = 0;
	if (yy < 0)
		yy = 0;

	if (_x >= dst.w || _y >= dst.h) {
		srcAdapted->free();
		delete srcAdapted;
		return;
	}

	byte *dstBuffer = (byte *)dst.getBasePtr(xx, yy);

	int32 w = srcRect.width();
	int32 h = srcRect.height();

	for (int32 y = 0; y < h; y++) {
		switch (srcAdapted->format.bytesPerPixel) {
		case 1: {
			const uint *srcTemp = (const uint *)srcBuffer;
			uint *dstTemp = (uint *)dstBuffer;
			for (int32 x = 0; x < w; x++) {
				if (*srcTemp != keycolor)
					*dstTemp = *srcTemp;
				srcTemp++;
				dstTemp++;
			}
		}
		break;

		case 2: {
			const uint16 *srcTemp = (const uint16 *)srcBuffer;
			uint16 *dstTemp = (uint16 *)dstBuffer;
			for (int32 x = 0; x < w; x++) {
				if (*srcTemp != keycolor)
					*dstTemp = *srcTemp;
				srcTemp++;
				dstTemp++;
			}
		}
		break;

		case 4: {
			const uint32 *srcTemp = (const uint32 *)srcBuffer;
			uint32 *dstTemp = (uint32 *)dstBuffer;
			for (int32 x = 0; x < w; x++) {
				if (*srcTemp != keycolor)
					*dstTemp = *srcTemp;
				srcTemp++;
				dstTemp++;
			}
		}
		break;

		default:
			break;
		}
		srcBuffer += srcAdapted->pitch;
		dstBuffer += dst.pitch;
	}

	srcAdapted->free();
	delete srcAdapted;
}
Example #29
0
bool UserInterface::getBounds(ScrCategory category, int v, Common::Rect &bounds) {
	int heightMultiplier, widthMultiplier;
	int leftStart, yOffset, widthAmt;

	switch (category) {
	case CAT_COMMAND:
		heightMultiplier = v % 5;
		widthMultiplier = v / 5;
		leftStart = 2;
		yOffset = 3;
		widthAmt = 32;
		break;

	case CAT_INV_LIST:
		if (v < _inventoryTopIndex || v >= (_inventoryTopIndex + 5))
			return false;

		heightMultiplier = v - _inventoryTopIndex;
		widthMultiplier = 0;
		leftStart = 90;
		yOffset = 3;
		widthAmt = 69;
		break;

	case CAT_TALK_ENTRY:
		heightMultiplier = v;
		widthMultiplier = 0;
		leftStart = 2;
		yOffset = 3;
		widthAmt = 310;
		break;

	case CAT_INV_SCROLLER:
		heightMultiplier = 0;
		widthMultiplier = 0;
		yOffset = 0;
		widthAmt = 9;
		leftStart = (v != 73) ? 73 : 75;
		break;

	default:
		heightMultiplier = v;
		widthMultiplier = 0;
		leftStart = 240;
		yOffset = 3;
		widthAmt = 80;
		break;
	}

	bounds.left = (widthMultiplier > 0) ? widthMultiplier * widthAmt + leftStart : leftStart;
	bounds.setWidth(widthAmt);
	bounds.top = heightMultiplier * 8 + yOffset;
	bounds.setHeight(8);

	if (category == CAT_INV_SCROLLER) {
		switch (v) {
		case SCROLLBAR_UP:
			// Arrow up
			bounds.top = 4;
			bounds.setHeight(7);
			break;
		case SCROLLBAR_DOWN:
			// Arrow down
			bounds.top = 35;
			bounds.setHeight(7);
			break;
		case SCROLLBAR_ELEVATOR:
			// Scroller
			bounds.top = 12;
			bounds.setHeight(22);
			break;
		case SCROLLBAR_THUMB:
			// Thumb
			bounds.top = _scrollbarElevator + 14;
			bounds.setHeight(1);
			break;
		default:
			break;
		}
	}

	return true;
}
Example #30
0
void Screen::setDisplayBounds(const Common::Rect &r) {
	_backBuffer.create(_backBuffer1, r);
	assert(_backBuffer.width()  == r.width());
	assert(_backBuffer.height() == r.height());
}