aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/pegasus/module.mk1
-rwxr-xr-xengines/pegasus/neighborhood/norad/alpha/panorama.cpp240
-rwxr-xr-xengines/pegasus/neighborhood/norad/alpha/panorama.h98
3 files changed, 339 insertions, 0 deletions
diff --git a/engines/pegasus/module.mk b/engines/pegasus/module.mk
index eaf36b85ed..2f207eaa6e 100644
--- a/engines/pegasus/module.mk
+++ b/engines/pegasus/module.mk
@@ -78,6 +78,7 @@ MODULE_OBJS = \
neighborhood/norad/subplatform.o \
neighborhood/norad/alpha/fillingstation.o \
neighborhood/norad/alpha/noradalpha.o \
+ neighborhood/norad/alpha/panorama.o \
neighborhood/prehistoric/prehistoric.o \
neighborhood/tsa/fulltsa.o \
neighborhood/tsa/tinytsa.o \
diff --git a/engines/pegasus/neighborhood/norad/alpha/panorama.cpp b/engines/pegasus/neighborhood/norad/alpha/panorama.cpp
new file mode 100755
index 0000000000..46b21eb1d9
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/alpha/panorama.cpp
@@ -0,0 +1,240 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * 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.
+ *
+ */
+
+#include "common/macresman.h"
+#include "common/stream.h"
+#include "pegasus/neighborhood/norad/alpha/panorama.h"
+
+namespace Pegasus {
+
+Panorama::Panorama() : _panoramaMovie(kNoDisplayElement) {
+ blankFields();
+}
+
+Panorama::~Panorama() {
+ releasePanorama();
+}
+
+void Panorama::blankFields() {
+ _viewBounds = Common::Rect();
+ _drawBounds = Common::Rect();
+ _mask = 0;
+ _panoramaWidth = 0;
+ _panoramaHeight = 0;
+ _stripWidth = 0;
+ _stripLeft = -1;
+ _stripRight = -1;
+}
+
+void Panorama::releasePanorama() {
+ if (_panoramaMovie.isMovieValid()) {
+ _panoramaMovie.releaseMovie();
+ _panoramaWorld.deallocateSurface();
+ blankFields();
+ }
+}
+
+static const uint32 kPanoramaResType = MKTAG('P', 'a', 'n', 'I'); // Panorama Information.
+static const uint16 kPanoramaResID = 128;
+
+void Panorama::initFromMovieFile(const Common::String &fileName) {
+ // First, we need the resource fork for other reasons -- PanI resource
+ Common::MacResManager *resFork = new Common::MacResManager();
+ if (!resFork->open(fileName) || !resFork->hasResFork())
+ error("Could not open the resource fork of '%s'", fileName.c_str());
+
+ Common::SeekableReadStream *resource = resFork->getResource(kPanoramaResType, kPanoramaResID);
+ if (!resource)
+ error("No panorama information in the resource fork of '%s'", fileName.c_str());
+
+ _panoramaWidth = resource->readUint16BE();
+ _panoramaHeight = resource->readUint16BE();
+ _stripWidth = resource->readUint16BE();
+
+ delete resource;
+ delete resFork;
+
+ // Now we open the movie like normal
+ _panoramaMovie.initFromMovieFile(fileName);
+}
+
+void Panorama::setMask(Surface *mask) {
+ _mask = mask;
+}
+
+// If the panorama is not open, do nothing and return.
+// Otherwise, set up the view bounds.
+void Panorama::setViewBounds(const Common::Rect &newView) {
+ if (!isPanoramaOpen())
+ return;
+
+ if (newView.isEmpty())
+ return;
+
+ Common::Rect r = newView;
+
+ if (r.width() > _panoramaWidth) {
+ r.left = 0;
+ r.right = _panoramaWidth;
+ } else {
+ if (r.right > _panoramaWidth)
+ r.translate(_panoramaWidth - r.right, 0);
+
+ if (r.left < 0)
+ r.translate(-r.left, 0);
+ }
+
+ if (r.height() > _panoramaHeight) {
+ r.top = 0;
+ r.bottom = _panoramaHeight;
+ } else {
+ if (r.bottom > _panoramaHeight)
+ r.translate(0, _panoramaHeight - r.bottom);
+
+ if (r.top < 0)
+ r.translate(0, -r.top);
+ }
+
+ if (_viewBounds != r) {
+ tCoordType stripLeft = 0;
+
+ if (r.width() != _viewBounds.width() || !_panoramaWorld.isSurfaceValid()) {
+ _panoramaWorld.deallocateSurface();
+ makeNewSurface(r);
+ } else {
+ tCoordType stripRight;
+ calcStripRange(r, stripLeft, stripRight);
+ loadStrips(stripLeft, stripRight);
+ }
+
+ _viewBounds = r;
+ _drawBounds = r;
+ _drawBounds.translate(-stripLeft * _stripWidth, 0);
+ }
+}
+
+void Panorama::getViewBounds(Common::Rect &r) const {
+ r = _viewBounds;
+}
+
+void Panorama::getPanoramaBounds(Common::Rect &r) const {
+ r = Common::Rect(0, 0, _panoramaWidth, _panoramaHeight);
+}
+
+void Panorama::drawPanorama(const Common::Rect &destRect) {
+ if (_panoramaWorld.isSurfaceValid()) {
+ if (_mask)
+ _panoramaWorld.copyToCurrentPortMasked(_drawBounds, destRect, _mask);
+ else
+ _panoramaWorld.copyToCurrentPortTransparent(_drawBounds, destRect);
+ }
+}
+
+// Make a new Surface big enough to show r, which is assumed to be a valid view bounds.
+// Assumptions:
+// r is a valid view bounds.
+// _panoramaWorld is not allocated.
+// _panoramaHeight, _stripWidth is correct.
+// _panoramaMovie is allocated.
+void Panorama::makeNewSurface(const Common::Rect& view) {
+ tCoordType stripLeft, stripRight;
+ calcStripRange(view, stripLeft, stripRight);
+
+ Common::Rect r(0, 0, (stripRight - stripLeft + 1) * _stripWidth, _panoramaHeight);
+ _panoramaWorld.allocateSurface(r);
+ _panoramaMovie.shareSurface(&_panoramaWorld);
+ loadStrips(stripLeft, stripRight);
+}
+
+// Assumes view is not empty.
+void Panorama::calcStripRange(const Common::Rect &view, tCoordType &stripLeft, tCoordType &stripRight) {
+ stripLeft = view.left / _stripWidth;
+ stripRight = (view.left - view.left % _stripWidth + _stripWidth - 1 + view.width()) / _stripWidth;
+}
+
+// Load in all needed strips to put range (stripLeft, stripRight) into the
+// panorama's Surface. Try to optimize by saving any pixels already in the Surface.
+// Assumptions:
+// Surface is allocated and is big enough for maximum range of
+// stripLeft and stripRight
+void Panorama::loadStrips(tCoordType stripLeft, tCoordType stripRight) {
+ if (_stripLeft == -1) {
+ // Surface has just been allocated.
+ // Load in all strips.
+ for (tCoordType i = stripLeft; i <= stripRight; i++)
+ loadOneStrip(i, stripLeft);
+
+ _stripLeft = stripLeft;
+ _stripRight = stripRight;
+ } else if (stripLeft != _stripLeft) {
+ tCoordType overlapLeft = MAX(stripLeft, _stripLeft);
+ tCoordType overlapRight = MIN(stripRight, _stripRight);
+
+ if (overlapLeft <= overlapRight) {
+ Common::Rect r1((overlapLeft - _stripLeft) * _stripWidth, 0,
+ (overlapRight - _stripLeft + 1) * _stripWidth, _panoramaHeight);
+ Common::Rect r2 = r1;
+
+ if (stripLeft < _stripLeft) {
+ Common::Rect bounds;
+ _panoramaWorld.getSurfaceBounds(bounds);
+ _panoramaWorld.getSurface()->move(bounds.right - r1.right, 0, _panoramaHeight);
+
+ for (tCoordType i = stripLeft; i < _stripLeft; i++)
+ loadOneStrip(i, stripLeft);
+ } else {
+ _panoramaWorld.getSurface()->move(-r1.left, 0, _panoramaHeight);
+
+ for (tCoordType i = _stripRight + 1; i <= stripRight; i++)
+ loadOneStrip(i, stripLeft);
+ }
+ } else {
+ // No overlap.
+ // Load everything.
+ for (tCoordType i = stripLeft; i <= stripRight; i++)
+ loadOneStrip(i, stripLeft);
+ }
+
+ _stripLeft = stripLeft;
+ _stripRight = stripRight;
+ } else if (stripRight > _stripRight) {
+ // Need to add one or more strips.
+ for (tCoordType i = _stripRight + 1; i <= stripRight; i++)
+ loadOneStrip(i, _stripLeft);
+
+ _stripRight = stripRight;
+ } else if (stripRight < _stripRight) {
+ // Need to chop off one strip.
+ _stripRight = stripRight;
+ }
+}
+
+void Panorama::loadOneStrip(tCoordType stripToLoad, tCoordType leftStrip) {
+ _panoramaMovie.moveMovieBoxTo((stripToLoad - leftStrip) * _stripWidth, 0);
+ _panoramaMovie.setTime(stripToLoad);
+ _panoramaMovie.redrawMovieWorld();
+}
+
+} // End of namespace Pegasus
diff --git a/engines/pegasus/neighborhood/norad/alpha/panorama.h b/engines/pegasus/neighborhood/norad/alpha/panorama.h
new file mode 100755
index 0000000000..a773da9750
--- /dev/null
+++ b/engines/pegasus/neighborhood/norad/alpha/panorama.h
@@ -0,0 +1,98 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * Additional copyright for this file:
+ * Copyright (C) 1995-1997 Presto Studios, Inc.
+ *
+ * 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 PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_PANORAMA_H
+#define PEGASUS_NEIGHBORHOOD_NORAD_ALPHA_PANORAMA_H
+
+#include "pegasus/movie.h"
+
+namespace Pegasus {
+
+/*
+
+ Panorama implements a wide image using a specially constructed movie file.
+ The movie holds the image as a series of vertical strips, say 16 or 32 pixels wide.
+
+ The panorama bounds defines the entire panorama. The view bounds represents the
+ area on the panorama that is kept in memory.
+
+ The panorama bounds is also stored in the movie file; it cannot be changed. The
+ view bounds must always be a subset of the panorama bounds.
+
+ In actuality, the area kept in memory is at least as wide as the view bounds (but
+ may be wider to coincide with the width of the movies slices), and is as tall as
+ the panorama bounds. The view bounds is used by the drawPanorama function to draw
+ a piece of the panorama to the current screen.
+
+ The panorama movie is built at a time scale of 1, with each strip lasting for one
+ second, so that strip number corresponds exactly with the time value at which the
+ strip is stored.
+
+ TO USE:
+
+ Call one initFromMovieFile to open the movie. Then set up a view rect by
+ calling setViewBounds. Once these two functions have been called, drawPanorama
+ will draw the panorama.
+
+*/
+
+class Panorama {
+public:
+ Panorama();
+ virtual ~Panorama();
+
+ void initFromMovieFile(const Common::String &);
+ void releasePanorama();
+ bool isPanoramaOpen() { return _panoramaMovie.isMovieValid(); }
+
+ void setViewBounds(const Common::Rect &);
+ void getViewBounds(Common::Rect &) const;
+
+ void setMask(Surface *);
+
+ void getPanoramaBounds(Common::Rect &) const;
+
+ void drawPanorama(const Common::Rect &);
+
+protected:
+ void blankFields();
+ void makeNewSurface(const Common::Rect &);
+ void calcStripRange(const Common::Rect &, tCoordType &, tCoordType &);
+ void loadStrips(tCoordType, tCoordType);
+ void loadOneStrip(tCoordType, tCoordType);
+
+ Movie _panoramaMovie;
+ Surface _panoramaWorld, *_mask;
+ Common::Rect _viewBounds;
+ Common::Rect _drawBounds;
+ tCoordType _panoramaWidth, _panoramaHeight;
+ tCoordType _stripWidth; // Pixels per strip.
+ tCoordType _numStrips;
+ tCoordType _stripLeft, _stripRight;
+};
+
+} // End of namespace Pegasus
+
+#endif