diff options
Diffstat (limited to 'graphics')
-rw-r--r-- | graphics/cursorman.cpp | 6 | ||||
-rw-r--r-- | graphics/cursorman.h | 2 | ||||
-rw-r--r-- | graphics/dither.cpp | 4 | ||||
-rw-r--r-- | graphics/fonts/winfont.cpp | 89 | ||||
-rw-r--r-- | graphics/fonts/winfont.h | 4 | ||||
-rw-r--r-- | graphics/jpeg.cpp | 4 | ||||
-rw-r--r-- | graphics/module.mk | 3 | ||||
-rw-r--r-- | graphics/palette.h | 17 | ||||
-rw-r--r-- | graphics/pict.cpp | 17 | ||||
-rw-r--r-- | graphics/pict.h | 4 | ||||
-rw-r--r-- | graphics/png.cpp | 10 | ||||
-rw-r--r-- | graphics/png.h | 6 | ||||
-rw-r--r-- | graphics/scaler/2xsai.cpp | 3 | ||||
-rw-r--r-- | graphics/scaler/thumbnail_intern.cpp | 8 | ||||
-rw-r--r-- | graphics/sjis.cpp | 2 | ||||
-rw-r--r-- | graphics/thumbnail.cpp | 4 | ||||
-rw-r--r-- | graphics/wincursor.cpp | 317 | ||||
-rw-r--r-- | graphics/wincursor.h | 105 |
18 files changed, 538 insertions, 67 deletions
diff --git a/graphics/cursorman.cpp b/graphics/cursorman.cpp index fe90545280..8f31421a8b 100644 --- a/graphics/cursorman.cpp +++ b/graphics/cursorman.cpp @@ -206,7 +206,7 @@ void CursorManager::replaceCursorPalette(const byte *colors, uint start, uint nu } Palette *pal = _cursorPaletteStack.top(); - uint size = 4 * num; + uint size = 3 * num; if (pal->_size < size) { // Could not re-use the old buffer. Create a new one. @@ -219,7 +219,7 @@ void CursorManager::replaceCursorPalette(const byte *colors, uint start, uint nu pal->_num = num; if (num) { - memcpy(pal->_data, colors, 4 * num); + memcpy(pal->_data, colors, size); g_system->setCursorPalette(pal->_data, pal->_start, pal->_num); } else { g_system->disableCursorPalette(true); @@ -256,7 +256,7 @@ CursorManager::Cursor::~Cursor() { CursorManager::Palette::Palette(const byte *colors, uint start, uint num) { _start = start; _num = num; - _size = 4 * num; + _size = 3 * num; if (num) { _data = new byte[_size]; diff --git a/graphics/cursorman.h b/graphics/cursorman.h index c041beb957..2f3891aee7 100644 --- a/graphics/cursorman.h +++ b/graphics/cursorman.h @@ -130,7 +130,7 @@ public: * The palette entries from 'start' till (start+num-1) will be replaced * so a full palette updated is accomplished via start=0, num=256. * - * The palette data is specified in the same interleaved RGBA format as + * The palette data is specified in the same interleaved RGB format as * used by all backends. * * @param colors the new palette data, in interleaved RGB format diff --git a/graphics/dither.cpp b/graphics/dither.cpp index 6a37679b0a..5f423d1c7a 100644 --- a/graphics/dither.cpp +++ b/graphics/dither.cpp @@ -174,7 +174,7 @@ bool PaletteLUT::save(Common::WriteStream &stream) { while (_got < _dim1) buildNext(); - stream.writeUint32BE(MKID_BE('PLUT')); // Magic + stream.writeUint32BE(MKTAG('P','L','U','T')); // Magic stream.writeUint32BE(kVersion); stream.writeByte(_depth1); if (stream.write(_realPal, 768) != 768) @@ -200,7 +200,7 @@ bool PaletteLUT::load(Common::SeekableReadStream &stream) { return false; // Magic - if (stream.readUint32BE() != MKID_BE('PLUT')) + if (stream.readUint32BE() != MKTAG('P','L','U','T')) return false; if (stream.readUint32BE() != kVersion) diff --git a/graphics/fonts/winfont.cpp b/graphics/fonts/winfont.cpp index fb37c8ddef..12509fd9e1 100644 --- a/graphics/fonts/winfont.cpp +++ b/graphics/fonts/winfont.cpp @@ -23,8 +23,9 @@ */ #include "common/file.h" -#include "common/ne_exe.h" #include "common/str.h" +#include "common/winexe_ne.h" +#include "common/winexe_pe.h" #include "graphics/fonts/winfont.h" namespace Graphics { @@ -75,8 +76,15 @@ static WinFontDirEntry readDirEntry(Common::SeekableReadStream &stream) { } bool WinFont::loadFromFON(const Common::String &fileName, const WinFontDirEntry &dirEntry) { - // TODO: PE libraries (If it's used anywhere by a ScummVM game) + // First try loading via the NE code + if (loadFromNE(fileName, dirEntry)) + return true; + // Then try loading via the PE code + return loadFromPE(fileName, dirEntry); +} + +bool WinFont::loadFromNE(const Common::String &fileName, const WinFontDirEntry &dirEntry) { Common::NEResources exe; if (!exe.loadFromEXE(fileName)) @@ -89,44 +97,53 @@ bool WinFont::loadFromFON(const Common::String &fileName, const WinFontDirEntry return false; } - uint16 numFonts = fontDirectory->readUint16LE(); + uint32 fontId = getFontIndex(*fontDirectory, dirEntry); + + delete fontDirectory; - // Probably not possible, so this is really a sanity check - if (numFonts == 0) { - warning("No fonts in '%s'", fileName.c_str()); + // Couldn't match the face name + if (fontId == 0xffffffff) { + warning("Could not find face '%s' in '%s'", dirEntry.faceName.c_str(), fileName.c_str()); return false; } - // Scour the directory for our matching name - int fontId = -1; - for (uint16 i = 0; i < numFonts; i++) { - uint16 id = fontDirectory->readUint16LE(); + // Actually go get our font now... + Common::SeekableReadStream *fontStream = exe.getResource(Common::kNEFont, fontId); + if (!fontStream) { + warning("Could not find font %d in %s", fontId, fileName.c_str()); + return false; + } - if (dirEntry.faceName.empty()) { - // Use the first name when empty - fontId = id; - break; - } + bool ok = loadFromFNT(*fontStream); + delete fontStream; + return ok; +} - WinFontDirEntry entry = readDirEntry(*fontDirectory); +bool WinFont::loadFromPE(const Common::String &fileName, const WinFontDirEntry &dirEntry) { + Common::PEResources exe; - if (dirEntry.faceName.equalsIgnoreCase(entry.faceName) && dirEntry.points == entry.points) { - // Match! - fontId = id; - break; - } + if (!exe.loadFromEXE(fileName)) + return false; + + // Let's pull out the font directory + Common::SeekableReadStream *fontDirectory = exe.getResource(Common::kPEFontDir, Common::String("FONTDIR")); + if (!fontDirectory) { + warning("No font directory in '%s'", fileName.c_str()); + return false; } + uint32 fontId = getFontIndex(*fontDirectory, dirEntry); + delete fontDirectory; // Couldn't match the face name - if (fontId < 0) { + if (fontId == 0xffffffff) { warning("Could not find face '%s' in '%s'", dirEntry.faceName.c_str(), fileName.c_str()); return false; } // Actually go get our font now... - Common::SeekableReadStream *fontStream = exe.getResource(Common::kNEFont, fontId); + Common::SeekableReadStream *fontStream = exe.getResource(Common::kPEFont, fontId); if (!fontStream) { warning("Could not find font %d in %s", fontId, fileName.c_str()); return false; @@ -137,6 +154,32 @@ bool WinFont::loadFromFON(const Common::String &fileName, const WinFontDirEntry return ok; } +uint32 WinFont::getFontIndex(Common::SeekableReadStream &stream, const WinFontDirEntry &dirEntry) { + uint16 numFonts = stream.readUint16LE(); + + // Probably not possible, so this is really a sanity check + if (numFonts == 0) { + warning("No fonts in exe"); + return 0xffffffff; + } + + // Scour the directory for our matching name + for (uint16 i = 0; i < numFonts; i++) { + uint16 id = stream.readUint16LE(); + + // Use the first name when empty + if (dirEntry.faceName.empty()) + return id; + + WinFontDirEntry entry = readDirEntry(stream); + + if (dirEntry.faceName.equalsIgnoreCase(entry.faceName) && dirEntry.points == entry.points) // Match! + return id; + } + + return 0xffffffff; +} + bool WinFont::loadFromFNT(const Common::String &fileName) { Common::File file; diff --git a/graphics/fonts/winfont.h b/graphics/fonts/winfont.h index b23455e2d5..fbe4a778e2 100644 --- a/graphics/fonts/winfont.h +++ b/graphics/fonts/winfont.h @@ -69,6 +69,10 @@ public: void drawChar(Surface *dst, byte chr, int x, int y, uint32 color) const; private: + bool loadFromPE(const Common::String &fileName, const WinFontDirEntry &dirEntry); + bool loadFromNE(const Common::String &fileName, const WinFontDirEntry &dirEntry); + + uint32 getFontIndex(Common::SeekableReadStream &stream, const WinFontDirEntry &dirEntry); bool loadFromFNT(Common::SeekableReadStream &stream); char indexToCharacter(uint16 index) const; uint16 characterToIndex(byte character) const; diff --git a/graphics/jpeg.cpp b/graphics/jpeg.cpp index aa4b876680..169c3b5f1b 100644 --- a/graphics/jpeg.cpp +++ b/graphics/jpeg.cpp @@ -46,7 +46,7 @@ static const uint8 _zigZagOrder[64] = { }; // IDCT table built with : -// _idct8x8[x][y] = cos(((2 * x + 1) * y) * (PI / 16.0)) * 0.5; +// _idct8x8[x][y] = cos(((2 * x + 1) * y) * (M_PI / 16.0)) * 0.5; // _idct8x8[x][y] /= sqrt(2.0) if y == 0 static const double _idct8x8[8][8] = { { 0.353553390593274, 0.490392640201615, 0.461939766255643, 0.415734806151273, 0.353553390593274, 0.277785116509801, 0.191341716182545, 0.097545161008064 }, @@ -226,7 +226,7 @@ bool JPEG::read(Common::SeekableReadStream *stream) { bool JPEG::readJFIF() { uint16 length = _stream->readUint16BE(); uint32 tag = _stream->readUint32BE(); - if (tag != MKID_BE('JFIF')) { + if (tag != MKTAG('J','F','I','F')) { warning("JPEG::readJFIF() tag mismatch"); return false; } diff --git a/graphics/module.mk b/graphics/module.mk index c962f0617d..cb3a07e691 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -23,7 +23,8 @@ MODULE_OBJS := \ surface.o \ thumbnail.o \ VectorRenderer.o \ - VectorRendererSpec.o + VectorRendererSpec.o \ + wincursor.o ifdef USE_SCALERS MODULE_OBJS += \ diff --git a/graphics/palette.h b/graphics/palette.h index 72db16a3d3..8d7fdbd99a 100644 --- a/graphics/palette.h +++ b/graphics/palette.h @@ -46,14 +46,14 @@ public: * The palette entries from 'start' till (start+num-1) will be replaced - so * a full palette update is accomplished via start=0, num=256. * - * The palette data is specified in interleaved RGBA format. That is, the + * The palette data is specified in interleaved RGB format. That is, the * first byte of the memory block 'colors' points at is the red component * of the first new color; the second byte the green component of the first * new color; the third byte the blue component, the last byte to the alpha * (transparency) value. Then the second color starts, and so on. So memory - * looks like this: R1-G1-B1-A1-R2-G2-B2-A2-R3-... + * looks like this: R1-G1-B1-R2-G2-B2-R3-... * - * @param colors the new palette data, in interleaved RGBA format + * @param colors the new palette data, in interleaved RGB format * @param start the first palette entry to be updated * @param num the number of palette entries to be updated * @@ -62,8 +62,6 @@ public: * @note It is an error if this function gets called when the pixel format * in use (the return value of getScreenFormat) has more than one * byte per pixel. - * @note The alpha value is not actually used, and future revisions of this - * API are probably going to remove it. * * @see getScreenFormat */ @@ -79,19 +77,18 @@ public: * For example, for every valid value of start and num of the following * code: * - * byte origPal[num*4]; + * byte origPal[num*3]; * // Setup origPal's data however you like * g_system->setPalette(origPal, start, num); - * byte obtainedPal[num*4]; + * byte obtainedPal[num*3]; * g_system->grabPalette(obtainedPal, start, num); * * the following should be true: * - * For each i < num : memcmp(&origPal[i*4], &obtainedPal[i*4], 3) == 0 - * (i is an uint here) + * memcmp(origPal, obtainedPal, num*3) == 0 * * @see setPalette - * @param colors the palette data, in interleaved RGBA format + * @param colors the palette data, in interleaved RGB format * @param start the first platte entry to be read * @param num the number of palette entries to be read * diff --git a/graphics/pict.cpp b/graphics/pict.cpp index 95f659c19b..ca4aac751d 100644 --- a/graphics/pict.cpp +++ b/graphics/pict.cpp @@ -95,10 +95,10 @@ Surface *PictDecoder::decodeImage(Common::SeekableReadStream *stream, byte *pale } else if (opcode == 0x001E) { // DefHilite // Ignore, Contains no Data } else if (opcode == 0x0098) { // PackBitsRect - decodeDirectBitsRect(stream, _imageRect.width(), _imageRect.height(), true); + decodeDirectBitsRect(stream, true); _isPaletted = true; } else if (opcode == 0x009A) { // DirectBitsRect - decodeDirectBitsRect(stream, _imageRect.width(), _imageRect.height(), false); + decodeDirectBitsRect(stream, false); } else if (opcode == 0x00A1) { // LongComment stream->readUint16BE(); uint16 dataSize = stream->readUint16BE(); @@ -127,7 +127,7 @@ Surface *PictDecoder::decodeImage(Common::SeekableReadStream *stream, byte *pale // If we got a palette throughout this nonsense, go and grab it if (palette && _isPaletted) - memcpy(palette, _palette, 256 * 4); + memcpy(palette, _palette, 256 * 3); return _outputSurface; } @@ -162,7 +162,7 @@ struct DirectBitsRectData { uint16 mode; }; -void PictDecoder::decodeDirectBitsRect(Common::SeekableReadStream *stream, uint16 width, uint16 height, bool hasPalette) { +void PictDecoder::decodeDirectBitsRect(Common::SeekableReadStream *stream, bool hasPalette) { static const PixelFormat directBitsFormat16 = PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0); // Clear the palette @@ -180,9 +180,9 @@ void PictDecoder::decodeDirectBitsRect(Common::SeekableReadStream *stream, uint1 for (uint32 i = 0; i < colorCount; i++) { stream->readUint16BE(); - _palette[i * 4] = stream->readUint16BE() >> 8; - _palette[i * 4 + 1] = stream->readUint16BE() >> 8; - _palette[i * 4 + 2] = stream->readUint16BE() >> 8; + _palette[i * 3] = stream->readUint16BE() >> 8; + _palette[i * 3 + 1] = stream->readUint16BE() >> 8; + _palette[i * 3 + 2] = stream->readUint16BE() >> 8; } } @@ -196,6 +196,9 @@ void PictDecoder::decodeDirectBitsRect(Common::SeekableReadStream *stream, uint1 directBitsData.dstRect.right = stream->readUint16BE(); directBitsData.mode = stream->readUint16BE(); + uint16 width = directBitsData.srcRect.width(); + uint16 height = directBitsData.srcRect.height(); + byte bytesPerPixel = 0; if (directBitsData.pixMap.pixelSize <= 8) diff --git a/graphics/pict.h b/graphics/pict.h index a9ea170292..a683a23bf6 100644 --- a/graphics/pict.h +++ b/graphics/pict.h @@ -70,11 +70,11 @@ private: Common::Rect _imageRect; PixelFormat _pixelFormat; JPEG *_jpeg; - byte _palette[256 * 4]; + byte _palette[256 * 3]; bool _isPaletted; Graphics::Surface *_outputSurface; - void decodeDirectBitsRect(Common::SeekableReadStream *stream, uint16 width, uint16 height, bool hasPalette); + void decodeDirectBitsRect(Common::SeekableReadStream *stream, bool hasPalette); void decodeDirectBitsLine(byte *out, uint32 length, Common::SeekableReadStream *data, byte bitsPerPixel, byte bytesPerPixel); void decodeCompressedQuickTime(Common::SeekableReadStream *stream); void outputPixelBuffer(byte *&out, byte value, byte bitsPerPixel); diff --git a/graphics/png.cpp b/graphics/png.cpp index 5292ea0100..eb066efa57 100644 --- a/graphics/png.cpp +++ b/graphics/png.cpp @@ -67,12 +67,12 @@ namespace Graphics { enum PNGChunks { // == Critical chunks ===================================================== - kChunkIHDR = MKID_BE('IHDR'), // Image header - kChunkIDAT = MKID_BE('IDAT'), // Image data - kChunkPLTE = MKID_BE('PLTE'), // Palette - kChunkIEND = MKID_BE('IEND'), // Image trailer + kChunkIHDR = MKTAG('I','H','D','R'), // Image header + kChunkIDAT = MKTAG('I','D','A','T'), // Image data + kChunkPLTE = MKTAG('P','L','T','E'), // Palette + kChunkIEND = MKTAG('I','E','N','D'), // Image trailer // == Ancillary chunks ==================================================== - kChunktRNS = MKID_BE('tRNS') // Transparency + kChunktRNS = MKTAG('t','R','N','S') // Transparency // All of the other ancillary chunks are ignored. They're added here for // reference only. // cHRM - Primary chromacities and white point diff --git a/graphics/png.h b/graphics/png.h index b2ba7ac0f2..70f2e4ba27 100644 --- a/graphics/png.h +++ b/graphics/png.h @@ -117,9 +117,11 @@ public: } /** - * Returns the palette of the specified PNG8 image + * Returns the palette of the specified PNG8 image. + * + * Note that the palette's format is RGBA. */ - void getPalette(byte *palette, byte &entries) { + void getPalette(byte *palette, uint16 &entries) { if (_header.colorType != kIndexed) error("Palette requested for a non-indexed PNG"); palette = _palette; diff --git a/graphics/scaler/2xsai.cpp b/graphics/scaler/2xsai.cpp index 936ed19124..43a5b2fd1d 100644 --- a/graphics/scaler/2xsai.cpp +++ b/graphics/scaler/2xsai.cpp @@ -287,7 +287,7 @@ void _2xSaITemplate(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 register unsigned colorA, colorB; unsigned colorC, colorD, - colorE, colorF, colorG, colorH, colorI, colorJ, colorK, colorL, colorM, colorN, colorO, colorP; + colorE, colorF, colorG, colorH, colorI, colorJ, colorK, colorL, colorM, colorN, colorO; unsigned product, product1, product2; //--------------------------------------- @@ -313,7 +313,6 @@ void _2xSaITemplate(const uint8 *srcPtr, uint32 srcPitch, uint8 *dstPtr, uint32 colorM = *(bP + 2 * nextlineSrc - 1); colorN = *(bP + 2 * nextlineSrc); colorO = *(bP + 2 * nextlineSrc + 1); - colorP = *(bP + 2 * nextlineSrc + 2); if ((colorA == colorD) && (colorB != colorC)) { if (((colorA == colorE) && (colorB == colorL)) || diff --git a/graphics/scaler/thumbnail_intern.cpp b/graphics/scaler/thumbnail_intern.cpp index bd325aca63..5cee1c7a72 100644 --- a/graphics/scaler/thumbnail_intern.cpp +++ b/graphics/scaler/thumbnail_intern.cpp @@ -108,7 +108,7 @@ static bool grabScreen565(Graphics::Surface *surf) { byte *palette = 0; if (screenFormat.bytesPerPixel == 1) { - palette = new byte[256 * 4]; + palette = new byte[256 * 3]; assert(palette); g_system->getPaletteManager()->grabPalette(palette, 0, 256); } @@ -118,9 +118,9 @@ static bool grabScreen565(Graphics::Surface *surf) { byte r = 0, g = 0, b = 0; if (screenFormat.bytesPerPixel == 1) { - r = palette[((uint8*)screen->pixels)[y * screen->pitch + x] * 4]; - g = palette[((uint8*)screen->pixels)[y * screen->pitch + x] * 4 + 1]; - b = palette[((uint8*)screen->pixels)[y * screen->pitch + x] * 4 + 2]; + r = palette[((uint8*)screen->pixels)[y * screen->pitch + x] * 3]; + g = palette[((uint8*)screen->pixels)[y * screen->pitch + x] * 3 + 1]; + b = palette[((uint8*)screen->pixels)[y * screen->pitch + x] * 3 + 2]; } else if (screenFormat.bytesPerPixel == 2) { uint16 col = READ_UINT16(screen->getBasePtr(x, y)); screenFormat.colorToRGB(col, r, g, b); diff --git a/graphics/sjis.cpp b/graphics/sjis.cpp index bb9f33aa26..c581f9b265 100644 --- a/graphics/sjis.cpp +++ b/graphics/sjis.cpp @@ -362,7 +362,7 @@ bool FontSjisSVM::loadData() { uint32 magic1 = data->readUint32BE(); uint32 magic2 = data->readUint32BE(); - if (magic1 != MKID_BE('SCVM') || magic2 != MKID_BE('SJIS')) { + if (magic1 != MKTAG('S','C','V','M') || magic2 != MKTAG('S','J','I','S')) { delete data; return false; } diff --git a/graphics/thumbnail.cpp b/graphics/thumbnail.cpp index b245cfc5fa..8688096c3d 100644 --- a/graphics/thumbnail.cpp +++ b/graphics/thumbnail.cpp @@ -49,7 +49,7 @@ bool loadHeader(Common::SeekableReadStream &in, ThumbnailHeader &header, bool ou // We also accept the bad 'BMHT' header here, for the sake of compatibility // with some older savegames which were written incorrectly due to a bug in // ScummVM which wrote the thumb header type incorrectly on LE systems. - if (header.type != MKID_BE('THMB') && header.type != MKID_BE('BMHT')) { + if (header.type != MKTAG('T','H','M','B') && header.type != MKTAG('B','M','H','T')) { if (outputWarnings) warning("couldn't find thumbnail header type"); return false; @@ -145,7 +145,7 @@ bool saveThumbnail(Common::WriteStream &out, const Graphics::Surface &thumb) { } ThumbnailHeader header; - header.type = MKID_BE('THMB'); + header.type = MKTAG('T','H','M','B'); header.size = ThumbnailHeaderSize + thumb.w*thumb.h*thumb.bytesPerPixel; header.version = THMB_VERSION; header.width = thumb.w; diff --git a/graphics/wincursor.cpp b/graphics/wincursor.cpp new file mode 100644 index 0000000000..10939a677a --- /dev/null +++ b/graphics/wincursor.cpp @@ -0,0 +1,317 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "common/debug.h" +#include "common/file.h" +#include "common/memstream.h" +#include "common/ptr.h" +#include "common/str.h" +#include "common/stream.h" +#include "common/winexe_ne.h" +#include "common/winexe_pe.h" + +#include "graphics/wincursor.h" + +namespace Graphics { + +WinCursor::WinCursor() { + _width = 0; + _height = 0; + _hotspotX = 0; + _hotspotY = 0; + _surface = 0; + _keyColor = 0; + memset(_palette, 0, 256 * 3); +} + +WinCursor::~WinCursor() { + clear(); +} + +uint16 WinCursor::getWidth() const { + return _width; +} + +uint16 WinCursor::getHeight() const { + return _height; +} + +uint16 WinCursor::getHotspotX() const { + return _hotspotX; +} + +uint16 WinCursor::getHotspotY() const { + return _hotspotY; +} + +byte WinCursor::getKeyColor() const { + return _keyColor; +} + +bool WinCursor::readFromStream(Common::SeekableReadStream &stream) { + clear(); + + _hotspotX = stream.readUint16LE(); + _hotspotY = stream.readUint16LE(); + + // Check header size + if (stream.readUint32LE() != 40) + return false; + + // Check dimensions + _width = stream.readUint32LE(); + _height = stream.readUint32LE() / 2; + + if (_width & 3) { + // Cursors should always be a power of 2 + // Of course, it wouldn't be hard to handle but if we have no examples... + warning("Non-divisible-by-4 width cursor found"); + return false; + } + + // Color planes + if (stream.readUint16LE() != 1) + return false; + + // Only 1bpp and 8bpp supported + uint16 bitsPerPixel = stream.readUint16LE(); + if (bitsPerPixel != 1 && bitsPerPixel != 8) + return false; + + // Compression + if (stream.readUint32LE() != 0) + return false; + + // Image size + X resolution + Y resolution + stream.skip(12); + + uint32 numColors = stream.readUint32LE(); + + // If the color count is 0, then it uses up the maximum amount + if (numColors == 0) + numColors = 1 << bitsPerPixel; + + // Reading the palette + stream.seek(40 + 4); + for (uint32 i = 0 ; i < numColors; i++) { + _palette[i * 3 + 2] = stream.readByte(); + _palette[i * 3 + 1] = stream.readByte(); + _palette[i * 3 ] = stream.readByte(); + stream.readByte(); + } + + // Reading the bitmap data + uint32 dataSize = stream.size() - stream.pos(); + byte *initialSource = new byte[dataSize]; + stream.read(initialSource, dataSize); + + // Parse the XOR map + const byte *src = initialSource; + _surface = new byte[_width * _height]; + byte *dest = _surface + _width * (_height - 1); + uint32 imagePitch = _width * bitsPerPixel / 8; + + for (uint32 i = 0; i < _height; i++) { + byte *rowDest = dest; + + if (bitsPerPixel == 1) { + // 1bpp + for (uint16 j = 0; j < (_width / 8); j++) { + byte p = src[j]; + + for (int k = 0; k < 8; k++, rowDest++, p <<= 1) { + if ((p & 0x80) == 0x80) + *rowDest = 1; + else + *rowDest = 0; + } + } + } else { + // 8bpp + memcpy(rowDest, src, _width); + } + + dest -= _width; + src += imagePitch; + } + + // Calculate our key color + if (numColors < 256) { + // If we're not using the maximum colors in a byte, we can fit it in + _keyColor = numColors; + } else { + // HACK: Try to find a color that's not being used so it can become + // our keycolor. It's quite impossible to fit 257 entries into 256... + for (uint32 i = 0; i < 256; i++) { + for (int j = 0; j < _width * _height; j++) { + // TODO: Also check to see if the space is transparent + + if (_surface[j] == i) + break; + + if (j == _width * _height - 1) { + _keyColor = i; + i = 256; + break; + } + } + } + } + + // Now go through and apply the AND map to get the transparency + uint32 andWidth = (_width + 7) / 8; + src += andWidth * (_height - 1); + + for (uint32 y = 0; y < _height; y++) { + for (uint32 x = 0; x < _width; x++) + if (src[x / 8] & (1 << (7 - x % 8))) + _surface[y * _width + x] = _keyColor; + + src -= andWidth; + } + + delete[] initialSource; + return true; +} + +void WinCursor::clear() { + delete[] _surface; _surface = 0; +} + +WinCursorGroup::WinCursorGroup() { +} + +WinCursorGroup::~WinCursorGroup() { + for (uint32 i = 0; i < cursors.size(); i++) + delete cursors[i].cursor; +} + +WinCursorGroup *WinCursorGroup::createCursorGroup(Common::NEResources &exe, const Common::WinResourceID &id) { + Common::ScopedPtr<Common::SeekableReadStream> stream(exe.getResource(Common::kNEGroupCursor, id)); + + if (!stream || stream->size() <= 6) + return 0; + + stream->skip(4); + uint32 cursorCount = stream->readUint16LE(); + if ((uint32)stream->size() < (6 + cursorCount * 16)) + return 0; + + WinCursorGroup *group = new WinCursorGroup(); + group->cursors.reserve(cursorCount); + + for (uint32 i = 0; i < cursorCount; i++) { + stream->readUint16LE(); // width + stream->readUint16LE(); // height + + // Plane count + if (stream->readUint16LE() != 1) { + delete group; + return 0; + } + + // Bits per pixel + // NE cursors can only be 1bpp + if (stream->readUint16LE() != 1) { + delete group; + return 0; + } + + stream->readUint32LE(); // data size + uint32 cursorId = stream->readUint32LE(); + + Common::ScopedPtr<Common::SeekableReadStream> cursorStream(exe.getResource(Common::kNECursor, cursorId)); + if (!cursorStream) { + delete group; + return 0; + } + + WinCursor *cursor = new WinCursor(); + if (!cursor->readFromStream(*cursorStream)) { + delete cursor; + delete group; + return 0; + } + + CursorItem item; + item.id = cursorId; + item.cursor = cursor; + group->cursors.push_back(item); + } + + return group; +} + +WinCursorGroup *WinCursorGroup::createCursorGroup(Common::PEResources &exe, const Common::WinResourceID &id) { + Common::ScopedPtr<Common::SeekableReadStream> stream(exe.getResource(Common::kPEGroupCursor, id)); + + if (!stream || stream->size() <= 6) + return 0; + + stream->skip(4); + uint32 cursorCount = stream->readUint16LE(); + if ((uint32)stream->size() < (6 + cursorCount * 14)) + return 0; + + WinCursorGroup *group = new WinCursorGroup(); + group->cursors.reserve(cursorCount); + + for (uint32 i = 0; i < cursorCount; i++) { + stream->readUint16LE(); // width + stream->readUint16LE(); // height + + // Plane count + if (stream->readUint16LE() != 1) { + delete group; + return 0; + } + + stream->readUint16LE(); // bits per pixel + stream->readUint32LE(); // data size + uint32 cursorId = stream->readUint16LE(); + + Common::ScopedPtr<Common::SeekableReadStream> cursorStream(exe.getResource(Common::kPECursor, cursorId)); + if (!cursorStream) { + delete group; + return 0; + } + + WinCursor *cursor = new WinCursor(); + if (!cursor->readFromStream(*cursorStream)) { + delete cursor; + delete group; + return 0; + } + + CursorItem item; + item.id = cursorId; + item.cursor = cursor; + group->cursors.push_back(item); + } + + return group; +} + +} // End of namespace Graphics diff --git a/graphics/wincursor.h b/graphics/wincursor.h new file mode 100644 index 0000000000..ca0abf6fe1 --- /dev/null +++ b/graphics/wincursor.h @@ -0,0 +1,105 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GRAPHICS_WINCURSOR_H +#define GRAPHICS_WINCURSOR_H + +#include "common/array.h" +#include "common/winexe.h" + +namespace Common { + class NEResources; + class PEResources; + class SeekableReadStream; +} + +namespace Graphics { + +/** A Windows cursor. */ +class WinCursor { +public: + WinCursor(); + ~WinCursor(); + + /** Return the cursor's width. */ + uint16 getWidth() const; + /** Return the cursor's height. */ + uint16 getHeight() const; + /** Return the cursor's hotspot's x coordinate. */ + uint16 getHotspotX() const; + /** Return the cursor's hotspot's y coordinate. */ + uint16 getHotspotY() const; + /** Return the cursor's transparent key. */ + byte getKeyColor() const; + + const byte *getSurface() const { return _surface; } + const byte *getPalette() const { return _palette; } + + /** Read the cursor's data out of a stream. */ + bool readFromStream(Common::SeekableReadStream &stream); + +private: + byte *_surface; + byte _palette[256 * 3]; + + uint16 _width; ///< The cursor's width. + uint16 _height; ///< The cursor's height. + uint16 _hotspotX; ///< The cursor's hotspot's x coordinate. + uint16 _hotspotY; ///< The cursor's hotspot's y coordinate. + byte _keyColor; ///< The cursor's transparent key + + /** Clear the cursor. */ + void clear(); +}; + +/** + * A structure holding an array of cursors from a single Windows Executable cursor group. + * + * Windows lumps different versions of the same cursors/icons together and decides which one + * to use based on the screen's color depth and resolution. For instance, one cursor group + * could hold a 1bpp 16x16 cursorand a 8bpp 16x16 cursor. This will hold all cursors in the + * group. This class should be used to actually parse the cursors, whereas WinCursor is just + * the representation used by this struct to store the cursors. + */ +struct WinCursorGroup { + WinCursorGroup(); + ~WinCursorGroup(); + + struct CursorItem { + Common::WinResourceID id; + WinCursor *cursor; + }; + + Common::Array<CursorItem> cursors; + + /** Create a cursor group from an NE EXE, returns 0 on failure */ + static WinCursorGroup *createCursorGroup(Common::NEResources &exe, const Common::WinResourceID &id); + /** Create a cursor group from an PE EXE, returns 0 on failure */ + static WinCursorGroup *createCursorGroup(Common::PEResources &exe, const Common::WinResourceID &id); +}; + +} // End of namespace Graphics + +#endif |