MYST3: Initial version of the widescreen mod
This commit is contained in:
parent
1537ec2de2
commit
19a8b11d85
28 changed files with 608 additions and 187 deletions
|
@ -1,2 +1,2 @@
|
|||
engines/myst3/detection.cpp
|
||||
engines/myst3/myst3.cpp
|
||||
|
||||
|
|
|
@ -23,10 +23,8 @@
|
|||
#include "engines/myst3/cursor.h"
|
||||
#include "engines/myst3/directorysubentry.h"
|
||||
#include "engines/myst3/myst3.h"
|
||||
#include "engines/myst3/scene.h"
|
||||
#include "engines/myst3/state.h"
|
||||
|
||||
#include "graphics/surface.h"
|
||||
#include "image/bmp.h"
|
||||
|
||||
namespace Myst3 {
|
||||
|
@ -57,10 +55,14 @@ static const CursorData availableCursors[] = {
|
|||
|
||||
Cursor::Cursor(Myst3Engine *vm) :
|
||||
_vm(vm),
|
||||
_position(vm->_scene->frameCenter()),
|
||||
_position(vm->_scene->getCenter()),
|
||||
_hideLevel(0),
|
||||
_lockedAtCenter(false) {
|
||||
|
||||
// The cursor is drawn unscaled
|
||||
_scaled = false;
|
||||
_isConstrainedToWindow = false;
|
||||
|
||||
// Load available cursors
|
||||
loadAvailableCursors();
|
||||
|
||||
|
@ -146,7 +148,7 @@ void Cursor::lockPosition(bool lock) {
|
|||
|
||||
g_system->lockMouse(lock);
|
||||
|
||||
Common::Point center = _vm->_scene->frameCenter();
|
||||
Common::Point center = _vm->_scene->getCenter();
|
||||
if (_lockedAtCenter) {
|
||||
// Locking, just move the cursor at the center of the screen
|
||||
_position = center;
|
||||
|
@ -162,19 +164,23 @@ void Cursor::updatePosition(Common::Point &mouse) {
|
|||
}
|
||||
}
|
||||
|
||||
Common::Point Cursor::getPosition() {
|
||||
Common::Rect viewport = _vm->_gfx->viewport();
|
||||
Common::Point Cursor::getPosition(bool scaled) {
|
||||
if (scaled) {
|
||||
Common::Rect viewport = _vm->_gfx->viewport();
|
||||
|
||||
// The rest of the engine expects 640x480 coordinates
|
||||
Common::Point scaledPosition = _position;
|
||||
scaledPosition.x -= viewport.left;
|
||||
scaledPosition.y -= viewport.top;
|
||||
scaledPosition.x = CLIP<int16>(scaledPosition.x, 0, viewport.width());
|
||||
scaledPosition.y = CLIP<int16>(scaledPosition.y, 0, viewport.height());
|
||||
scaledPosition.x *= Renderer::kOriginalWidth / (float)viewport.width();
|
||||
scaledPosition.y *= Renderer::kOriginalHeight / (float)viewport.height();
|
||||
// The rest of the engine expects 640x480 coordinates
|
||||
Common::Point scaledPosition = _position;
|
||||
scaledPosition.x -= viewport.left;
|
||||
scaledPosition.y -= viewport.top;
|
||||
scaledPosition.x = CLIP<int16>(scaledPosition.x, 0, viewport.width());
|
||||
scaledPosition.y = CLIP<int16>(scaledPosition.y, 0, viewport.height());
|
||||
scaledPosition.x *= Renderer::kOriginalWidth / (float) viewport.width();
|
||||
scaledPosition.y *= Renderer::kOriginalHeight / (float) viewport.height();
|
||||
|
||||
return scaledPosition;
|
||||
return scaledPosition;
|
||||
} else {
|
||||
return _position;
|
||||
}
|
||||
}
|
||||
|
||||
void Cursor::draw() {
|
||||
|
|
|
@ -26,12 +26,14 @@
|
|||
#include "common/hashmap.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
#include "engines/myst3/gfx.h"
|
||||
|
||||
namespace Myst3 {
|
||||
|
||||
class Myst3Engine;
|
||||
class Texture;
|
||||
|
||||
class Cursor {
|
||||
class Cursor : public Drawable {
|
||||
public:
|
||||
Cursor(Myst3Engine *vm);
|
||||
virtual ~Cursor();
|
||||
|
@ -40,12 +42,20 @@ public:
|
|||
bool isPositionLocked() { return _lockedAtCenter; }
|
||||
void lockPosition(bool lock);
|
||||
|
||||
Common::Point getPosition();
|
||||
/**
|
||||
* Get the mouse cursor position
|
||||
*
|
||||
* By default it is in 640x480 equivalent coordinates
|
||||
*
|
||||
* @param scaled When false the position is in actual game screen coordinates.
|
||||
* @return
|
||||
*/
|
||||
Common::Point getPosition(bool scaled = true);
|
||||
void updatePosition(Common::Point &mouse);
|
||||
|
||||
void getDirection(float &pitch, float &heading);
|
||||
|
||||
void draw();
|
||||
void draw() override;
|
||||
void setVisible(bool show);
|
||||
bool isVisible();
|
||||
private:
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/translation.h"
|
||||
|
||||
#include "graphics/scaler.h"
|
||||
|
||||
|
@ -169,11 +170,27 @@ static const Myst3GameDescription gameDescriptions[] = {
|
|||
{ AD_TABLE_END_MARKER, 0 }
|
||||
};
|
||||
|
||||
#define GAMEOPTION_WIDESCREEN_MOD GUIO_GAMEOPTIONS1
|
||||
|
||||
static const ADExtraGuiOptionsMap optionsList[] = {
|
||||
{
|
||||
GAMEOPTION_WIDESCREEN_MOD,
|
||||
{
|
||||
_s("Widescreen mod"),
|
||||
_s("Enable enable widescreen rendering in fullscreen mode."),
|
||||
"widescreen_mod",
|
||||
false
|
||||
}
|
||||
},
|
||||
|
||||
AD_EXTRA_GUI_OPTIONS_TERMINATOR
|
||||
};
|
||||
|
||||
class Myst3MetaEngine : public AdvancedMetaEngine {
|
||||
public:
|
||||
Myst3MetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(Myst3GameDescription), myst3Games) {
|
||||
Myst3MetaEngine() : AdvancedMetaEngine(gameDescriptions, sizeof(Myst3GameDescription), myst3Games, optionsList) {
|
||||
_singleid = "myst3";
|
||||
_guioptions = GUIO4(GUIO_NOMIDI, GUIO_NOSFX, GUIO_NOSPEECH, GUIO_NOSUBTITLES);
|
||||
_guioptions = GUIO5(GUIO_NOMIDI, GUIO_NOSFX, GUIO_NOSPEECH, GUIO_NOSUBTITLES, GAMEOPTION_WIDESCREEN_MOD);
|
||||
_maxScanDepth = 3;
|
||||
_directoryGlobs = directoryGlobs;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
#endif
|
||||
|
||||
#include "math/glmath.h"
|
||||
#include "math/vector2d.h"
|
||||
|
||||
namespace Myst3 {
|
||||
|
||||
|
@ -71,7 +70,8 @@ const float Renderer::cubeVertices[] = {
|
|||
};
|
||||
|
||||
Renderer::Renderer(OSystem *system)
|
||||
: _system(system), _font(NULL) {
|
||||
: _system(system),
|
||||
_font(nullptr) {
|
||||
|
||||
// Compute the cube faces Axis Aligned Bounding Boxes
|
||||
for (uint i = 0; i < ARRAYSIZE(_cubeFacesAABB); i++) {
|
||||
|
@ -122,7 +122,9 @@ void Renderer::computeScreenViewport() {
|
|||
int32 screenWidth = _system->getWidth();
|
||||
int32 screenHeight = _system->getHeight();
|
||||
|
||||
if (_system->getFeatureState(OSystem::kFeatureAspectRatioCorrection)) {
|
||||
if (ConfMan.getBool("widescreen_mod")) {
|
||||
_screenViewport = Common::Rect(screenWidth, screenHeight);
|
||||
} else if (_system->getFeatureState(OSystem::kFeatureAspectRatioCorrection)) {
|
||||
// Aspect ratio correction
|
||||
int32 viewportWidth = MIN<int32>(screenWidth, screenHeight * kOriginalWidth / kOriginalHeight);
|
||||
int32 viewportHeight = MIN<int32>(screenHeight, screenWidth * kOriginalHeight / kOriginalWidth);
|
||||
|
@ -220,6 +222,69 @@ Renderer *createRenderer(OSystem *system) {
|
|||
error("Unable to create a '%s' renderer", rendererConfig.c_str());
|
||||
}
|
||||
|
||||
void Renderer::renderDrawable(Drawable *drawable, Window *window) {
|
||||
if (drawable->isConstrainedToWindow()) {
|
||||
selectTargetWindow(window, drawable->is3D(), drawable->isScaled());
|
||||
} else {
|
||||
selectTargetWindow(nullptr, drawable->is3D(), drawable->isScaled());
|
||||
}
|
||||
drawable->draw();
|
||||
}
|
||||
|
||||
void Renderer::renderDrawableOverlay(Drawable *drawable, Window *window) {
|
||||
// Overlays are always 2D
|
||||
if (drawable->isConstrainedToWindow()) {
|
||||
selectTargetWindow(window, drawable->is3D(), drawable->isScaled());
|
||||
} else {
|
||||
selectTargetWindow(nullptr, drawable->is3D(), drawable->isScaled());
|
||||
}
|
||||
drawable->drawOverlay();
|
||||
}
|
||||
|
||||
void Renderer::renderWindow(Window *window) {
|
||||
renderDrawable(window, window);
|
||||
}
|
||||
|
||||
void Renderer::renderWindowOverlay(Window *window) {
|
||||
renderDrawableOverlay(window, window);
|
||||
}
|
||||
|
||||
Drawable::Drawable() :
|
||||
_isConstrainedToWindow(true),
|
||||
_is3D(false),
|
||||
_scaled(true) {
|
||||
}
|
||||
|
||||
Common::Point Window::getCenter() const {
|
||||
Common::Rect frame = getPosition();
|
||||
|
||||
return Common::Point((frame.left + frame.right) / 2, (frame.top + frame.bottom) / 2);
|
||||
}
|
||||
|
||||
Common::Point Window::screenPosToWindowPos(const Common::Point &screen) const {
|
||||
Common::Rect frame = getPosition();
|
||||
|
||||
return Common::Point(screen.x - frame.left, screen.y - frame.top);
|
||||
}
|
||||
|
||||
Common::Point Window::scalePoint(const Common::Point &screen) const {
|
||||
Common::Rect viewport = getPosition();
|
||||
Common::Rect originalViewport = getOriginalPosition();
|
||||
|
||||
Common::Point scaledPosition = screen;
|
||||
scaledPosition.x -= viewport.left;
|
||||
scaledPosition.y -= viewport.top;
|
||||
scaledPosition.x = CLIP<int16>(scaledPosition.x, 0, viewport.width());
|
||||
scaledPosition.y = CLIP<int16>(scaledPosition.y, 0, viewport.height());
|
||||
|
||||
if (_scaled) {
|
||||
scaledPosition.x *= originalViewport.width() / (float) viewport.width();
|
||||
scaledPosition.y *= originalViewport.height() / (float) viewport.height();
|
||||
}
|
||||
|
||||
return scaledPosition;
|
||||
}
|
||||
|
||||
FrameLimiter::FrameLimiter(OSystem *system, const uint framerate) :
|
||||
_system(system),
|
||||
_speedLimitMs(1000 / framerate),
|
||||
|
|
|
@ -32,11 +32,63 @@
|
|||
|
||||
namespace Myst3 {
|
||||
|
||||
class Renderer;
|
||||
|
||||
class Drawable {
|
||||
public:
|
||||
Drawable();
|
||||
virtual ~Drawable() {}
|
||||
|
||||
virtual void draw() {}
|
||||
virtual void drawOverlay() {}
|
||||
virtual ~Drawable() {}
|
||||
|
||||
/** Should the drawable be drawn inside the active window, or is it allowed to draw on the entire screen? */
|
||||
bool isConstrainedToWindow() const { return _isConstrainedToWindow; }
|
||||
|
||||
/** Whether to setup the renderer state for 2D or 3D when processing the drawable */
|
||||
bool is3D() const { return _is3D; }
|
||||
|
||||
/** Whether to scale the drawable to a size equivalent to the original engine or to draw it at its native size */
|
||||
bool isScaled() const { return _scaled; }
|
||||
|
||||
protected:
|
||||
bool _isConstrainedToWindow;
|
||||
bool _is3D;
|
||||
bool _scaled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Game screen window
|
||||
*
|
||||
* A window represents a game screen pane.
|
||||
* It allows abstracting the rendering position from the behavior.
|
||||
*/
|
||||
class Window : public Drawable {
|
||||
public:
|
||||
/**
|
||||
* Get the window position in screen coordinates
|
||||
*/
|
||||
virtual Common::Rect getPosition() const = 0;
|
||||
|
||||
/**
|
||||
* Get the window position in original (640x480) screen coordinates
|
||||
*/
|
||||
virtual Common::Rect getOriginalPosition() const = 0;
|
||||
|
||||
/**
|
||||
* Get the window center in screen coordinates
|
||||
*/
|
||||
Common::Point getCenter() const;
|
||||
|
||||
/**
|
||||
* Convert screen coordinates to window coordinates
|
||||
*/
|
||||
Common::Point screenPosToWindowPos(const Common::Point &screen) const;
|
||||
|
||||
/**
|
||||
* Transform a point from screen coordinates to scaled window coordinates
|
||||
*/
|
||||
Common::Point scalePoint(const Common::Point &screen) const;
|
||||
};
|
||||
|
||||
class Texture {
|
||||
|
@ -83,13 +135,30 @@ public:
|
|||
|
||||
virtual Graphics::Surface *getScreenshot() = 0;
|
||||
|
||||
/** Render a Drawable in the specified window */
|
||||
void renderDrawable(Drawable *drawable, Window *window);
|
||||
|
||||
/** Render a Drawable overlay in the specified window */
|
||||
void renderDrawableOverlay(Drawable *drawable, Window *window);
|
||||
|
||||
/** Render the main Drawable of a Window */
|
||||
void renderWindow(Window *window);
|
||||
|
||||
/** Render the main Drawable overlay of a Window */
|
||||
void renderWindowOverlay(Window *window);
|
||||
|
||||
Common::Rect viewport() const;
|
||||
|
||||
Math::Matrix4 makeProjectionMatrix(float fov) const;
|
||||
|
||||
virtual void setupCameraOrtho2D(bool noScaling) = 0;
|
||||
/**
|
||||
* Select the window where to render
|
||||
*
|
||||
* This also sets the viewport
|
||||
*/
|
||||
virtual void selectTargetWindow(Window *window, bool is3D, bool scaled) = 0;
|
||||
|
||||
virtual void setupCameraPerspective(float pitch, float heading, float fov);
|
||||
virtual void setViewport(const Common::Rect &vp) = 0;
|
||||
|
||||
bool isCubeFaceVisible(uint face);
|
||||
|
||||
|
|
|
@ -87,24 +87,46 @@ void OpenGLRenderer::clear() {
|
|||
glColor3f(1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::setupCameraOrtho2D(bool noScaling) {
|
||||
if (noScaling) {
|
||||
glViewport(0, 0, _system->getWidth(), _system->getHeight());
|
||||
void OpenGLRenderer::selectTargetWindow(Window *window, bool is3D, bool scaled) {
|
||||
if (!window) {
|
||||
// No window found ...
|
||||
if (scaled) {
|
||||
// ... in scaled mode draw in the original game screen area
|
||||
Common::Rect vp = viewport();
|
||||
glViewport(vp.left, _system->getHeight() - vp.top - vp.height(), vp.width(), vp.height());
|
||||
} else {
|
||||
// ... otherwise, draw on the whole screen
|
||||
glViewport(0, 0, _system->getWidth(), _system->getHeight());
|
||||
}
|
||||
} else {
|
||||
glViewport(_screenViewport.left, _screenViewport.top, _screenViewport.width(), _screenViewport.height());
|
||||
// Found a window, draw inside it
|
||||
Common::Rect vp = window->getPosition();
|
||||
glViewport(vp.left, _system->getHeight() - vp.top - vp.height(), vp.width(), vp.height());
|
||||
}
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
if (!is3D) {
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
|
||||
if (noScaling) {
|
||||
glOrtho(0.0, _system->getWidth(), _system->getHeight(), 0.0, -1.0, 1.0);
|
||||
} else {
|
||||
glOrtho(0.0, kOriginalWidth, kOriginalHeight, 0.0, -1.0, 1.0);
|
||||
if (!window) {
|
||||
if (scaled) {
|
||||
glOrtho(0.0, kOriginalWidth, kOriginalHeight, 0.0, -1.0, 1.0);
|
||||
} else {
|
||||
glOrtho(0.0, _system->getWidth(), _system->getHeight(), 0.0, -1.0, 1.0);
|
||||
}
|
||||
} else {
|
||||
if (scaled) {
|
||||
Common::Rect originalRect = window->getOriginalPosition();
|
||||
glOrtho(0.0, originalRect.width(), originalRect.height(), 0.0, -1.0, 1.0);
|
||||
} else {
|
||||
Common::Rect vp = window->getPosition();
|
||||
glOrtho(0.0, vp.width(), vp.height(), 0.0, -1.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
void OpenGLRenderer::setupCameraPerspective(float pitch, float heading, float fov) {
|
||||
|
@ -117,10 +139,6 @@ void OpenGLRenderer::setupCameraPerspective(float pitch, float heading, float fo
|
|||
glLoadMatrixf(_modelViewMatrix.getData());
|
||||
}
|
||||
|
||||
void OpenGLRenderer::setViewport(const Common::Rect &vp) {
|
||||
glViewport(vp.left, _system->getHeight() - vp.top - vp.height(), vp.width(), vp.height());
|
||||
}
|
||||
|
||||
void OpenGLRenderer::drawRect2D(const Common::Rect &rect, uint32 color) {
|
||||
uint8 a, r, g, b;
|
||||
Graphics::colorToARGB< Graphics::ColorMasks<8888> >(color, a, r, g, b);
|
||||
|
|
|
@ -39,9 +39,8 @@ public:
|
|||
virtual void init() override;
|
||||
|
||||
virtual void clear() override;
|
||||
virtual void setupCameraOrtho2D(bool noScaling) override;
|
||||
virtual void selectTargetWindow(Window *window, bool is3D, bool scaled) override;
|
||||
virtual void setupCameraPerspective(float pitch, float heading, float fov) override;
|
||||
virtual void setViewport(const Common::Rect &vp) override;
|
||||
|
||||
Texture *createTexture(const Graphics::Surface *surface) override;
|
||||
void freeTexture(Texture *texture) override;
|
||||
|
|
|
@ -90,14 +90,14 @@ void ShaderRenderer::setupQuadEBO() {
|
|||
}
|
||||
|
||||
Math::Vector2d ShaderRenderer::scaled(float x, float y) const {
|
||||
return Math::Vector2d(x / _currentViewport.getWidth(), y / _currentViewport.getHeight());
|
||||
return Math::Vector2d(x / _currentViewport.width(), y / _currentViewport.height());
|
||||
}
|
||||
|
||||
ShaderRenderer::ShaderRenderer(OSystem *system) :
|
||||
Renderer(system),
|
||||
_prevText(""),
|
||||
_prevTextPosition(0,0),
|
||||
_currentViewport(Math::Vector2d(0.0, 0.0), Math::Vector2d(kOriginalWidth, kOriginalHeight)),
|
||||
_currentViewport(kOriginalWidth, kOriginalHeight),
|
||||
_boxShader(nullptr),
|
||||
_cubeShader(nullptr),
|
||||
_rect3dShader(nullptr),
|
||||
|
@ -166,18 +166,30 @@ void ShaderRenderer::clear() {
|
|||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void ShaderRenderer::setupCameraOrtho2D(bool noScaling) {
|
||||
if (noScaling) {
|
||||
glViewport(0, 0, _system->getWidth(), _system->getHeight());
|
||||
_currentViewport = Math::Rect2d(Math::Vector2d(0, 0), Math::Vector2d(_system->getWidth(), _system->getHeight()));
|
||||
void ShaderRenderer::selectTargetWindow(Window *window, bool is3D, bool scaled) {
|
||||
if (!window) {
|
||||
// No window found ...
|
||||
if (scaled) {
|
||||
// ... in scaled mode draw in the original game screen area
|
||||
Common::Rect vp = viewport();
|
||||
glViewport(vp.left, _system->getHeight() - vp.top - vp.height(), vp.width(), vp.height());
|
||||
_currentViewport = Common::Rect(kOriginalWidth, kOriginalHeight);
|
||||
} else {
|
||||
// ... otherwise, draw on the whole screen
|
||||
glViewport(0, 0, _system->getWidth(), _system->getHeight());
|
||||
_currentViewport = Common::Rect(_system->getWidth(), _system->getHeight());
|
||||
}
|
||||
} else {
|
||||
glViewport(_screenViewport.left, _screenViewport.top, _screenViewport.width(), _screenViewport.height());
|
||||
_currentViewport = Math::Rect2d(Math::Vector2d(0, 0), Math::Vector2d(kOriginalWidth, kOriginalHeight));
|
||||
}
|
||||
}
|
||||
// Found a window, draw inside it
|
||||
Common::Rect vp = window->getPosition();
|
||||
glViewport(vp.left, _system->getHeight() - vp.top - vp.height(), vp.width(), vp.height());
|
||||
|
||||
void ShaderRenderer::setViewport(const Common::Rect &vp) {
|
||||
glViewport(vp.left, _system->getHeight() - vp.top - vp.height(), vp.width(), vp.height());
|
||||
if (scaled) {
|
||||
_currentViewport = window->getOriginalPosition();
|
||||
} else {
|
||||
_currentViewport = vp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderRenderer::drawRect2D(const Common::Rect &rect, uint32 color) {
|
||||
|
@ -264,16 +276,16 @@ void ShaderRenderer::draw2DText(const Common::String &text, const Common::Point
|
|||
_prevText = textToDraw;
|
||||
_prevTextPosition = position;
|
||||
|
||||
float x = position.x / _currentViewport.getWidth();
|
||||
float y = position.y / _currentViewport.getHeight();
|
||||
float x = position.x / (float) _currentViewport.width();
|
||||
float y = position.y / (float) _currentViewport.height();
|
||||
|
||||
float *bufData = new float[16 * textToDraw.size()];
|
||||
float *cur = bufData;
|
||||
|
||||
for (uint i = 0; i < textToDraw.size(); i++) {
|
||||
Common::Rect textureRect = getFontCharacterRect(textToDraw[i]);
|
||||
float w = textureRect.width() / _currentViewport.getWidth();
|
||||
float h = textureRect.height() / _currentViewport.getHeight();
|
||||
float w = textureRect.width() / (float) _currentViewport.width();
|
||||
float h = textureRect.height() / (float) _currentViewport.height();
|
||||
|
||||
float cw = textureRect.width() / (float)glFont->internalWidth;
|
||||
float ch = textureRect.height() / (float)glFont->internalHeight;
|
||||
|
@ -290,7 +302,7 @@ void ShaderRenderer::draw2DText(const Common::String &text, const Common::Point
|
|||
memcpy(cur, charData, 16 * sizeof(float));
|
||||
cur += 16;
|
||||
|
||||
x += (textureRect.width() - 3) / _currentViewport.getWidth();
|
||||
x += (textureRect.width() - 3) / (float) _currentViewport.width();
|
||||
}
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _textVBO);
|
||||
|
|
|
@ -40,8 +40,7 @@ public:
|
|||
virtual void init() override;
|
||||
|
||||
virtual void clear() override;
|
||||
virtual void setupCameraOrtho2D(bool noScaling) override;
|
||||
virtual void setViewport(const Common::Rect &vp) override;
|
||||
virtual void selectTargetWindow(Window *window, bool is3D, bool scaled) override;
|
||||
|
||||
virtual Texture *createTexture(const Graphics::Surface *surface) override;
|
||||
virtual void freeTexture(Texture *texture) override;
|
||||
|
@ -73,7 +72,7 @@ private:
|
|||
GLuint _textVBO;
|
||||
GLuint _quadEBO;
|
||||
|
||||
Math::Rect2d _currentViewport;
|
||||
Common::Rect _currentViewport;
|
||||
|
||||
Common::String _prevText;
|
||||
Common::Point _prevTextPosition;
|
||||
|
|
|
@ -88,14 +88,50 @@ void TinyGLRenderer::clear() {
|
|||
tglColor3f(1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
void TinyGLRenderer::setupCameraOrtho2D(bool noScaling) {
|
||||
tglViewport(0, 0, kOriginalWidth, kOriginalHeight);
|
||||
tglMatrixMode(TGL_PROJECTION);
|
||||
tglLoadIdentity();
|
||||
tglOrtho(0.0, kOriginalWidth, kOriginalHeight, 0.0, -1.0, 1.0);
|
||||
void TinyGLRenderer::selectTargetWindow(Window *window, bool is3D, bool scaled) {
|
||||
// NOTE: tinyGL viewport implementation needs to be checked as it doesn't behave the same as openGL
|
||||
|
||||
tglMatrixMode(TGL_MODELVIEW);
|
||||
tglLoadIdentity();
|
||||
if (!window) {
|
||||
// No window found ...
|
||||
if (scaled) {
|
||||
// ... in scaled mode draw in the original game screen area
|
||||
Common::Rect vp = viewport();
|
||||
tglViewport(vp.left, vp.top, vp.width(), vp.height());
|
||||
//tglViewport(vp.left, _system->getHeight() - vp.top - vp.height(), vp.width(), vp.height());
|
||||
} else {
|
||||
// ... otherwise, draw on the whole screen
|
||||
tglViewport(0, 0, _system->getWidth(), _system->getHeight());
|
||||
}
|
||||
} else {
|
||||
// Found a window, draw inside it
|
||||
Common::Rect vp = window->getPosition();
|
||||
tglViewport(vp.left, vp.top, vp.width(), vp.height());
|
||||
//tglViewport(vp.left, _system->getHeight() - vp.top - vp.height(), vp.width(), vp.height());
|
||||
}
|
||||
|
||||
if (!is3D) {
|
||||
tglMatrixMode(TGL_PROJECTION);
|
||||
tglLoadIdentity();
|
||||
|
||||
if (!window) {
|
||||
if (scaled) {
|
||||
tglOrtho(0.0, kOriginalWidth, kOriginalHeight, 0.0, -1.0, 1.0);
|
||||
} else {
|
||||
tglOrtho(0.0, _system->getWidth(), _system->getHeight(), 0.0, -1.0, 1.0);
|
||||
}
|
||||
} else {
|
||||
if (scaled) {
|
||||
Common::Rect originalRect = window->getOriginalPosition();
|
||||
tglOrtho(0.0, originalRect.width(), originalRect.height(), 0.0, -1.0, 1.0);
|
||||
} else {
|
||||
Common::Rect vp = window->getPosition();
|
||||
tglOrtho(0.0, vp.width(), vp.height(), 0.0, -1.0, 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
tglMatrixMode(TGL_MODELVIEW);
|
||||
tglLoadIdentity();
|
||||
}
|
||||
}
|
||||
|
||||
void TinyGLRenderer::setupCameraPerspective(float pitch, float heading, float fov) {
|
||||
|
@ -108,11 +144,6 @@ void TinyGLRenderer::setupCameraPerspective(float pitch, float heading, float fo
|
|||
tglLoadMatrixf(_modelViewMatrix.getData());
|
||||
}
|
||||
|
||||
void TinyGLRenderer::setViewport(const Common::Rect &vp) {
|
||||
// NOTE: tinyGL viewport implementation needs to be checked as it doesn't behave the same as openGL
|
||||
tglViewport(vp.left, vp.top, vp.width(), vp.height());
|
||||
}
|
||||
|
||||
void TinyGLRenderer::drawRect2D(const Common::Rect &rect, uint32 color) {
|
||||
uint8 a, r, g, b;
|
||||
Graphics::colorToARGB< Graphics::ColorMasks<8888> >(color, a, r, g, b);
|
||||
|
@ -153,10 +184,14 @@ void TinyGLRenderer::drawTexturedRect2D(const Common::Rect &screenRect, const Co
|
|||
transparency = 1.0;
|
||||
}
|
||||
|
||||
// HACK: tglBlit is not affected by the viewport, so we offset the draw coordinates here
|
||||
int viewport[4];
|
||||
tglGetIntegerv(TGL_VIEWPORT, viewport);
|
||||
|
||||
tglEnable(TGL_TEXTURE_2D);
|
||||
tglDepthMask(TGL_FALSE);
|
||||
|
||||
Graphics::BlitTransform transform(sLeft, sTop);
|
||||
Graphics::BlitTransform transform(sLeft + viewport[0], sTop + viewport[1]);
|
||||
transform.sourceRectangle(textureRect.left, textureRect.top, sWidth, sHeight);
|
||||
transform.tint(transparency);
|
||||
tglBlit(((TinyGLTexture *)texture)->getBlitTexture(), transform);
|
||||
|
|
|
@ -40,9 +40,8 @@ public:
|
|||
virtual void init() override;
|
||||
|
||||
virtual void clear() override;
|
||||
virtual void setupCameraOrtho2D(bool noScaling) override;
|
||||
virtual void selectTargetWindow(Window *window, bool is3D, bool scaled) override;
|
||||
virtual void setupCameraPerspective(float pitch, float heading, float fov) override;
|
||||
virtual void setViewport(const Common::Rect &vp) override;
|
||||
|
||||
Texture *createTexture(const Graphics::Surface *surface) override;
|
||||
void freeTexture(Texture *texture) override;
|
||||
|
|
|
@ -38,8 +38,10 @@ const Inventory::ItemData Inventory::_availableItems[8] = {
|
|||
};
|
||||
|
||||
Inventory::Inventory(Myst3Engine *vm) :
|
||||
Window(),
|
||||
_vm(vm),
|
||||
_texture(0) {
|
||||
_scaled = !_vm->isWideScreenModEnabled();
|
||||
initializeTexture();
|
||||
}
|
||||
|
||||
|
@ -56,8 +58,19 @@ void Inventory::initializeTexture() {
|
|||
delete s;
|
||||
}
|
||||
|
||||
bool Inventory::isMouseInside() {
|
||||
Common::Point mouse = _vm->_cursor->getPosition(false);
|
||||
return getPosition().contains(mouse);
|
||||
}
|
||||
|
||||
void Inventory::draw() {
|
||||
Common::Point mouse = _vm->_cursor->getPosition();
|
||||
if (_vm->isWideScreenModEnabled()) {
|
||||
// Draw a black background to cover the main game frame
|
||||
Common::Rect screen = _vm->_gfx->viewport();
|
||||
_vm->_gfx->drawRect2D(Common::Rect(screen.width(), Renderer::kBottomBorderHeight), 0xFF000000);
|
||||
}
|
||||
|
||||
uint16 hoveredItemVar = hoveredItem();
|
||||
|
||||
for (ItemList::const_iterator it = _inventory.begin(); it != _inventory.end(); it++) {
|
||||
int32 state = _vm->_state->getVar(it->var);
|
||||
|
@ -72,7 +85,7 @@ void Inventory::draw() {
|
|||
item.textureHeight);
|
||||
textureRect.translate(item.textureX, 0);
|
||||
|
||||
bool itemHighlighted = it->rect.contains(mouse) || state == 2;
|
||||
bool itemHighlighted = it->var == hoveredItemVar || state == 2;
|
||||
|
||||
if (itemHighlighted)
|
||||
textureRect.translate(0, _texture->height / 2);
|
||||
|
@ -157,16 +170,20 @@ void Inventory::reflow() {
|
|||
if (itemCount >= 2)
|
||||
totalWidth += 9 * (itemCount - 1);
|
||||
|
||||
uint16 left = (Renderer::kOriginalWidth - totalWidth) / 2;
|
||||
uint16 left;
|
||||
if (_vm->isWideScreenModEnabled()) {
|
||||
Common::Rect screen = _vm->_gfx->viewport();
|
||||
left = (screen.width() - totalWidth) / 2;
|
||||
} else {
|
||||
left = (Renderer::kOriginalWidth - totalWidth) / 2;
|
||||
}
|
||||
|
||||
for (ItemList::iterator it = _inventory.begin(); it != _inventory.end(); it++) {
|
||||
const ItemData &item = getData(it->var);
|
||||
|
||||
uint16 top = Renderer::kTopBorderHeight + Renderer::kFrameHeight
|
||||
+ (Renderer::kBottomBorderHeight - item.textureHeight) / 2;
|
||||
uint16 top = (Renderer::kBottomBorderHeight - item.textureHeight) / 2;
|
||||
|
||||
it->rect = Common::Rect(item.textureWidth,
|
||||
item.textureHeight);
|
||||
it->rect = Common::Rect(item.textureWidth, item.textureHeight);
|
||||
it->rect.translate(left, top);
|
||||
|
||||
left += item.textureWidth;
|
||||
|
@ -177,7 +194,8 @@ void Inventory::reflow() {
|
|||
}
|
||||
|
||||
uint16 Inventory::hoveredItem() {
|
||||
Common::Point mouse = _vm->_cursor->getPosition();
|
||||
Common::Point mouse = _vm->_cursor->getPosition(false);
|
||||
mouse = scalePoint(mouse);
|
||||
|
||||
for (ItemList::const_iterator it = _inventory.begin(); it != _inventory.end(); it++) {
|
||||
if(it->rect.contains(mouse))
|
||||
|
@ -270,10 +288,44 @@ void Inventory::updateState() {
|
|||
_vm->_state->updateInventory(items);
|
||||
}
|
||||
|
||||
Common::Rect Inventory::getPosition() const {
|
||||
Common::Rect screen = _vm->_gfx->viewport();
|
||||
|
||||
Common::Rect frame;
|
||||
if (_vm->isWideScreenModEnabled()) {
|
||||
frame = Common::Rect(screen.width(), Renderer::kBottomBorderHeight);
|
||||
frame.translate(0, screen.height() - frame.height());
|
||||
} else {
|
||||
frame = Common::Rect(screen.width(), screen.height() * Renderer::kBottomBorderHeight / Renderer::kOriginalHeight);
|
||||
frame.translate(screen.left, screen.top + screen.height() * (Renderer::kTopBorderHeight + Renderer::kFrameHeight) / Renderer::kOriginalHeight);
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
Common::Rect Inventory::getOriginalPosition() const {
|
||||
Common::Rect originalPosition = Common::Rect(Renderer::kOriginalWidth, Renderer::kBottomBorderHeight);
|
||||
originalPosition.translate(0, Renderer::kTopBorderHeight + Renderer::kFrameHeight);
|
||||
return originalPosition;
|
||||
}
|
||||
|
||||
void Inventory::updateCursor() {
|
||||
uint16 item = hoveredItem();
|
||||
if (item > 0) {
|
||||
_vm->_cursor->changeCursor(1);
|
||||
} else {
|
||||
_vm->_cursor->changeCursor(8);
|
||||
}
|
||||
}
|
||||
|
||||
DragItem::DragItem(Myst3Engine *vm, uint id):
|
||||
_vm(vm),
|
||||
_texture(0),
|
||||
_frame(1) {
|
||||
// Draw on the whole screen
|
||||
_isConstrainedToWindow = false;
|
||||
_scaled = !_vm->isWideScreenModEnabled();
|
||||
|
||||
const DirectorySubEntry *movieDesc = _vm->getFileDescription("DRAG", id, 0, DirectorySubEntry::kStillMovie);
|
||||
|
||||
if (!movieDesc)
|
||||
|
@ -308,9 +360,19 @@ void DragItem::setFrame(uint16 frame) {
|
|||
}
|
||||
|
||||
Common::Rect DragItem::getPosition() {
|
||||
Common::Point mouse = _vm->_cursor->getPosition();
|
||||
uint posX = CLIP<uint>(mouse.x, _texture->width / 2, Renderer::kOriginalWidth - _texture->width / 2);
|
||||
uint posY = CLIP<uint>(mouse.y, _texture->height / 2, Renderer::kOriginalHeight - _texture->height / 2);
|
||||
Common::Rect viewport;
|
||||
Common::Point mouse;
|
||||
|
||||
if (_scaled) {
|
||||
viewport = Common::Rect(Renderer::kOriginalWidth, Renderer::kOriginalHeight);
|
||||
mouse = _vm->_cursor->getPosition(true);
|
||||
} else {
|
||||
viewport = _vm->_gfx->viewport();
|
||||
mouse = _vm->_cursor->getPosition(false);
|
||||
}
|
||||
|
||||
uint posX = CLIP<uint>(mouse.x, _texture->width / 2, viewport.width() - _texture->width / 2);
|
||||
uint posY = CLIP<uint>(mouse.y, _texture->height / 2, viewport.height() - _texture->height / 2);
|
||||
|
||||
Common::Rect screenRect = Common::Rect::center(posX, posY, _texture->width, _texture->height);
|
||||
return screenRect;
|
||||
|
|
|
@ -36,11 +36,15 @@ namespace Myst3 {
|
|||
class Myst3Engine;
|
||||
class Texture;
|
||||
|
||||
class Inventory : public Drawable {
|
||||
class Inventory : public Window {
|
||||
public:
|
||||
Inventory(Myst3Engine *vm);
|
||||
virtual ~Inventory();
|
||||
|
||||
// Window API
|
||||
Common::Rect getPosition() const override;
|
||||
Common::Rect getOriginalPosition() const override;
|
||||
|
||||
void loadFromState();
|
||||
void updateState();
|
||||
|
||||
|
@ -50,10 +54,17 @@ public:
|
|||
void removeItem(uint16 var);
|
||||
void reset();
|
||||
|
||||
/** Is the mouse inside the inventory area */
|
||||
bool isMouseInside();
|
||||
|
||||
/** Change the cursor when it is hovering an item */
|
||||
void updateCursor();
|
||||
|
||||
uint16 hoveredItem();
|
||||
void useItem(uint16 var);
|
||||
|
||||
void draw() override;
|
||||
|
||||
private:
|
||||
struct InventoryItem {
|
||||
uint16 var;
|
||||
|
|
|
@ -37,6 +37,10 @@ namespace Myst3 {
|
|||
Dialog::Dialog(Myst3Engine *vm, uint id):
|
||||
_vm(vm),
|
||||
_texture(0) {
|
||||
// Draw on the whole screen
|
||||
_isConstrainedToWindow = false;
|
||||
_scaled = !_vm->isWideScreenModEnabled();
|
||||
|
||||
const DirectorySubEntry *countDesc = _vm->getFileDescription("DLGI", id, 0, DirectorySubEntry::kNumMetadata);
|
||||
const DirectorySubEntry *movieDesc = _vm->getFileDescription("DLOG", id, 0, DirectorySubEntry::kDialogMovie);
|
||||
if (!movieDesc) {
|
||||
|
@ -71,10 +75,17 @@ void Dialog::draw() {
|
|||
_vm->_gfx->drawTexturedRect2D(getPosition(), textureRect, _texture);
|
||||
}
|
||||
|
||||
Common::Rect Dialog::getPosition() {
|
||||
Common::Rect Dialog::getPosition() const {
|
||||
Common::Rect viewport;
|
||||
if (_scaled) {
|
||||
viewport = Common::Rect(Renderer::kOriginalWidth, Renderer::kOriginalHeight);
|
||||
} else {
|
||||
viewport = _vm->_gfx->viewport();
|
||||
}
|
||||
|
||||
Common::Rect screenRect = Common::Rect(_texture->width, _texture->height);
|
||||
screenRect.translate((Renderer::kOriginalWidth - _texture->width) / 2,
|
||||
(Renderer::kOriginalHeight - _texture->height) / 2);
|
||||
screenRect.translate((viewport.width() - _texture->width) / 2,
|
||||
(viewport.height() - _texture->height) / 2);
|
||||
return screenRect;
|
||||
}
|
||||
|
||||
|
@ -125,10 +136,7 @@ int16 ButtonsDialog::update() {
|
|||
if (event.type == Common::EVENT_MOUSEMOVE) {
|
||||
// Compute local mouse coordinates
|
||||
_vm->_cursor->updatePosition(event.mouse);
|
||||
Common::Rect position = getPosition();
|
||||
Common::Point localMouse = _vm->_cursor->getPosition();
|
||||
localMouse.x -= position.left;
|
||||
localMouse.y -= position.top;
|
||||
Common::Point localMouse = getRelativeMousePosition();
|
||||
|
||||
// No hovered button
|
||||
_frameToDisplay = 0;
|
||||
|
@ -146,7 +154,6 @@ int16 ButtonsDialog::update() {
|
|||
switch (event.kbd.keycode) {
|
||||
case Common::KEYCODE_ESCAPE:
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -156,6 +163,14 @@ int16 ButtonsDialog::update() {
|
|||
return -2;
|
||||
}
|
||||
|
||||
Common::Point ButtonsDialog::getRelativeMousePosition() const {
|
||||
Common::Rect position = getPosition();
|
||||
Common::Point localMouse =_vm->_cursor->getPosition(_scaled);
|
||||
localMouse.x -= position.left;
|
||||
localMouse.y -= position.top;
|
||||
return localMouse;
|
||||
}
|
||||
|
||||
GamepadDialog::GamepadDialog(Myst3Engine *vm, uint id):
|
||||
Dialog(vm, id) {
|
||||
}
|
||||
|
@ -175,14 +190,12 @@ int16 GamepadDialog::update() {
|
|||
case Common::KEYCODE_RETURN:
|
||||
case Common::KEYCODE_KP_ENTER:
|
||||
return 1;
|
||||
break;
|
||||
case Common::KEYCODE_ESCAPE:
|
||||
if (_buttonCount == 2) {
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -396,7 +409,7 @@ Graphics::Surface *Menu::createThumbnail(Graphics::Surface *big) {
|
|||
Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
|
||||
|
||||
// The portion of the screenshot to keep
|
||||
Common::Rect frame = _vm->_scene->frameViewport();
|
||||
Common::Rect frame = _vm->_scene->getPosition();
|
||||
Graphics::Surface frameSurface = big->getSubArea(frame);
|
||||
|
||||
uint32 *dst = (uint32 *)small->getPixels();
|
||||
|
|
|
@ -49,13 +49,11 @@ enum DialogType {
|
|||
kConfirmQuit
|
||||
};
|
||||
|
||||
class Menu {
|
||||
class Menu : public Drawable {
|
||||
public:
|
||||
Menu(Myst3Engine *vm);
|
||||
virtual ~Menu();
|
||||
|
||||
virtual void draw() = 0;
|
||||
|
||||
/**
|
||||
* Handle an event for the menu
|
||||
*
|
||||
|
@ -156,13 +154,13 @@ public:
|
|||
virtual int16 update() = 0;
|
||||
|
||||
protected:
|
||||
Common::Rect getPosition() const;
|
||||
|
||||
Myst3Engine *_vm;
|
||||
Video::BinkDecoder _bink;
|
||||
Texture *_texture;
|
||||
|
||||
uint _buttonCount;
|
||||
|
||||
Common::Rect getPosition();
|
||||
};
|
||||
|
||||
class ButtonsDialog : public Dialog {
|
||||
|
@ -174,6 +172,8 @@ public:
|
|||
int16 update() override;
|
||||
|
||||
private:
|
||||
Common::Point getRelativeMousePosition() const;
|
||||
|
||||
uint16 _previousframe;
|
||||
uint16 _frameToDisplay;
|
||||
|
||||
|
|
|
@ -97,6 +97,8 @@ Movie::Movie(Myst3Engine *vm, uint16 id) :
|
|||
void Movie::loadPosition(const VideoData &videoData) {
|
||||
static const float scale = 50.0f;
|
||||
|
||||
_is3D = _vm->_state->getViewType() == kCube;
|
||||
|
||||
Math::Vector3d planeDirection = videoData.v1;
|
||||
planeDirection.normalize();
|
||||
|
||||
|
@ -132,9 +134,6 @@ void Movie::draw2d() {
|
|||
Common::Rect screenRect = Common::Rect(_bink.getWidth(), _bink.getHeight());
|
||||
screenRect.translate(_posU, _posV);
|
||||
|
||||
if (_vm->_state->getViewType() != kMenu)
|
||||
screenRect.translate(0, Renderer::kTopBorderHeight);
|
||||
|
||||
Common::Rect textureRect = Common::Rect(_bink.getWidth(), _bink.getHeight());
|
||||
|
||||
if (_forceOpaque)
|
||||
|
@ -151,10 +150,10 @@ void Movie::draw() {
|
|||
if (_force2d)
|
||||
return;
|
||||
|
||||
if (_vm->_state->getViewType() != kCube) {
|
||||
draw2d();
|
||||
} else {
|
||||
if (_is3D) {
|
||||
draw3d();
|
||||
} else {
|
||||
draw2d();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,7 +163,7 @@ void Movie::drawOverlay() {
|
|||
|
||||
if (_subtitles) {
|
||||
_subtitles->setFrame(adjustFrameForRate(_bink.getCurFrame(), false));
|
||||
_subtitles->drawOverlay();
|
||||
_vm->_gfx->renderWindowOverlay(_subtitles);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,6 +212,13 @@ Movie::~Movie() {
|
|||
delete _subtitles;
|
||||
}
|
||||
|
||||
void Movie::setForce2d(bool b) {
|
||||
_force2d = b;
|
||||
if (_force2d) {
|
||||
_is3D = false;
|
||||
}
|
||||
}
|
||||
|
||||
ScriptedMovie::ScriptedMovie(Myst3Engine *vm, uint16 id) :
|
||||
Movie(vm, id),
|
||||
_condition(0),
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
bool isVideoLoaded() {return _bink.isVideoLoaded(); }
|
||||
void setPosU(int32 v) { _posU = v; }
|
||||
void setPosV(int32 v) { _posV = v; }
|
||||
void setForce2d(bool b) { _force2d = b; }
|
||||
void setForce2d(bool b);
|
||||
void setForceOpaque(bool b) { _forceOpaque = b; }
|
||||
void setStartFrame(int32 v);
|
||||
void setEndFrame(int32 v);
|
||||
|
|
|
@ -80,7 +80,7 @@ Myst3Engine::Myst3Engine(OSystem *syst, const Myst3GameDescription *version) :
|
|||
_inputEscapePressedNotConsumed(false),
|
||||
_menuAction(0), _projectorBackground(0),
|
||||
_shakeEffect(0), _rotationEffect(0), _backgroundSoundScriptLastRoomId(0),
|
||||
_transition(0), _frameLimiter(0) {
|
||||
_transition(0), _frameLimiter(0), _inventoryManualHide(false) {
|
||||
DebugMan.addDebugChannel(kDebugVariable, "Variable", "Track Variable Accesses");
|
||||
DebugMan.addDebugChannel(kDebugSaveLoad, "SaveLoad", "Track Save/Load Function");
|
||||
DebugMan.addDebugChannel(kDebugScript, "Script", "Track Script Execution");
|
||||
|
@ -371,12 +371,9 @@ HotSpot *Myst3Engine::getHoveredHotspot(NodePtr nodeData, uint16 var) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
Common::Point mouse = _cursor->getPosition();
|
||||
|
||||
if (_state->getViewType() == kFrame) {
|
||||
mouse.y -= Renderer::kTopBorderHeight;
|
||||
mouse.y = CLIP<uint>(mouse.y, 0, Renderer::kFrameHeight);
|
||||
}
|
||||
// get the mouse position in original game window coordinates
|
||||
Common::Point mouse = _cursor->getPosition(false);
|
||||
mouse = _scene->scalePoint(mouse);
|
||||
|
||||
for (uint j = 0; j < nodeData->hotspots.size(); j++) {
|
||||
int32 hitRect = nodeData->hotspots[j].isPointInRectsFrame(_state, mouse);
|
||||
|
@ -394,18 +391,23 @@ HotSpot *Myst3Engine::getHoveredHotspot(NodePtr nodeData, uint16 var) {
|
|||
}
|
||||
|
||||
void Myst3Engine::updateCursor() {
|
||||
if (!_inventory->isMouseInside()) {
|
||||
_inventoryManualHide = false;
|
||||
}
|
||||
|
||||
if (isInventoryVisible() && _inventory->isMouseInside()) {
|
||||
_inventory->updateCursor();
|
||||
return;
|
||||
}
|
||||
|
||||
NodePtr nodeData = _db->getNodeData(_state->getLocationNode(), _state->getLocationRoom());
|
||||
|
||||
_state->setHotspotIgnoreClick(true);
|
||||
HotSpot *hovered = getHoveredHotspot(nodeData);
|
||||
_state->setHotspotIgnoreClick(false);
|
||||
|
||||
uint16 hoveredInventory = _inventory->hoveredItem();
|
||||
|
||||
if (hovered) {
|
||||
_cursor->changeCursor(hovered->cursor);
|
||||
} else if (isInventoryVisible() && hoveredInventory > 0) {
|
||||
_cursor->changeCursor(1);
|
||||
} else {
|
||||
_cursor->changeCursor(8);
|
||||
}
|
||||
|
@ -581,9 +583,15 @@ void Myst3Engine::interactWithHoveredElement(bool lookOnly) {
|
|||
if (lookOnly)
|
||||
return;
|
||||
|
||||
uint16 hoveredInventory = _inventory->hoveredItem();
|
||||
if (isInventoryVisible() && hoveredInventory > 0) {
|
||||
_inventory->useItem(hoveredInventory);
|
||||
if (isInventoryVisible() && _inventory->isMouseInside()) {
|
||||
uint16 hoveredInventory = _inventory->hoveredItem();
|
||||
if (hoveredInventory > 0) {
|
||||
_inventory->useItem(hoveredInventory);
|
||||
} else {
|
||||
if (isWideScreenModEnabled()) {
|
||||
_inventoryManualHide = true;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -624,31 +632,24 @@ void Myst3Engine::drawFrame(bool noSwap) {
|
|||
}
|
||||
|
||||
_gfx->setupCameraPerspective(pitch, heading, fov);
|
||||
_gfx->setViewport(_scene->frameViewport());
|
||||
} else {
|
||||
_gfx->setupCameraOrtho2D(false);
|
||||
}
|
||||
|
||||
if (_node) {
|
||||
_node->update();
|
||||
_node->draw();
|
||||
_gfx->renderDrawable(_node, _scene);
|
||||
}
|
||||
|
||||
for (int i = _movies.size() - 1; i >= 0 ; i--) {
|
||||
_movies[i]->update();
|
||||
_movies[i]->draw();
|
||||
_gfx->renderDrawable(_movies[i], _scene);
|
||||
}
|
||||
|
||||
if (_state->getViewType() == kMenu) {
|
||||
_menu->draw();
|
||||
_gfx->renderDrawable(_menu, _scene);
|
||||
}
|
||||
|
||||
for (uint i = 0; i < _drawables.size(); i++) {
|
||||
_drawables[i]->draw();
|
||||
}
|
||||
|
||||
if (_state->getViewType() == kCube) {
|
||||
_gfx->setupCameraOrtho2D(false);
|
||||
_gfx->renderDrawable(_drawables[i], _scene);
|
||||
}
|
||||
|
||||
if (_state->getViewType() != kMenu) {
|
||||
|
@ -659,26 +660,24 @@ void Myst3Engine::drawFrame(bool noSwap) {
|
|||
_scene->drawSunspotFlare(flare);
|
||||
}
|
||||
|
||||
if (isInventoryVisible())
|
||||
_inventory->draw();
|
||||
if (isInventoryVisible()) {
|
||||
_gfx->renderWindow(_inventory);
|
||||
}
|
||||
|
||||
// Draw overlay 2D movies
|
||||
for (int i = _movies.size() - 1; i >= 0 ; i--) {
|
||||
_movies[i]->drawOverlay();
|
||||
_gfx->renderDrawableOverlay(_movies[i], _scene);
|
||||
}
|
||||
|
||||
for (uint i = 0; i < _drawables.size(); i++) {
|
||||
_drawables[i]->drawOverlay();
|
||||
_gfx->renderDrawableOverlay(_drawables[i], _scene);
|
||||
}
|
||||
|
||||
// Draw spot subtitles
|
||||
if (_node) {
|
||||
_node->drawOverlay();
|
||||
_gfx->renderDrawableOverlay(_node, _scene);
|
||||
}
|
||||
|
||||
// The cursor is drawn unscaled
|
||||
_gfx->setupCameraOrtho2D(true);
|
||||
|
||||
bool cursorVisible = _cursor->isVisible();
|
||||
|
||||
if (getPlatform() == Common::kPlatformXbox) {
|
||||
|
@ -687,7 +686,7 @@ void Myst3Engine::drawFrame(bool noSwap) {
|
|||
}
|
||||
|
||||
if (cursorVisible)
|
||||
_cursor->draw();
|
||||
_gfx->renderDrawable(_cursor, _scene);
|
||||
|
||||
_gfx->flipBuffer();
|
||||
|
||||
|
@ -706,6 +705,15 @@ bool Myst3Engine::isInventoryVisible() {
|
|||
if (_node && _node->hasSubtitlesToDraw())
|
||||
return false;
|
||||
|
||||
if (_inventoryManualHide) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only draw the inventory when the mouse is inside its area
|
||||
if (isWideScreenModEnabled() && !_inventory->isMouseInside()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1507,7 +1515,7 @@ void Myst3Engine::getMovieLookAt(uint16 id, bool start, float &pitch, float &hea
|
|||
else
|
||||
v = desc->getVideoData().v2;
|
||||
|
||||
Math::Vector2d horizontalProjection = Math::Vector2d(v.x(), v.z());
|
||||
Math::Vector2d horizontalProjection(v.x(), v.z());
|
||||
horizontalProjection.normalize();
|
||||
|
||||
pitch = 90 - Math::Angle::arcCosine(v.y()).getDegrees();
|
||||
|
@ -1735,6 +1743,10 @@ void Myst3Engine::syncSoundSettings() {
|
|||
_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, soundVolumeMusic * soundOverall / 256);
|
||||
}
|
||||
|
||||
bool Myst3Engine::isWideScreenModEnabled() const {
|
||||
return ConfMan.getBool("widescreen_mod");
|
||||
}
|
||||
|
||||
void Myst3Engine::pauseEngineIntern(bool pause) {
|
||||
Engine::pauseEngineIntern(pause);
|
||||
|
||||
|
|
|
@ -119,6 +119,7 @@ public:
|
|||
int16 getGameLanguageCode() const;
|
||||
bool isMonolingual() const;
|
||||
bool isDVDVersion() const;
|
||||
bool isWideScreenModEnabled() const;
|
||||
|
||||
bool canLoadGameStateCurrently() override;
|
||||
Common::Error loadGameState(int slot) override;
|
||||
|
@ -217,6 +218,14 @@ private:
|
|||
|
||||
uint32 _backgroundSoundScriptLastRoomId;
|
||||
|
||||
/**
|
||||
* When the widescreen mode is active, the user can manually hide
|
||||
* the inventory by clicking on an unused inventory space.
|
||||
* This allows interacting with the scene portion that is below
|
||||
* the inventory.
|
||||
*/
|
||||
bool _inventoryManualHide;
|
||||
|
||||
HotSpot *getHoveredHotspot(NodePtr nodeData, uint16 var = 0);
|
||||
void updateCursor();
|
||||
|
||||
|
|
|
@ -207,7 +207,7 @@ void Node::drawOverlay() {
|
|||
if (hasSubtitlesToDraw()) {
|
||||
uint subId = _vm->_state->getSpotSubtitle();
|
||||
_subtitles->setFrame(15 * subId + 1);
|
||||
_subtitles->drawOverlay();
|
||||
_vm->_gfx->renderWindowOverlay(_subtitles);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,8 @@ namespace Myst3 {
|
|||
|
||||
NodeCube::NodeCube(Myst3Engine *vm, uint16 id) :
|
||||
Node(vm, id) {
|
||||
_is3D = true;
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
const DirectorySubEntry *jpegDesc = _vm->getFileDescription("", id, i + 1, DirectorySubEntry::kCubeFace);
|
||||
|
||||
|
|
|
@ -56,7 +56,6 @@ void NodeFrame::draw() {
|
|||
screenRect = Common::Rect(Renderer::kOriginalWidth, Renderer::kOriginalHeight);
|
||||
} else {
|
||||
screenRect = Common::Rect(Renderer::kOriginalWidth, Renderer::kFrameHeight);
|
||||
screenRect.translate(0, Renderer::kTopBorderHeight);
|
||||
}
|
||||
|
||||
// Used fragment of texture
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
namespace Myst3 {
|
||||
|
||||
Scene::Scene(Myst3Engine *vm) :
|
||||
Window(),
|
||||
_vm(vm),
|
||||
_mouseSpeed(50) {
|
||||
updateMouseSpeed();
|
||||
|
@ -97,13 +98,13 @@ void Scene::updateCamera(Common::Point &mouse) {
|
|||
|
||||
void Scene::drawSunspotFlare(const SunSpot &s) {
|
||||
Common::Rect frame = Common::Rect(Renderer::kOriginalWidth, Renderer::kFrameHeight);
|
||||
frame.translate(0, Renderer::kTopBorderHeight);
|
||||
|
||||
uint8 a = (uint8)(s.intensity * s.radius);
|
||||
uint8 r, g, b;
|
||||
Graphics::colorToRGB< Graphics::ColorMasks<888> >(s.color, r, g, b);
|
||||
uint32 color = Graphics::ARGBToColor< Graphics::ColorMasks<8888> >(a, r, g, b);
|
||||
|
||||
_vm->_gfx->selectTargetWindow(this, false, false);
|
||||
_vm->_gfx->drawRect2D(frame, color);
|
||||
}
|
||||
|
||||
|
@ -134,29 +135,62 @@ void Scene::updateMouseSpeed() {
|
|||
_mouseSpeed = ConfMan.getInt("mouse_speed");
|
||||
}
|
||||
|
||||
Common::Rect Scene::frameViewport() const {
|
||||
Common::Rect Scene::getPosition() const {
|
||||
Common::Rect screen = _vm->_gfx->viewport();
|
||||
|
||||
Common::Rect frame = Common::Rect(screen.width(), screen.height() * Renderer::kFrameHeight / Renderer::kOriginalHeight);
|
||||
frame.translate(screen.left, screen.top + screen.height() * Renderer::kTopBorderHeight / Renderer::kOriginalHeight);
|
||||
Common::Rect frame;
|
||||
if (_vm->isWideScreenModEnabled()) {
|
||||
int32 viewportWidth = Renderer::kOriginalWidth;
|
||||
|
||||
int32 viewportHeight;
|
||||
if (_vm->_state->getViewType() == kMenu) {
|
||||
viewportHeight = Renderer::kOriginalHeight;
|
||||
} else {
|
||||
viewportHeight = Renderer::kFrameHeight;
|
||||
}
|
||||
|
||||
// Aspect ratio correction
|
||||
frame = Common::Rect(MIN<int32>(screen.width(), screen.height() * viewportWidth / viewportHeight),
|
||||
MIN<int32>(screen.height(), screen.width() * viewportHeight / viewportWidth));
|
||||
|
||||
// Pillarboxing
|
||||
uint left = (screen.width() - frame.width()) / 2;
|
||||
|
||||
uint top;
|
||||
if (_vm->_state->getViewType() == kMenu) {
|
||||
top = (screen.height() - frame.height()) / 2;
|
||||
} else {
|
||||
top = (screen.height() - frame.height()) * Renderer::kTopBorderHeight / (Renderer::kTopBorderHeight + Renderer::kBottomBorderHeight);
|
||||
}
|
||||
|
||||
frame.translate(left, top);
|
||||
} else {
|
||||
if (_vm->_state->getViewType() != kMenu) {
|
||||
frame = Common::Rect(screen.width(), screen.height() * Renderer::kFrameHeight / Renderer::kOriginalHeight);
|
||||
frame.translate(screen.left, screen.top + screen.height() * Renderer::kTopBorderHeight / Renderer::kOriginalHeight);
|
||||
} else {
|
||||
frame = screen;
|
||||
}
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
Common::Point Scene::frameCenter() const {
|
||||
Common::Rect frame = frameViewport();
|
||||
Common::Rect Scene::getOriginalPosition() const {
|
||||
Common::Rect originalPosition;
|
||||
|
||||
return Common::Point((frame.left + frame.right) / 2, (frame.top + frame.bottom) / 2);
|
||||
}
|
||||
if (_vm->_state->getViewType() != kMenu) {
|
||||
originalPosition = Common::Rect(Renderer::kOriginalWidth, Renderer::kFrameHeight);
|
||||
originalPosition.translate(0, Renderer::kTopBorderHeight);
|
||||
} else {
|
||||
originalPosition = Common::Rect(Renderer::kOriginalWidth, Renderer::kOriginalHeight);
|
||||
}
|
||||
|
||||
Common::Point Scene::screenPosToWindowPos(const Common::Point &screen) const {
|
||||
Common::Rect frame = frameViewport();
|
||||
|
||||
return Common::Point(screen.x - frame.left, screen.y - frame.top);
|
||||
return originalPosition;
|
||||
}
|
||||
|
||||
void Scene::screenPosToDirection(const Common::Point screen, float &pitch, float &heading) const {
|
||||
Common::Rect frame = frameViewport();
|
||||
Common::Rect frame = getPosition();
|
||||
|
||||
// Screen coords to window coords
|
||||
Common::Point pos = screenPosToWindowPos(screen);
|
||||
|
|
|
@ -25,32 +25,32 @@
|
|||
|
||||
#include "common/rect.h"
|
||||
|
||||
#include "engines/myst3/gfx.h"
|
||||
|
||||
namespace Myst3 {
|
||||
|
||||
class Myst3Engine;
|
||||
class SunSpot;
|
||||
|
||||
class Scene {
|
||||
class Scene : public Window {
|
||||
private:
|
||||
Myst3Engine *_vm;
|
||||
|
||||
Common::Point _mouseOld;
|
||||
uint _mouseSpeed;
|
||||
|
||||
public:
|
||||
Scene(Myst3Engine *vm);
|
||||
|
||||
// Window API
|
||||
Common::Rect getPosition() const override;
|
||||
Common::Rect getOriginalPosition() const override;
|
||||
|
||||
void updateCamera(Common::Point &mouse);
|
||||
|
||||
void updateMouseSpeed();
|
||||
|
||||
Common::Rect frameViewport() const;
|
||||
Common::Point frameCenter() const;
|
||||
|
||||
void screenPosToDirection(const Common::Point screen, float &pitch, float &heading) const;
|
||||
|
||||
Common::Point screenPosToWindowPos(const Common::Point &screen) const;
|
||||
|
||||
void drawSunspotFlare(const SunSpot &s);
|
||||
float distanceToZone(float spotHeading, float spotPitch, float spotRadius, float heading, float pitch);
|
||||
};
|
||||
|
|
|
@ -24,9 +24,7 @@
|
|||
#include "engines/myst3/myst3.h"
|
||||
#include "engines/myst3/state.h"
|
||||
|
||||
#ifdef USE_ICONV
|
||||
#include "common/iconv.h"
|
||||
#endif
|
||||
|
||||
#include "graphics/fontman.h"
|
||||
#include "graphics/font.h"
|
||||
|
@ -78,6 +76,11 @@ FontSubtitles::~FontSubtitles() {
|
|||
}
|
||||
|
||||
void FontSubtitles::loadResources() {
|
||||
// We draw the subtitles in the adequate resolution so that they are not
|
||||
// scaled up. This is the scale factor of the current resolution
|
||||
// compared to the original
|
||||
_scale = getPosition().width() / (float) getOriginalPosition().width();
|
||||
|
||||
#ifdef USE_FREETYPE2
|
||||
Common::String ttfFile;
|
||||
if (_fontFace == "Arial Narrow") {
|
||||
|
@ -98,13 +101,6 @@ void FontSubtitles::loadResources() {
|
|||
warning("Unable to load the subtitles font '%s'", ttfFile.c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
// We draw the subtitles in the adequate resolution so that they are not
|
||||
// scaled up. This is the scale factor of the current resolution
|
||||
// compared to the original
|
||||
Common::Rect screen = _vm->_gfx->viewport();
|
||||
_scale = screen.width() / Renderer::kOriginalWidth;
|
||||
|
||||
}
|
||||
|
||||
void FontSubtitles::loadCharset(int32 id) {
|
||||
|
@ -338,9 +334,11 @@ void MovieSubtitles::drawToTexture(const Phrase *phrase) {
|
|||
}
|
||||
|
||||
Subtitles::Subtitles(Myst3Engine *vm) :
|
||||
Window(),
|
||||
_vm(vm),
|
||||
_texture(0),
|
||||
_frame(-1) {
|
||||
_scaled = !_vm->isWideScreenModEnabled();
|
||||
}
|
||||
|
||||
Subtitles::~Subtitles() {
|
||||
|
@ -360,7 +358,7 @@ void Subtitles::loadFontSettings(int32 id) {
|
|||
_singleLineTop = fontNums->getMiscData(3);
|
||||
_line1Top = fontNums->getMiscData(4);
|
||||
_line2Top = fontNums->getMiscData(5);
|
||||
_surfaceTop = fontNums->getMiscData(6) + Renderer::kTopBorderHeight + Renderer::kFrameHeight;
|
||||
_surfaceTop = fontNums->getMiscData(6);
|
||||
_fontCharsetCode = fontNums->getMiscData(7);
|
||||
|
||||
if (_fontCharsetCode > 0) {
|
||||
|
@ -425,10 +423,20 @@ void Subtitles::setFrame(int32 frame) {
|
|||
void Subtitles::drawOverlay() {
|
||||
if (!_texture) return;
|
||||
|
||||
Common::Rect textureRect = Common::Rect(_texture->width, _texture->height);
|
||||
Common::Rect screen = _vm->_gfx->viewport();
|
||||
Common::Rect bottomBorder = Common::Rect(Renderer::kOriginalWidth, _surfaceHeight);
|
||||
bottomBorder.translate(0, _surfaceTop);
|
||||
|
||||
if (_vm->isWideScreenModEnabled()) {
|
||||
// Draw a black background to cover the main game frame
|
||||
_vm->_gfx->drawRect2D(Common::Rect(screen.width(), Renderer::kBottomBorderHeight), 0xFF000000);
|
||||
|
||||
// Center the subtitles in the screen
|
||||
bottomBorder.translate((screen.width() - Renderer::kOriginalWidth) / 2, 0);
|
||||
}
|
||||
|
||||
Common::Rect textureRect = Common::Rect(_texture->width, _texture->height);
|
||||
|
||||
_vm->_gfx->drawTexturedRect2D(bottomBorder, textureRect, _texture);
|
||||
}
|
||||
|
||||
|
@ -460,4 +468,26 @@ void Subtitles::freeTexture() {
|
|||
}
|
||||
}
|
||||
|
||||
Common::Rect Subtitles::getPosition() const {
|
||||
Common::Rect screen = _vm->_gfx->viewport();
|
||||
|
||||
Common::Rect frame;
|
||||
|
||||
if (_vm->isWideScreenModEnabled()) {
|
||||
frame = Common::Rect(screen.width(), Renderer::kBottomBorderHeight);
|
||||
frame.translate(0, screen.height() - frame.height());
|
||||
} else {
|
||||
frame = Common::Rect(screen.width(), screen.height() * Renderer::kBottomBorderHeight / Renderer::kOriginalHeight);
|
||||
frame.translate(screen.left, screen.top + screen.height() * (Renderer::kTopBorderHeight + Renderer::kFrameHeight) / Renderer::kOriginalHeight);
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
Common::Rect Subtitles::getOriginalPosition() const {
|
||||
Common::Rect originalPosition = Common::Rect(Renderer::kOriginalWidth, Renderer::kBottomBorderHeight);
|
||||
originalPosition.translate(0, Renderer::kTopBorderHeight + Renderer::kFrameHeight);
|
||||
return originalPosition;
|
||||
}
|
||||
|
||||
} // End of namespace Myst3
|
||||
|
|
|
@ -32,11 +32,15 @@ namespace Myst3 {
|
|||
class Myst3Engine;
|
||||
class DirectorySubEntry;
|
||||
|
||||
class Subtitles : public Drawable {
|
||||
class Subtitles : public Window {
|
||||
public:
|
||||
static Subtitles *create(Myst3Engine *vm, uint32 id);
|
||||
virtual ~Subtitles();
|
||||
|
||||
// Window API
|
||||
Common::Rect getPosition() const override;
|
||||
Common::Rect getOriginalPosition() const override;
|
||||
|
||||
void setFrame(int32 frame);
|
||||
void drawOverlay() override;
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "common/events.h"
|
||||
#include "common/config-manager.h"
|
||||
|
||||
#include "engines/myst3/transition.h"
|
||||
|
@ -97,9 +98,12 @@ void Transition::draw(TransitionType type) {
|
|||
int startTick = _vm->_state->getTickCount();
|
||||
uint endTick = startTick + durationTicks;
|
||||
|
||||
// Draw on the full screen
|
||||
_vm->_gfx->selectTargetWindow(nullptr, false, false);
|
||||
|
||||
// Draw each step until completion
|
||||
int completion = 0;
|
||||
while (_vm->_state->getTickCount() <= endTick || completion < 100) {
|
||||
while ((_vm->_state->getTickCount() <= endTick || completion < 100) && !_vm->shouldQuit()) {
|
||||
_frameLimiter->startFrame();
|
||||
|
||||
completion = CLIP<int>(100 * (_vm->_state->getTickCount() - startTick) / durationTicks, 0, 100);
|
||||
|
@ -110,6 +114,12 @@ void Transition::draw(TransitionType type) {
|
|||
_frameLimiter->delayBeforeSwap();
|
||||
g_system->updateScreen();
|
||||
_vm->_state->updateFrameCounters();
|
||||
|
||||
Common::Event event;
|
||||
while (_vm->getEventManager()->pollEvent(event)) {
|
||||
// Ignore all the events happening during transitions, so that the view does not move
|
||||
// between the initial transition screen shoot and the first frame drawn after the transition.
|
||||
}
|
||||
}
|
||||
|
||||
_vm->_gfx->freeTexture(sourceTexture);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue