mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-21 01:05:59 +00:00
Merge pull request #278 from bluegr/pcxdecoder
GRAPHICS: Add a PCX decoder
This commit is contained in:
commit
c0babb010a
@ -23,6 +23,7 @@
|
||||
#include "dreamweb/dreamweb.h"
|
||||
#include "engines/util.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "graphics/decoders/pcx.h"
|
||||
|
||||
namespace DreamWeb {
|
||||
|
||||
@ -152,70 +153,33 @@ void DreamWebEngine::setMode() {
|
||||
void DreamWebEngine::showPCX(const Common::String &suffix) {
|
||||
Common::String name = getDatafilePrefix() + suffix;
|
||||
Common::File pcxFile;
|
||||
|
||||
if (!pcxFile.open(name)) {
|
||||
warning("showpcx: Could not open '%s'", name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 *mainGamePal;
|
||||
int i, j;
|
||||
Graphics::PCXDecoder pcx;
|
||||
if (!pcx.loadStream(pcxFile)) {
|
||||
warning("showpcx: Could not process '%s'", name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Read the 16-color palette into the 'maingamepal' buffer. Note that
|
||||
// the color components have to be adjusted from 8 to 6 bits.
|
||||
|
||||
pcxFile.seek(16, SEEK_SET);
|
||||
mainGamePal = _mainPal;
|
||||
pcxFile.read(mainGamePal, 48);
|
||||
|
||||
memset(mainGamePal + 48, 0xff, 720);
|
||||
for (i = 0; i < 48; i++) {
|
||||
mainGamePal[i] >>= 2;
|
||||
memset(_mainPal, 0xff, 256 * 3);
|
||||
memcpy(_mainPal, pcx.getPalette(), 48);
|
||||
for (int i = 0; i < 48; i++) {
|
||||
_mainPal[i] >>= 2;
|
||||
}
|
||||
|
||||
// Decode the image data.
|
||||
|
||||
Graphics::Surface *s = g_system->lockScreen();
|
||||
Common::Rect rect(640, 480);
|
||||
|
||||
s->fillRect(rect, 0);
|
||||
pcxFile.seek(128, SEEK_SET);
|
||||
|
||||
for (int y = 0; y < 480; y++) {
|
||||
byte *dst = (byte *)s->getBasePtr(0, y);
|
||||
int decoded = 0;
|
||||
|
||||
while (decoded < 320) {
|
||||
byte col = pcxFile.readByte();
|
||||
byte len;
|
||||
|
||||
if ((col & 0xc0) == 0xc0) {
|
||||
len = col & 0x3f;
|
||||
col = pcxFile.readByte();
|
||||
} else {
|
||||
len = 1;
|
||||
}
|
||||
|
||||
// The image uses 16 colors and is stored as four bit
|
||||
// planes, one for each bit of the color, least
|
||||
// significant bit plane first.
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int plane = decoded / 80;
|
||||
int pos = decoded % 80;
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
byte bit = (col >> (7 - j)) & 1;
|
||||
dst[8 * pos + j] |= (bit << plane);
|
||||
}
|
||||
|
||||
decoded++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s->fillRect(Common::Rect(640, 480), 0);
|
||||
const Graphics::Surface *pcxSurface = pcx.getSurface();
|
||||
if (pcxSurface->format.bytesPerPixel != 1)
|
||||
error("Invalid bytes per pixel in PCX surface (%d)", pcxSurface->format.bytesPerPixel);
|
||||
for (uint16 y = 0; y < pcxSurface->h; y++)
|
||||
memcpy((byte *)s->getBasePtr(0, y), pcxSurface->getBasePtr(0, y), pcxSurface->w);
|
||||
g_system->unlockScreen();
|
||||
pcxFile.close();
|
||||
}
|
||||
|
||||
void DreamWebEngine::frameOutV(uint8 *dst, const uint8 *src, uint16 pitch, uint16 width, uint16 height, int16 x, int16 y) {
|
||||
|
@ -32,7 +32,11 @@
|
||||
#include "common/savefile.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "common/config-manager.h"
|
||||
|
||||
#include "graphics/surface.h"
|
||||
#include "graphics/decoders/pcx.h"
|
||||
#include "graphics/thumbnail.h"
|
||||
|
||||
#include "gui/saveload.h"
|
||||
|
||||
#include "hugo/hugo.h"
|
||||
@ -87,67 +91,34 @@ const char *FileManager::getUifFilename() const {
|
||||
return "uif.dat";
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert 4 planes (RGBI) data to 8-bit DIB format
|
||||
* Return original plane data ptr
|
||||
*/
|
||||
byte *FileManager::convertPCC(byte *p, const uint16 y, const uint16 bpl, ImagePtr dataPtr) const {
|
||||
debugC(2, kDebugFile, "convertPCC(byte *p, %d, %d, ImagePtr dataPtr)", y, bpl);
|
||||
|
||||
dataPtr += y * bpl * 8; // Point to correct DIB line
|
||||
for (int16 r = 0, g = bpl, b = g + bpl, i = b + bpl; r < bpl; r++, g++, b++, i++) { // Each byte in all planes
|
||||
for (int8 bit = 7; bit >= 0; bit--) { // Each bit in byte
|
||||
*dataPtr++ = (((p[r] >> bit & 1) << 0) |
|
||||
((p[g] >> bit & 1) << 1) |
|
||||
((p[b] >> bit & 1) << 2) |
|
||||
((p[i] >> bit & 1) << 3));
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a pcx file of length len. Use supplied seqPtr and image_p or
|
||||
* allocate space if NULL. Name used for errors. Returns address of seqPtr
|
||||
* Set first TRUE to initialize b_index (i.e. not reading a sequential image in file).
|
||||
*/
|
||||
Seq *FileManager::readPCX(Common::ReadStream &f, Seq *seqPtr, byte *imagePtr, const bool firstFl, const char *name) {
|
||||
Seq *FileManager::readPCX(Common::SeekableReadStream &f, Seq *seqPtr, byte *imagePtr, const bool firstFl, const char *name) {
|
||||
debugC(1, kDebugFile, "readPCX(..., %s)", name);
|
||||
|
||||
// Read in the PCC header and check consistency
|
||||
_PCCHeader._mfctr = f.readByte();
|
||||
_PCCHeader._vers = f.readByte();
|
||||
_PCCHeader._enc = f.readByte();
|
||||
_PCCHeader._bpx = f.readByte();
|
||||
_PCCHeader._x1 = f.readUint16LE();
|
||||
_PCCHeader._y1 = f.readUint16LE();
|
||||
_PCCHeader._x2 = f.readUint16LE();
|
||||
_PCCHeader._y2 = f.readUint16LE();
|
||||
_PCCHeader._xres = f.readUint16LE();
|
||||
_PCCHeader._yres = f.readUint16LE();
|
||||
f.read(_PCCHeader._palette, sizeof(_PCCHeader._palette));
|
||||
_PCCHeader._vmode = f.readByte();
|
||||
_PCCHeader._planes = f.readByte();
|
||||
_PCCHeader._bytesPerLine = f.readUint16LE();
|
||||
f.read(_PCCHeader._fill2, sizeof(_PCCHeader._fill2));
|
||||
|
||||
if (_PCCHeader._mfctr != 10)
|
||||
error("Bad data file format: %s", name);
|
||||
|
||||
// Allocate memory for Seq if 0
|
||||
if (seqPtr == 0) {
|
||||
if ((seqPtr = (Seq *)malloc(sizeof(Seq))) == 0)
|
||||
error("Insufficient memory to run game.");
|
||||
}
|
||||
|
||||
Graphics::PCXDecoder pcx;
|
||||
if (!pcx.loadStream(f))
|
||||
error("Error while reading PCX image");
|
||||
|
||||
const Graphics::Surface *pcxSurface = pcx.getSurface();
|
||||
if (pcxSurface->format.bytesPerPixel != 1)
|
||||
error("Invalid bytes per pixel in PCX surface (%d)", pcxSurface->format.bytesPerPixel);
|
||||
|
||||
// Find size of image data in 8-bit DIB format
|
||||
// Note save of x2 - marks end of valid data before garbage
|
||||
uint16 bytesPerLine4 = _PCCHeader._bytesPerLine * 4; // 4-bit bpl
|
||||
seqPtr->_bytesPerLine8 = bytesPerLine4 * 2; // 8-bit bpl
|
||||
seqPtr->_lines = _PCCHeader._y2 - _PCCHeader._y1 + 1;
|
||||
seqPtr->_x2 = _PCCHeader._x2 - _PCCHeader._x1 + 1;
|
||||
seqPtr->_lines = pcxSurface->h;
|
||||
seqPtr->_x2 = seqPtr->_bytesPerLine8 = pcxSurface->w;
|
||||
// Size of the image
|
||||
uint16 size = seqPtr->_lines * seqPtr->_bytesPerLine8;
|
||||
uint16 size = pcxSurface->w * pcxSurface->h;
|
||||
|
||||
// Allocate memory for image data if NULL
|
||||
if (imagePtr == 0)
|
||||
@ -156,26 +127,9 @@ Seq *FileManager::readPCX(Common::ReadStream &f, Seq *seqPtr, byte *imagePtr, co
|
||||
assert(imagePtr);
|
||||
|
||||
seqPtr->_imagePtr = imagePtr;
|
||||
for (uint16 y = 0; y < pcxSurface->h; y++)
|
||||
memcpy(imagePtr + y * pcxSurface->w, pcxSurface->getBasePtr(0, y), pcxSurface->w);
|
||||
|
||||
// Process the image data, converting to 8-bit DIB format
|
||||
uint16 y = 0; // Current line index
|
||||
byte pline[kXPix]; // Hold 4 planes of data
|
||||
byte *p = pline; // Ptr to above
|
||||
while (y < seqPtr->_lines) {
|
||||
byte c = f.readByte();
|
||||
if ((c & kRepeatMask) == kRepeatMask) {
|
||||
byte d = f.readByte(); // Read data byte
|
||||
for (int i = 0; i < (c & kLengthMask); i++) {
|
||||
*p++ = d;
|
||||
if ((uint16)(p - pline) == bytesPerLine4)
|
||||
p = convertPCC(pline, y++, _PCCHeader._bytesPerLine, imagePtr);
|
||||
}
|
||||
} else {
|
||||
*p++ = c;
|
||||
if ((uint16)(p - pline) == bytesPerLine4)
|
||||
p = convertPCC(pline, y++, _PCCHeader._bytesPerLine, imagePtr);
|
||||
}
|
||||
}
|
||||
return seqPtr;
|
||||
}
|
||||
|
||||
|
@ -112,16 +112,13 @@ protected:
|
||||
Common::File _sceneryArchive1; // Handle for scenery file
|
||||
Common::File _objectsArchive; // Handle for objects file
|
||||
|
||||
PCCHeader _PCCHeader;
|
||||
|
||||
Seq *readPCX(Common::ReadStream &f, Seq *seqPtr, byte *imagePtr, const bool firstFl, const char *name);
|
||||
Seq *readPCX(Common::SeekableReadStream &f, Seq *seqPtr, byte *imagePtr, const bool firstFl, const char *name);
|
||||
|
||||
// If this is the first call, read the lookup table
|
||||
bool _hasReadHeader;
|
||||
SoundHdr _soundHdr[kMaxSounds]; // Sound lookup table
|
||||
|
||||
private:
|
||||
byte *convertPCC(byte *p, const uint16 y, const uint16 bpl, ImagePtr dataPtr) const;
|
||||
UifHdr *getUIFHeader(const Uif id);
|
||||
};
|
||||
|
||||
|
@ -23,9 +23,13 @@
|
||||
|
||||
#include "common/system.h"
|
||||
#include "common/events.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/memstream.h"
|
||||
|
||||
#include "graphics/cursorman.h"
|
||||
#include "graphics/palette.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "graphics/decoders/pcx.h"
|
||||
|
||||
#include "queen/display.h"
|
||||
#include "queen/input.h"
|
||||
@ -806,28 +810,22 @@ void Display::fill(uint8 *dstBuf, uint16 dstPitch, uint16 x, uint16 y, uint16 w,
|
||||
}
|
||||
|
||||
void Display::decodePCX(const uint8 *src, uint32 srcSize, uint8 *dst, uint16 dstPitch, uint16 *w, uint16 *h, uint8 *pal, uint16 palStart, uint16 palEnd) {
|
||||
*w = READ_LE_UINT16(src + 12);
|
||||
*h = READ_LE_UINT16(src + 14);
|
||||
Common::MemoryReadStream str(src, srcSize);
|
||||
|
||||
::Graphics::PCXDecoder pcx;
|
||||
if (!pcx.loadStream(str))
|
||||
error("Error while reading PCX image");
|
||||
|
||||
const ::Graphics::Surface *pcxSurface = pcx.getSurface();
|
||||
if (pcxSurface->format.bytesPerPixel != 1)
|
||||
error("Invalid bytes per pixel in PCX surface (%d)", pcxSurface->format.bytesPerPixel);
|
||||
*w = pcxSurface->w;
|
||||
*h = pcxSurface->h;
|
||||
|
||||
assert(palStart <= palEnd && palEnd <= 256);
|
||||
const uint8 *palData = src + srcSize - 768;
|
||||
memcpy(pal, palData + palStart * 3, (palEnd - palStart) * 3);
|
||||
|
||||
src += 128;
|
||||
for (int y = 0; y < *h; ++y) {
|
||||
uint8 *p = dst;
|
||||
while (p < dst + *w) {
|
||||
uint8 col = *src++;
|
||||
if ((col & 0xC0) == 0xC0) {
|
||||
uint8 len = col & 0x3F;
|
||||
memset(p, *src++, len);
|
||||
p += len;
|
||||
} else {
|
||||
*p++ = col;
|
||||
}
|
||||
}
|
||||
dst += dstPitch;
|
||||
}
|
||||
memcpy(pal, pcx.getPalette() + palStart * 3, (palEnd - palStart) * 3);
|
||||
for (uint16 y = 0; y < pcxSurface->h; y++)
|
||||
memcpy(dst + y * dstPitch, pcxSurface->getBasePtr(0, y), pcxSurface->w);
|
||||
}
|
||||
|
||||
void Display::decodeLBM(const uint8 *src, uint32 srcSize, uint8 *dst, uint16 dstPitch, uint16 *w, uint16 *h, uint8 *pal, uint16 palStart, uint16 palEnd, uint8 colorBase) {
|
||||
|
@ -29,6 +29,9 @@
|
||||
#include "audio/decoders/vorbis.h"
|
||||
#include "audio/decoders/wave.h"
|
||||
|
||||
#include "graphics/surface.h"
|
||||
#include "graphics/decoders/pcx.h"
|
||||
|
||||
#include "tucker/tucker.h"
|
||||
#include "tucker/graphics.h"
|
||||
|
||||
@ -298,23 +301,21 @@ void TuckerEngine::loadImage(const char *fname, uint8 *dst, int type) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
f.seek(128, SEEK_SET);
|
||||
int size = 0;
|
||||
while (size < 64000) {
|
||||
int code = f.readByte();
|
||||
if (code >= 0xC0) {
|
||||
const int sz = code - 0xC0;
|
||||
code = f.readByte();
|
||||
memset(dst + size, code, sz);
|
||||
size += sz;
|
||||
} else {
|
||||
dst[size++] = code;
|
||||
}
|
||||
}
|
||||
|
||||
::Graphics::PCXDecoder pcx;
|
||||
if (!pcx.loadStream(f))
|
||||
error("Error while reading PCX image");
|
||||
|
||||
const ::Graphics::Surface *pcxSurface = pcx.getSurface();
|
||||
if (pcxSurface->format.bytesPerPixel != 1)
|
||||
error("Invalid bytes per pixel in PCX surface (%d)", pcxSurface->format.bytesPerPixel);
|
||||
if (pcxSurface->w != 320 || pcxSurface->h != 200)
|
||||
error("Invalid PCX surface size (%d x %d)", pcxSurface->w, pcxSurface->h);
|
||||
for (uint16 y = 0; y < pcxSurface->h; y++)
|
||||
memcpy(dst + y * 320, pcxSurface->getBasePtr(0, y), pcxSurface->w);
|
||||
|
||||
if (type != 0) {
|
||||
if (f.readByte() != 12)
|
||||
return;
|
||||
f.read(_currentPalette, 768);
|
||||
memcpy(_currentPalette, pcx.getPalette(), 3 * 256);
|
||||
setBlackPalette();
|
||||
}
|
||||
}
|
||||
|
213
graphics/decoders/pcx.cpp
Normal file
213
graphics/decoders/pcx.cpp
Normal file
@ -0,0 +1,213 @@
|
||||
/* 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 2
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "common/stream.h"
|
||||
#include "common/textconsole.h"
|
||||
|
||||
#include "graphics/pixelformat.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "graphics/decoders/pcx.h"
|
||||
|
||||
/**
|
||||
* Based on the PCX specs:
|
||||
* http://www.fileformat.info/format/pcx/spec/a10e75307b3a4cc49c3bbe6db4c41fa2/view.htm
|
||||
* and the PCX decoder of FFmpeg (libavcodec/pcx.c):
|
||||
* http://git.videolan.org/?p=ffmpeg.git;a=blob;f=libavcodec/pcx.c
|
||||
*/
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
PCXDecoder::PCXDecoder() {
|
||||
_surface = 0;
|
||||
_palette = 0;
|
||||
_paletteColorCount = 0;
|
||||
}
|
||||
|
||||
PCXDecoder::~PCXDecoder() {
|
||||
destroy();
|
||||
}
|
||||
|
||||
void PCXDecoder::destroy() {
|
||||
if (_surface) {
|
||||
_surface->free();
|
||||
delete _surface;
|
||||
_surface = 0;
|
||||
}
|
||||
|
||||
delete[] _palette;
|
||||
_palette = 0;
|
||||
_paletteColorCount = 0;
|
||||
}
|
||||
|
||||
bool PCXDecoder::loadStream(Common::SeekableReadStream &stream) {
|
||||
destroy();
|
||||
|
||||
if (stream.readByte() != 0x0a) // ZSoft PCX
|
||||
return false;
|
||||
|
||||
byte version = stream.readByte(); // 0 - 5
|
||||
if (version > 5)
|
||||
return false;
|
||||
|
||||
bool compressed = stream.readByte(); // encoding, 1 = run length encoding
|
||||
byte bitsPerPixel = stream.readByte(); // 1, 2, 4 or 8
|
||||
|
||||
// Window
|
||||
uint16 xMin = stream.readUint16LE();
|
||||
uint16 yMin = stream.readUint16LE();
|
||||
uint16 xMax = stream.readUint16LE();
|
||||
uint16 yMax = stream.readUint16LE();
|
||||
|
||||
uint16 width = xMax - xMin + 1;
|
||||
uint16 height = yMax - yMin + 1;
|
||||
|
||||
if (xMax < xMin || yMax < yMin) {
|
||||
warning("Invalid PCX image dimensions");
|
||||
return false;
|
||||
}
|
||||
|
||||
stream.skip(4); // HDpi, VDpi
|
||||
|
||||
// Read the EGA palette (colormap)
|
||||
_palette = new byte[16 * 3];
|
||||
for (uint16 i = 0; i < 16; i++) {
|
||||
_palette[i * 3 + 0] = stream.readByte();
|
||||
_palette[i * 3 + 1] = stream.readByte();
|
||||
_palette[i * 3 + 2] = stream.readByte();
|
||||
}
|
||||
|
||||
if (stream.readByte() != 0) // reserved, should be set to 0
|
||||
return false;
|
||||
|
||||
byte nPlanes = stream.readByte();
|
||||
uint16 bytesPerLine = stream.readUint16LE();
|
||||
uint16 bytesPerscanLine = nPlanes * bytesPerLine;
|
||||
|
||||
if (bytesPerscanLine < width * bitsPerPixel * nPlanes / 8) {
|
||||
warning("PCX data is corrupted");
|
||||
return false;
|
||||
}
|
||||
|
||||
stream.skip(60); // PaletteInfo, HscreenSize, VscreenSize, Filler
|
||||
|
||||
_surface = new Graphics::Surface();
|
||||
|
||||
byte *scanLine = new byte[bytesPerscanLine];
|
||||
byte *dst;
|
||||
int x, y;
|
||||
|
||||
if (nPlanes == 3 && bitsPerPixel == 8) { // 24bpp
|
||||
Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
|
||||
_surface->create(width, height, format);
|
||||
dst = (byte *)_surface->pixels;
|
||||
_paletteColorCount = 0;
|
||||
|
||||
for (y = 0; y < height; y++) {
|
||||
decodeRLE(stream, scanLine, bytesPerscanLine, compressed);
|
||||
|
||||
for (x = 0; x < width; x++) {
|
||||
byte b = scanLine[x];
|
||||
byte g = scanLine[x + bytesPerLine];
|
||||
byte r = scanLine[x + (bytesPerLine << 1)];
|
||||
uint32 color = format.RGBToColor(r, g, b);
|
||||
|
||||
*((uint32 *)dst) = color;
|
||||
dst += format.bytesPerPixel;
|
||||
}
|
||||
}
|
||||
} else if (nPlanes == 1 && bitsPerPixel == 8) { // 8bpp indexed
|
||||
_surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
|
||||
dst = (byte *)_surface->pixels;
|
||||
_paletteColorCount = 16;
|
||||
|
||||
for (y = 0; y < height; y++, dst += _surface->pitch) {
|
||||
decodeRLE(stream, scanLine, bytesPerscanLine, compressed);
|
||||
memcpy(dst, scanLine, width);
|
||||
}
|
||||
|
||||
if (version == 5) {
|
||||
if (stream.readByte() != 12) {
|
||||
warning("Expected a palette after the PCX image data");
|
||||
delete[] scanLine;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the VGA palette
|
||||
delete[] _palette;
|
||||
_palette = new byte[256 * 3];
|
||||
for (uint16 i = 0; i < 256; i++) {
|
||||
_palette[i * 3 + 0] = stream.readByte();
|
||||
_palette[i * 3 + 1] = stream.readByte();
|
||||
_palette[i * 3 + 2] = stream.readByte();
|
||||
}
|
||||
|
||||
_paletteColorCount = 256;
|
||||
}
|
||||
} else if ((nPlanes == 2 || nPlanes == 3 || nPlanes == 4) && bitsPerPixel == 1) { // planar, 4, 8 or 16 colors
|
||||
_surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
|
||||
dst = (byte *)_surface->pixels;
|
||||
_paletteColorCount = 16;
|
||||
|
||||
for (y = 0; y < height; y++, dst += _surface->pitch) {
|
||||
decodeRLE(stream, scanLine, bytesPerscanLine, compressed);
|
||||
|
||||
for (x = 0; x < width; x++) {
|
||||
int m = 0x80 >> (x & 7), v = 0;
|
||||
for (int i = nPlanes - 1; i >= 0; i--) {
|
||||
v <<= 1;
|
||||
v += (scanLine[i * bytesPerLine + (x >> 3)] & m) == 0 ? 0 : 1;
|
||||
}
|
||||
dst[x] = v;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Known unsupported case: 1 plane and bpp < 8 (1, 2 or 4)
|
||||
warning("Invalid PCX file (%d planes, %d bpp)", nPlanes, bitsPerPixel);
|
||||
delete[] scanLine;
|
||||
return false;
|
||||
}
|
||||
|
||||
delete[] scanLine;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PCXDecoder::decodeRLE(Common::SeekableReadStream &stream, byte *dst, uint32 bytesPerscanLine, bool compressed) {
|
||||
uint32 i = 0;
|
||||
byte run, value;
|
||||
|
||||
if (compressed) {
|
||||
while (i < bytesPerscanLine) {
|
||||
run = 1;
|
||||
value = stream.readByte();
|
||||
if (value >= 0xc0) {
|
||||
run = value & 0x3f;
|
||||
value = stream.readByte();
|
||||
}
|
||||
while (i < bytesPerscanLine && run--)
|
||||
dst[i++] = value;
|
||||
}
|
||||
} else {
|
||||
stream.read(dst, bytesPerscanLine);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Graphics
|
68
graphics/decoders/pcx.h
Normal file
68
graphics/decoders/pcx.h
Normal file
@ -0,0 +1,68 @@
|
||||
/* 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 2
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* PCX decoder used in engines:
|
||||
* - dreamweb
|
||||
* - hugo
|
||||
* - queen
|
||||
* - tucker
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_DECODERS_PCX_H
|
||||
#define GRAPHICS_DECODERS_PCX_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/str.h"
|
||||
#include "graphics/decoders/image_decoder.h"
|
||||
|
||||
namespace Common{
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
struct PixelFormat;
|
||||
struct Surface;
|
||||
|
||||
class PCXDecoder : public ImageDecoder {
|
||||
public:
|
||||
PCXDecoder();
|
||||
virtual ~PCXDecoder();
|
||||
|
||||
// ImageDecoder API
|
||||
void destroy();
|
||||
virtual bool loadStream(Common::SeekableReadStream &stream);
|
||||
virtual const Surface *getSurface() const { return _surface; }
|
||||
const byte *getPalette() const { return _palette; }
|
||||
uint16 getPaletteColorCount() const { return _paletteColorCount; }
|
||||
|
||||
private:
|
||||
void decodeRLE(Common::SeekableReadStream &stream, byte *dst, uint32 bytesPerScanline, bool compressed);
|
||||
|
||||
Surface *_surface;
|
||||
byte *_palette;
|
||||
uint16 _paletteColorCount;
|
||||
};
|
||||
|
||||
} // End of namespace Graphics
|
||||
|
||||
#endif
|
@ -25,6 +25,7 @@ MODULE_OBJS := \
|
||||
yuv_to_rgb.o \
|
||||
decoders/bmp.o \
|
||||
decoders/jpeg.o \
|
||||
decoders/pcx.o \
|
||||
decoders/pict.o \
|
||||
decoders/png.o \
|
||||
decoders/tga.o
|
||||
|
Loading…
x
Reference in New Issue
Block a user