diff --git a/engines/myst3/movie.cpp b/engines/myst3/movie.cpp index e682ce73c63..d15e70e5d00 100644 --- a/engines/myst3/movie.cpp +++ b/engines/myst3/movie.cpp @@ -24,6 +24,8 @@ #include "engines/myst3/myst3.h" #include "engines/myst3/state.h" +#include "graphics/colormasks.h" + namespace Myst3 { Movie::Movie(Myst3Engine *vm, uint16 id) : @@ -294,4 +296,57 @@ bool SimpleMovie::update() { SimpleMovie::~SimpleMovie() { } +ProjectorMovie::ProjectorMovie(Myst3Engine *vm, uint16 id, Graphics::Surface *background) : + ScriptedMovie(vm, id), + _background(background), + _frame(0) { + _enabled = true; +} + +ProjectorMovie::~ProjectorMovie() { + if (_frame) { + _frame->free(); + delete _frame; + } + + if (_background) { + _background->free(); + delete _background; + } +} + +void ProjectorMovie::update() { + if (!_frame) { + // First call, get the alpha channel from the bink file + const Graphics::Surface *frame = _bink.decodeNextFrame(); + _frame = new Graphics::Surface(); + _frame->copyFrom(*frame); + } + + uint16 _backgroundX = _vm->_state->getProjectorX() / 10 - _frame->w / 2; + uint16 _backgroundY = _vm->_state->getProjectorY() / 10 - _frame->h / 2; + + for (uint i = 0; i < _frame->h; i++) { + uint32 *src = (uint32 *)_background->getBasePtr(_backgroundX, _backgroundY + i); + uint32 *dst = (uint32 *)_frame->getBasePtr(0, i); + for (uint j = 0; j < _frame->w; j++) { + uint8 a, r, g, b; + + // Keep the alpha channel from the previous frame + Graphics::colorToARGB< Graphics::ColorMasks<8888> >(*dst, a, r, g, b); + + // Get the colors from the background + Graphics::colorToRGB< Graphics::ColorMasks<8888> >(*src++, r, g, b); + + // Draw the new frame + *dst++ = Graphics::ARGBToColor< Graphics::ColorMasks<8888> >(a, r, g, b); + } + } + + if (_texture) + _texture->update(_frame); + else + _texture = _vm->_gfx->createTexture(_frame); +} + } /* namespace Myst3 */ diff --git a/engines/myst3/movie.h b/engines/myst3/movie.h index 902a00aba57..9d78eedcdd6 100644 --- a/engines/myst3/movie.h +++ b/engines/myst3/movie.h @@ -79,7 +79,7 @@ public: virtual ~ScriptedMovie(); void draw(); - void update(); + virtual void update(); void setEndFrameVar(uint16 v) { _endFrameVar = v; } void setNextFrameReadVar(uint16 v) { _nextFrameReadVar = v; } @@ -97,7 +97,7 @@ public: void setScriptDriven(bool b) { _scriptDriven = b; } void setForce2d(bool b) { _force2d = b; } -private: +protected: bool _enabled; bool _loop; bool _disableWhenComplete; @@ -130,5 +130,18 @@ private: bool _synchronized; }; +// Used by the projectors on J'nanin, see puzzle #14 +class ProjectorMovie : public ScriptedMovie { +public: + ProjectorMovie(Myst3Engine *vm, uint16 id, Graphics::Surface *background); + virtual ~ProjectorMovie(); + + void update(); + +private: + Graphics::Surface *_background; + Graphics::Surface *_frame; +}; + } /* namespace Myst3 */ #endif /* MOVIE_H_ */ diff --git a/engines/myst3/myst3.cpp b/engines/myst3/myst3.cpp index 038792e0b34..7db110ffc86 100644 --- a/engines/myst3/myst3.cpp +++ b/engines/myst3/myst3.cpp @@ -54,7 +54,7 @@ Myst3Engine::Myst3Engine(OSystem *syst, int gameFlags) : _state(0), _node(0), _scene(0), _archiveNode(0), _cursor(0), _inventory(0), _gfx(0), _menu(0), _rnd(0), _shouldQuit(false), - _menuAction(0) { + _menuAction(0), _projectorBackground(0) { DebugMan.addDebugChannel(kDebugVariable, "Variable", "Track Variable Accesses"); DebugMan.addDebugChannel(kDebugSaveLoad, "SaveLoad", "Track Save/Load Function"); DebugMan.addDebugChannel(kDebugScript, "Script", "Track Script Execution"); @@ -498,7 +498,16 @@ void Myst3Engine::runScriptsFromNode(uint16 nodeID, uint32 roomID, uint32 ageID) } void Myst3Engine::loadMovie(uint16 id, uint16 condition, bool resetCond, bool loop) { - ScriptedMovie *movie = new ScriptedMovie(this, id); + ScriptedMovie *movie; + + if (!_state->getMovieUseBackground()) { + movie = new ScriptedMovie(this, id); + } else { + movie = new ProjectorMovie(this, id, _projectorBackground); + _projectorBackground = 0; + _state->setMovieUseBackground(0); + } + movie->setCondition(condition); movie->setDisableWhenComplete(resetCond); movie->setLoop(loop); diff --git a/engines/myst3/myst3.h b/engines/myst3/myst3.h index 3be84aabbe3..99bf5b1b0b9 100644 --- a/engines/myst3/myst3.h +++ b/engines/myst3/myst3.h @@ -77,6 +77,9 @@ public: Common::RandomSource *_rnd; + // Used by the projectors on J'nanin, see puzzle #14 + Graphics::Surface *_projectorBackground; + Myst3Engine(OSystem *syst, int gameFlags); virtual ~Myst3Engine(); diff --git a/engines/myst3/puzzles.cpp b/engines/myst3/puzzles.cpp index 862893b9720..ad7fcf989d7 100644 --- a/engines/myst3/puzzles.cpp +++ b/engines/myst3/puzzles.cpp @@ -42,8 +42,11 @@ void Puzzles::run(uint16 id, uint16 arg0, uint16 arg1, uint16 arg3) { case 9: journalAtrus(arg0, arg1); break; + case 14: + projectorLoadBitmap(arg0); + break; case 16: - projector(); + projectorUpdateCoordinates(); break; case 20: saveLoadMenu(arg0, arg1); @@ -206,7 +209,36 @@ void Puzzles::saveLoadMenu(uint16 action, uint16 item) { } } -void Puzzles::projector() { +static void copySurfaceRect(Graphics::Surface *dest, const Common::Point &destPoint, const Graphics::Surface *src) { + for (uint16 i = 0; i < src->h; i++) + memcpy(dest->getBasePtr(destPoint.x, i + destPoint.y), src->getBasePtr(0, i), src->pitch); +} + +void Puzzles::projectorLoadBitmap(uint16 bitmap) { + assert(_vm->_projectorBackground == 0 && "Previous background not yet used."); + + // This surface is freed by the destructor of the movie that uses it + _vm->_projectorBackground = new Graphics::Surface(); + _vm->_projectorBackground->create(1024, 1024, Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24)); + + const DirectorySubEntry *movieDesc = _vm->getFileDescription(0, bitmap, 0, DirectorySubEntry::kStillMovie); + + if (!movieDesc) + error("Movie %d does not exist", bitmap); + + // Rebuild the complete background image from the frames of the bink movie + Common::MemoryReadStream *movieStream = movieDesc->getData(); + Video::SeekableBinkDecoder bink; + bink.loadStream(movieStream, Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24)); + + for (uint i = 0; i < 1024; i += 256) + for (uint j = 0; j < 1024; j += 256) { + const Graphics::Surface *frame = bink.decodeNextFrame(); + copySurfaceRect(_vm->_projectorBackground, Common::Point(j, i), frame); + } +} + +void Puzzles::projectorUpdateCoordinates() { int16 x = CLIP(_vm->_state->getProjectorX(), 840, 9400); int16 y = CLIP(_vm->_state->getProjectorY(), 840, 9400); int16 zoom = CLIP(_vm->_state->getProjectorZoom(), 1280, 5120); diff --git a/engines/myst3/puzzles.h b/engines/myst3/puzzles.h index c5177155270..667967916b9 100644 --- a/engines/myst3/puzzles.h +++ b/engines/myst3/puzzles.h @@ -1,23 +1,23 @@ -/* ResidualVM - A 3D game interpreter - * - * ResidualVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the AUTHORS - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * +/* ResidualVM - A 3D game interpreter + * + * ResidualVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the AUTHORS + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * */ #ifndef PUZZLES_H_ @@ -25,6 +25,8 @@ #include "common/scummsys.h" +#include "graphics/surface.h" + namespace Myst3 { class Myst3Engine; @@ -45,10 +47,11 @@ private: bool _journalSaavedroHasChapter(uint16 chapter); uint16 _journalSaavedroNextChapter(uint16 chapter, bool forward); - void journalAtrus(uint16 node, uint16 var); - void mainMenu(uint16 action); - void saveLoadMenu(uint16 action, uint16 item); - void projector(); + void journalAtrus(uint16 node, uint16 var); + void mainMenu(uint16 action); + void saveLoadMenu(uint16 action, uint16 item); + void projectorLoadBitmap(uint16 bitmap); + void projectorUpdateCoordinates(); }; } /* namespace Myst3 */ diff --git a/engines/myst3/state.cpp b/engines/myst3/state.cpp index 97624ecf940..caa14ea58a5 100644 --- a/engines/myst3/state.cpp +++ b/engines/myst3/state.cpp @@ -95,7 +95,7 @@ GameState::GameState(Myst3Engine *vm): VAR(172, MovieUnk172, true) VAR(173, MoviePlayingVar, true) - VAR(178, MovieUnk178, true) + VAR(178, MovieUseBackground, false) VAR(189, LocationNextNode, false) VAR(190, LocationNextRoom, false) diff --git a/engines/myst3/state.h b/engines/myst3/state.h index e45fb32194c..82dabd067e5 100644 --- a/engines/myst3/state.h +++ b/engines/myst3/state.h @@ -109,6 +109,8 @@ public: DECLARE_VAR(168, MovieOverridePosV) DECLARE_VAR(173, MoviePlayingVar) + DECLARE_VAR(178, MovieUseBackground) + DECLARE_VAR(189, LocationNextNode) DECLARE_VAR(190, LocationNextRoom) DECLARE_VAR(191, LocationNextAge)