示例#1
0
void ImageDecoder::decompress(MipMap &out, const MipMap &in, PixelFormatRaw format) {
	if ((format != kPixelFormatDXT1) &&
	    (format != kPixelFormatDXT3) &&
	    (format != kPixelFormatDXT5))
		throw Common::Exception("Unknown compressed format %d", format);

	/* The DXT algorithms work on 4x4 pixel blocks. Textures smaller than one
	 * block will be padded, but larger textures need to be correctly aligned. */
	if (!hasValidDimensions(format, in.width, in.height))
		throw Common::Exception("Invalid dimensions (%dx%d) for format %d", in.width, in.height, format);

	out.width  = in.width;
	out.height = in.height;
	out.size   = out.width * out.height * 4;

	out.data.reset(new byte[out.size]);

	Common::ScopedPtr<Common::MemoryReadStream> stream(new Common::MemoryReadStream(in.data.get(), in.size));

	if      (format == kPixelFormatDXT1)
		decompressDXT1(out.data.get(), *stream, out.width, out.height, out.width * 4);
	else if (format == kPixelFormatDXT3)
		decompressDXT3(out.data.get(), *stream, out.width, out.height, out.width * 4);
	else if (format == kPixelFormatDXT5)
		decompressDXT5(out.data.get(), *stream, out.width, out.height, out.width * 4);
}
示例#2
0
文件: tpc.cpp 项目: TC01/phaethon
void TPC::readHeader(Common::SeekableReadStream &tpc, byte &encoding) {
	// Number of bytes for the pixel data in one full image
	uint32 dataSize = tpc.readUint32LE();

	tpc.skip(4); // Some float

	// Image dimensions
	uint32 width  = tpc.readUint16LE();
	uint32 height = tpc.readUint16LE();

	if ((width >= 0x8000) || (height >= 0x8000))
		throw Common::Exception("Unsupported image dimensions (%ux%u)", width, height);

	// How's the pixel data encoded?
	encoding = tpc.readByte();

	// Number of mip maps in the image
	size_t mipMapCount = tpc.readByte();

	tpc.skip(114); // Reserved

	uint32 minDataSize = 0;
	if (dataSize == 0) {
		// Uncompressed

		if        (encoding == kEncodingGray) {
			// 8bpp grayscale

			_format = kPixelFormatR8G8B8;

			minDataSize = 1;
			dataSize    = width * height;

		} else if (encoding == kEncodingRGB) {
			// RGB, no alpha channel

			_format = kPixelFormatR8G8B8;

			minDataSize = 3;
			dataSize    = width * height * 3;

		} else if (encoding == kEncodingRGBA) {
			// RGBA, alpha channel

			_format = kPixelFormatR8G8B8A8;

			minDataSize = 4;
			dataSize    = width * height * 4;

		} else if (encoding == kEncodingSwizzledBGRA) {
			// BGRA, alpha channel, texture memory layout is "swizzled"

			_format = kPixelFormatB8G8R8A8;

			minDataSize = 4;
			dataSize    = width * height * 4;

		} else
			throw Common::Exception("Unknown TPC raw encoding: %d (%d), %dx%d, %u", encoding, dataSize, width, height, (uint) mipMapCount);

	} else if (encoding == kEncodingRGB) {
		// S3TC DXT1

		_format = kPixelFormatDXT1;

		minDataSize = 8;

		checkCubeMap(width, height);

		if (dataSize != ((width * height) / 2))
			throw Common::Exception("Invalid data size for a texture of %ux%u pixels and format %u",
			                        width, height, encoding);

	} else if (encoding == kEncodingRGBA) {
		// S3TC DXT5

		_format = kPixelFormatDXT5;

		minDataSize = 16;

		checkCubeMap(width, height);

		if (dataSize != (width * height))
			throw Common::Exception("Invalid data size for a texture of %ux%u pixels and format %u",
			                        width, height, encoding);

	} else
		throw Common::Exception("Unknown TPC encoding: %d (%d)", encoding, dataSize);

	if (!hasValidDimensions(_format, width, height))
		throw Common::Exception("Invalid dimensions (%dx%d) for format %d", width, height, _format);

	const size_t fullImageDataSize = getDataSize(_format, width, height);

	size_t fullDataSize = tpc.size() - 128;
	if (fullDataSize < (_layerCount * fullImageDataSize))
		throw Common::Exception("Image wouldn't fit into data");

	_mipMaps.reserve(mipMapCount * _layerCount);

	size_t layerCount;
	for (layerCount = 0; layerCount < _layerCount; layerCount++) {
		uint32 layerWidth  = width;
		uint32 layerHeight = height;
		uint32 layerSize   = dataSize;

		for (size_t i = 0; i < mipMapCount; i++) {
			MipMap *mipMap = new MipMap;

			mipMap->width  = MAX<uint32>(layerWidth,  1);
			mipMap->height = MAX<uint32>(layerHeight, 1);

			mipMap->size = MAX<uint32>(layerSize, minDataSize);

			mipMap->data = 0;

			const size_t mipMapDataSize = getDataSize(_format, mipMap->width, mipMap->height);

			if ((fullDataSize < mipMap->size) || (mipMap->size < mipMapDataSize)) {
				// Wouldn't fit
				delete mipMap;
				break;
			}

			fullDataSize -= mipMap->size;

			_mipMaps.push_back(mipMap);

			layerWidth  >>= 1;
			layerHeight >>= 1;
			layerSize   >>= 2;

			if ((layerWidth < 1) && (layerHeight < 1))
				break;
		}
	}

	if ((layerCount != _layerCount) || ((_mipMaps.size() % _layerCount) != 0))
		throw Common::Exception("Failed to correctly read all texture layers (%u, %u, %u, %u)",
		                        (uint) _layerCount, (uint) mipMapCount,
		                        (uint) layerCount, (uint) _mipMaps.size());
}
示例#3
0
文件: txb.cpp 项目: kevL/xoreos
void TXB::readHeader(Common::SeekableReadStream &txb, bool &needDeSwizzle, uint32 &dataSize) {
	// Number of bytes for the pixel data in one full image
	dataSize = txb.readUint32LE();

	txb.skip(4); // Some float

	// Image dimensions
	uint32 width  = txb.readUint16LE();
	uint32 height = txb.readUint16LE();

	if ((width >= 0x8000) || (height >= 0x8000))
		throw Common::Exception("Unsupported image dimensions (%ux%u)", width, height);

	// How's the pixel data encoded?
	byte encoding    = txb.readByte();
	// Number of mip maps in the image
	byte mipMapCount = txb.readByte();

	txb.skip(2); // Unknown (Always 0x0101 on 0x0A and 0x0C types, 0x0100 on 0x09?)
	txb.skip(4); // Some float
	txb.skip(108); // Reserved

	needDeSwizzle = false;

	uint32 minDataSize, mipMapSize;
	if        (encoding == kEncodingBGRA) {
		// Raw BGRA

		needDeSwizzle = true;

		_compressed = false;
		_hasAlpha   = true;
		_format     = kPixelFormatBGRA;
		_formatRaw  = kPixelFormatRGBA8;
		_dataType   = kPixelDataType8;

		minDataSize = 4;
		mipMapSize  = width * height * 4;

	} else if (encoding == kEncodingDXT1) {
		// S3TC DXT1

		_compressed = true;
		_hasAlpha   = false;
		_format     = kPixelFormatBGR;
		_formatRaw  = kPixelFormatDXT1;
		_dataType   = kPixelDataType8;

		minDataSize = 8;
		mipMapSize  = width * height / 2;

	} else if (encoding == kEncodingDXT5) {
		// S3TC DXT5

		_compressed = true;
		_hasAlpha   = true;
		_format     = kPixelFormatBGRA;
		_formatRaw  = kPixelFormatDXT5;
		_dataType   = kPixelDataType8;

		minDataSize = 16;
		mipMapSize  = width * height;

	} else if (encoding == 0x09)
		// TODO: This seems to be some compression with 8bit per pixel. No min
		//       data size; 2*2 and 1*1 mipmaps seem to be just that big.
		//       Image data doesn't seem to be simple grayscale, paletted,
		//       RGB2222 or RGB332 data either.
		throw Common::Exception("Unsupported TXB encoding 0x09");
	 else
		throw Common::Exception("Unknown TXB encoding 0x%02X (%dx%d, %d, %d)",
				encoding, width, height, mipMapCount, dataSize);

	if (!hasValidDimensions(_formatRaw, width, height))
		throw Common::Exception("Invalid dimensions (%dx%d) for format %d", width, height, _formatRaw);

	const size_t fullImageDataSize = getDataSize(_formatRaw, width, height);
	if (dataSize < fullImageDataSize)
		throw Common::Exception("Image wouldn't fit into data");

	_mipMaps.reserve(mipMapCount);
	for (uint32 i = 0; i < mipMapCount; i++) {
		MipMap *mipMap = new MipMap(this);

		mipMap->width  = MAX<uint32>(width,  1);
		mipMap->height = MAX<uint32>(height, 1);

		if (((mipMap->width < 4) || (mipMap->height < 4)) && (mipMap->width != mipMap->height)) {
			// Invalid mipmap dimensions
			delete mipMap;
			break;
		}

		mipMap->size = MAX<uint32>(mipMapSize, minDataSize);

		mipMap->data = 0;

		const size_t mipMapDataSize = getDataSize(_formatRaw, mipMap->width, mipMap->height);

		if ((dataSize < mipMap->size) || (mipMap->size < mipMapDataSize)) {
			// Wouldn't fit
			delete mipMap;
			break;
		}

		dataSize -= mipMap->size;

		_mipMaps.push_back(mipMap);

		width      >>= 1;
		height     >>= 1;
		mipMapSize >>= 2;

		if ((width < 1) && (height < 1))
			break;
	}

}