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 
00027 #include "graphics/wincursor.h"
00028 
00029 namespace Graphics {
00030 
00032 class WinCursor : public Cursor {
00033 public:
00034     WinCursor();
00035     ~WinCursor();
00036 
00038     uint16 getWidth() const;
00040     uint16 getHeight() const;
00042     uint16 getHotspotX() const;
00044     uint16 getHotspotY() const;
00046     byte getKeyColor() const;
00047 
00048     const byte *getSurface() const { return _surface; }
00049 
00050     const byte *getPalette() const { return _palette; }
00051     byte getPaletteStartIndex() const { return 0; }
00052     uint16 getPaletteCount() const { return 256; }
00053 
00055     bool readFromStream(Common::SeekableReadStream &stream);
00056 
00057 private:
00058     byte *_surface;
00059     byte _palette[256 * 3];
00060 
00061     uint16 _width;    
00062     uint16 _height;   
00063     uint16 _hotspotX; 
00064     uint16 _hotspotY; 
00065     byte   _keyColor; 
00066 
00068     void clear();
00069 };
00070 
00071 WinCursor::WinCursor() {
00072     _width    = 0;
00073     _height   = 0;
00074     _hotspotX = 0;
00075     _hotspotY = 0;
00076     _surface  = 0;
00077     _keyColor = 0;
00078     memset(_palette, 0, 256 * 3);
00079 }
00080 
00081 WinCursor::~WinCursor() {
00082     clear();
00083 }
00084 
00085 uint16 WinCursor::getWidth() const {
00086     return _width;
00087 }
00088 
00089 uint16 WinCursor::getHeight() const {
00090     return _height;
00091 }
00092 
00093 uint16 WinCursor::getHotspotX() const {
00094     return _hotspotX;
00095 }
00096 
00097 uint16 WinCursor::getHotspotY() const {
00098     return _hotspotY;
00099 }
00100 
00101 byte WinCursor::getKeyColor() const {
00102     return _keyColor;
00103 }
00104 
00105 bool WinCursor::readFromStream(Common::SeekableReadStream &stream) {
00106     clear();
00107 
00108     _hotspotX = stream.readUint16LE();
00109     _hotspotY = stream.readUint16LE();
00110 
00111     // Check header size
00112     if (stream.readUint32LE() != 40)
00113         return false;
00114 
00115     // Check dimensions
00116     _width = stream.readUint32LE();
00117     _height = stream.readUint32LE() / 2;
00118 
00119     if (_width & 3) {
00120         // Cursors should always be a power of 2
00121         // Of course, it wouldn't be hard to handle but if we have no examples...
00122         warning("Non-divisible-by-4 width cursor found");
00123         return false;
00124     }
00125 
00126     // Color planes
00127     if (stream.readUint16LE() != 1)
00128         return false;
00129 
00130     // Only 1bpp and 8bpp supported
00131     uint16 bitsPerPixel = stream.readUint16LE();
00132     if (bitsPerPixel != 1 && bitsPerPixel != 8)
00133         return false;
00134 
00135     // Compression
00136     if (stream.readUint32LE() != 0)
00137         return false;
00138 
00139     // Image size + X resolution + Y resolution
00140     stream.skip(12);
00141 
00142     uint32 numColors = stream.readUint32LE();
00143 
00144     // If the color count is 0, then it uses up the maximum amount
00145     if (numColors == 0)
00146         numColors = 1 << bitsPerPixel;
00147 
00148     // Reading the palette
00149     stream.seek(40 + 4);
00150     for (uint32 i = 0 ; i < numColors; i++) {
00151         _palette[i * 3 + 2] = stream.readByte();
00152         _palette[i * 3 + 1] = stream.readByte();
00153         _palette[i * 3    ] = stream.readByte();
00154         stream.readByte();
00155     }
00156 
00157     // Reading the bitmap data
00158     uint32 dataSize = stream.size() - stream.pos();
00159     byte *initialSource = new byte[dataSize];
00160     stream.read(initialSource, dataSize);
00161 
00162     // Parse the XOR map
00163     const byte *src = initialSource;
00164     _surface = new byte[_width * _height];
00165     byte *dest = _surface + _width * (_height - 1);
00166     uint32 imagePitch = _width * bitsPerPixel / 8;
00167 
00168     for (uint32 i = 0; i < _height; i++) {
00169         byte *rowDest = dest;
00170 
00171         if (bitsPerPixel == 1) {
00172             // 1bpp
00173             for (uint16 j = 0; j < (_width / 8); j++) {
00174                 byte p = src[j];
00175 
00176                 for (int k = 0; k < 8; k++, rowDest++, p <<= 1) {
00177                     if ((p & 0x80) == 0x80)
00178                         *rowDest = 1;
00179                     else
00180                         *rowDest = 0;
00181                 }
00182             }
00183         } else {
00184             // 8bpp
00185             memcpy(rowDest, src, _width);
00186         }
00187 
00188         dest -= _width;
00189         src += imagePitch;
00190     }
00191 
00192     // Calculate our key color
00193     if (numColors < 256) {
00194         // If we're not using the maximum colors in a byte, we can fit it in
00195         _keyColor = numColors;
00196     } else {
00197         // HACK: Try to find a color that's not being used so it can become
00198         // our keycolor. It's quite impossible to fit 257 entries into 256...
00199         for (uint32 i = 0; i < 256; i++) {
00200             for (int j = 0; j < _width * _height; j++) {
00201                 // TODO: Also check to see if the space is transparent
00202 
00203                 if (_surface[j] == i)
00204                     break;
00205 
00206                 if (j == _width * _height - 1) {
00207                     _keyColor = i;
00208                     i = 256;
00209                     break;
00210                 }
00211             }
00212         }
00213     }
00214 
00215     // Now go through and apply the AND map to get the transparency
00216     uint32 andWidth = (_width + 7) / 8;
00217     src += andWidth * (_height - 1);
00218 
00219     for (uint32 y = 0; y < _height; y++) {
00220         for (uint32 x = 0; x < _width; x++)
00221             if (src[x / 8] & (1 << (7 - x % 8)))
00222                 _surface[y * _width + x] = _keyColor;
00223 
00224         src -= andWidth;
00225     }
00226 
00227     delete[] initialSource;
00228     return true;
00229 }
00230 
00231 void WinCursor::clear() {
00232     delete[] _surface; _surface = 0;
00233 }
00234 
00235 WinCursorGroup::WinCursorGroup() {
00236 }
00237 
00238 WinCursorGroup::~WinCursorGroup() {
00239     for (uint32 i = 0; i < cursors.size(); i++)
00240         delete cursors[i].cursor;
00241 }
00242 
00243 WinCursorGroup *WinCursorGroup::createCursorGroup(Common::WinResources *exe, const Common::WinResourceID &id) {
00244     Common::ScopedPtr<Common::SeekableReadStream> stream(exe->getResource(Common::kWinGroupCursor, id));
00245 
00246     if (!stream || stream->size() <= 6)
00247         return 0;
00248 
00249     stream->skip(4);
00250     uint32 cursorCount = stream->readUint16LE();
00251     if ((uint32)stream->size() < (6 + cursorCount * 14))
00252         return 0;
00253 
00254     WinCursorGroup *group = new WinCursorGroup();
00255     group->cursors.reserve(cursorCount);
00256 
00257     for (uint32 i = 0; i < cursorCount; i++) {
00258         stream->readUint16LE(); // width
00259         stream->readUint16LE(); // height
00260 
00261         // Plane count
00262         if (stream->readUint16LE() != 1) {
00263             warning("PlaneCount is not 1.");
00264         }
00265 
00266         stream->readUint16LE(); // bits per pixel
00267         stream->readUint32LE(); // data size
00268         uint32 cursorId = stream->readUint16LE();
00269 
00270         Common::ScopedPtr<Common::SeekableReadStream> cursorStream(exe->getResource(Common::kWinCursor, cursorId));
00271         if (!cursorStream) {
00272             delete group;
00273             return 0;
00274         }
00275 
00276         WinCursor *cursor = new WinCursor();
00277         if (!cursor->readFromStream(*cursorStream)) {
00278             delete cursor;
00279             delete group;
00280             return 0;
00281         }
00282 
00283         CursorItem item;
00284         item.id = cursorId;
00285         item.cursor = cursor;
00286         group->cursors.push_back(item);
00287     }
00288 
00289     return group;
00290 }
00291 
00295 class DefaultWinCursor : public Cursor {
00296 public:
00297     DefaultWinCursor() {}
00298     ~DefaultWinCursor() {}
00299 
00300     uint16 getWidth() const { return 12; }
00301     uint16 getHeight() const { return 20; }
00302     uint16 getHotspotX() const { return 0; }
00303     uint16 getHotspotY() const { return 0; }
00304     byte getKeyColor() const { return 0; }
00305 
00306     const byte *getSurface() const {
00307         static const byte defaultCursor[] = {
00308             1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00309             1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00310             1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0,
00311             1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0,
00312             1, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0,
00313             1, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0,
00314             1, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0,
00315             1, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0,
00316             1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0,
00317             1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 0,
00318             1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1,
00319             1, 2, 2, 2, 1, 2, 2, 1, 0, 0, 0, 0,
00320             1, 2, 2, 1, 1, 2, 2, 1, 0, 0, 0, 0,
00321             1, 2, 1, 0, 1, 1, 2, 2, 1, 0, 0, 0,
00322             1, 1, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0,
00323             1, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0,
00324             0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0,
00325             0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0,
00326             0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0,
00327             0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0
00328         };
00329 
00330         return defaultCursor;
00331     }
00332 
00333     const byte *getPalette() const {
00334         static const byte bwPalette[] = {
00335             0x00, 0x00, 0x00,   // Black
00336             0xFF, 0xFF, 0xFF    // White
00337         };
00338 
00339         return bwPalette;
00340     }
00341     byte getPaletteStartIndex() const { return 1; }
00342     uint16 getPaletteCount() const { return 2; }
00343 };
00344 
00345 Cursor *makeDefaultWinCursor() {
00346     return new DefaultWinCursor();
00347 }
00348 
00349 } // End of namespace Graphics


Generated on Sat May 30 2020 05:01:03 for ResidualVM by doxygen 1.7.1
curved edge   curved edge