Files
2026-02-02 04:50:13 +01:00

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