MYST3: Initial version of the widescreen mod

This commit is contained in:
Bastien Bouclet 2015-05-02 08:42:01 +02:00
parent 1537ec2de2
commit 19a8b11d85
28 changed files with 608 additions and 187 deletions

View file

@ -1,2 +1,2 @@
engines/myst3/detection.cpp
engines/myst3/myst3.cpp

View file

@ -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() {

View file

@ -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:

View file

@ -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;
}

View file

@ -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),

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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();

View file

@ -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;

View file

@ -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),

View file

@ -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);

View file

@ -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);

View file

@ -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();

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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);
};

View file

@ -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

View file

@ -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;

View file

@ -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);