Пример #1
0
void VisualText::createTexture() {
	Common::CodePage codePage = StarkSettings->getTextCodePage();
	Common::U32String unicodeText = Common::convertToU32String(_text.c_str(), codePage);

	// Get the font and required metrics
	const Graphics::Font *font = StarkFontProvider->getScaledFont(_fontType, _fontCustomIndex);
	uint scaledLineHeight = StarkFontProvider->getScaledFontHeight(_fontType, _fontCustomIndex);
	uint originalLineHeight = StarkFontProvider->getOriginalFontHeight(_fontType, _fontCustomIndex);
	uint maxScaledLineWidth = StarkGfx->scaleWidthOriginalToCurrent(_targetWidth);

	// Word wrap the text
	Common::Array<Common::U32String> lines;
	font->wordWrapText(unicodeText, maxScaledLineWidth, lines);

	// Use the actual font bounding box to prevent text from being cut off
	Common::Rect scaledRect;
	if (!lines.empty()) {
		scaledRect = font->getBoundingBox(lines[0]);
		for (uint i = 1; i < lines.size(); i++) {
			scaledRect.extend(font->getBoundingBox(lines[i], 0, scaledLineHeight * i));
		}
	}

	// Make sure lines have approximately consistent height regardless of the characters they use
	scaledRect.bottom = MAX<int16>(scaledRect.bottom, scaledLineHeight * lines.size());

	if (!isBlank()) {
		_originalRect.right = StarkGfx->scaleWidthCurrentToOriginal(scaledRect.right);
		_originalRect.bottom = originalLineHeight * lines.size();
	} else {
		// For Empty text, preserve the original width and height for being used as clicking area
		_originalRect.right = _targetWidth;
		_originalRect.bottom = _targetHeight;
	}

	// Create a surface to render to
	Graphics::Surface surface;
	surface.create(scaledRect.right, scaledRect.bottom, Gfx::Driver::getRGBAPixelFormat());

	uint32 color = surface.format.ARGBToColor(
			_color.a, _color.r, _color.g, _color.b
	);
	uint32 bgColor = surface.format.ARGBToColor(
			_backgroundColor.a, _backgroundColor.r, _backgroundColor.g, _backgroundColor.b
	);

	surface.fillRect(Common::Rect(surface.w, surface.h), bgColor);

	// Render the lines to the surface
	for (uint i = 0; i < lines.size(); i++) {
		font->drawString(&surface, lines[i], 0, scaledLineHeight * i, surface.w, color, _align);
	}

	// Create a texture from the surface
	_texture = _gfx->createTexture(&surface);
	_texture->setSamplingFilter(Gfx::Texture::kNearest);

	surface.free();
}
Пример #2
0
void MacFontManager::generateFontSubstitute(MacFont &macFont) {
	Common::String name;

	// First we try twice size
	name = getFontName(macFont.getId(), macFont.getSize() * 2, macFont.getSlant());
	if (_fontRegistry.contains(name) && !_fontRegistry[name]->isGenerated()) {
		generateFont(macFont, *_fontRegistry[name]);

		return;
	}

	// Now half size
	name = getFontName(macFont.getId(), macFont.getSize() / 2, macFont.getSlant());
	if (_fontRegistry.contains(name) && !_fontRegistry[name]->isGenerated()) {
		generateFont(macFont, *_fontRegistry[name]);

		return;
	}

	// No simple substitute was found. Looking for neighborhood fonts

	// First we gather all font sizes for this font
	Common::Array<int> sizes;
	for (Common::HashMap<Common::String, MacFont *>::iterator i = _fontRegistry.begin(); i != _fontRegistry.end(); ++i) {
		if (i->_value->getId() == macFont.getId() && i->_value->getSlant() == macFont.getSlant() && !i->_value->isGenerated())
			sizes.push_back(i->_value->getSize());
	}

	if (sizes.empty()) {
		warning("No viable substitute found for font %s", getFontName(macFont));
		return;
	}

	// Now looking next larger font, and store the largest one for next check
	int candidate = 1000;
	int maxSize = sizes[0];
	for (uint i = 0; i < sizes.size(); i++) {
		if (sizes[i] > macFont.getSize() && sizes[i] < candidate)
			candidate = sizes[i];

		if (sizes[i] > maxSize)
			maxSize = sizes[i];
	}

	if (candidate != 1000) {
		generateFont(macFont, *_fontRegistry[getFontName(macFont.getId(), candidate, macFont.getSlant())]);
		return;
	}

	// Now next smaller font, which is the biggest we have
	generateFont(macFont, *_fontRegistry[getFontName(macFont.getId(), maxSize, macFont.getSlant())]);
}
Пример #3
0
void DefaultSaveFileManager::assureCached(const Common::String &savePathName) {
	// Check that path exists and is usable.
	checkPath(Common::FSNode(savePathName));

#ifdef USE_LIBCURL
	Common::Array<Common::String> files = CloudMan.getSyncingFiles(); //returns empty array if not syncing
	if (!files.empty()) updateSavefilesList(files); //makes this cache invalid
	else _lockedFiles = files;
#endif

	if (_cachedDirectory == savePathName) {
		return;
	}

	_saveFileCache.clear();
	_cachedDirectory.clear();

	if (getError().getCode() != Common::kNoError) {
		warning("DefaultSaveFileManager::assureCached: Can not cache path '%s': '%s'", savePathName.c_str(), getErrorDesc().c_str());
		return;
	}

	// FSNode can cache its members, thus create it after checkPath to reflect
	// actual file system state.
	const Common::FSNode savePath(savePathName);

	Common::FSList children;
	if (!savePath.getChildren(children, Common::FSNode::kListFilesOnly)) {
		return;
	}

	// Build the savefile name cache.
	for (Common::FSList::const_iterator file = children.begin(), end = children.end(); file != end; ++file) {
		if (_saveFileCache.contains(file->getName())) {
			warning("DefaultSaveFileManager::assureCached: Name clash when building cache, ignoring file '%s'", file->getName().c_str());
		} else {
			_saveFileCache[file->getName()] = *file;
		}
	}

	// Only now store that we cached 'savePathName' to indicate we successfully
	// cached the directory.
	_cachedDirectory = savePathName;
}
Пример #4
0
Graphics::Surface *CDToonsDecoder::decodeImage(Common::SeekableReadStream *stream) {
	uint16 u0 = stream->readUint16BE(); // always 9?
	uint16 frameId = stream->readUint16BE();
	uint16 blocksValidUntil = stream->readUint16BE();
	byte u6 = stream->readByte();
	byte backgroundColor = stream->readByte();
	debugN(5, "CDToons frame %d, size %d, unknown %04x (at 0), blocks valid until %d, unknown 6 is %02x, bkg color is %02x\n",
		frameId, stream->size(), u0, blocksValidUntil, u6, backgroundColor);

	Common::Rect clipRect = readRect(stream);
	debugN(9, "CDToons clipRect: (%d, %d) to (%d, %d)\n",
		clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);

	Common::Rect dirtyRect = readRect(stream);
	debugN(9, "CDToons dirtyRect: (%d, %d) to (%d, %d)\n",
		dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom);

	uint32 flags = stream->readUint32BE();
	if (flags & 0x80)
		error("CDToons: frame already processed?");
	debugN(5, "CDToons flags: %08x\n", flags);

	uint16 blockCount = stream->readUint16BE();
	uint16 blockOffset = stream->readUint16BE();
	debugN(9, "CDToons: %d blocks at 0x%04x\n",
		blockCount, blockOffset);

	// max block id?
	uint16 u32 = stream->readUint16BE();
	debugN(5, "CDToons unknown at 32: %04x\n", u32);

	byte actionCount = stream->readByte();
	byte u35 = stream->readByte();

	uint16 paletteId = stream->readUint16BE();
	byte paletteSet = stream->readByte();
	debugN(9, "CDToons palette id %04x, palette byte %02x\n",
		paletteId, paletteSet);

	byte u39 = stream->readByte();
	uint16 u40 = stream->readUint16BE();
	uint16 u42 = stream->readUint16BE();
	debugN(5, "CDToons: unknown at 35 is %02x, unknowns at 39: %02x, %04x, %04x\n",
		u35, u39, u40, u42);

	Common::Array<CDToonsAction> actions;

	for (uint i = 0; i < actionCount; i++) {
		CDToonsAction action;
		action.blockId = stream->readUint16BE();
		action.rect = readRect(stream);
		debugN(9, "CDToons action: render block %d at (%d, %d) to (%d, %d)\n",
			action.blockId, action.rect.left, action.rect.top, action.rect.right, action.rect.bottom);
		actions.push_back(action);
	}

	if (stream->pos() > blockOffset)
		error("CDToons header ended at 0x%08x, but blocks should have started at 0x%08x",
			stream->pos(), blockOffset);

	if (stream->pos() != blockOffset)
		error("CDToons had %d unknown bytes after header", blockOffset - stream->pos());

	for (uint i = 0; i < blockCount; i++) {
		uint16 blockId = stream->readUint16BE();
		if (blockId >= 1200)
			error("CDToons: block id %d was too high", blockId);
		if (_blocks.contains(blockId))
			error("CDToons: new block %d was already seen", blockId);

		CDToonsBlock block;
		block.flags = stream->readUint16BE();
		// flag 1 = palette, flag 2 = data?
		if (block.flags & 0x8000)
			error("CDToons: block already processed?");
		block.size = stream->readUint32BE();
		if (block.size < 14)
			error("CDToons: block size was %d, too small", block.size);
		block.size -= 14;
		block.startFrame = stream->readUint16BE();
		block.endFrame = stream->readUint16BE();
		block.unknown12 = stream->readUint16BE();
		block.data = new byte[block.size];
		stream->read(block.data, block.size);

		debugN(9, "CDToons block id 0x%04x of size 0x%08x, flags %04x, from frame %d to %d, unknown at 12 is %04x\n",
			blockId, block.size, block.flags, block.startFrame, block.endFrame, block.unknown12);

		_blocks[blockId] = block;
	}

	byte xFrmBegin = 0, xFrmCount;
	Common::Array<CDToonsDiff> diffs;

	while (true) {
		int32 nextPos = stream->pos();
		uint32 tag = stream->readUint32BE();
		uint32 size = stream->readUint32BE();
		nextPos += size;

		switch (tag) {
		case MKTAG('D','i','f','f'):
			{
			debugN(5, "CDToons: Diff\n");
			uint16 count = stream->readUint16BE();

			Common::Rect diffClipRect = readRect(stream);
			debugN(9, "CDToons diffClipRect: (%d, %d) to (%d, %d)\n",
				diffClipRect.left, diffClipRect.top, diffClipRect.right, diffClipRect.bottom);

			debugN(5, "CDToons Diff: %d subentries\n", count);
			for (uint i = 0; i < count; i++) {
				CDToonsDiff diff;

				diff.rect = readRect(stream);
				diff.size = stream->readUint32BE();
				if (diff.size < 20)
					error("CDToons: Diff block size was %d, too small", diff.size);

				uint16 diffWidth = stream->readUint16BE();
				uint16 diffHeight = stream->readUint16BE();
				uint16 unknown16 = stream->readUint16BE();
				uint16 unknown18 = stream->readUint16BE();
				diff.size -= 8;

				if (diffWidth != diff.rect.width() || diffHeight != diff.rect.height())
					error("CDToons: Diff sizes didn't match");
				debugN(5, "CDToons Diff: size %d, frame from (%d, %d) to (%d, %d), unknowns %04x, %04x\n",
					diff.size, diff.rect.left, diff.rect.top, diff.rect.right, diff.rect.bottom,
					unknown16, unknown18);

				diff.data = new byte[diff.size];
				stream->read(diff.data, diff.size);
				diffs.push_back(diff);
			}
			}
			break;
		case MKTAG('X','F','r','m'):
			{
			debugN(5, "CDToons: XFrm\n");
			if (!(flags & 0x10))
				error("CDToons: useless XFrm?");

			if (xFrmBegin)
				error("CDToons: duplicate XFrm");
			xFrmBegin = stream->readByte();
			xFrmCount = stream->readByte();
			debugN(9, "CDToons XFrm: run %d actions from %d\n", xFrmCount, xFrmBegin - 1);

			// TODO: don't ignore (if xFrmCount is non-zero)
			Common::Rect dirtyRectXFrm = readRect(stream);
			debugN(9, "CDToons XFrm dirtyRect: (%d, %d) to (%d, %d)\n",
				dirtyRectXFrm.left, dirtyRectXFrm.top, dirtyRectXFrm.right, dirtyRectXFrm.bottom);

			// always zero?
			Common::Rect dirtyRect2XFrm = readRect(stream);
			debugN(9, "CDToons XFrm dirtyRect2: (%d, %d) to (%d, %d)\n",
				dirtyRect2XFrm.left, dirtyRect2XFrm.top, dirtyRect2XFrm.right, dirtyRect2XFrm.bottom);
			}
			break;
		case MKTAG('M','r','k','s'):
			debugN(5, "CDToons: Mrks\n");
			if (!(flags & 0x2))
				error("CDToons: useless Mrks?");

			// TODO
			warning("CDToons: encountered Mrks, not implemented yet");
			break;
		case MKTAG('S','c','a','l'):
			// TODO
			warning("CDToons: encountered Scal, not implemented yet");
			break;
		case MKTAG('W','r','M','p'):
			warning("CDToons: encountered WrMp, ignoring");
			break;
		case MKTAG('F','r','t','R'):
			{
			debugN(5, "CDToons: FrtR\n");
			if (!(flags & 0x40))
				error("CDToons: useless FrtR?");

			uint16 count = stream->readUint16BE();
			debugN(9, "CDToons FrtR: %d dirty rectangles\n", count);
			for (uint i = 0; i < count; i++) {
				Common::Rect dirtyRectFrtR = readRect(stream);
				debugN(9, "CDToons FrtR dirtyRect: (%d, %d) to (%d, %d)\n",
					dirtyRectFrtR.left, dirtyRectFrtR.top, dirtyRectFrtR.right, dirtyRectFrtR.bottom);
			}
			}
			break;
		case MKTAG('B','c','k','R'):
			{
			debugN(5, "CDToons: BckR\n");
			if (!(flags & 0x20))
				error("CDToons: useless BckR?");

			uint16 count = stream->readUint16BE();
			debugN(9, "CDToons BckR: %d subentries\n", count);
			for (uint i = 0; i < count; i++) {
				Common::Rect dirtyRectBckR = readRect(stream);
				debugN(9, "CDToons BckR dirtyRect: (%d, %d) to (%d, %d)\n",
					dirtyRectBckR.left, dirtyRectBckR.top, dirtyRectBckR.right, dirtyRectBckR.bottom);
			}
			}
			break;
		default:
			warning("Unknown CDToons tag '%s'", tag2str(tag));
		}

		if (stream->pos() > nextPos)
			error("CDToons ran off the end of a block while reading it (at %d, next block at %d)",
				stream->pos(), nextPos);
		if (stream->pos() != nextPos) {
			warning("CDToons had %d unknown bytes after block", nextPos - stream->pos());
			stream->seek(nextPos);
		}

		if (stream->pos() == stream->size())
			break;
	}

	for (uint i = 0; i < diffs.size(); i++) {
		renderBlock(diffs[i].data, diffs[i].size, diffs[i].rect.left, diffs[i].rect.top, diffs[i].rect.width(), diffs[i].rect.height());
		delete[] diffs[i].data;
	}
	if (!diffs.empty())
		return _surface;

	for (uint i = 0; i < actions.size(); i++) {
		CDToonsAction &action = actions[i];
		if (i == 0 && action.blockId == 0)
			memset(_surface->pixels, backgroundColor, _surface->w * _surface->h);
		if (!_blocks.contains(action.blockId))
			continue;
		if (!action.rect.right)
			continue;
		if (i == 0 && !diffs.empty())
			continue;

		CDToonsBlock &block = _blocks[action.blockId];
		uint16 width = READ_BE_UINT16(block.data + 2);
		uint16 height = READ_BE_UINT16(block.data);

		renderBlock(block.data + 14, block.size - 14, action.rect.left, action.rect.top, width, height);
	}

	if (paletteId && _currentPaletteId != paletteId) {
		if (!_blocks.contains(paletteId))
			error("CDToons: no block for palette %04x", paletteId);
		if (_blocks[paletteId].size != 2 * 3 * 256)
			error("CDToons: palette %04x is wrong size (%d)", paletteId, _blocks[paletteId].size);

		_currentPaletteId = paletteId;
		if (!paletteSet)
			setPalette(_blocks[paletteId].data);
	}

	return _surface;
}