aboutsummaryrefslogtreecommitdiff
path: root/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'graphics')
-rw-r--r--graphics/cursorman.cpp6
-rw-r--r--graphics/cursorman.h2
-rw-r--r--graphics/dither.cpp4
-rw-r--r--graphics/fonts/winfont.cpp89
-rw-r--r--graphics/fonts/winfont.h4
-rw-r--r--graphics/jpeg.cpp4
-rw-r--r--graphics/module.mk3
-rw-r--r--graphics/palette.h17
-rw-r--r--graphics/pict.cpp17
-rw-r--r--graphics/pict.h4
-rw-r--r--graphics/png.cpp10
-rw-r--r--graphics/png.h6
-rw-r--r--graphics/scaler/2xsai.cpp3
-rw-r--r--graphics/scaler/thumbnail_intern.cpp8
-rw-r--r--graphics/sjis.cpp2
-rw-r--r--graphics/thumbnail.cpp4
-rw-r--r--graphics/wincursor.cpp317
-rw-r--r--graphics/wincursor.h105
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