249 lines
5.7 KiB
C++
249 lines
5.7 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "engines/stark/formats/xmg.h"
|
|
#include "engines/stark/debug.h"
|
|
#include "engines/stark/gfx/driver.h"
|
|
|
|
#include "graphics/conversion.h"
|
|
#include "graphics/pixelformat.h"
|
|
#include "graphics/surface.h"
|
|
#include "common/stream.h"
|
|
#include "common/textconsole.h"
|
|
|
|
namespace Stark {
|
|
namespace Formats {
|
|
|
|
XMGDecoder::XMGDecoder(Common::ReadStream *stream) :
|
|
_width(0),
|
|
_height(0),
|
|
_currX(0),
|
|
_currY(0),
|
|
_stream(stream),
|
|
_transColor(0) {
|
|
}
|
|
|
|
Graphics::Surface *XMGDecoder::decode(Common::ReadStream *stream) {
|
|
XMGDecoder dec(stream);
|
|
dec.readHeader();
|
|
return dec.decodeImage();
|
|
}
|
|
|
|
void XMGDecoder::readSize(Common::ReadStream *stream, uint &width, uint &height) {
|
|
XMGDecoder dec(stream);
|
|
dec.readHeader();
|
|
|
|
width = dec._width;
|
|
height = dec._height;
|
|
}
|
|
|
|
void XMGDecoder::readHeader() {
|
|
// Read the file version
|
|
uint32 version = _stream->readUint32LE();
|
|
if (version != 3) {
|
|
error("Stark::XMG: File version unknown: %d", version);
|
|
}
|
|
|
|
// Read the transparency color (RGBA)
|
|
_transColor = _stream->readUint32LE();
|
|
|
|
// Read the image size
|
|
_width = _stream->readUint32LE();
|
|
_height = _stream->readUint32LE();
|
|
debugC(10, kDebugXMG, "Stark::XMG: Version=%d, TransparencyColor=0x%08x, size=%dx%d", version, _transColor, _width, _height);
|
|
|
|
// Read the scan length
|
|
uint32 scanLen = _stream->readUint32LE();
|
|
if (scanLen != 3 * _width) {
|
|
error("Stark::XMG: The scan length (%d) doesn't match the width bytes (%d)", scanLen, 3 * _width);
|
|
}
|
|
|
|
// Unknown
|
|
uint32 unknown2 = _stream->readUint32LE();
|
|
debugC(kDebugUnknown, "Stark::XMG: unknown2 = %08x = %d", unknown2, unknown2);
|
|
uint32 unknown3 = _stream->readUint32LE();
|
|
debugC(kDebugUnknown, "Stark::XMG: unknown3 = %08x = %d", unknown3, unknown3);
|
|
}
|
|
|
|
Graphics::Surface *XMGDecoder::decodeImage() {
|
|
// Create the destination surface
|
|
Graphics::Surface *surface = new Graphics::Surface();
|
|
surface->create(_width, _height, Gfx::Driver::getRGBAPixelFormat());
|
|
|
|
_currX = 0, _currY = 0;
|
|
while (!_stream->eos()) {
|
|
if (_currX >= _width) {
|
|
assert(_currX == _width);
|
|
_currX = 0;
|
|
_currY += 2;
|
|
if (_currY >= _height)
|
|
break;
|
|
}
|
|
|
|
// Read the number and mode of the tiles
|
|
byte op = _stream->readByte();
|
|
uint16 count;
|
|
if ((op & 0xC0) != 0xC0) {
|
|
count = op & 0x3F;
|
|
} else {
|
|
count = ((op & 0xF) << 8) + _stream->readByte();
|
|
op <<= 2;
|
|
}
|
|
op &= 0xC0;
|
|
|
|
// Process the current serie
|
|
for (int i = 0; i < count; i++) {
|
|
Block block = decodeBlock(op);
|
|
drawBlock(block, surface);
|
|
}
|
|
}
|
|
|
|
return surface;
|
|
}
|
|
|
|
XMGDecoder::Block XMGDecoder::decodeBlock(byte op) {
|
|
Block block;
|
|
|
|
switch (op) {
|
|
case 0x00:
|
|
// YCrCb
|
|
block = processYCrCb();
|
|
break;
|
|
case 0x40:
|
|
// Trans
|
|
block = processTrans();
|
|
break;
|
|
case 0x80:
|
|
// RGB
|
|
block = processRGB();
|
|
break;
|
|
default:
|
|
error("Unsupported color mode '%d'", op);
|
|
}
|
|
|
|
return block;
|
|
}
|
|
|
|
void XMGDecoder::drawBlock(const Block &block, Graphics::Surface *surface) {
|
|
uint32 *pixels = (uint32 *)surface->getBasePtr(_currX, _currY);
|
|
|
|
bool drawTwoColumns = _currX + 1 < _width;
|
|
bool drawTwoLines = _currY + 1 < _height;
|
|
|
|
pixels[0] = TO_LE_32(block.a1);
|
|
|
|
if (drawTwoColumns) {
|
|
pixels[1] = TO_LE_32(block.a2);
|
|
}
|
|
|
|
if (drawTwoLines) {
|
|
pixels[_width + 0] = TO_LE_32(block.b1);
|
|
}
|
|
|
|
if (drawTwoColumns && drawTwoLines) {
|
|
pixels[_width + 1] = TO_LE_32(block.b2);
|
|
}
|
|
|
|
_currX += drawTwoColumns ? 2 : 1;
|
|
}
|
|
|
|
XMGDecoder::Block XMGDecoder::processYCrCb() {
|
|
byte y0, y1, y2, y3;
|
|
byte cr, cb;
|
|
|
|
y0 = _stream->readByte();
|
|
y1 = _stream->readByte();
|
|
y2 = _stream->readByte();
|
|
y3 = _stream->readByte();
|
|
cr = _stream->readByte();
|
|
cb = _stream->readByte();
|
|
|
|
byte r, g, b;
|
|
Block block;
|
|
|
|
Graphics::YUV2RGB(y0, cb, cr, r, g, b);
|
|
block.a1 = (255u << 24) + (b << 16) + (g << 8) + r;
|
|
|
|
Graphics::YUV2RGB(y1, cb, cr, r, g, b);
|
|
block.a2 = (255u << 24) + (b << 16) + (g << 8) + r;
|
|
|
|
Graphics::YUV2RGB(y2, cb, cr, r, g, b);
|
|
block.b1 = (255u << 24) + (b << 16) + (g << 8) + r;
|
|
|
|
Graphics::YUV2RGB(y3, cb, cr, r, g, b);
|
|
block.b2 = (255u << 24) + (b << 16) + (g << 8) + r;
|
|
|
|
return block;
|
|
}
|
|
|
|
XMGDecoder::Block XMGDecoder::processTrans() {
|
|
Block block;
|
|
|
|
block.a1 = 0;
|
|
block.a2 = 0;
|
|
block.b1 = 0;
|
|
block.b2 = 0;
|
|
|
|
return block;
|
|
}
|
|
|
|
XMGDecoder::Block XMGDecoder::processRGB() {
|
|
Block block;
|
|
uint32 color;
|
|
|
|
color = _stream->readUint16LE();
|
|
color += _stream->readByte() << 16;
|
|
if (color != _transColor)
|
|
color += 255u << 24;
|
|
else
|
|
color = 0;
|
|
block.a1 = color;
|
|
|
|
color = _stream->readUint16LE();
|
|
color += _stream->readByte() << 16;
|
|
if (color != _transColor)
|
|
color += 255u << 24;
|
|
else
|
|
color = 0;
|
|
block.a2 = color;
|
|
|
|
color = _stream->readUint16LE();
|
|
color += _stream->readByte() << 16;
|
|
if (color != _transColor)
|
|
color += 255u << 24;
|
|
else
|
|
color = 0;
|
|
block.b1 = color;
|
|
|
|
color = _stream->readUint16LE();
|
|
color += _stream->readByte() << 16;
|
|
if (color != _transColor)
|
|
color += 255u << 24;
|
|
else
|
|
color = 0;
|
|
block.b2 = color;
|
|
|
|
return block;
|
|
}
|
|
|
|
} // End of namespace Formats
|
|
} // End of namespace Stark
|