ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

wincursor.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
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     // Check header size
00114     if (stream.readUint32LE() != 40)
00115         return false;
00116 
00117     // Check dimensions
00118     _width = stream.readUint32LE();
00119     _height = stream.readUint32LE() / 2;
00120 
00121     if (_width & 3) {
00122         // Cursors should always be a power of 2
00123         // Of course, it wouldn't be hard to handle but if we have no examples...
00124         warning("Non-divisible-by-4 width cursor found");
00125         return false;
00126     }
00127 
00128     // Color planes
00129     if (stream.readUint16LE() != 1)
00130         return false;
00131 
00132     // Only 1bpp and 8bpp supported
00133     uint16 bitsPerPixel = stream.readUint16LE();
00134     if (bitsPerPixel != 1 && bitsPerPixel != 8)
00135         return false;
00136 
00137     // Compression
00138     if (stream.readUint32LE() != 0)
00139         return false;
00140 
00141     // Image size + X resolution + Y resolution
00142     stream.skip(12);
00143 
00144     uint32 numColors = stream.readUint32LE();
00145 
00146     // If the color count is 0, then it uses up the maximum amount
00147     if (numColors == 0)
00148         numColors = 1 << bitsPerPixel;
00149 
00150     // Reading the palette
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     // Reading the bitmap data
00160     uint32 dataSize = stream.size() - stream.pos();
00161     byte *initialSource = new byte[dataSize];
00162     stream.read(initialSource, dataSize);
00163 
00164     // Parse the XOR map
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             // 1bpp
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             // 8bpp
00187             memcpy(rowDest, src, _width);
00188         }
00189 
00190         dest -= _width;
00191         src += imagePitch;
00192     }
00193 
00194     // Calculate our key color
00195     if (numColors < 256) {
00196         // If we're not using the maximum colors in a byte, we can fit it in
00197         _keyColor = numColors;
00198     } else {
00199         // HACK: Try to find a color that's not being used so it can become
00200         // our keycolor. It's quite impossible to fit 257 entries into 256...
00201         for (uint32 i = 0; i < 256; i++) {
00202             for (int j = 0; j < _width * _height; j++) {
00203                 // TODO: Also check to see if the space is transparent
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     // Now go through and apply the AND map to get the transparency
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(); // width
00261         stream->readUint16LE(); // height
00262 
00263         // Plane count
00264         if (stream->readUint16LE() != 1) {
00265             delete group;
00266             return 0;
00267         }
00268 
00269         // Bits per pixel
00270         // NE cursors can only be 1bpp
00271         if (stream->readUint16LE() != 1) {
00272             delete group;
00273             return 0;
00274         }
00275 
00276         stream->readUint32LE(); // data size
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(); // width
00317         stream->readUint16LE(); // height
00318 
00319         // Plane count
00320         if (stream->readUint16LE() != 1) {
00321             warning("PlaneCount is not 1.");
00322         }
00323 
00324         stream->readUint16LE(); // bits per pixel
00325         stream->readUint32LE(); // data size
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,   // Black
00394             0xFF, 0xFF, 0xFF    // White
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 } // End of namespace Graphics


Generated on Sat Mar 16 2019 05:02:03 for ResidualVM by doxygen 1.7.1
curved edge   curved edge