mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-11 04:06:12 +00:00
PEGASUS: Add the panorama class
This commit is contained in:
parent
48cabb18d6
commit
dec8fcdbbd
@ -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 \
|
||||
|
240
engines/pegasus/neighborhood/norad/alpha/panorama.cpp
Executable file
240
engines/pegasus/neighborhood/norad/alpha/panorama.cpp
Executable file
@ -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
|
98
engines/pegasus/neighborhood/norad/alpha/panorama.h
Executable file
98
engines/pegasus/neighborhood/norad/alpha/panorama.h
Executable file
@ -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
|
Loading…
x
Reference in New Issue
Block a user