diff --git a/engines/zvision/graphics/render_manager.cpp b/engines/zvision/graphics/render_manager.cpp index a1cc8ac53c8e..4a43e09b079f 100644 --- a/engines/zvision/graphics/render_manager.cpp +++ b/engines/zvision/graphics/render_manager.cpp @@ -42,28 +42,25 @@ namespace ZVision { RenderManager::RenderManager(ZVision *engine, uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow, const Graphics::PixelFormat pixelFormat, bool doubleFPS) : _engine(engine), _system(engine->_system), - _workingWidth(workingWindow.width()), - _workingHeight(workingWindow.height()), - _screenCenterX(_workingWidth / 2), - _screenCenterY(_workingHeight / 2), + _screenCenterX(_workingWindow.width() / 2), + _screenCenterY(_workingWindow.height() / 2), _workingWindow(workingWindow), _pixelFormat(pixelFormat), _backgroundWidth(0), _backgroundHeight(0), _backgroundOffset(0), - _renderTable(_workingWidth, _workingHeight), - _doubleFPS(doubleFPS) { + _renderTable(_workingWindow.width(), _workingWindow.height()), + _doubleFPS(doubleFPS), + _subid(0) { - _backgroundSurface.create(_workingWidth, _workingHeight, _pixelFormat); - _effectSurface.create(_workingWidth, _workingHeight, _pixelFormat); - _warpedSceneSurface.create(_workingWidth, _workingHeight, _pixelFormat); + _backgroundSurface.create(_workingWindow.width(), _workingWindow.height(), _pixelFormat); + _effectSurface.create(_workingWindow.width(), _workingWindow.height(), _pixelFormat); + _warpedSceneSurface.create(_workingWindow.width(), _workingWindow.height(), _pixelFormat); _menuSurface.create(windowWidth, workingWindow.top, _pixelFormat); - _subtitleSurface.create(windowWidth, windowHeight - workingWindow.bottom, _pixelFormat); - + _menuArea = Common::Rect(0, 0, windowWidth, workingWindow.top); - _subtitleArea = Common::Rect(0, workingWindow.bottom, windowWidth, windowHeight); - _subid = 0; + initSubArea(windowWidth, windowHeight, workingWindow); } RenderManager::~RenderManager() { @@ -83,7 +80,7 @@ void RenderManager::renderSceneToScreen() { // If we have graphical effects, we apply them using a temporary buffer if (!_effects.empty()) { bool copied = false; - Common::Rect windowRect(_workingWidth, _workingHeight); + Common::Rect windowRect(_workingWindow.width(), _workingWindow.height()); for (EffectsList::iterator it = _effects.begin(); it != _effects.end(); it++) { Common::Rect rect = (*it)->getRegion(); @@ -121,7 +118,7 @@ void RenderManager::renderSceneToScreen() { if (!_backgroundSurfaceDirtyRect.isEmpty()) { _renderTable.mutateImage(&_warpedSceneSurface, in); out = &_warpedSceneSurface; - outWndDirtyRect = Common::Rect(_workingWidth, _workingHeight); + outWndDirtyRect = Common::Rect(_workingWindow.width(), _workingWindow.height()); } } else { out = in; @@ -590,7 +587,7 @@ void RenderManager::prepareBackground() { if (state == RenderTable::PANORAMA) { // Calculate the visible portion of the background - Common::Rect viewPort(_workingWidth, _workingHeight); + Common::Rect viewPort(_workingWindow.width(), _workingWindow.height()); viewPort.translate(-(_screenCenterX - _backgroundOffset), 0); Common::Rect drawRect = _backgroundDirtyRect; drawRect.clip(viewPort); @@ -635,7 +632,7 @@ void RenderManager::prepareBackground() { } } else if (state == RenderTable::TILT) { // Tilt doesn't allow wrapping, so we just do a simple clip - Common::Rect viewPort(_workingWidth, _workingHeight); + Common::Rect viewPort(_workingWindow.width(), _workingWindow.height()); viewPort.translate(0, -(_screenCenterY - _backgroundOffset)); Common::Rect drawRect = _backgroundDirtyRect; drawRect.clip(viewPort); @@ -655,7 +652,7 @@ void RenderManager::prepareBackground() { // Clear the dirty rect since everything is clean now _backgroundDirtyRect = Common::Rect(); - _backgroundSurfaceDirtyRect.clip(_workingWidth, _workingHeight); + _backgroundSurfaceDirtyRect.clip(_workingWindow.width(), _workingWindow.height()); } void RenderManager::clearMenuSurface() { @@ -687,6 +684,15 @@ void RenderManager::renderMenuToScreen() { } } +void RenderManager::initSubArea(uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow) { + _workingWindow = workingWindow; + + _subtitleSurface.free(); + + _subtitleSurface.create(windowWidth, windowHeight - workingWindow.bottom, _pixelFormat); + _subtitleArea = Common::Rect(0, workingWindow.bottom, windowWidth, windowHeight); +} + uint16 RenderManager::createSubArea(const Common::Rect &area) { _subid++; @@ -791,8 +797,8 @@ Common::Rect RenderManager::transformBackgroundSpaceRectToScreenSpace(const Comm if (state == RenderTable::PANORAMA) { if (_backgroundOffset < _screenCenterX) { - Common::Rect rScreen(_screenCenterX + _backgroundOffset, _workingHeight); - Common::Rect lScreen(_workingWidth - rScreen.width(), _workingHeight); + Common::Rect rScreen(_screenCenterX + _backgroundOffset, _workingWindow.height()); + Common::Rect lScreen(_workingWindow.width() - rScreen.width(), _workingWindow.height()); lScreen.translate(_backgroundWidth - lScreen.width(), 0); lScreen.clip(src); rScreen.clip(src); @@ -802,8 +808,8 @@ Common::Rect RenderManager::transformBackgroundSpaceRectToScreenSpace(const Comm tmp.translate(_screenCenterX - _backgroundOffset, 0); } } else if (_backgroundWidth - _backgroundOffset < _screenCenterX) { - Common::Rect rScreen(_screenCenterX - (_backgroundWidth - _backgroundOffset), _workingHeight); - Common::Rect lScreen(_workingWidth - rScreen.width(), _workingHeight); + Common::Rect rScreen(_screenCenterX - (_backgroundWidth - _backgroundOffset), _workingWindow.height()); + Common::Rect lScreen(_workingWindow.width() - rScreen.width(), _workingWindow.height()); lScreen.translate(_backgroundWidth - lScreen.width(), 0); lScreen.clip(src); rScreen.clip(src); @@ -1172,4 +1178,11 @@ void RenderManager::rotateTo(int16 _toPos, int16 _time) { _engine->startClock(); } +void RenderManager::upscaleRect(Common::Rect &rect) { + rect.top = rect.top * HIRES_WINDOW_HEIGHT / WINDOW_HEIGHT; + rect.left = rect.left * HIRES_WINDOW_WIDTH / WINDOW_WIDTH; + rect.bottom = rect.bottom * HIRES_WINDOW_HEIGHT / WINDOW_HEIGHT; + rect.right = rect.right * HIRES_WINDOW_WIDTH / WINDOW_WIDTH; +} + } // End of namespace ZVision diff --git a/engines/zvision/graphics/render_manager.h b/engines/zvision/graphics/render_manager.h index 6081e982f927..e3cbbc34ce4f 100644 --- a/engines/zvision/graphics/render_manager.h +++ b/engines/zvision/graphics/render_manager.h @@ -73,12 +73,8 @@ class RenderManager { * are given in this coordinate space. Also, all images are clipped to the * edges of this Rectangle */ - const Common::Rect _workingWindow; + Common::Rect _workingWindow; - // Width of the working window. Saved to prevent extraneous calls to _workingWindow.width() - const int _workingWidth; - // Height of the working window. Saved to prevent extraneous calls to _workingWindow.height() - const int _workingHeight; // Center of the screen in the x direction const int _screenCenterX; // Center of the screen in the y direction @@ -241,6 +237,8 @@ class RenderManager { // Subtitles methods + void initSubArea(uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow); + // Create subtitle area and return ID uint16 createSubArea(const Common::Rect &area); uint16 createSubArea(); @@ -334,6 +332,8 @@ class RenderManager { void checkBorders(); void rotateTo(int16 to, int16 time); void updateRotation(); + + void upscaleRect(Common::Rect &rect); }; } // End of namespace ZVision diff --git a/engines/zvision/scripting/actions.cpp b/engines/zvision/scripting/actions.cpp index f60fdbb97322..e3fc6fa54921 100644 --- a/engines/zvision/scripting/actions.cpp +++ b/engines/zvision/scripting/actions.cpp @@ -912,7 +912,15 @@ ActionStreamVideo::ActionStreamVideo(ZVision *engine, int32 slotkey, const Commo bool ActionStreamVideo::execute() { Video::VideoDecoder *decoder; Common::Rect destRect = Common::Rect(_x1, _y1, _x2 + 1, _y2 + 1); + Common::String subname = _fileName; + subname.setChar('s', subname.size() - 3); + subname.setChar('u', subname.size() - 2); + subname.setChar('b', subname.size() - 1); + bool subtitleExists = _engine->getSearchManager()->hasFile(subname); + bool switchToHires = false; +// NOTE: We only show the hires MPEG2 videos when libmpeg2 is compiled in, +// otherwise we fall back to the lowres ones #ifdef USE_MPEG2 Common::String hiresFileName = _fileName; hiresFileName.setChar('d', hiresFileName.size() - 8); @@ -920,36 +928,44 @@ bool ActionStreamVideo::execute() { hiresFileName.setChar('o', hiresFileName.size() - 2); hiresFileName.setChar('b', hiresFileName.size() - 1); - if (_engine->getScriptManager()->getStateValue(StateKey_MPEGMovies) == 1 &&_engine->getSearchManager()->hasFile(hiresFileName)) - // TODO: Enable once VOB + AC3 support is implemented - //_fileName = hiresFileName; + if (_engine->getScriptManager()->getStateValue(StateKey_MPEGMovies) == 1 &&_engine->getSearchManager()->hasFile(hiresFileName)) { + // TODO: Enable once AC3 support is implemented + if (!_engine->getSearchManager()->hasFile(_fileName)) // Check for the regular video + return true; warning("The hires videos of the DVD version of ZGI aren't supported yet, using lowres"); -#endif - - Common::String subname = _fileName; - subname.setChar('s', subname.size() - 3); - subname.setChar('u', subname.size() - 2); - subname.setChar('b', subname.size() - 1); - + //_fileName = hiresFileName; + //switchToHires = true; + } else if (!_engine->getSearchManager()->hasFile(_fileName)) + return true; +#else if (!_engine->getSearchManager()->hasFile(_fileName)) return true; +#endif decoder = _engine->loadAnimation(_fileName); + Subtitle *sub = (subtitleExists) ? new Subtitle(_engine, subname, switchToHires) : NULL; _engine->getCursorManager()->showMouse(false); - Subtitle *sub = NULL; - - if (_engine->getSearchManager()->hasFile(subname)) - sub = new Subtitle(_engine, subname); + if (switchToHires) { + _engine->initHiresScreen(); + destRect = Common::Rect(40, -40, 760, 440); + Common::Rect workingWindow = _engine->_workingWindow; + workingWindow.translate(0, -40); + _engine->getRenderManager()->initSubArea(HIRES_WINDOW_WIDTH, HIRES_WINDOW_HEIGHT, workingWindow); + } _engine->playVideo(*decoder, destRect, _skippable, sub); - delete decoder; + + if (switchToHires) { + _engine->initScreen(); + _engine->getRenderManager()->initSubArea(WINDOW_WIDTH, WINDOW_HEIGHT, _engine->_workingWindow); + } _engine->getCursorManager()->showMouse(true); - if (sub) - delete sub; + delete decoder; + delete sub; return true; } diff --git a/engines/zvision/text/subtitles.cpp b/engines/zvision/text/subtitles.cpp index acf4c37c2fb1..d549e2a0c6a2 100644 --- a/engines/zvision/text/subtitles.cpp +++ b/engines/zvision/text/subtitles.cpp @@ -27,7 +27,7 @@ namespace ZVision { -Subtitle::Subtitle(ZVision *engine, const Common::String &subname) : +Subtitle::Subtitle(ZVision *engine, const Common::String &subname, bool upscaleToHires) : _engine(engine), _areaId(-1), _subId(-1) { @@ -44,6 +44,8 @@ Subtitle::Subtitle(ZVision *engine, const Common::String &subname) : int32 x1, y1, x2, y2; sscanf(str.c_str(), "%*[^:]:%d %d %d %d", &x1, &y1, &x2, &y2); Common::Rect rct = Common::Rect(x1, y1, x2, y2); + if (upscaleToHires) + _engine->getRenderManager()->upscaleRect(rct); _areaId = _engine->getRenderManager()->createSubArea(rct); } else if (str.matchString("*TextFile*", true)) { char filename[64]; @@ -67,6 +69,11 @@ Subtitle::Subtitle(ZVision *engine, const Common::String &subname) : int32 sb; if (sscanf(str.c_str(), "%*[^:]:(%d,%d)=%d", &st, &en, &sb) == 3) { if (sb <= (int32)_subs.size()) { + if (upscaleToHires) { + // Convert from 15FPS (AVI) to 29.97FPS (VOB) + st = st * 29.97 / 15; + en = en * 29.97 / 15; + } _subs[sb].start = st; _subs[sb].stop = en; } diff --git a/engines/zvision/text/subtitles.h b/engines/zvision/text/subtitles.h index c3da6583a4c4..329339be5540 100644 --- a/engines/zvision/text/subtitles.h +++ b/engines/zvision/text/subtitles.h @@ -31,7 +31,7 @@ class ZVision; class Subtitle { public: - Subtitle(ZVision *engine, const Common::String &subname); + Subtitle(ZVision *engine, const Common::String &subname, bool upscaleToHires = false); ~Subtitle(); void process(int32 time); diff --git a/engines/zvision/video/video.cpp b/engines/zvision/video/video.cpp index 66a567abb2ac..d5ffbeb536c9 100644 --- a/engines/zvision/video/video.cpp +++ b/engines/zvision/video/video.cpp @@ -23,9 +23,7 @@ #include "common/scummsys.h" #include "common/system.h" #include "video/video_decoder.h" -// TODO: Enable once VOB + AC3 support is implemented -#if 0 -//#ifdef USE_MPEG2 +#ifdef USE_MPEG2 #include "video/mpegps_decoder.h" #endif #include "engines/util.h" @@ -50,9 +48,7 @@ Video::VideoDecoder *ZVision::loadAnimation(const Common::String &fileName) { animation = new RLFDecoder(); else if (tmpFileName.hasSuffix(".avi")) animation = new ZorkAVIDecoder(); -// TODO: Enable once VOB + AC3 support is implemented -#if 0 -//#ifdef USE_MPEG2 +#ifdef USE_MPEG2 else if (tmpFileName.hasSuffix(".vob")) animation = new Video::MPEGPSDecoder(); #endif diff --git a/engines/zvision/zvision.cpp b/engines/zvision/zvision.cpp index 5b6d63e869a6..b42906fef391 100644 --- a/engines/zvision/zvision.cpp +++ b/engines/zvision/zvision.cpp @@ -360,4 +360,10 @@ void ZVision::initScreen() { initGraphics(WINDOW_WIDTH, WINDOW_HEIGHT, true, &_screenPixelFormat); } +void ZVision::initHiresScreen() { + _renderManager->upscaleRect(_workingWindow); + + initGraphics(HIRES_WINDOW_WIDTH, HIRES_WINDOW_HEIGHT, true, &_screenPixelFormat); +} + } // End of namespace ZVision diff --git a/engines/zvision/zvision.h b/engines/zvision/zvision.h index a3bcb384d125..854cd77bb87a 100644 --- a/engines/zvision/zvision.h +++ b/engines/zvision/zvision.h @@ -67,6 +67,27 @@ class TextRenderer; class Subtitle; class MidiManager; +enum { + WINDOW_WIDTH = 640, + WINDOW_HEIGHT = 480, + + HIRES_WINDOW_WIDTH = 800, + HIRES_WINDOW_HEIGHT = 600, + + // Zork nemesis working window sizes + ZNM_WORKING_WINDOW_WIDTH = 512, + ZNM_WORKING_WINDOW_HEIGHT = 320, + + // ZGI working window sizes + ZGI_WORKING_WINDOW_WIDTH = 640, + ZGI_WORKING_WINDOW_HEIGHT = 344, + + ROTATION_SCREEN_EDGE_OFFSET = 60, + MAX_ROTATION_SPEED = 400, // Pixels per second + + KEYBUF_SIZE = 20 +}; + class ZVision : public Engine { public: ZVision(OSystem *syst, const ZVisionGameDescription *gameDesc); @@ -83,24 +104,6 @@ class ZVision : public Engine { const Graphics::PixelFormat _screenPixelFormat; private: - enum { - WINDOW_WIDTH = 640, - WINDOW_HEIGHT = 480, - - // Zork nemesis working window sizes - ZNM_WORKING_WINDOW_WIDTH = 512, - ZNM_WORKING_WINDOW_HEIGHT = 320, - - // ZGI working window sizes - ZGI_WORKING_WINDOW_WIDTH = 640, - ZGI_WORKING_WINDOW_HEIGHT = 344, - - ROTATION_SCREEN_EDGE_OFFSET = 60, - MAX_ROTATION_SPEED = 400, // Pixels per second - - KEYBUF_SIZE = 20 - }; - Console *_console; const ZVisionGameDescription *_gameDescription; @@ -195,6 +198,7 @@ class ZVision : public Engine { } void initScreen(); + void initHiresScreen(); /** * Play a video until it is finished. This is a blocking call. It will call