GRAPHICS: Split the NE cursor code from the NEResources class

Now the code lies in Graphics and all cursors are not cached upon opening an exe. The engine is now in charge of caching which cursors it wants.
This commit is contained in:
Matthew Hoops 2011-03-04 23:17:57 -05:00
parent 550cff84f8
commit c66233f83e
6 changed files with 339 additions and 346 deletions

View File

@ -32,153 +32,6 @@
namespace Common {
NECursor::NECursor() {
_width = 0;
_height = 0;
_hotspotX = 0;
_hotspotY = 0;
_surface = 0;
_keyColor = 0;
memset(_palette, 0, 256 * 3);
}
NECursor::~NECursor() {
clear();
}
uint16 NECursor::getWidth() const {
return _width;
}
uint16 NECursor::getHeight() const {
return _height;
}
uint16 NECursor::getHotspotX() const {
return _hotspotX;
}
uint16 NECursor::getHotspotY() const {
return _hotspotY;
}
byte NECursor::getKeyColor() const {
return _keyColor;
}
void NECursor::setDimensions(uint16 width, uint16 height) {
_width = width;
_height = height;
}
void NECursor::setHotspot(uint16 x, uint16 y) {
_hotspotX = x;
_hotspotY = y;
}
bool NECursor::readCursor(SeekableReadStream &stream, uint32 count) {
clear();
SeekableReadStream *bitmap = stream.readStream(count);
_surface = new byte[_width * _height];
uint32 width = _width;
uint32 height = _height * 2;
// Sanity checks
assert((width > 0) && (height > 0));
// Check header size
if (bitmap->readUint32LE() != 40)
return false;
// Check dimensions
if (bitmap->readUint32LE() != width)
return false;
if (bitmap->readUint32LE() != height)
return false;
// Color planes
if (bitmap->readUint16LE() != 1)
return false;
// Bits per pixel
if (bitmap->readUint16LE() != 1)
return false;
// Compression
if (bitmap->readUint32LE() != 0)
return false;
// Image size + X resolution + Y resolution
bitmap->skip(12);
uint32 numColors = bitmap->readUint32LE();
if (numColors == 0)
numColors = 2;
else if (numColors > 2)
return false;
// Assert that enough data is there for the whole cursor
if ((uint32)bitmap->size() < 40 + numColors * 4 + width * height / 8)
return false;
// Height includes AND-mask and XOR-mask
height /= 2;
// Standard palette: transparent, black, white
_palette[6] = 0xff;
_palette[7] = 0xff;
_palette[8] = 0xff;
// Reading the palette
bitmap->seek(40);
for (uint32 i = 0 ; i < numColors; i++) {
_palette[(i + 1) * 3 + 2] = bitmap->readByte();
_palette[(i + 1) * 3 + 1] = bitmap->readByte();
_palette[(i + 1) * 3 + 0] = bitmap->readByte();
bitmap->readByte();
}
// Reading the bitmap data
uint32 dataSize = bitmap->size() - 40 - numColors * 4;
byte *initialSource = new byte[dataSize];
bitmap->read(initialSource, dataSize);
const byte *srcP = initialSource;
const byte *srcM = srcP + ((width * height) / 8);
byte *dest = _surface + width * (height - 1);
for (uint32 i = 0; i < height; i++) {
byte *rowDest = dest;
for (uint32 j = 0; j < (width / 8); j++) {
byte p = srcP[j];
byte m = srcM[j];
for (int k = 0; k < 8; k++, rowDest++, p <<= 1, m <<= 1) {
if ((m & 0x80) != 0x80) {
if ((p & 0x80) == 0x80)
*rowDest = 2;
else
*rowDest = 1;
} else
*rowDest = _keyColor;
}
}
dest -= width;
srcP += width / 8;
srcM += width / 8;
}
delete bitmap;
delete[] initialSource;
return true;
}
void NECursor::clear() {
delete[] _surface; _surface = 0;
}
NEResources::NEResources() {
_exe = 0;
}
@ -194,16 +47,6 @@ void NEResources::clear() {
}
_resources.clear();
for (uint32 i = 0; i < _cursors.size(); i++)
for (uint32 j = 0; j < _cursors[i].cursors.size(); j++)
delete _cursors[i].cursors[j];
_cursors.clear();
}
const Array<NECursorGroup> &NEResources::getCursors() const {
return _cursors;
}
bool NEResources::loadFromEXE(const String &fileName) {
@ -237,9 +80,6 @@ bool NEResources::loadFromEXE(SeekableReadStream *stream) {
if (!readResourceTable(offsetResourceTable))
return false;
if (!readCursors())
return false;
return true;
}
@ -444,121 +284,4 @@ const Array<WinResourceID> NEResources::getIDList(uint16 type) const {
return idArray;
}
bool NEResources::readCursors() {
uint32 cursorCount = 0;
for (List<Resource>::const_iterator it = _resources.begin(); it != _resources.end(); ++it)
if (it->type == kNEGroupCursor)
cursorCount++;
if (cursorCount == 0) {
_cursors.clear();
return true;
}
_cursors.resize(cursorCount);
Array<NECursorGroup>::iterator cursorGroup = _cursors.begin();
for (List<Resource>::const_iterator it = _resources.begin(); it != _resources.end(); ++it) {
if (it->type == kNEGroupCursor) {
if (!readCursorGroup(*cursorGroup, *it))
return false;
++cursorGroup;
}
}
return true;
}
bool NEResources::readCursorGroup(NECursorGroup &group, const Resource &resource) {
if (!_exe)
return false;
if (resource.size <= 6)
return false;
if (!_exe->seek(resource.offset))
return false;
byte *data = new byte[resource.size];
if (!_exe->read(data, resource.size)) {
delete[] data;
return false;
}
uint32 cursorCount = READ_LE_UINT16(data + 4);
if (resource.size < (6 + cursorCount * 16)) {
delete[] data;
return false;
}
group.cursors.resize(cursorCount);
uint32 offset = 6;
for (uint32 i = 0; i < cursorCount; i++) {
group.cursors[i] = new NECursor();
NECursor *cursor = group.cursors[i];
// Plane count
if (READ_LE_UINT16(data + offset + 4) != 1) {
delete[] data;
return false;
}
// Bit count
if (READ_LE_UINT16(data + offset + 6) != 1) {
delete[] data;
return false;
}
uint32 id = READ_LE_UINT32(data + offset + 12);
const Resource *cursorResource = findResource(kNECursor, id);
if (!cursorResource) {
delete[] data;
return false;
}
cursor->setDimensions(READ_LE_UINT16(data + offset), READ_LE_UINT16(data + offset + 2) / 2);
uint32 dataSize = READ_LE_UINT32(data + offset + 8);
if (!readCursor(*cursor, *cursorResource, dataSize)) {
delete[] data;
return false;
}
offset += 16;
}
group.id = resource.id;
delete[] data;
return true;
}
bool NEResources::readCursor(NECursor &cursor, const Resource &resource, uint32 size) {
if (!_exe)
return false;
if (size <= 4)
return false;
if (resource.size < size)
return false;
if (!_exe->seek(resource.offset))
return false;
uint32 hotspotX = _exe->readUint16LE();
uint32 hotspotY = _exe->readUint16LE();
cursor.setHotspot(hotspotX, hotspotY);
size -= 4;
if (!cursor.readCursor(*_exe, size))
return false;
return true;
}
} // End of namespace Common

