00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "common/ptr.h"
00024 #include "common/stream.h"
00025 #include "common/textconsole.h"
00026 #include "common/winexe_ne.h"
00027 #include "common/winexe_pe.h"
00028
00029 #include "graphics/wincursor.h"
00030
00031 namespace Graphics {
00032
00034 class WinCursor : public Cursor {
00035 public:
00036 WinCursor();
00037 ~WinCursor();
00038
00040 uint16 getWidth() const;
00042 uint16 getHeight() const;
00044 uint16 getHotspotX() const;
00046 uint16 getHotspotY() const;
00048 byte getKeyColor() const;
00049
00050 const byte *getSurface() const { return _surface; }
00051
00052 const byte *getPalette() const { return _palette; }
00053 byte getPaletteStartIndex() const { return 0; }
00054 uint16 getPaletteCount() const { return 256; }
00055
00057 bool readFromStream(Common::SeekableReadStream &stream);
00058
00059 private:
00060 byte *_surface;
00061 byte _palette[256 * 3];
00062
00063 uint16 _width;
00064 uint16 _height;
00065 uint16 _hotspotX;
00066 uint16 _hotspotY;
00067 byte _keyColor;
00068
00070 void clear();
00071 };
00072
00073 WinCursor::WinCursor() {
00074 _width = 0;
00075 _height = 0;
00076 _hotspotX = 0;
00077 _hotspotY = 0;
00078 _surface = 0;
00079 _keyColor = 0;
00080 memset(_palette, 0, 256 * 3);
00081 }
00082
00083 WinCursor::~WinCursor() {
00084 clear();
00085 }
00086
00087 uint16 WinCursor::getWidth() const {
00088 return _width;
00089 }
00090
00091 uint16 WinCursor::getHeight() const {
00092 return _height;
00093 }
00094
00095 uint16 WinCursor::getHotspotX() const {
00096 return _hotspotX;
00097 }
00098
00099 uint16 WinCursor::getHotspotY() const {
00100 return _hotspotY;
00101 }
00102
00103 byte WinCursor::getKeyColor() const {
00104 return _keyColor;
00105 }
00106
00107 bool WinCursor::readFromStream(Common::SeekableReadStream &stream) {
00108 clear();
00109
00110 _hotspotX = stream.readUint16LE();
00111 _hotspotY = stream.readUint16LE();
00112
00113
00114 if (stream.readUint32LE() != 40)
00115 return false;
00116
00117
00118 _width = stream.readUint32LE();
00119 _height = stream.readUint32LE() / 2;
00120
00121 if (_width & 3) {
00122
00123
00124 warning("Non-divisible-by-4 width cursor found");
00125 return false;
00126 }
00127
00128
00129 if (stream.readUint16LE() != 1)
00130 return false;
00131
00132
00133 uint16 bitsPerPixel = stream.readUint16LE();
00134 if (bitsPerPixel != 1 && bitsPerPixel != 8)
00135 return false;
00136
00137
00138 if (stream.readUint32LE() != 0)
00139 return false;
00140
00141
00142 stream.skip(12);
00143
00144 uint32 numColors = stream.readUint32LE();
00145
00146
00147 if (numColors == 0)
00148 numColors = 1 << bitsPerPixel;
00149
00150
00151 stream.seek(40 + 4);
00152 for (uint32 i = 0 ; i < numColors; i++) {
00153 _palette[i * 3 + 2] = stream.readByte();
00154 _palette[i * 3 + 1] = stream.readByte();
00155 _palette[i * 3 ] = stream.readByte();
00156 stream.readByte();
00157 }
00158
00159
00160 uint32 dataSize = stream.size() - stream.pos();
00161 byte *initialSource = new byte[dataSize];
00162 stream.read(initialSource, dataSize);
00163
00164
00165 const byte *src = initialSource;
00166 _surface = new byte[_width * _height];
00167 byte *dest = _surface + _width * (_height - 1);
00168 uint32 imagePitch = _width * bitsPerPixel / 8;
00169
00170 for (uint32 i = 0; i < _height; i++) {
00171 byte *rowDest = dest;
00172
00173 if (bitsPerPixel == 1) {
00174
00175 for (uint16 j = 0; j < (_width / 8); j++) {
00176 byte p = src[j];
00177
00178 for (int k = 0; k < 8; k++, rowDest++, p <<= 1) {
00179 if ((p & 0x80) == 0x80)
00180 *rowDest = 1;
00181 else
00182 *rowDest = 0;
00183 }
00184 }
00185 } else {
00186
00187 memcpy(rowDest, src, _width);
00188 }
00189
00190 dest -= _width;
00191 src += imagePitch;
00192 }
00193
00194
00195 if (numColors < 256) {
00196
00197 _keyColor = numColors;
00198 } else {
00199
00200
00201 for (uint32 i = 0; i < 256; i++) {
00202 for (int j = 0; j < _width * _height; j++) {
00203
00204
00205 if (_surface[j] == i)
00206 break;
00207
00208 if (j == _width * _height - 1) {
00209 _keyColor = i;
00210 i = 256;
00211 break;
00212 }
00213 }
00214 }
00215 }
00216
00217
00218 uint32 andWidth = (_width + 7) / 8;
00219 src += andWidth * (_height - 1);
00220
00221 for (uint32 y = 0; y < _height; y++) {
00222 for (uint32 x = 0; x < _width; x++)
00223 if (src[x / 8] & (1 << (7 - x % 8)))
00224 _surface[y * _width + x] = _keyColor;
00225
00226 src -= andWidth;
00227 }
00228
00229 delete[] initialSource;
00230 return true;
00231 }
00232
00233 void WinCursor::clear() {
00234 delete[] _surface; _surface = 0;
00235 }
00236
00237 WinCursorGroup::WinCursorGroup() {
00238 }
00239
00240 WinCursorGroup::~WinCursorGroup() {
00241 for (uint32 i = 0; i < cursors.size(); i++)
00242 delete cursors[i].cursor;
00243 }
00244
00245 WinCursorGroup *WinCursorGroup::createCursorGroup(Common::NEResources &exe, const Common::WinResourceID &id) {
00246 Common::ScopedPtr<Common::SeekableReadStream> stream(exe.getResource(Common::kNEGroupCursor, id));
00247
00248 if (!stream || stream->size() <= 6)
00249 return 0;
00250
00251 stream->skip(4);
00252 uint32 cursorCount = stream->readUint16LE();
00253 if ((uint32)stream->size() < (6 + cursorCount * 16))
00254 return 0;
00255
00256 WinCursorGroup *group = new WinCursorGroup();
00257 group->cursors.reserve(cursorCount);
00258
00259 for (uint32 i = 0; i < cursorCount; i++) {
00260 stream->readUint16LE();
00261 stream->readUint16LE();
00262
00263
00264 if (stream->readUint16LE() != 1) {
00265 delete group;
00266 return 0;
00267 }
00268
00269
00270
00271 if (stream->readUint16LE() != 1) {
00272 delete group;
00273 return 0;
00274 }
00275
00276 stream->readUint32LE();
00277 uint32 cursorId = stream->readUint32LE();
00278
00279 Common::ScopedPtr<Common::SeekableReadStream> cursorStream(exe.getResource(Common::kNECursor, cursorId));
00280 if (!cursorStream) {
00281 delete group;
00282 return 0;
00283 }
00284
00285 WinCursor *cursor = new WinCursor();
00286 if (!cursor->readFromStream(*cursorStream)) {
00287 delete cursor;
00288 delete group;
00289 return 0;
00290 }
00291
00292 CursorItem item;
00293 item.id = cursorId;
00294 item.cursor = cursor;
00295 group->cursors.push_back(item);
00296 }
00297
00298 return group;
00299 }
00300
00301 WinCursorGroup *WinCursorGroup::createCursorGroup(Common::PEResources &exe, const Common::WinResourceID &id) {
00302 Common::ScopedPtr<Common::SeekableReadStream> stream(exe.getResource(Common::kPEGroupCursor, id));
00303
00304 if (!stream || stream->size() <= 6)
00305 return 0;
00306
00307 stream->skip(4);
00308 uint32 cursorCount = stream->readUint16LE();
00309 if ((uint32)stream->size() < (6 + cursorCount * 14))
00310 return 0;
00311
00312 WinCursorGroup *group = new WinCursorGroup();
00313 group->cursors.reserve(cursorCount);
00314
00315 for (uint32 i = 0; i < cursorCount; i++) {
00316 stream->readUint16LE();
00317 stream->readUint16LE();
00318
00319
00320 if (stream->readUint16LE() != 1) {
00321 warning("PlaneCount is not 1.");
00322 }
00323
00324 stream->readUint16LE();
00325 stream->readUint32LE();
00326 uint32 cursorId = stream->readUint16LE();
00327
00328 Common::ScopedPtr<Common::SeekableReadStream> cursorStream(exe.getResource(Common::kPECursor, cursorId));
00329 if (!cursorStream) {
00330 delete group;
00331 return 0;
00332 }
00333
00334 WinCursor *cursor = new WinCursor();
00335 if (!cursor->readFromStream(*cursorStream)) {
00336 delete cursor;
00337 delete group;
00338 return 0;
00339 }
00340
00341 CursorItem item;
00342 item.id = cursorId;
00343 item.cursor = cursor;
00344 group->cursors.push_back(item);
00345 }
00346
00347 return group;
00348 }
00349
00353 class DefaultWinCursor : public Cursor {
00354 public:
00355 DefaultWinCursor() {}
00356 ~DefaultWinCursor() {}
00357
00358 uint16 getWidth() const { return 12; }
00359 uint16 getHeight() const { return 20; }
00360 uint16 getHotspotX() const { return 0; }
00361 uint16 getHotspotY() const { return 0; }
00362 byte getKeyColor() const { return 0; }
00363
00364 const byte *getSurface() const {
00365 static const byte defaultCursor[] = {
00366 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00367 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00368 1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0,
00369 1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0,
00370 1, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0,
00371 1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0,
00372 1, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0,
00373 1, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0,
00374 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0,
00375 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0,
00376 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
00377 1, 2, 2, 2, 1, 2, 2, 1, 0, 0, 0, 0,
00378 1, 2, 2, 1, 1, 2, 2, 1, 0, 0, 0, 0,
00379 1, 2, 1, 0, 1, 1, 2, 2, 1, 0, 0, 0,
00380 1, 1, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0,
00381 1, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0,
00382 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0,
00383 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0,
00384 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0,
00385 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0
00386 };
00387
00388 return defaultCursor;
00389 }
00390
00391 const byte *getPalette() const {
00392 static const byte bwPalette[] = {
00393 0x00, 0x00, 0x00,
00394 0xFF, 0xFF, 0xFF
00395 };
00396
00397 return bwPalette;
00398 }
00399 byte getPaletteStartIndex() const { return 1; }
00400 uint16 getPaletteCount() const { return 2; }
00401 };
00402
00403 Cursor *makeDefaultWinCursor() {
00404 return new DefaultWinCursor();
00405 }
00406
00407 }