Exemplo n.º 1
0
void NutRenderer::loadFont(const char *filename) {
	ScummFile file;
	_vm->openFile(file, filename);
	if (!file.isOpen()) {
		error("NutRenderer::loadFont() Can't open font file: %s", filename);
	}

	uint32 tag = file.readUint32BE();
	if (tag != MKID_BE('ANIM')) {
		error("NutRenderer::loadFont() there is no ANIM chunk in font header");
	}

	uint32 length = file.readUint32BE();
	byte *dataSrc = new byte[length];
	file.read(dataSrc, length);
	file.close();

	if (READ_BE_UINT32(dataSrc) != MKID_BE('AHDR')) {
		error("NutRenderer::loadFont() there is no AHDR chunk in font header");
	}

	// We pre-decode the font, which may seem wasteful at first. Actually,
	// the memory needed for just the decoded glyphs is smaller than the
	// whole of the undecoded font file.

	_numChars = READ_LE_UINT16(dataSrc + 10);
	assert(_numChars <= ARRAYSIZE(_chars));

	uint32 offset = 0;
	uint32 decodedLength = 0;
	int l;

	_paletteMap = new byte[256];
	for (l = 0; l < 256; l++) {
		_paletteMap[l] = 0;
	}

	for (l = 0; l < _numChars; l++) {
		offset += READ_BE_UINT32(dataSrc + offset + 4) + 16;
		int width = READ_LE_UINT16(dataSrc + offset + 14);
		int height = READ_LE_UINT16(dataSrc + offset + 16);
		int size = width * height;
		decodedLength += size;
		if (size > _maxCharSize)
			_maxCharSize = size;
	}

	debug(1, "NutRenderer::loadFont('%s') - decodedLength = %d", filename, decodedLength);

	_decodedData = new byte[decodedLength];
	byte *decodedPtr = _decodedData;

	offset = 0;
	for (l = 0; l < _numChars; l++) {
		offset += READ_BE_UINT32(dataSrc + offset + 4) + 8;
		if (READ_BE_UINT32(dataSrc + offset) != MKID_BE('FRME')) {
			error("NutRenderer::loadFont(%s) there is no FRME chunk %d (offset %x)", filename, l, offset);
			break;
		}
		offset += 8;
		if (READ_BE_UINT32(dataSrc + offset) != MKID_BE('FOBJ')) {
			error("NutRenderer::loadFont(%s) there is no FOBJ chunk in FRME chunk %d (offset %x)", filename, l, offset);
			break;
		}
		int codec = READ_LE_UINT16(dataSrc + offset + 8);
		// _chars[l].xoffs = READ_LE_UINT16(dataSrc + offset + 10);
		// _chars[l].yoffs = READ_LE_UINT16(dataSrc + offset + 12);
		_chars[l].width = READ_LE_UINT16(dataSrc + offset + 14);
		_chars[l].height = READ_LE_UINT16(dataSrc + offset + 16);
		_chars[l].src = decodedPtr;

		decodedPtr += (_chars[l].width * _chars[l].height);

		// If characters have transparency, then bytes just get skipped and
		// so there may appear some garbage. That's why we have to fill it
		// with a default color first.
		if (codec == 44) {
			memset(_chars[l].src, kSmush44TransparentColor, _chars[l].width * _chars[l].height);
			_paletteMap[kSmush44TransparentColor] = 1;
			_chars[l].transparency = kSmush44TransparentColor;
		} else {
			memset(_chars[l].src, kDefaultTransparentColor, _chars[l].width * _chars[l].height);
			_paletteMap[kDefaultTransparentColor] = 1;
			_chars[l].transparency = kDefaultTransparentColor;
		}

		const uint8 *fobjptr = dataSrc + offset + 22;
		switch (codec) {
		case 1:
			codec1(_chars[l].src, fobjptr, _chars[l].width, _chars[l].height, _chars[l].width);
			break;
		case 21:
		case 44:
			codec21(_chars[l].src, fobjptr, _chars[l].width, _chars[l].height, _chars[l].width);
			break;
		default:
			error("NutRenderer::loadFont: unknown codec: %d", codec);
		}
	}

	// We have decoded the font. Now let's see if we can re-compress it to
	// a more compact format. Start by counting the number of colors.

	int numColors = 0;
	for (l = 0; l < 256; l++) {
		if (_paletteMap[l]) {
			if (numColors < ARRAYSIZE(_palette)) {
				_paletteMap[l] = numColors;
				_palette[numColors] = l;
			}
			numColors++;
		}
	}

	// Now _palette contains all the used colors, and _paletteMap maps the
	// real color to the palette index.

	if (numColors <= 2)
		_bpp = 1;
	else if (numColors <= 4)
		_bpp = 2;
	else if (numColors <= 16)
		_bpp = 4;
	else
		_bpp = 8;

	if (_bpp < 8) {
		int compressedLength = 0;
		for (l = 0; l < 256; l++) {
			compressedLength += (((_bpp * _chars[l].width + 7) / 8) * _chars[l].height);
		}

		debug(1, "NutRenderer::loadFont('%s') - compressedLength = %d (%d bpp)", filename, compressedLength, _bpp);

		byte *compressedData = new byte[compressedLength];
		memset(compressedData, 0, compressedLength);

		offset = 0;

		for (l = 0; l < 256; l++) {
			byte *src = _chars[l].src;
			byte *dst = compressedData + offset;
			int srcPitch = _chars[l].width;
			int dstPitch = (_bpp * _chars[l].width + 7) / 8;

			for (int h = 0; h < _chars[l].height; h++) {
				byte bit = 0x80;
				byte *nextDst = dst + dstPitch;
				for (int w = 0; w < srcPitch; w++) {
					byte color = _paletteMap[src[w]];
					for (int i = 0; i < _bpp; i++) {
						if (color & (1 << i))
							*dst |= bit;
						bit >>= 1;
					}
					if (!bit) {
						bit = 0x80;
						dst++;
					}
				}
				src += srcPitch;
				dst = nextDst;
			}
			_chars[l].src = compressedData + offset;
			offset += (dstPitch * _chars[l].height);
		}

		delete[] _decodedData;
		_decodedData = compressedData;

		_charBuffer = new byte[_maxCharSize];
	}
int BundleDirCache::matchFile(const char *filename) {
	int32 tag, offset;
	bool found = false;
	int freeSlot = -1;
	int fileId;

	for (fileId = 0; fileId < ARRAYSIZE(_budleDirCache); fileId++) {
		if ((_budleDirCache[fileId].bundleTable == NULL) && (freeSlot == -1)) {
			freeSlot = fileId;
		}
		if (scumm_stricmp(filename, _budleDirCache[fileId].fileName) == 0) {
			found = true;
			break;
		}
	}

	if (!found) {
		ScummFile file;

		if (g_scumm->openFile(file, filename) == false) {
			error("BundleDirCache::matchFile() Can't open bundle file: %s", filename);
			return false;
		}

		if (freeSlot == -1)
			error("BundleDirCache::matchFileFile() Can't find free slot for file bundle dir cache");

		tag = file.readUint32BE();
		if (tag == 'LB23')
			_budleDirCache[freeSlot].compressedBun = true;
		offset = file.readUint32BE();

		strcpy(_budleDirCache[freeSlot].fileName, filename);
		_budleDirCache[freeSlot].numFiles = file.readUint32BE();
		_budleDirCache[freeSlot].bundleTable = (AudioTable *)malloc(_budleDirCache[freeSlot].numFiles * sizeof(AudioTable));
		assert(_budleDirCache[freeSlot].bundleTable);

		file.seek(offset, SEEK_SET);

		_budleDirCache[freeSlot].indexTable =
				(IndexNode *)calloc(_budleDirCache[freeSlot].numFiles, sizeof(IndexNode));
		assert(_budleDirCache[freeSlot].indexTable);

		for (int32 i = 0; i < _budleDirCache[freeSlot].numFiles; i++) {
			char name[24], c;
			int32 z = 0;
			int32 z2;

			if (tag == 'LB23') {
				file.read(_budleDirCache[freeSlot].bundleTable[i].filename, 24);
			} else {
				for (z2 = 0; z2 < 8; z2++)
					if ((c = file.readByte()) != 0)
						name[z++] = c;
				name[z++] = '.';
				for (z2 = 0; z2 < 4; z2++)
					if ((c = file.readByte()) != 0)
						name[z++] = c;

				name[z] = '\0';
				strcpy(_budleDirCache[freeSlot].bundleTable[i].filename, name);
			}
			_budleDirCache[freeSlot].bundleTable[i].offset = file.readUint32BE();
			_budleDirCache[freeSlot].bundleTable[i].size = file.readUint32BE();
			strcpy(_budleDirCache[freeSlot].indexTable[i].filename,
					_budleDirCache[freeSlot].bundleTable[i].filename);
			_budleDirCache[freeSlot].indexTable[i].index = i;
		}
		qsort(_budleDirCache[freeSlot].indexTable, _budleDirCache[freeSlot].numFiles,
				sizeof(IndexNode), (int (*)(const void*, const void*))scumm_stricmp);
		return freeSlot;
	} else {
		return fileId;
	}
}