mirror of
https://github.com/libretro/scummvm.git
synced 2025-03-06 02:10:28 +00:00
MYST3: Add preliminary cursor support
This commit is contained in:
parent
d677c4b3d2
commit
77cc7f1afc
162
engines/myst3/cursor.cpp
Normal file
162
engines/myst3/cursor.cpp
Normal file
@ -0,0 +1,162 @@
|
||||
/* Residual - A 3D game interpreter
|
||||
*
|
||||
* Residual 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 library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/myst3/archive.h"
|
||||
#include "engines/myst3/cursor.h"
|
||||
|
||||
#include "graphics/surface.h"
|
||||
#include "graphics/imagedec.h"
|
||||
|
||||
namespace Myst3 {
|
||||
|
||||
struct CursorData {
|
||||
uint32 nodeID;
|
||||
uint16 hotspotX;
|
||||
uint16 hotspotY;
|
||||
Graphics::Surface *surface;
|
||||
double transparency;
|
||||
};
|
||||
|
||||
static CursorData availableCursors[13] = {
|
||||
{ 1000, 8, 8, 0, 0.25 },
|
||||
{ 1001, 8, 8, 0, 0.5 },
|
||||
{ 1002, 8, 8, 0, 0.5 },
|
||||
{ 1003, 1, 5, 0, 0.5 },
|
||||
{ 1004, 14, 5, 0, 0.5 },
|
||||
{ 1005, 16, 14, 0, 0.5 },
|
||||
{ 1006, 16, 14, 0, 0.5 },
|
||||
{ 1007, 8, 8, 0, 0.55 },
|
||||
{ 1000, 8, 8, 0, 0.25 },
|
||||
{ 1001, 8, 8, 0, 0.5 },
|
||||
{ 1011, 16, 16, 0, 0.5 },
|
||||
{ 1000, 6, 1, 0, 0.5 },
|
||||
{ 0, 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
Cursor::Cursor(Archive *archive) :
|
||||
_position(320, 210) {
|
||||
|
||||
// Load available cursors
|
||||
loadAvailableCursors(archive);
|
||||
|
||||
// Generate texture
|
||||
generateTexture();
|
||||
|
||||
// Set default cursor
|
||||
changeCursor(8);
|
||||
}
|
||||
|
||||
void Cursor::loadAvailableCursors(Archive *archive) {
|
||||
// Load available cursors
|
||||
for (uint i = 0; availableCursors[i].nodeID; i++) {
|
||||
const DirectorySubEntry *cursorDesc = archive->getDescription(availableCursors[i].nodeID, 0, DirectorySubEntry::kCursor);
|
||||
|
||||
if (!cursorDesc)
|
||||
error("Cursor %d does not exist", availableCursors[i].nodeID);
|
||||
|
||||
Common::MemoryReadStream *bmpStream = archive->getData(cursorDesc);
|
||||
availableCursors[i].surface = Graphics::ImageDecoder::loadFile(*bmpStream, Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
|
||||
|
||||
// Apply the colorkey for transparency
|
||||
for (uint u = 0; u < availableCursors[i].surface->w; u++) {
|
||||
for (uint v = 0; v < availableCursors[i].surface->h; v++) {
|
||||
uint32 *pixel = (uint32*)(availableCursors[i].surface->getBasePtr(u, v));
|
||||
if (*pixel == 0xFF00FF00)
|
||||
*pixel = 0x0000FF00;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
delete bmpStream;
|
||||
}
|
||||
}
|
||||
|
||||
void Cursor::generateTexture() {
|
||||
glGenTextures(1, &_textureId);
|
||||
glBindTexture(GL_TEXTURE_2D, _textureId);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _textureSize, _textureSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
|
||||
Cursor::~Cursor() {
|
||||
// Free available cursors
|
||||
for (uint i = 0; availableCursors[i].nodeID; i++) {
|
||||
if (availableCursors[i].surface) {
|
||||
availableCursors[i].surface->free();
|
||||
delete availableCursors[i].surface;
|
||||
availableCursors[i].surface = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete texture
|
||||
glDeleteTextures(1, &_textureId);
|
||||
}
|
||||
|
||||
void Cursor::changeCursor(uint32 index) {
|
||||
assert(index >= 0 && index <= 12);
|
||||
|
||||
if (_currentCursorID != index) {
|
||||
_currentCursorID = index;
|
||||
uploadTexture();
|
||||
}
|
||||
}
|
||||
|
||||
void Cursor::uploadTexture() {
|
||||
Graphics::Surface *bitmap = availableCursors[_currentCursorID].surface;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, _textureId);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap->w, bitmap->h, GL_RGBA, GL_UNSIGNED_BYTE, bitmap->pixels);
|
||||
}
|
||||
|
||||
void Cursor::draw()
|
||||
{
|
||||
CursorData & cursor = availableCursors[_currentCursorID];
|
||||
// Size of the cursor
|
||||
const float w = cursor.surface->w;
|
||||
const float h = cursor.surface->h;
|
||||
// Used fragment of texture
|
||||
const float u = w / (float)(_textureSize);
|
||||
const float v = h / (float)(_textureSize);
|
||||
|
||||
const float left = _position.x - cursor.hotspotX;
|
||||
const float top = _position.y - cursor.hotspotY;
|
||||
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, _textureId);
|
||||
glBegin(GL_TRIANGLE_STRIP);
|
||||
glTexCoord2f(0, v); glVertex3f( left + 0, top + h, 1.0f);
|
||||
glTexCoord2f(u, v); glVertex3f( left + w, top + h, 1.0f);
|
||||
glTexCoord2f(0, 0); glVertex3f( left + 0, top + 0, 1.0f);
|
||||
glTexCoord2f(u, 0); glVertex3f( left + w, top + 0, 1.0f);
|
||||
glEnd();
|
||||
|
||||
glDepthMask(GL_TRUE);
|
||||
}
|
||||
|
||||
} /* namespace Myst3 */
|
58
engines/myst3/cursor.h
Normal file
58
engines/myst3/cursor.h
Normal file
@ -0,0 +1,58 @@
|
||||
/* Residual - A 3D game interpreter
|
||||
*
|
||||
* Residual 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 library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CURSOR_H_
|
||||
#define CURSOR_H_
|
||||
|
||||
#ifdef SDL_BACKEND
|
||||
#include <SDL_opengl.h>
|
||||
#else
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#endif
|
||||
|
||||
#include "common/rect.h"
|
||||
|
||||
namespace Myst3 {
|
||||
|
||||
class Cursor {
|
||||
public:
|
||||
Cursor(Archive *archive);
|
||||
virtual ~Cursor();
|
||||
|
||||
void changeCursor(uint32 index);
|
||||
void draw();
|
||||
private:
|
||||
uint32 _currentCursorID;
|
||||
GLuint _textureId;
|
||||
static const uint _textureSize = 32;
|
||||
|
||||
/** Position of the cursor */
|
||||
Common::Point _position;
|
||||
|
||||
void loadAvailableCursors(Archive *archive);
|
||||
void generateTexture();
|
||||
void uploadTexture();
|
||||
};
|
||||
|
||||
} /* namespace Myst3 */
|
||||
#endif /* CURSOR_H_ */
|
@ -279,7 +279,7 @@ HotSpot Database::loadHotspot(Common::ReadStream &s) {
|
||||
|
||||
if (hotspot.condition != -1) {
|
||||
hotspot.rects = loadRects(s);
|
||||
hotspot.unk2 = s.readUint16LE();
|
||||
hotspot.cursor = s.readUint16LE();
|
||||
}
|
||||
|
||||
hotspot.script = loadOpcodes(s);
|
||||
|
@ -46,6 +46,7 @@ class DirectorySubEntry {
|
||||
kFaceMask = 1,
|
||||
kSpotItem = 5,
|
||||
kFrame = 6,
|
||||
kCursor = 7,
|
||||
kMovie = 8,
|
||||
kStillMovie = 10,
|
||||
kImagerMovie = 72
|
||||
|
@ -49,7 +49,7 @@ class HotSpot {
|
||||
public:
|
||||
int16 condition;
|
||||
Common::Array<PolarRect> rects;
|
||||
int16 unk2;
|
||||
int16 cursor;
|
||||
Common::Array<Opcode> script;
|
||||
|
||||
bool isPointInRectsCube(const Common::Point &p);
|
||||
|
@ -70,6 +70,7 @@ Myst3Engine::Myst3Engine(OSystem *syst, int gameFlags) :
|
||||
Myst3Engine::~Myst3Engine() {
|
||||
DebugMan.clearAllDebugChannels();
|
||||
|
||||
delete _cursor;
|
||||
delete _scene;
|
||||
delete _archive;
|
||||
delete _db;
|
||||
@ -80,8 +81,8 @@ Myst3Engine::~Myst3Engine() {
|
||||
}
|
||||
|
||||
Common::Error Myst3Engine::run() {
|
||||
const int w = 800;
|
||||
const int h = 600;
|
||||
const int w = 640;
|
||||
const int h = 480;
|
||||
|
||||
_rnd = new Common::RandomSource("sprint");
|
||||
_console = new Console(this);
|
||||
@ -93,6 +94,12 @@ Common::Error Myst3Engine::run() {
|
||||
|
||||
_system->setupScreen(w, h, false, true);
|
||||
|
||||
Archive *archiveRSRC = new Archive();
|
||||
archiveRSRC->open("RSRC.m3r");
|
||||
_cursor = new Cursor(archiveRSRC);
|
||||
archiveRSRC->close();
|
||||
delete archiveRSRC;
|
||||
|
||||
_scene->init(w, h);
|
||||
|
||||
// Var init script
|
||||
@ -118,6 +125,45 @@ Common::Error Myst3Engine::run() {
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
Common::Array<HotSpot *> Myst3Engine::listHoveredHotspots() {
|
||||
Common::Array<HotSpot *> hovered;
|
||||
|
||||
NodePtr nodeData = _db->getNodeData(_vars->getLocationNode());
|
||||
if (_viewType == kCube) {
|
||||
Common::Point mouse = _scene->getMousePos();
|
||||
|
||||
for (uint j = 0; j < nodeData->hotspots.size(); j++) {
|
||||
if (nodeData->hotspots[j].isPointInRectsCube(mouse)) {
|
||||
hovered.push_back(&nodeData->hotspots[j]);
|
||||
}
|
||||
}
|
||||
} else if (_viewType == kFrame) {
|
||||
Common::Point mouse = _system->getEventManager()->getMousePos();
|
||||
Common::Point scaledMouse = Common::Point(
|
||||
mouse.x * Scene::_originalWidth / _system->getWidth(),
|
||||
CLIP<uint>(mouse.y * Scene::_originalHeight / _system->getHeight()
|
||||
- Scene::_topBorderHeight, 0, Scene::_frameHeight));
|
||||
|
||||
for (uint j = 0; j < nodeData->hotspots.size(); j++) {
|
||||
if (nodeData->hotspots[j].isPointInRectsFrame(scaledMouse)) {
|
||||
hovered.push_back(&nodeData->hotspots[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hovered;
|
||||
}
|
||||
|
||||
void Myst3Engine::updateCursor() {
|
||||
Common::Array<HotSpot *> hovered = listHoveredHotspots();
|
||||
if (hovered.size() > 0) {
|
||||
HotSpot *h = hovered.back();
|
||||
_cursor->changeCursor(h->cursor);
|
||||
} else {
|
||||
_cursor->changeCursor(8);
|
||||
}
|
||||
}
|
||||
|
||||
void Myst3Engine::processInput(bool lookOnly) {
|
||||
// Process events
|
||||
Common::Event event;
|
||||
@ -129,39 +175,21 @@ void Myst3Engine::processInput(bool lookOnly) {
|
||||
if (_viewType == kCube) {
|
||||
_scene->updateCamera(event.relMouse);
|
||||
}
|
||||
|
||||
updateCursor();
|
||||
|
||||
} else if (event.type == Common::EVENT_LBUTTONDOWN) {
|
||||
// Skip the event when in look only mode
|
||||
if (lookOnly) continue;
|
||||
|
||||
NodePtr nodeData = _db->getNodeData(_vars->getLocationNode());
|
||||
if (_viewType == kCube) {
|
||||
Common::Point mouse = _scene->getMousePos();
|
||||
Common::Array<HotSpot *> hovered = listHoveredHotspots();
|
||||
|
||||
for (uint j = 0; j < nodeData->hotspots.size(); j++) {
|
||||
if (nodeData->hotspots[j].isPointInRectsCube(mouse)
|
||||
&& _vars->evaluate(nodeData->hotspots[j].condition)) {
|
||||
_scriptEngine->run(&nodeData->hotspots[j].script);
|
||||
|
||||
}
|
||||
}
|
||||
} else if (_viewType == kFrame) {
|
||||
static const uint originalWidth = 640;
|
||||
static const uint originalHeight = 480;
|
||||
static const uint frameHeight = 360;
|
||||
|
||||
Common::Point mouse = _system->getEventManager()->getMousePos();
|
||||
Common::Point scaledMouse = Common::Point(
|
||||
mouse.x * originalWidth / _system->getWidth(),
|
||||
CLIP<uint>(mouse.y * originalHeight / _system->getHeight()
|
||||
- 30, 0, frameHeight));
|
||||
|
||||
for (uint j = 0; j < nodeData->hotspots.size(); j++) {
|
||||
if (nodeData->hotspots[j].isPointInRectsFrame(scaledMouse)
|
||||
&& _vars->evaluate(nodeData->hotspots[j].condition)) {
|
||||
_scriptEngine->run(&nodeData->hotspots[j].script);
|
||||
}
|
||||
for (uint j = 0; j < hovered.size(); j++) {
|
||||
if (_vars->evaluate(hovered[j]->condition)) {
|
||||
_scriptEngine->run(&hovered[j]->script);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (event.type == Common::EVENT_KEYDOWN) {
|
||||
switch (event.kbd.keycode) {
|
||||
case Common::KEYCODE_d:
|
||||
@ -203,6 +231,7 @@ void Myst3Engine::drawFrame() {
|
||||
}
|
||||
|
||||
_scene->drawBlackBorders();
|
||||
_cursor->draw();
|
||||
|
||||
_system->updateScreen();
|
||||
_system->delayMillis(10);
|
||||
@ -300,6 +329,7 @@ void Myst3Engine::runNodeBackgroundScripts() {
|
||||
void Myst3Engine::loadNodeCubeFaces(uint16 nodeID) {
|
||||
_viewType = kCube;
|
||||
|
||||
updateCursor();
|
||||
_system->showMouse(false);
|
||||
|
||||
_node = new NodeCube(this, _archive, nodeID);
|
||||
@ -308,6 +338,7 @@ void Myst3Engine::loadNodeCubeFaces(uint16 nodeID) {
|
||||
void Myst3Engine::loadNodeFrame(uint16 nodeID) {
|
||||
_viewType = kFrame;
|
||||
|
||||
updateCursor();
|
||||
_system->showMouse(true);
|
||||
|
||||
_node = new NodeFrame(this, _archive, nodeID);
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "engines/myst3/node.h"
|
||||
#include "engines/myst3/scene.h"
|
||||
#include "engines/myst3/script.h"
|
||||
#include "engines/myst3/cursor.h"
|
||||
|
||||
namespace Myst3 {
|
||||
|
||||
@ -55,6 +56,7 @@ enum ViewType {
|
||||
|
||||
class Console;
|
||||
class Variables;
|
||||
class HotSpot;
|
||||
|
||||
class Myst3Engine : public Engine {
|
||||
|
||||
@ -94,6 +96,7 @@ private:
|
||||
Archive *_archive;
|
||||
Script *_scriptEngine;
|
||||
Database *_db;
|
||||
Cursor *_cursor;
|
||||
|
||||
Common::Array<ScriptedMovie *> _movies;
|
||||
Common::Array<Drawable *> _drawables;
|
||||
@ -103,6 +106,9 @@ private:
|
||||
uint _frameCount;
|
||||
bool _shouldQuit;
|
||||
|
||||
Common::Array<HotSpot *> listHoveredHotspots();
|
||||
void updateCursor();
|
||||
|
||||
friend class Console;
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user