https://github.com/scummvm/scummvm
Tip revision: 72148570de56e5c42e2fe8091e9b466610e49785 authored by Willem Jan Palenstijn on 05 June 2011, 09:00:00 UTC
DREAMWEB: Add original Dreamweb assembly sources
DREAMWEB: Add original Dreamweb assembly sources
Tip revision: 7214857
wincursor.cpp
/* 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/ptr.h"
#include "common/stream.h"
#include "common/textconsole.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