Example #1
0
void ScreenItem::update(const reg_t object) {
	SegManager *segMan = g_sci->getEngineState()->_segMan;

	const GuiResourceId view = readSelectorValue(segMan, object, SELECTOR(view));
	const int16 loopNo = readSelectorValue(segMan, object, SELECTOR(loop));
	const int16 celNo = readSelectorValue(segMan, object, SELECTOR(cel));

	const bool updateCel = (
		_celInfo.resourceId != view ||
		_celInfo.loopNo != loopNo ||
		_celInfo.celNo != celNo
	);

	const bool updateBitmap = !readSelector(segMan, object, SELECTOR(bitmap)).isNull();

	setFromObject(segMan, object, updateCel, updateBitmap);

	if (!_created) {
		_updated = g_sci->_gfxFrameout->getScreenCount();
	}

	_deleted = 0;
}
Example #2
0
reg_t kListFirstTrue(EngineState *s, int argc, reg_t *argv) {
	List *list = s->_segMan->lookupList(argv[0]);

	Node *curNode = s->_segMan->lookupNode(list->first);
	reg_t curObject;
	Selector slc = argv[1].toUint16();

	ObjVarRef address;

	s->r_acc = NULL_REG;	// reset the accumulator

	while (curNode) {
		reg_t nextNode = curNode->succ;
		curObject = curNode->value;

		// First, check if the target selector is a variable
		if (lookupSelector(s->_segMan, curObject, slc, &address, NULL) == kSelectorVariable) {
			// If it's a variable selector, check its value.
			// Example: script 64893 in Torin, MenuHandler::isHilited checks
			// all children for variable selector 0x03ba (bHilited).
			if (!readSelector(s->_segMan, curObject, slc).isNull())
				return curObject;
		} else {
			invokeSelector(s, curObject, slc, argc, argv, argc - 2, argv + 2);

			// Check if the result is true
			if (!s->r_acc.isNull())
				return curObject;
		}

		curNode = s->_segMan->lookupNode(nextNode);
	}

	// No selector returned true
	return NULL_REG;
}
Example #3
0
void GuestAdditions::syncTorinVolumeFromScummVM(const int16 musicVolume, const int16 sfxVolume, const int16 speechVolume) const {
	_state->variables[VAR_GLOBAL][kGlobalVarTorinMusicVolume]  = make_reg(0, musicVolume);
	_state->variables[VAR_GLOBAL][kGlobalVarTorinSFXVolume]    = make_reg(0, sfxVolume);
	_state->variables[VAR_GLOBAL][kGlobalVarTorinSpeechVolume] = make_reg(0, speechVolume);

	// Calling `reSyncVol` on all sounds is necessary to propagate the
	// volume change to existing sounds, and matches how game scripts
	// propagate volume changes when the in-game volume sliders are moved
	const reg_t soundsId = _state->variables[VAR_GLOBAL][kGlobalVarSounds];
	if (!soundsId.isNull()) {
		const Selector selector = SELECTOR(reSyncVol);
		List *sounds = _segMan->lookupList(readSelector(_segMan, soundsId, SELECTOR(elements)));
		reg_t soundId = sounds->first;
		while (!soundId.isNull()) {
			Node *sound = _segMan->lookupNode(soundId);
			const reg_t &soundObj = sound->value;

			if (_segMan->isHeapObject(soundObj) && lookupSelector(_segMan, soundObj, selector, nullptr, nullptr) != kSelectorNone) {
				invokeSelector(sound->value, SELECTOR(reSyncVol));
			}
			soundId = sound->succ;
		}
	}
}
Example #4
0
void GfxText32::drawTextBitmap(uint16 x, uint16 y, Common::Rect planeRect, reg_t textObject) {
	reg_t hunkId = readSelector(_segMan, textObject, SELECTOR(bitmap));
	// Sanity check: Check if the hunk is set. If not, either the game scripts
	// didn't set it, or an old saved game has been loaded, where it wasn't set.
	if (hunkId.isNull())
		return;

	byte *memoryPtr = _segMan->getHunkPointer(hunkId);

	if (!memoryPtr)
		error("Attempt to draw an invalid text bitmap");

	byte *surface = memoryPtr + BITMAP_HEADER_SIZE;

	int curByte = 0;
	uint16 skipColor = readSelectorValue(_segMan, textObject, SELECTOR(skip));
	uint16 textX = planeRect.left + x;
	uint16 textY = planeRect.top + y;
	// Get totalWidth, totalHeight
	uint16 width = READ_LE_UINT16(memoryPtr);
	uint16 height = READ_LE_UINT16(memoryPtr + 2);

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

	for (int curY = 0; curY < height; curY++) {
		for (int curX = 0; curX < width; curX++) {
			byte pixel = surface[curByte++];
			if (pixel != skipColor)
				_screen->putFontPixel(textY, curX + textX, curY, pixel);
		}
	}
}
Example #5
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 doesn't 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
			warning("kernelTexteditChange");
#if 0
			_text->createTextBitmap(controlObject, 0, 0, hunkId);

			_text->drawTextBitmap(0, 0, nsRect, controlObject);
			//texteditCursorDraw(rect, text.c_str(), cursorPos);	// TODO: Cursor
			g_system->updateScreen();
#endif
		} 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 #6