View File

@ -36,54 +36,6 @@ class MemoryReadStream;
class SeekableReadStream;
class String;
/** A New Executable cursor. */
class NECursor {
public:
NECursor();
~NECursor();
/** 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; }
/** Set the cursor's dimensions. */
void setDimensions(uint16 width, uint16 height);
/** Set the cursor's hotspot. */
void setHotspot(uint16 x, uint16 y);
/** Read the cursor's data out of a stream. */
bool readCursor(SeekableReadStream &stream, uint32 count);
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 New Executable cursor group. */
struct NECursorGroup {
WinResourceID id;
Array<NECursor *> cursors; ///< The cursors.
};
/** The default Windows resources. */
enum NEResourceType {
kNECursor = 0x8001,
@ -132,9 +84,6 @@ public:
/** Load from a stream. */
bool loadFromEXE(SeekableReadStream *stream);
/** Get all cursor's read from the New Executable. */
const Array<NECursorGroup> &getCursors() const;
/** Return a list of resources for a given type. */
const Array<WinResourceID> getIDList(uint16 type) const;
@ -161,19 +110,11 @@ private:
/** All resources. */
List<Resource> _resources;
/** All cursor resources. */
Array<NECursorGroup> _cursors;
/** Read the offset to the resource table. */
uint32 getResourceTableOffset();
/** Read the resource table. */
bool readResourceTable(uint32 offset);
// Cursor reading helpers
bool readCursors();
bool readCursorGroup(NECursorGroup &group, const Resource &resource);
bool readCursor(NECursor &cursor, const Resource &resource, uint32 size);
/** Find a specific resource. */
const Resource *findResource(uint16 type, WinResourceID id) const;

View File

@ -34,6 +34,7 @@
#include "common/system.h"
#include "common/winexe_ne.h"
#include "graphics/cursorman.h"
#include "graphics/wincursor.h"
namespace Mohawk {
@ -295,16 +296,14 @@ NECursorManager::~NECursorManager() {
}
void NECursorManager::setCursor(uint16 id) {
if (!_exe) {
Common::Array<Common::NECursorGroup> cursors = _exe->getCursors();
if (_exe) {
Graphics::WinCursorGroup *cursorGroup = Graphics::WinCursorGroup::createCursorGroup(*_exe, id);
for (uint32 i = 0; i < cursors.size(); i++) {
if (cursors[i].id == id) {
Common::NECursor *cursor = cursors[i].cursors[0];
CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(), cursor->getHotspotY(), cursor->getKeyColor());
CursorMan.replaceCursorPalette(cursor->getPalette(), 0, 256);
return;
}
if (cursorGroup) {
Graphics::WinCursor *cursor = cursorGroup->cursors[0].cursor;
CursorMan.replaceCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(), cursor->getHotspotX(), cursor->getHotspotY(), cursor->getKeyColor());
CursorMan.replaceCursorPalette(cursor->getPalette(), 0, 256);
return;
}
}

View File

@ -23,7 +23,8 @@ MODULE_OBJS := \
surface.o \
thumbnail.o \
VectorRenderer.o \
VectorRendererSpec.o
VectorRendererSpec.o \
wincursor.o
ifdef USE_SCALERS
MODULE_OBJS += \

235
graphics/wincursor.cpp Normal file
View File

@ -0,0 +1,235 @@
/* 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/str.h"
#include "common/stream.h"
#include "common/winexe_ne.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;
// Color planes
if (stream.readUint16LE() != 1)
return false;
// Bits per pixel
if (stream.readUint16LE() != 1)
return false;
// Compression
if (stream.readUint32LE() != 0)
return false;
// Image size + X resolution + Y resolution
stream.skip(12);
uint32 numColors = stream.readUint32LE();
if (numColors == 0)
numColors = 2;
else if (numColors > 2)
return false;
// Sanity check: ensure that enough data is there for the whole cursor
if ((uint32)(stream.size() - stream.pos()) < 40 + numColors * 4 + _width * _height * 2 / 8)
return false;
// Standard palette: transparent, black, white
_palette[6] = 0xff;
_palette[7] = 0xff;
_palette[8] = 0xff;
// Reading the palette
stream.seek(40 + 4);
for (uint32 i = 0 ; i < numColors; i++) {
_palette[(i + 1) * 3 + 2] = stream.readByte();
_palette[(i + 1) * 3 + 1] = stream.readByte();
_palette[(i + 1) * 3 + 0] = stream.readByte();
stream.readByte();
}
// Reading the bitmap data
uint32 dataSize = stream.size() - stream.pos();
byte *initialSource = new byte[dataSize];
stream.read(initialSource, dataSize);
const byte *srcP = initialSource;
const byte *srcM = srcP + ((_width * _height) / 8);
_surface = new byte[_width * _height];
byte *dest = _surface + _width * (_height - 1);
for (uint32 i = 0; i < _height; i++) {
byte *rowDest = dest;
for (uint32 j = 0; j < (_width / 8); j++) {
byte p = srcP[j];
byte m = srcM[j];
for (int k = 0; k < 8; k++, rowDest++, p <<= 1, m <<= 1) {
if ((m & 0x80) != 0x80) {
if ((p & 0x80) == 0x80)
*rowDest = 2;
else
*rowDest = 1;
} else
*rowDest = _keyColor;
}
}
dest -= _width;
srcP += _width / 8;
srcM += _width / 8;
}
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::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 stream;
delete group;
return 0;
}
// Bit count
if (stream->readUint16LE() != 1) {
delete stream;
delete group;
return 0;
}
stream->readUint32LE(); // data size
uint32 cursorId = stream->readUint32LE();
Common::SeekableReadStream *cursorStream = exe.getResource(Common::kNECursor, cursorId);
if (!cursorStream) {
delete stream;
delete group;
return 0;
}
WinCursor *cursor = new WinCursor();
if (!cursor->readFromStream(*cursorStream)) {
delete stream;
delete cursorStream;
delete cursor;
delete group;
return 0;
}
delete cursorStream;
CursorItem item;
item.id = cursorId;
item.cursor = cursor;
group->cursors.push_back(item);
}
delete stream;
return group;
}
} // End of namespace Graphics

94
graphics/wincursor.h Normal file
View File

@ -0,0 +1,94 @@
/* 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();
};
struct WinCursorGroup {
WinCursorGroup();
~WinCursorGroup();
struct CursorItem {
Common::WinResourceID id;
WinCursor *cursor;
};
Common::Array<CursorItem> cursors;
static WinCursorGroup *createCursorGroup(Common::NEResources &exe, const Common::WinResourceID &id);
//static WinCursorGroup *createCursorGroup(Common::PEResources &exe, const Common::WinResourceID &id);
};
} // End of namespace Graphics
#endif