scummvm/graphics/wincursor.cpp

300 lines
6.6 KiB
C++
Raw Normal View History

/* 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 "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;
// 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;
}
WinCursorGroup *WinCursorGroup::createCursorGroup(Common::PEResources &exe, const Common::WinResourceID &id) {
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 * 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::kPECursor, 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