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

myst3/cursor.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the AUTHORS
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 "engines/myst3/cursor.h"
00024 #include "engines/myst3/directorysubentry.h"
00025 #include "engines/myst3/gfx.h"
00026 #include "engines/myst3/myst3.h"
00027 #include "engines/myst3/scene.h"
00028 #include "engines/myst3/state.h"
00029 
00030 #include "graphics/surface.h"
00031 
00032 #include "image/bmp.h"
00033 
00034 namespace Myst3 {
00035 
00036 struct CursorData {
00037     uint32 nodeID;
00038     uint16 hotspotX;
00039     uint16 hotspotY;
00040     float transparency;
00041     float transparencyXbox;
00042 };
00043 
00044 static const CursorData availableCursors[] = {
00045     { 1000,  8,  8, 0.25f, 0.00f }, // Default cursor
00046     { 1001,  8,  8, 0.50f, 0.50f }, // On top of inventory item
00047     { 1002,  8,  8, 0.50f, 0.50f }, // Drag cursor
00048     { 1003,  1,  5, 0.50f, 0.50f },
00049     { 1004, 14,  5, 0.50f, 0.50f },
00050     { 1005, 16, 14, 0.50f, 0.50f },
00051     { 1006, 16, 14, 0.50f, 0.50f },
00052     { 1007,  8,  8, 0.55f, 0.55f },
00053     { 1000,  8,  8, 0.25f, 0.00f }, // Default cursor
00054     { 1001,  8,  8, 0.50f, 0.50f },
00055     { 1011, 16, 16, 0.50f, 0.50f },
00056     { 1000,  6,  1, 0.50f, 0.50f },
00057     { 1000,  8,  8, 0.00f, 0.25f }  // Invisible cursor
00058 };
00059 
00060 Cursor::Cursor(Myst3Engine *vm) :
00061     _vm(vm),
00062     _position(vm->_scene->getCenter()),
00063     _hideLevel(0),
00064     _lockedAtCenter(false) {
00065 
00066     // The cursor is manually scaled
00067     _scaled = false;
00068     _isConstrainedToWindow = false;
00069 
00070     // Load available cursors
00071     loadAvailableCursors();
00072 
00073     // Set default cursor
00074     changeCursor(8);
00075 }
00076 
00077 void Cursor::loadAvailableCursors() {
00078     assert(_textures.empty());
00079 
00080     // Load available cursors
00081     for (uint i = 0; i < ARRAYSIZE(availableCursors); i++) {
00082         // Check if a cursor sharing the same texture has already been loaded
00083         if (_textures.contains(availableCursors[i].nodeID)) continue;
00084 
00085         // Load the cursor bitmap
00086         const DirectorySubEntry *cursorDesc = _vm->getFileDescription("GLOB", availableCursors[i].nodeID, 0, DirectorySubEntry::kRawData);
00087         if (!cursorDesc)
00088             error("Cursor %d does not exist", availableCursors[i].nodeID);
00089 
00090         Common::MemoryReadStream *bmpStream = cursorDesc->getData();
00091 
00092         Image::BitmapDecoder bitmapDecoder;
00093         if (!bitmapDecoder.loadStream(*bmpStream))
00094             error("Could not decode Myst III bitmap");
00095         const Graphics::Surface *surfaceBGRA = bitmapDecoder.getSurface();
00096         Graphics::Surface *surfaceRGBA = surfaceBGRA->convertTo(Texture::getRGBAPixelFormat());
00097 
00098         delete bmpStream;
00099 
00100         // Apply the colorkey for transparency
00101         for (uint y = 0; y < surfaceRGBA->h; y++) {
00102             byte *pixels = (byte *)(surfaceRGBA->getBasePtr(0, y));
00103             for (uint x = 0; x < surfaceRGBA->w; x++) {
00104                 byte *r = pixels + 0;
00105                 byte *g = pixels + 1;
00106                 byte *b = pixels + 2;
00107                 byte *a = pixels + 3;
00108 
00109                 if (*r == 0 && *g == 0xFF && *b == 0 && *a == 0xFF) {
00110                     *g = 0;
00111                     *a = 0;
00112                 }
00113 
00114                 pixels += 4;
00115             }
00116         }
00117 
00118         // Create and store the texture
00119         _textures.setVal(availableCursors[i].nodeID, _vm->_gfx->createTexture(surfaceRGBA));
00120 
00121         surfaceRGBA->free();
00122         delete surfaceRGBA;
00123     }
00124 }
00125 
00126 Cursor::~Cursor() {
00127     // Free cursors textures
00128     for (TextureMap::iterator it = _textures.begin(); it != _textures.end(); it++) {
00129         _vm->_gfx->freeTexture(it->_value);
00130     }
00131 }
00132 
00133 void Cursor::changeCursor(uint32 index) {
00134     if (index >= ARRAYSIZE(availableCursors))
00135         return;
00136 
00137     if (_vm->getPlatform() == Common::kPlatformXbox) {
00138         // The cursor is hidden when it is not hovering hotspots
00139         if ((index == 0 || index == 8) && _vm->_state->getViewType() != kCube)
00140             index = 12;
00141     }
00142 
00143     _currentCursorID = index;
00144 }
00145 
00146 float Cursor::getTransparencyForId(uint32 cursorId) {
00147     assert(cursorId < ARRAYSIZE(availableCursors));
00148     if (_vm->getPlatform() == Common::kPlatformXbox) {
00149         return availableCursors[cursorId].transparencyXbox;
00150     } else {
00151         return availableCursors[cursorId].transparency;
00152     }
00153 }
00154 
00155 void Cursor::lockPosition(bool lock) {
00156     if (_lockedAtCenter == lock)
00157         return;
00158 
00159     _lockedAtCenter = lock;
00160 
00161     g_system->lockMouse(lock);
00162 
00163     Common::Point center = _vm->_scene->getCenter();
00164     if (_lockedAtCenter) {
00165         // Locking, just move the cursor at the center of the screen
00166         _position = center;
00167     } else {
00168         // Unlocking, warp the actual mouse position to the cursor
00169         g_system->warpMouse(center.x, center.y);
00170     }
00171 }
00172 
00173 void Cursor::updatePosition(const Common::Point &mouse) {
00174     if (!_lockedAtCenter) {
00175         _position = mouse;
00176     } else {
00177         _position = _vm->_scene->getCenter();
00178     }
00179 }
00180 
00181 Common::Point Cursor::getPosition(bool scaled) {
00182     if (scaled) {
00183         Common::Rect viewport = _vm->_gfx->viewport();
00184 
00185         // The rest of the engine expects 640x480 coordinates
00186         Common::Point scaledPosition = _position;
00187         scaledPosition.x -= viewport.left;
00188         scaledPosition.y -= viewport.top;
00189         scaledPosition.x = CLIP<int16>(scaledPosition.x, 0, viewport.width());
00190         scaledPosition.y = CLIP<int16>(scaledPosition.y, 0, viewport.height());
00191         scaledPosition.x *= Renderer::kOriginalWidth / (float) viewport.width();
00192         scaledPosition.y *= Renderer::kOriginalHeight / (float) viewport.height();
00193 
00194         return scaledPosition;
00195     } else {
00196         return _position;
00197     }
00198 }
00199 
00200 void Cursor::draw() {
00201     assert(_currentCursorID < ARRAYSIZE(availableCursors));
00202 
00203     const CursorData &cursor = availableCursors[_currentCursorID];
00204 
00205     Texture *texture = _textures[cursor.nodeID];
00206     if (!texture) {
00207         error("No texture for cursor with id %d", cursor.nodeID);
00208     }
00209 
00210     // Rect where to draw the cursor
00211     Common::Rect viewport = _vm->_gfx->viewport();
00212     float scale = MIN(
00213             viewport.width()  / (float) Renderer::kOriginalWidth,
00214             viewport.height() / (float) Renderer::kOriginalHeight
00215     );
00216 
00217     Common::Rect screenRect = Common::Rect(texture->width * scale, texture->height * scale);
00218     screenRect.translate(_position.x - cursor.hotspotX * scale, _position.y - cursor.hotspotY * scale);
00219 
00220     // Texture rect
00221     Common::Rect textureRect = Common::Rect(texture->width, texture->height);
00222 
00223     float transparency = 1.0f;
00224 
00225     int32 varTransparency = _vm->_state->getCursorTransparency();
00226     if (_lockedAtCenter || varTransparency == 0) {
00227         if (varTransparency >= 0)
00228             transparency = varTransparency / 100.0f;
00229         else
00230             transparency = getTransparencyForId(_currentCursorID);
00231     }
00232 
00233     _vm->_gfx->drawTexturedRect2D(screenRect, textureRect, texture, transparency);
00234 }
00235 
00236 void Cursor::setVisible(bool show) {
00237     if (show)
00238         _hideLevel = MAX<int32>(0, --_hideLevel);
00239     else
00240         _hideLevel++;
00241 }
00242 
00243 bool Cursor::isVisible() {
00244     return !_hideLevel && !_vm->_state->getCursorHidden() && !_vm->_state->getCursorLocked();
00245 }
00246 
00247 void Cursor::getDirection(float &pitch, float &heading) {
00248     if (_lockedAtCenter) {
00249         pitch = _vm->_state->getLookAtPitch();
00250         heading = _vm->_state->getLookAtHeading();
00251     } else {
00252         _vm->_scene->screenPosToDirection(_position, pitch, heading);
00253     }
00254 }
00255 
00256 } // End of namespace Myst3


Generated on Sat Feb 16 2019 05:00:48 for ResidualVM by doxygen 1.7.1
curved edge   curved edge