0
reg_t GfxText32::createTextBitmap(reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t prevHunk) {
	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 = NULL_REG;
	if (prevHunk.isNull()) {
		memoryId = _segMan->allocateHunkEntry("TextBitmap()", entrySize);
		writeSelector(_segMan, textObject, SELECTOR(bitmap), memoryId);
	} else {
		memoryId = prevHunk;
	}
	byte *memoryPtr = _segMan->getHunkPointer(memoryId);

	if (prevHunk.isNull())
		memset(memoryPtr, 0, BITMAP_HEADER_SIZE);

	byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE;
	memset(bitmap, backColor, width * height);

	// 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 #7
0
reg_t GfxControls32::kernelEditText(const reg_t controlObject) {
	SegManager *segMan = _segMan;

	TextEditor editor;
	reg_t textObject = readSelector(_segMan, controlObject, SELECTOR(text));
	editor.text = _segMan->getString(textObject);
	editor.foreColor = readSelectorValue(_segMan, controlObject, SELECTOR(fore));
	editor.backColor = readSelectorValue(_segMan, controlObject, SELECTOR(back));
	editor.skipColor = readSelectorValue(_segMan, controlObject, SELECTOR(skip));
	editor.fontId = readSelectorValue(_segMan, controlObject, SELECTOR(font));
	editor.maxLength = readSelectorValue(_segMan, controlObject, SELECTOR(width));
	editor.bitmap = readSelector(_segMan, controlObject, SELECTOR(bitmap));
	editor.cursorCharPosition = 0;
	editor.cursorIsDrawn = false;
	editor.borderColor = readSelectorValue(_segMan, controlObject, SELECTOR(borderColor));

	reg_t titleObject = readSelector(_segMan, controlObject, SELECTOR(title));

	int16 titleHeight = 0;
	GuiResourceId titleFontId = readSelectorValue(_segMan, controlObject, SELECTOR(titleFont));
	if (!titleObject.isNull()) {
		GfxFont *titleFont = _gfxCache->getFont(titleFontId);
		titleHeight += _gfxText32->scaleUpHeight(titleFont->getHeight()) + 1;
		if (editor.borderColor != -1) {
			titleHeight += 2;
		}
	}

	int16 width = 0;
	int16 height = titleHeight;

	GfxFont *editorFont = _gfxCache->getFont(editor.fontId);
	height += _gfxText32->scaleUpHeight(editorFont->getHeight()) + 1;
	_gfxText32->setFont(editor.fontId);
	int16 emSize = _gfxText32->getCharWidth('M', true);
	width += editor.maxLength * emSize + 1;
	if (editor.borderColor != -1) {
		width += 4;
		height += 2;
	}

	Common::Rect editorPlaneRect(width, height);
	editorPlaneRect.translate(readSelectorValue(_segMan, controlObject, SELECTOR(x)), readSelectorValue(_segMan, controlObject, SELECTOR(y)));

	reg_t planeObj = readSelector(_segMan, controlObject, SELECTOR(plane));
	Plane *sourcePlane = g_sci->_gfxFrameout->getVisiblePlanes().findByObject(planeObj);
	if (sourcePlane == nullptr) {
		sourcePlane = g_sci->_gfxFrameout->getPlanes().findByObject(planeObj);
		if (sourcePlane == nullptr) {
			error("Could not find plane %04x:%04x", PRINT_REG(planeObj));
		}
	}
	editorPlaneRect.translate(sourcePlane->_gameRect.left, sourcePlane->_gameRect.top);

	editor.textRect = Common::Rect(2, titleHeight + 2, width - 1, height - 1);
	editor.width = width;

	if (editor.bitmap.isNull()) {
		TextAlign alignment = (TextAlign)readSelectorValue(_segMan, controlObject, SELECTOR(mode));

		if (titleObject.isNull()) {
			bool dimmed = readSelectorValue(_segMan, controlObject, SELECTOR(dimmed));
			editor.bitmap = _gfxText32->createFontBitmap(width, height, editor.textRect, editor.text, editor.foreColor, editor.backColor, editor.skipColor, editor.fontId, alignment, editor.borderColor, dimmed, true, false);
		} else {
			error("Titled bitmaps are not known to be used by any game. Please submit a bug report with details about the game you were playing and what you were doing that triggered this error. Thanks!");
		}
	}

	drawCursor(editor);

	Plane *plane = new Plane(editorPlaneRect, kPlanePicTransparent);
	plane->changePic();
	g_sci->_gfxFrameout->addPlane(*plane);

	CelInfo32 celInfo;
	celInfo.type = kCelTypeMem;
	celInfo.bitmap = editor.bitmap;

	ScreenItem *screenItem = new ScreenItem(plane->_object, celInfo, Common::Point(), ScaleInfo());
	plane->_screenItemList.add(screenItem);

	// frameOut must be called after the screen item is
	// created, and before it is updated at the end of the
	// event loop, otherwise it has both created and updated
	// flags set which crashes the engine (it runs updates
	// before creations)
	g_sci->_gfxFrameout->frameOut(true);

	EventManager *eventManager = g_sci->getEventManager();
	bool clearTextOnInput = true;
	bool textChanged = false;
	for (;;) {
		// We peek here because the last event needs to be allowed to
		// dispatch a second time to the normal event handling system.
		// In the actual engine, the event is always consumed and then
		// the last event just gets posted back to the event manager for
		// reprocessing, but instead, we only remove the event from the
		// queue *after* we have determined it is not a defocusing event
		const SciEvent event = eventManager->getSciEvent(SCI_EVENT_ANY | SCI_EVENT_PEEK);

		bool focused = true;
		// Original engine did not have a QUIT event but we have to handle it
		if (event.type == SCI_EVENT_QUIT) {
			focused = false;
			break;
		} else if (event.type == SCI_EVENT_MOUSE_PRESS && !editorPlaneRect.contains(event.mousePosSci)) {
			focused = false;
		} else if (event.type == SCI_EVENT_KEYBOARD) {
			switch (event.character) {
			case SCI_KEY_ESC:
			case SCI_KEY_UP:
			case SCI_KEY_DOWN:
			case SCI_KEY_TAB:
			case SCI_KEY_SHIFT_TAB:
			case SCI_KEY_ENTER:
				focused = false;
				break;
			}
		}

		if (!focused) {
			break;
		}

		// Consume the event now that we know it is not one of the
		// defocusing events above
		if (event.type != SCI_EVENT_NONE)
			eventManager->getSciEvent(SCI_EVENT_ANY);

		// NOTE: In the original engine, the font and bitmap were
		// reset here on each iteration through the loop, but it
		// doesn't seem like this should be necessary since
		// control is not yielded back to the VM until input is
		// received, which means there is nothing that could modify
		// the GfxText32's state with a different font in the
		// meantime

		bool shouldDeleteChar = false;
		bool shouldRedrawText = false;
		uint16 lastCursorPosition = editor.cursorCharPosition;
 		if (event.type == SCI_EVENT_KEYBOARD) {
			switch (event.character) {
			case SCI_KEY_LEFT:
				clearTextOnInput = false;
				if (editor.cursorCharPosition > 0) {
					--editor.cursorCharPosition;
				}
				break;

			case SCI_KEY_RIGHT:
				clearTextOnInput = false;
				if (editor.cursorCharPosition < editor.text.size()) {
					++editor.cursorCharPosition;
				}
				break;

			case SCI_KEY_HOME:
				clearTextOnInput = false;
				editor.cursorCharPosition = 0;
				break;

			case SCI_KEY_END:
				clearTextOnInput = false;
				editor.cursorCharPosition = editor.text.size();
				break;

			case SCI_KEY_INSERT:
				clearTextOnInput = false;
				// Redrawing also changes the cursor rect to
				// reflect the new insertion mode
				shouldRedrawText = true;
				_overwriteMode = !_overwriteMode;
				break;

			case SCI_KEY_DELETE:
				clearTextOnInput = false;
				if (editor.cursorCharPosition < editor.text.size()) {
					shouldDeleteChar = true;
				}
				break;

			case SCI_KEY_BACKSPACE:
				clearTextOnInput = false;
				shouldDeleteChar = true;
				if (editor.cursorCharPosition > 0) {
					--editor.cursorCharPosition;
				}
				break;

			case SCI_KEY_ETX:
				editor.text.clear();
				editor.cursorCharPosition = 0;
				shouldRedrawText = true;
				break;

			default: {
				if (event.character >= 20 && event.character < 257) {
					if (clearTextOnInput) {
						clearTextOnInput = false;
						editor.text.clear();
					}

					if (
						(_overwriteMode && editor.cursorCharPosition < editor.maxLength) ||
						(editor.text.size() < editor.maxLength && _gfxText32->getCharWidth(event.character, true) + _gfxText32->getStringWidth(editor.text) < editor.textRect.width())
					) {
						if (_overwriteMode && editor.cursorCharPosition < editor.text.size()) {
							editor.text.setChar(event.character, editor.cursorCharPosition);
						} else {
							editor.text.insertChar(event.character, editor.cursorCharPosition);
						}

						++editor.cursorCharPosition;
						shouldRedrawText = true;
					}
				}
			}
			}
		}

		if (shouldDeleteChar) {
			shouldRedrawText = true;
			if (editor.cursorCharPosition < editor.text.size()) {
				editor.text.deleteChar(editor.cursorCharPosition);
			}
		}

		if (shouldRedrawText) {
			eraseCursor(editor);
			_gfxText32->erase(editor.textRect, true);
			_gfxText32->drawTextBox(editor.text);
			drawCursor(editor);
			textChanged = true;
			screenItem->_updated = g_sci->_gfxFrameout->getScreenCount();
		} else if (editor.cursorCharPosition != lastCursorPosition) {
			eraseCursor(editor);
			drawCursor(editor);
			screenItem->_updated = g_sci->_gfxFrameout->getScreenCount();
		} else {
			flashCursor(editor);
			screenItem->_updated = g_sci->_gfxFrameout->getScreenCount();
		}

		g_sci->_gfxFrameout->frameOut(true);
		g_sci->getSciDebugger()->onFrame();
		g_sci->_gfxFrameout->throttle();
	}

	g_sci->_gfxFrameout->deletePlane(*plane);
	if (readSelectorValue(segMan, controlObject, SELECTOR(frameOut))) {
		g_sci->_gfxFrameout->frameOut(true);
	}

	_segMan->freeBitmap(editor.bitmap);

	if (textChanged) {
		editor.text.trim();
		SciArray &string = *_segMan->lookupArray(textObject);
		string.fromString(editor.text);
	}

	return make_reg(0, textChanged);
}
Example #8
0
void GfxFrameout::kernelUpdatePlane(reg_t object) {
	for (PlaneList::iterator it = _planes.begin(); it != _planes.end(); ++it) {
		if (it->object == object) {
			// Read some information
			it->priority = readSelectorValue(_segMan, object, SELECTOR(priority));
			GuiResourceId lastPictureId = it->pictureId;
			it->pictureId = readSelectorValue(_segMan, object, SELECTOR(picture));
			if (lastPictureId != it->pictureId) {
				// picture got changed, load new picture
				deletePlanePictures(object);
				// Draw the plane's picture if it's not a translucent/plane colored frame
				if ((it->pictureId != kPlanePlainColored) && (it->pictureId != kPlaneTranslucent)) {
					// SQ6 gives us a bad picture number for the control menu
					if (_resMan->testResource(ResourceId(kResourceTypePic, it->pictureId)))
						addPlanePicture(object, it->pictureId, 0);
				}
			}
			it->planeRect.top = readSelectorValue(_segMan, object, SELECTOR(top));
			it->planeRect.left = readSelectorValue(_segMan, object, SELECTOR(left));
			it->planeRect.bottom = readSelectorValue(_segMan, object, SELECTOR(bottom));
			it->planeRect.right = readSelectorValue(_segMan, object, SELECTOR(right));

			_coordAdjuster->fromScriptToDisplay(it->planeRect.top, it->planeRect.left);
			_coordAdjuster->fromScriptToDisplay(it->planeRect.bottom, it->planeRect.right);

			// We get negative left in kq7 in scrolling rooms
			if (it->planeRect.left < 0) {
				it->planeOffsetX = -it->planeRect.left;
				it->planeRect.left = 0;
			} else {
				it->planeOffsetX = 0;
			}

			if (it->planeRect.top < 0) {
				it->planeOffsetY = -it->planeRect.top;
				it->planeRect.top = 0;
			} else {
				it->planeOffsetY = 0;
			}

			// We get bad plane-bottom in sq6
			if (it->planeRect.right > _screen->getWidth())
				it->planeRect.right = _screen->getWidth();
			if (it->planeRect.bottom > _screen->getHeight())
				it->planeRect.bottom = _screen->getHeight();

			it->planeClipRect = Common::Rect(it->planeRect.width(), it->planeRect.height());
			it->upscaledPlaneRect = it->planeRect;
			it->upscaledPlaneClipRect = it->planeClipRect;
			if (_screen->getUpscaledHires()) {
				_screen->adjustToUpscaledCoordinates(it->upscaledPlaneRect.top, it->upscaledPlaneRect.left);
				_screen->adjustToUpscaledCoordinates(it->upscaledPlaneRect.bottom, it->upscaledPlaneRect.right);
				_screen->adjustToUpscaledCoordinates(it->upscaledPlaneClipRect.top, it->upscaledPlaneClipRect.left);
				_screen->adjustToUpscaledCoordinates(it->upscaledPlaneClipRect.bottom, it->upscaledPlaneClipRect.right);
			}

			it->planePictureMirrored = readSelectorValue(_segMan, object, SELECTOR(mirrored));
			it->planeBack = readSelectorValue(_segMan, object, SELECTOR(back));

			sortPlanes();

			// Update the items in the plane
			for (FrameoutList::iterator listIterator = _screenItems.begin(); listIterator != _screenItems.end(); listIterator++) {
				reg_t itemPlane = readSelector(_segMan, (*listIterator)->object, SELECTOR(plane));
				if (object == itemPlane) {
					kernelUpdateScreenItem((*listIterator)->object);
				}
			}

			return;
		}
	}
	error("kUpdatePlane called on plane that wasn't added before");
}
Example #9
0
void GfxControls32::kernelTexteditChange(reg_t controlObject) {
	SciEvent curEvent;
	uint16 maxChars = readSelectorValue(_segMan, controlObject, SELECTOR(max));
	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, add a loop etc
	warning("kEditText ('%s')", text.c_str());
	return;

	uint16 cursorPos = 0;
	//uint16 oldCursorPos = cursorPos;

	curEvent = g_sci->getEventManager()->getSciEvent(SCI_EVENT_KEYBOARD);
	if (curEvent.type != SCI_EVENT_NONE) {
		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.data) {
			case SCI_KEY_BACKSPACE:
				if (cursorPos > 0) {
					cursorPos--; text.deleteChar(cursorPos);
					textChanged = true;
				}
				break;
			case SCI_KEY_DELETE:
				if (cursorPos < textSize) {
					text.deleteChar(cursorPos);
					textChanged = true;
				}
				break;
			case SCI_KEY_HOME: // HOME
				cursorPos = 0; textChanged = true;
				break;
			case SCI_KEY_END: // END
				cursorPos = textSize; textChanged = true;
				break;
			case SCI_KEY_LEFT: // LEFT
				if (cursorPos > 0) {
					cursorPos--; textChanged = true;
				}
				break;
			case SCI_KEY_RIGHT: // RIGHT
				if (cursorPos + 1 <= textSize) {
					cursorPos++; textChanged = true;
				}
				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;
				}
				break;
			default:
				if ((curEvent.modifiers & SCI_KEYMOD_CTRL) && curEvent.data == 99) {
					// Control-C in earlier SCI games (SCI0 - SCI1 middle)
					// Control-C erases the whole line
					cursorPos = 0; text.clear();
					textChanged = true;
				} else if (curEvent.data > 31 && curEvent.data < 256 && textSize < maxChars) {
					// insert pressed character
					textAddChar = true;
					textChanged = true;
				}
				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.data);

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

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

			// Note: the following checkAltInput call might make the text
			// too wide to fit, but SSCI fails to check that too.
		}
		// TODO: Cursor
		/*
		texteditCursorErase();
		_paint16->eraseRect(rect);
		_text16->Box(text.c_str(), false, rect, SCI_TEXT16_ALIGNMENT_LEFT, -1);
		_paint16->bitsShow(rect);
		texteditCursorDraw(rect, text.c_str(), cursorPos);
		*/
		// Write back string
		_segMan->strcpy(textReference, text.c_str());
	} else {
		// TODO: Cursor
		/*
		if (g_system->getMillis() >= _texteditBlinkTime) {
			_paint16->invertRect(_texteditCursorRect);
			_paint16->bitsShow(_texteditCursorRect);
			_texteditCursorVisible = !_texteditCursorVisible;
			texteditSetBlinkTime();
		}
		*/
	}
}
Example #10
0
reg_t kArray(EngineState *s, int argc, reg_t *argv) {
	uint16 op = argv[0].toUint16();

	// Use kString when accessing strings
	// This is possible, as strings inherit from arrays
	// and in this case (type 3) arrays are of type char *.
	// kString is almost exactly the same as kArray, so
	// this call is possible
	// TODO: we need to either merge SCI2 strings and
	// arrays together, and in the future merge them with
	// the SCI1 strings and arrays in the segment manager
	if (op == 0) {
		// New, check if the target type is 3 (string)
		if (argv[2].toUint16() == 3)
			return kString(s, argc, argv);
	} else {
		if (s->_segMan->getSegmentType(argv[1].segment) == SEG_TYPE_STRING ||
			s->_segMan->getSegmentType(argv[1].segment) == SEG_TYPE_SCRIPT) {
			return kString(s, argc, argv);
		}

#if 0
		if (op == 6) {
			if (s->_segMan->getSegmentType(argv[3].segment) == SEG_TYPE_STRING ||
				s->_segMan->getSegmentType(argv[3].segment) == SEG_TYPE_SCRIPT) {
				return kString(s, argc, argv);
			}
		}
#endif
	}

	switch (op) {
	case 0: { // New
		reg_t arrayHandle;
		SciArray<reg_t> *array = s->_segMan->allocateArray(&arrayHandle);
		array->setType(argv[2].toUint16());
		array->setSize(argv[1].toUint16());
		return arrayHandle;
	}
	case 1: { // Size
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);
		return make_reg(0, array->getSize());
	}
	case 2: { // At (return value at an index)
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);
		return array->getValue(argv[2].toUint16());
	}
	case 3: { // Atput (put value at an index)
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);

		uint32 index = argv[2].toUint16();
		uint32 count = argc - 3;

		if (index + count > 65535)
			break;

		if (array->getSize() < index + count)
			array->setSize(index + count);

		for (uint16 i = 0; i < count; i++)
			array->setValue(i + index, argv[i + 3]);

		return argv[1]; // We also have to return the handle
	}
	case 4: // Free
		// Freeing of arrays is handled by the garbage collector
		return s->r_acc;
	case 5: { // Fill
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);
		uint16 index = argv[2].toUint16();

		// A count of -1 means fill the rest of the array
		uint16 count = argv[3].toSint16() == -1 ? array->getSize() - index : argv[3].toUint16();
		uint16 arraySize = array->getSize();

		if (arraySize < index + count)
			array->setSize(index + count);

		for (uint16 i = 0; i < count; i++)
			array->setValue(i + index, argv[4]);

		return argv[1];
	}
	case 6: { // Cpy
		if (argv[1].isNull() || argv[3].isNull()) {
			if (getSciVersion() == SCI_VERSION_3) {
				// FIXME: Happens in SCI3, probably because of a missing kernel function.
				warning("kArray(Cpy): Request to copy from or to a null pointer");
				return NULL_REG;
			} else {
				// SCI2-2.1: error out
				error("kArray(Cpy): Request to copy from or to a null pointer");
			}
		}

		reg_t arrayHandle = argv[1];
		SciArray<reg_t> *array1 = s->_segMan->lookupArray(argv[1]);
		//SciArray<reg_t> *array1 = !argv[1].isNull() ? s->_segMan->lookupArray(argv[1]) : s->_segMan->allocateArray(&arrayHandle);
		SciArray<reg_t> *array2 = s->_segMan->lookupArray(argv[3]);
		uint32 index1 = argv[2].toUint16();
		uint32 index2 = argv[4].toUint16();

		// The original engine ignores bad copies too
		if (index2 > array2->getSize())
			break;

		// A count of -1 means fill the rest of the array
		uint32 count = argv[5].toSint16() == -1 ? array2->getSize() - index2 : argv[5].toUint16();

		if (array1->getSize() < index1 + count)
			array1->setSize(index1 + count);

		for (uint16 i = 0; i < count; i++)
			array1->setValue(i + index1, array2->getValue(i + index2));

		return arrayHandle;
	}
	case 7: // Cmp
		// Not implemented in SSCI
		warning("kArray(Cmp) called");
		return s->r_acc;
	case 8: { // Dup
		if (argv[1].isNull()) {
			warning("kArray(Dup): Request to duplicate a null pointer");
#if 0
			// Allocate an array anyway
			reg_t arrayHandle;
			SciArray<reg_t> *dupArray = s->_segMan->allocateArray(&arrayHandle);
			dupArray->setType(3);
			dupArray->setSize(0);
			return arrayHandle;
#endif
			return NULL_REG;
		}
		SegmentType sourceType = s->_segMan->getSegmentObj(argv[1].segment)->getType();
		if (sourceType == SEG_TYPE_SCRIPT) {
			// A technique used in later SCI2.1 and SCI3 games: the contents of a script
			// are loaded in an array (well, actually a string).
			Script *scr = s->_segMan->getScript(argv[1].segment);
			reg_t stringHandle;

			SciString *dupString = s->_segMan->allocateString(&stringHandle);
			dupString->setSize(scr->getBufSize());
			dupString->fromString(Common::String((const char *)scr->getBuf()));

			return stringHandle;
		} else if (sourceType != SEG_TYPE_ARRAY && sourceType != SEG_TYPE_SCRIPT) {
			error("kArray(Dup): Request to duplicate a segment which isn't an array or a script");
		}

		reg_t arrayHandle;
		SciArray<reg_t> *dupArray = s->_segMan->allocateArray(&arrayHandle);
		// This must occur after allocateArray, as inserting a new object
		// in the heap object list might invalidate this pointer. Also refer
		// to the same issue in kClone()
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);

		dupArray->setType(array->getType());
		dupArray->setSize(array->getSize());

		for (uint32 i = 0; i < array->getSize(); i++)
			dupArray->setValue(i, array->getValue(i));

		return arrayHandle;
	}
	case 9: // Getdata
		if (!s->_segMan->isHeapObject(argv[1]))
			return argv[1];

		return readSelector(s->_segMan, argv[1], SELECTOR(data));
	default:
		error("Unknown kArray subop %d", op);
	}

	return NULL_REG;
}
Example #11
0
void GfxControls16::kernelTexteditChange(reg_t controlObject, reg_t eventObject) {
	uint16 cursorPos = readSelectorValue(_segMan, controlObject, SELECTOR(cursor));
	uint16 maxChars = readSelectorValue(_segMan, controlObject, SELECTOR(max));
	reg_t textReference = readSelector(_segMan, controlObject, SELECTOR(text));
	Common::String text;
	uint16 textSize, eventType, eventKey = 0, modifiers = 0;
	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);

	uint16 oldCursorPos = cursorPos;

	if (!eventObject.isNull()) {
		textSize = text.size();
		eventType = readSelectorValue(_segMan, eventObject, SELECTOR(type));

		switch (eventType) {
		case SCI_EVENT_MOUSE_PRESS:
			// TODO: Implement mouse support for cursor change
			break;
		case SCI_EVENT_KEYBOARD:
			eventKey = readSelectorValue(_segMan, eventObject, SELECTOR(message));
			modifiers = readSelectorValue(_segMan, eventObject, SELECTOR(modifiers));
			switch (eventKey) {
			case SCI_KEY_BACKSPACE:
				if (cursorPos > 0) {
					cursorPos--; text.deleteChar(cursorPos);
					textChanged = true;
				}
				break;
			case SCI_KEY_DELETE:
				if (cursorPos < textSize) {
					text.deleteChar(cursorPos);
					textChanged = true;
				}
				break;
			case SCI_KEY_HOME: // HOME
				cursorPos = 0; textChanged = true;
				break;
			case SCI_KEY_END: // END
				cursorPos = textSize; textChanged = true;
				break;
			case SCI_KEY_LEFT: // LEFT
				if (cursorPos > 0) {
					cursorPos--; textChanged = true;
				}
				break;
			case SCI_KEY_RIGHT: // RIGHT
				if (cursorPos + 1 <= textSize) {
					cursorPos++; textChanged = true;
				}
				break;
			case 3:	// returned in SCI1 late and newer when Control - C is pressed
				if (modifiers & SCI_KEYMOD_CTRL) {
					// Control-C erases the whole line
					cursorPos = 0; text.clear();
					textChanged = true;
				}
				break;
			default:
				if ((modifiers & SCI_KEYMOD_CTRL) && eventKey == 99) {
					// Control-C in earlier SCI games (SCI0 - SCI1 middle)
					// Control-C erases the whole line
					cursorPos = 0; text.clear();
					textChanged = true;
				} else if (eventKey > 31 && eventKey < 256 && textSize < maxChars) {
					// insert pressed character
					textAddChar = true;
					textChanged = true;
				}
				break;
			}
			break;
		}
	}

	if (g_sci->getVocabulary() && !textChanged && oldCursorPos != cursorPos) {
		assert(!textAddChar);
		textChanged = g_sci->getVocabulary()->checkAltInput(text, cursorPos);
	}

	if (textChanged) {
		GuiResourceId oldFontId = _text16->GetFontId();
		GuiResourceId fontId = readSelectorValue(_segMan, controlObject, SELECTOR(font));
		rect = g_sci->_gfxCompare->getNSRect(controlObject);

		_text16->SetFont(fontId);
		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 += _text16->_font->getCharWidth((byte)*textPtr++);
			textWidth += _text16->_font->getCharWidth(eventKey);

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

			text.insertChar(eventKey, cursorPos++);

			// Note: the following checkAltInput call might make the text
			// too wide to fit, but SSCI fails to check that too.
		}
		if (g_sci->getVocabulary())
			g_sci->getVocabulary()->checkAltInput(text, cursorPos);
		texteditCursorErase();
		_paint16->eraseRect(rect);
		_text16->Box(text.c_str(), false, rect, SCI_TEXT16_ALIGNMENT_LEFT, -1);
		_paint16->bitsShow(rect);
		texteditCursorDraw(rect, text.c_str(), cursorPos);
		_text16->SetFont(oldFontId);
		// Write back string
		_segMan->strcpy(textReference, text.c_str());
	} else {
		if (g_system->getMillis() >= _texteditBlinkTime) {
			_paint16->invertRect(_texteditCursorRect);
			_paint16->bitsShow(_texteditCursorRect);
			_texteditCursorVisible = !_texteditCursorVisible;
			texteditSetBlinkTime();
		}
	}

	writeSelectorValue(_segMan, controlObject, SELECTOR(cursor), cursorPos);
}
Example #12
0
/**
 * Handles the sciAudio calls in fanmade games.
 * sciAudio is an external .NET library for playing MP3 files in fanmade games.
 * It runs in the background, and obtains sound commands from the
 * currently running game via text files (called "conductor files").
 * For further info, check: http://sciprogramming.com/community/index.php?topic=634.0
 */
void AudioPlayer::handleFanmadeSciAudio(reg_t sciAudioObject, SegManager *segMan) {
	// TODO: This is a bare bones implementation. Only the play/playx and stop commands
	// are handled for now - the other commands haven't been observed in any fanmade game
	// yet. All the volume related and fading functionality is currently missing.

	Kernel *kernel = g_sci->getKernel();

	reg_t commandReg = readSelector(segMan, sciAudioObject, kernel->findSelector("command"));
	Common::String command = segMan->getString(commandReg);

	if (command == "play" || command == "playx") {
		reg_t fileNameReg = readSelector(segMan, sciAudioObject, kernel->findSelector("fileName"));
		Common::String fileName = segMan->getString(fileNameReg);

		reg_t loopCountReg = readSelector(segMan, sciAudioObject, kernel->findSelector("loopCount"));
		Common::String loopCountStr = segMan->getString(loopCountReg);
		int16 loopCount = atoi(loopCountStr.c_str());

		// Adjust loopCount for ScummVM's LoopingAudioStream semantics
		if (loopCount == -1) {
			loopCount = 0; // loop endlessly
		} else if (loopCount >= 0) {
			// sciAudio loopCount == 0 -> play 1 time  -> ScummVM's loopCount should be 1
			// sciAudio loopCount == 1 -> play 2 times -> ScummVM's loopCount should be 2
			loopCount++;
		} else {
			loopCount = 1; // play once in case the value makes no sense
		}

		// Determine sound type
		Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType;
		if (fileName.hasPrefix("music"))
			soundType = Audio::Mixer::kMusicSoundType;
		else if (fileName.hasPrefix("speech"))
			soundType = Audio::Mixer::kSpeechSoundType;

		// Determine compression
		uint32 audioCompressionType = 0;
		if ((fileName.hasSuffix(".mp3")) || (fileName.hasSuffix(".sciAudio")) || (fileName.hasSuffix(".sciaudio"))) {
			audioCompressionType = MKTAG('M','P','3',' ');
		} else if (fileName.hasSuffix(".wav")) {
			audioCompressionType = MKTAG('W','A','V',' ');
		} else if (fileName.hasSuffix(".aiff")) {
			audioCompressionType = MKTAG('A','I','F','F');
		} else {
			error("sciAudio: unsupported file type");
		}

		Common::File *sciAudioFile = new Common::File();
		// Replace backwards slashes
		for (uint i = 0; i < fileName.size(); i++) {
			if (fileName[i] == '\\')
				fileName.setChar('/', i);
		}
		sciAudioFile->open("sciAudio/" + fileName);

		Audio::RewindableAudioStream *audioStream = nullptr;

		switch (audioCompressionType) {
		case MKTAG('M','P','3',' '):
#ifdef USE_MAD
			audioStream = Audio::makeMP3Stream(sciAudioFile, DisposeAfterUse::YES);
#endif
			break;
		case MKTAG('W','A','V',' '):
			audioStream = Audio::makeWAVStream(sciAudioFile, DisposeAfterUse::YES);
			break;
		case MKTAG('A','I','F','F'):
			audioStream = Audio::makeAIFFStream(sciAudioFile, DisposeAfterUse::YES);
			break;
		default:
			break;
		}

		if (!audioStream) {
			error("sciAudio: requested compression not compiled into ScummVM");
		}

		// We only support one audio handle
		_mixer->playStream(soundType, &_audioHandle,
							Audio::makeLoopingAudioStream((Audio::RewindableAudioStream *)audioStream, loopCount));
	} else if (command == "stop") {
		_mixer->stopHandle(_audioHandle);
	} else {
		warning("Unhandled sciAudio command: %s", command.c_str());
	}
}
Example #13
0
reg_t kArray(EngineState *s, int argc, reg_t *argv) {
	uint16 op = argv[0].toUint16();

	// Use kString when accessing strings
	// This is possible, as strings inherit from arrays
	// and in this case (type 3) arrays are of type char *.
	// kString is almost exactly the same as kArray, so
	// this call is possible
	// TODO: we need to either merge SCI2 strings and
	// arrays together, and in the future merge them with
	// the SCI1 strings and arrays in the segment manager
	if (op == 0) {
		// New, check if the target type is 3 (string)
		if (argv[2].toUint16() == 3)
			return kString(s, argc, argv);
	} else {
		if (s->_segMan->getSegmentType(argv[1].getSegment()) == SEG_TYPE_STRING ||
			s->_segMan->getSegmentType(argv[1].getSegment()) == SEG_TYPE_SCRIPT) {
			return kString(s, argc, argv);
		}

#if 0
		if (op == 6) {
			if (s->_segMan->getSegmentType(argv[3].getSegment()) == SEG_TYPE_STRING ||
				s->_segMan->getSegmentType(argv[3].getSegment()) == SEG_TYPE_SCRIPT) {
				return kString(s, argc, argv);
			}
		}
#endif
	}

	switch (op) {
	case 0: { // New
		reg_t arrayHandle;
		SciArray<reg_t> *array = s->_segMan->allocateArray(&arrayHandle);
		array->setType(argv[2].toUint16());
		array->setSize(argv[1].toUint16());
		return arrayHandle;
	}
	case 1: { // Size
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);
		return make_reg(0, array->getSize());
	}
	case 2: { // At (return value at an index)
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);
		if (g_sci->getGameId() == GID_PHANTASMAGORIA2) {
			// HACK: Phantasmagoria 2 keeps trying to access past the end of an
			// array when it starts. I'm assuming it's trying to see where the
			// array ends, or tries to resize it. Adjust the array size
			// accordingly, and return NULL for now.
			if (array->getSize() == argv[2].toUint16()) {
				array->setSize(argv[2].toUint16());
				return NULL_REG;
			}
		}
		return array->getValue(argv[2].toUint16());
	}
	case 3: { // Atput (put value at an index)
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);

		uint32 index = argv[2].toUint16();
		uint32 count = argc - 3;

		if (index + count > 65535)
			break;

		if (array->getSize() < index + count)
			array->setSize(index + count);

		for (uint16 i = 0; i < count; i++)
			array->setValue(i + index, argv[i + 3]);

		return argv[1]; // We also have to return the handle
	}
	case 4: // Free
		// Freeing of arrays is handled by the garbage collector
		return s->r_acc;
	case 5: { // Fill
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);
		uint16 index = argv[2].toUint16();

		// A count of -1 means fill the rest of the array
		uint16 count = argv[3].toSint16() == -1 ? array->getSize() - index : argv[3].toUint16();
		uint16 arraySize = array->getSize();

		if (arraySize < index + count)
			array->setSize(index + count);

		for (uint16 i = 0; i < count; i++)
			array->setValue(i + index, argv[4]);

		return argv[1];
	}
	case 6: { // Cpy
		if (argv[1].isNull() || argv[3].isNull()) {
			if (getSciVersion() == SCI_VERSION_3) {
				// FIXME: Happens in SCI3, probably because of a missing kernel function.
				warning("kArray(Cpy): Request to copy from or to a null pointer");
				return NULL_REG;
			} else {
				// SCI2-2.1: error out
				error("kArray(Cpy): Request to copy from or to a null pointer");
			}
		}

		reg_t arrayHandle = argv[1];
		SciArray<reg_t> *array1 = s->_segMan->lookupArray(argv[1]);
		SciArray<reg_t> *array2 = s->_segMan->lookupArray(argv[3]);
		uint32 index1 = argv[2].toUint16();
		uint32 index2 = argv[4].toUint16();

		// The original engine ignores bad copies too
		if (index2 > array2->getSize())
			break;

		// A count of -1 means fill the rest of the array
		uint32 count = argv[5].toSint16() == -1 ? array2->getSize() - index2 : argv[5].toUint16();

		if (array1->getSize() < index1 + count)
			array1->setSize(index1 + count);

		for (uint16 i = 0; i < count; i++)
			array1->setValue(i + index1, array2->getValue(i + index2));

		return arrayHandle;
	}
	case 7: // Cmp
		// Not implemented in SSCI
		warning("kArray(Cmp) called");
		return s->r_acc;
	case 8: { // Dup
		if (argv[1].isNull()) {
			warning("kArray(Dup): Request to duplicate a null pointer");
#if 0
			// Allocate an array anyway
			reg_t arrayHandle;
			SciArray<reg_t> *dupArray = s->_segMan->allocateArray(&arrayHandle);
			dupArray->setType(3);
			dupArray->setSize(0);
			return arrayHandle;
#endif
			return NULL_REG;
		}
		SegmentObj *sobj = s->_segMan->getSegmentObj(argv[1].getSegment());
		if (!sobj || sobj->getType() != SEG_TYPE_ARRAY)
			error("kArray(Dup): Request to duplicate a segment which isn't an array");

		reg_t arrayHandle;
		SciArray<reg_t> *dupArray = s->_segMan->allocateArray(&arrayHandle);
		// This must occur after allocateArray, as inserting a new object
		// in the heap object list might invalidate this pointer. Also refer
		// to the same issue in kClone()
		SciArray<reg_t> *array = s->_segMan->lookupArray(argv[1]);

		dupArray->setType(array->getType());
		dupArray->setSize(array->getSize());

		for (uint32 i = 0; i < array->getSize(); i++)
			dupArray->setValue(i, array->getValue(i));

		return arrayHandle;
	}
	case 9: // Getdata
		if (!s->_segMan->isHeapObject(argv[1]))
			return argv[1];

		return readSelector(s->_segMan, argv[1], SELECTOR(data));
	default:
		error("Unknown kArray subop %d", op);
	}

	return NULL_REG;
}
Example #14
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 #15
0
void GfxAnimate::update() {
	reg_t bitsHandle;
	Common::Rect rect;
	AnimateList::iterator it;
	const AnimateList::iterator end = _list.end();

	// Remove all no-update cels, if requested
	for (it = _list.legacy_reverse_begin(); it != end; --it) {
		if (it->signal & kSignalNoUpdate) {
			if (!(it->signal & kSignalRemoveView)) {
				bitsHandle = readSelector(_s->_segMan, it->object, SELECTOR(underBits));
				if (_screen->_picNotValid != 1) {
					_paint16->bitsRestore(bitsHandle);
					it->showBitsFlag = true;
				} else	{
					_paint16->bitsFree(bitsHandle);
				}
				writeSelectorValue(_s->_segMan, it->object, SELECTOR(underBits), 0);
			}
			it->signal &= ~kSignalForceUpdate;
			if (it->signal & kSignalViewUpdated)
				it->signal &= ~(kSignalViewUpdated | kSignalNoUpdate);
		} else if (it->signal & kSignalStopUpdate) {
			it->signal &= ~kSignalStopUpdate;
			it->signal |= kSignalNoUpdate;
		}
	}

	// Draw always-update cels
	for (it = _list.begin(); it != end; ++it) {
		if (it->signal & kSignalAlwaysUpdate) {
			// draw corresponding cel
			_paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo, it->scaleX, it->scaleY);
			it->showBitsFlag = true;

			it->signal &= ~(kSignalStopUpdate | kSignalViewUpdated | kSignalNoUpdate | kSignalForceUpdate);
			if (!(it->signal & kSignalIgnoreActor)) {
				rect = it->celRect;
				rect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(it->priority) - 1, rect.top, rect.bottom - 1);
				_paint16->fillRect(rect, GFX_SCREEN_MASK_CONTROL, 0, 0, 15);
			}
		}
	}

	// Saving background for all NoUpdate-cels
	for (it = _list.begin(); it != end; ++it) {
		if (it->signal & kSignalNoUpdate) {
			if (it->signal & kSignalHidden) {
				it->signal |= kSignalRemoveView;
			} else {
				it->signal &= ~kSignalRemoveView;
				if (it->signal & kSignalIgnoreActor)
					bitsHandle = _paint16->bitsSave(it->celRect, GFX_SCREEN_MASK_VISUAL|GFX_SCREEN_MASK_PRIORITY);
				else
					bitsHandle = _paint16->bitsSave(it->celRect, GFX_SCREEN_MASK_ALL);
				writeSelector(_s->_segMan, it->object, SELECTOR(underBits), bitsHandle);
			}
		}
	}

	// Draw NoUpdate cels
	for (it = _list.begin(); it != end; ++it) {
		if (it->signal & kSignalNoUpdate && !(it->signal & kSignalHidden)) {
			// draw corresponding cel
			_paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo, it->scaleX, it->scaleY);
			it->showBitsFlag = true;

			if (!(it->signal & kSignalIgnoreActor)) {
				rect = it->celRect;
				rect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(it->priority) - 1, rect.top, rect.bottom - 1);
				_paint16->fillRect(rect, GFX_SCREEN_MASK_CONTROL, 0, 0, 15);
			}
		}
	}
}
Example #16
0
void ScreenItem::setFromObject(SegManager *segMan, const reg_t object, const bool updateCel, const bool updateBitmap) {
	_position.x = readSelectorValue(segMan, object, SELECTOR(x));
	_position.y = readSelectorValue(segMan, object, SELECTOR(y));
	_scale.x = readSelectorValue(segMan, object, SELECTOR(scaleX));
	_scale.y = readSelectorValue(segMan, object, SELECTOR(scaleY));
	_scale.max = readSelectorValue(segMan, object, SELECTOR(maxScale));
	_scale.signal = (ScaleSignals32)(readSelectorValue(segMan, object, SELECTOR(scaleSignal)) & 3);

	if (updateCel) {
		_celInfo.resourceId = (GuiResourceId)readSelectorValue(segMan, object, SELECTOR(view));
		_celInfo.loopNo = readSelectorValue(segMan, object, SELECTOR(loop));
		_celInfo.celNo = readSelectorValue(segMan, object, SELECTOR(cel));

		if (_celInfo.resourceId <= kPlanePic) {
			// TODO: Enhance GfxView or ResourceManager to allow
			// metadata for resources to be retrieved once, from a
			// single location
			Resource *view = g_sci->getResMan()->findResource(ResourceId(kResourceTypeView, _celInfo.resourceId), false);
			if (!view) {
				error("Failed to load resource %d", _celInfo.resourceId);
			}

			// NOTE: +2 because the header size field itself is excluded from
			// the header size in the data
			const uint16 headerSize = READ_SCI11ENDIAN_UINT16(view->data) + 2;
			const uint8 loopCount = view->data[2];
			const uint8 loopSize = view->data[12];

			if (_celInfo.loopNo >= loopCount) {
				const int maxLoopNo = loopCount - 1;
				_celInfo.loopNo = maxLoopNo;
				writeSelectorValue(segMan, object, SELECTOR(loop), maxLoopNo);
			}

			byte *loopData = view->data + headerSize + (_celInfo.loopNo * loopSize);
			const int8 seekEntry = loopData[0];
			if (seekEntry != -1) {
				loopData = view->data + headerSize + (seekEntry * loopSize);
			}
			const uint8 celCount = loopData[2];
			if (_celInfo.celNo >= celCount) {
				const int maxCelNo = celCount - 1;
				_celInfo.celNo = maxCelNo;
				writeSelectorValue(segMan, object, SELECTOR(cel), maxCelNo);
			}
		}
	}

	if (updateBitmap) {
		const reg_t bitmap = readSelector(segMan, object, SELECTOR(bitmap));
		if (!bitmap.isNull()) {
			_celInfo.bitmap = bitmap;
			_celInfo.type = kCelTypeMem;
		} else {
			_celInfo.bitmap = NULL_REG;
			_celInfo.type = kCelTypeView;
		}
	}

	if (updateCel || updateBitmap) {
		delete _celObj;
		_celObj = nullptr;
	}

	if (readSelectorValue(segMan, object, SELECTOR(fixPriority))) {
		_fixedPriority = true;
		_priority = readSelectorValue(segMan, object, SELECTOR(priority));
	} else {
		_fixedPriority = false;
		writeSelectorValue(segMan, object, SELECTOR(priority), _position.y);
	}

	_z = readSelectorValue(segMan, object, SELECTOR(z));
	_position.y -= _z;

	if (readSelectorValue(segMan, object, SELECTOR(useInsetRect))) {
		_useInsetRect = true;
		_insetRect.left = readSelectorValue(segMan, object, SELECTOR(inLeft));
		_insetRect.top = readSelectorValue(segMan, object, SELECTOR(inTop));
		_insetRect.right = readSelectorValue(segMan, object, SELECTOR(inRight)) + 1;
		_insetRect.bottom = readSelectorValue(segMan, object, SELECTOR(inBottom)) + 1;
	} else {
		_useInsetRect = false;
	}

	segMan->getObject(object)->clearInfoSelectorFlag(kInfoFlagViewVisible);
}