mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-16 06:39:17 +00:00
PEGASUS: Implement screen fading
This does linear instead of gamma for speed and complexity reasons.
This commit is contained in:
parent
91efe792d5
commit
3860f34136
@ -30,6 +30,7 @@
|
||||
|
||||
#include "pegasus/elements.h"
|
||||
#include "pegasus/graphics.h"
|
||||
#include "pegasus/transition.h"
|
||||
|
||||
namespace Pegasus {
|
||||
|
||||
@ -46,10 +47,13 @@ GraphicsManager::GraphicsManager(PegasusEngine *vm) : _vm(vm) {
|
||||
_modifiedScreen = false;
|
||||
_curSurface = &_workArea;
|
||||
_erase = false;
|
||||
_updatesEnabled = true;
|
||||
_screenFader = new ScreenFader();
|
||||
}
|
||||
|
||||
GraphicsManager::~GraphicsManager() {
|
||||
_workArea.free();
|
||||
delete _screenFader;
|
||||
}
|
||||
|
||||
void GraphicsManager::invalRect(const Common::Rect &rect) {
|
||||
@ -175,7 +179,7 @@ void GraphicsManager::updateDisplay() {
|
||||
_dirtyRect = Common::Rect();
|
||||
}
|
||||
|
||||
if (screenDirty || _modifiedScreen)
|
||||
if (_updatesEnabled && (screenDirty || _modifiedScreen))
|
||||
g_system->updateScreen();
|
||||
|
||||
_modifiedScreen = false;
|
||||
@ -200,19 +204,14 @@ DisplayElement *GraphicsManager::findDisplayElement(const DisplayElementID id) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GraphicsManager::doFadeOutSync(const TimeValue, const TimeValue, uint32 color) {
|
||||
if (color == 0)
|
||||
color = g_system->getScreenFormat().RGBToColor(0, 0, 0);
|
||||
|
||||
// HACK: Until fading out is done, white-out the screen here
|
||||
Graphics::Surface *screen = g_system->lockScreen();
|
||||
screen->fillRect(Common::Rect(0, 0, 640, 480), color);
|
||||
g_system->unlockScreen();
|
||||
g_system->updateScreen();
|
||||
void GraphicsManager::doFadeOutSync(const TimeValue time, const TimeScale scale, uint32 color) {
|
||||
_updatesEnabled = false;
|
||||
_screenFader->doFadeOutSync(time, scale, color == 0);
|
||||
}
|
||||
|
||||
void GraphicsManager::doFadeInSync(const TimeValue, const TimeValue, uint32) {
|
||||
// TODO
|
||||
void GraphicsManager::doFadeInSync(const TimeValue time, const TimeScale scale, uint32 color) {
|
||||
_screenFader->doFadeInSync(time, scale, color == 0);
|
||||
_updatesEnabled = true;
|
||||
}
|
||||
|
||||
void GraphicsManager::markCursorAsDirty() {
|
||||
@ -333,5 +332,15 @@ void GraphicsManager::enableErase() {
|
||||
void GraphicsManager::disableErase() {
|
||||
_erase = false;
|
||||
}
|
||||
|
||||
|
||||
void GraphicsManager::enableUpdates() {
|
||||
_updatesEnabled = true;
|
||||
_screenFader->setFaderValue(100);
|
||||
}
|
||||
|
||||
void GraphicsManager::disableUpdates() {
|
||||
_updatesEnabled = false;
|
||||
_screenFader->setFaderValue(0);
|
||||
}
|
||||
|
||||
} // End of namespace Pegasus
|
||||
|
@ -40,6 +40,7 @@ namespace Pegasus {
|
||||
class Cursor;
|
||||
class DisplayElement;
|
||||
class PegasusEngine;
|
||||
class ScreenFader;
|
||||
|
||||
class GraphicsManager {
|
||||
friend class Cursor;
|
||||
@ -61,6 +62,8 @@ public:
|
||||
void shakeTheWorld(TimeValue time, TimeScale scale);
|
||||
void enableErase();
|
||||
void disableErase();
|
||||
void enableUpdates();
|
||||
void disableUpdates();
|
||||
|
||||
// These default to black
|
||||
void doFadeOutSync(const TimeValue = kOneSecondPerThirtyTicks, const TimeScale = kThirtyTicksPerSecond, uint32 color = 0);
|
||||
@ -82,6 +85,9 @@ private:
|
||||
static const int kMaxShakeOffsets = 17;
|
||||
Common::Point _shakeOffsets[kMaxShakeOffsets];
|
||||
void newShakePoint(int32 index1, int32 index2, int32 maxRadius);
|
||||
|
||||
bool _updatesEnabled;
|
||||
ScreenFader *_screenFader;
|
||||
};
|
||||
|
||||
} // End of namespace Pegasus
|
||||
|
@ -237,10 +237,7 @@ void MainMenu::startMainMenuLoop() {
|
||||
|
||||
_menuLoop.loopSound();
|
||||
spec.makeTwoKnotFaderSpec(30, 0, 0, 30, 255);
|
||||
|
||||
// FIXME: Should be sync, but it's a pain to use the main menu right now
|
||||
// with this one.
|
||||
_menuFader.startFader(spec);
|
||||
_menuFader.startFaderSync(spec);
|
||||
}
|
||||
|
||||
void MainMenu::stopMainMenuLoop() {
|
||||
|
@ -204,17 +204,24 @@ void Caldoria::start() {
|
||||
if (!pullbackMovie->loadFile("Images/Caldoria/Pullback.movie"))
|
||||
error("Could not load pullback movie");
|
||||
|
||||
bool skipped = false;
|
||||
Input input;
|
||||
|
||||
// Draw the first frame so we can fade to it
|
||||
pullbackMovie->pauseVideo(true);
|
||||
const Graphics::Surface *frame = pullbackMovie->decodeNextFrame();
|
||||
assert(frame);
|
||||
assert(frame->format == g_system->getScreenFormat());
|
||||
g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, 64, 112, frame->w, frame->h);
|
||||
_vm->_gfx->doFadeInSync(kTwoSeconds * kFifteenTicksPerSecond, kFifteenTicksPerSecond);
|
||||
pullbackMovie->pauseVideo(false);
|
||||
|
||||
bool saveAllowed = _vm->swapSaveAllowed(false);
|
||||
bool openAllowed = _vm->swapLoadAllowed(false);
|
||||
|
||||
bool skipped = false;
|
||||
Input input;
|
||||
|
||||
while (!_vm->shouldQuit() && !pullbackMovie->endOfVideo()) {
|
||||
if (pullbackMovie->needsUpdate()) {
|
||||
const Graphics::Surface *frame = pullbackMovie->decodeNextFrame();
|
||||
frame = pullbackMovie->decodeNextFrame();
|
||||
|
||||
if (frame) {
|
||||
g_system->copyRectToScreen((byte *)frame->pixels, frame->pitch, 64, 112, frame->w, frame->h);
|
||||
@ -233,6 +240,9 @@ void Caldoria::start() {
|
||||
|
||||
delete pullbackMovie;
|
||||
|
||||
if (_vm->shouldQuit())
|
||||
return;
|
||||
|
||||
_vm->swapSaveAllowed(saveAllowed);
|
||||
_vm->swapLoadAllowed(openAllowed);
|
||||
|
||||
@ -240,11 +250,8 @@ void Caldoria::start() {
|
||||
|
||||
if (!skipped) {
|
||||
uint32 white = g_system->getScreenFormat().RGBToColor(0xff, 0xff, 0xff);
|
||||
|
||||
_vm->_gfx->doFadeOutSync(kThreeSeconds * kFifteenTicksPerSecond, kFifteenTicksPerSecond, white);
|
||||
|
||||
g_system->delayMillis(3 * 1000 / 2);
|
||||
|
||||
getExtraEntry(kCaldoria00WakeUp1, entry);
|
||||
_navMovie.setTime(entry.movieStart);
|
||||
_navMovie.redrawMovieWorld();
|
||||
|
@ -1479,6 +1479,7 @@ void PegasusEngine::startNewGame() {
|
||||
_gfx->doFadeOutSync();
|
||||
useMenu(0);
|
||||
_gfx->updateDisplay();
|
||||
_gfx->enableUpdates();
|
||||
|
||||
createInterface();
|
||||
|
||||
|
@ -24,43 +24,92 @@
|
||||
*/
|
||||
|
||||
#include "common/system.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "pegasus/transition.h"
|
||||
|
||||
namespace Pegasus {
|
||||
|
||||
ScreenFader::ScreenFader() {
|
||||
_fadeTarget = getBlack();
|
||||
_isBlack = true;
|
||||
// Initially, assume screens are on at full brightness.
|
||||
Fader::setFaderValue(100);
|
||||
_screen = new Graphics::Surface();
|
||||
}
|
||||
|
||||
void ScreenFader::doFadeOutSync(const TimeValue duration, const TimeValue scale, const uint32 fadeTarget) {
|
||||
_fadeTarget = fadeTarget;
|
||||
ScreenFader::~ScreenFader() {
|
||||
_screen->free();
|
||||
delete _screen;
|
||||
}
|
||||
|
||||
void ScreenFader::doFadeOutSync(const TimeValue duration, const TimeValue scale, bool isBlack) {
|
||||
_isBlack = isBlack;
|
||||
_screen->copyFrom(*g_system->lockScreen());
|
||||
g_system->unlockScreen();
|
||||
|
||||
FaderMoveSpec spec;
|
||||
spec.makeTwoKnotFaderSpec(scale, 0, getFaderValue(), duration, 0);
|
||||
startFaderSync(spec);
|
||||
|
||||
_screen->free();
|
||||
}
|
||||
|
||||
void ScreenFader::doFadeInSync(const TimeValue duration, const TimeValue scale, const uint32 fadeTarget) {
|
||||
_fadeTarget = fadeTarget;
|
||||
void ScreenFader::doFadeInSync(const TimeValue duration, const TimeValue scale, bool isBlack) {
|
||||
_isBlack = isBlack;
|
||||
_screen->copyFrom(*g_system->lockScreen());
|
||||
g_system->unlockScreen();
|
||||
|
||||
FaderMoveSpec spec;
|
||||
spec.makeTwoKnotFaderSpec(scale, 0, getFaderValue(), duration, 100);
|
||||
startFaderSync(spec);
|
||||
|
||||
_screen->free();
|
||||
}
|
||||
|
||||
void ScreenFader::setFaderValue(const int32 value) {
|
||||
if (value != getFaderValue()) {
|
||||
Fader::setFaderValue(value);
|
||||
|
||||
// TODO: Gamma fading
|
||||
if (_screen->pixels) {
|
||||
// The original game does a gamma fade here using the Mac API. In order to do
|
||||
// that, it would require an immense amount of CPU processing. This does a
|
||||
// linear fade instead, which looks fairly well, IMO.
|
||||
Graphics::Surface *screen = g_system->lockScreen();
|
||||
|
||||
for (uint y = 0; y < _screen->h; y++) {
|
||||
for (uint x = 0; x < _screen->w; x++) {
|
||||
if (_screen->format.bytesPerPixel == 2)
|
||||
WRITE_UINT16(screen->getBasePtr(x, y), fadePixel(READ_UINT16(_screen->getBasePtr(x, y)), value));
|
||||
else
|
||||
WRITE_UINT32(screen->getBasePtr(x, y), fadePixel(READ_UINT32(_screen->getBasePtr(x, y)), value));
|
||||
}
|
||||
}
|
||||
|
||||
g_system->unlockScreen();
|
||||
g_system->updateScreen();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 ScreenFader::getBlack() {
|
||||
return g_system->getScreenFormat().RGBToColor(0, 0, 0);
|
||||
static inline byte fadeComponent(byte comp, int32 percent) {
|
||||
return comp * percent / 100;
|
||||
}
|
||||
|
||||
uint32 ScreenFader::fadePixel(uint32 color, int32 percent) const {
|
||||
byte r, g, b;
|
||||
g_system->getScreenFormat().colorToRGB(color, r, g, b);
|
||||
|
||||
if (_isBlack) {
|
||||
r = fadeComponent(r, percent);
|
||||
g = fadeComponent(g, percent);
|
||||
b = fadeComponent(b, percent);
|
||||
} else {
|
||||
r = 0xFF - fadeComponent(0xFF - r, percent);
|
||||
g = 0xFF - fadeComponent(0xFF - g, percent);
|
||||
b = 0xFF - fadeComponent(0xFF - b, percent);
|
||||
}
|
||||
|
||||
return g_system->getScreenFormat().RGBToColor(r, g, b);
|
||||
}
|
||||
|
||||
Transition::Transition(const DisplayElementID id) : FaderAnimation(id) {
|
||||
|
@ -28,23 +28,26 @@
|
||||
|
||||
#include "pegasus/fader.h"
|
||||
|
||||
namespace Graphics {
|
||||
struct Surface;
|
||||
}
|
||||
|
||||
namespace Pegasus {
|
||||
|
||||
class ScreenFader : public Fader {
|
||||
public:
|
||||
ScreenFader();
|
||||
virtual ~ScreenFader() {}
|
||||
virtual ~ScreenFader();
|
||||
|
||||
void doFadeOutSync(const TimeValue = kOneSecondPerThirtyTicks, const TimeScale = kThirtyTicksPerSecond, const uint32 = getBlack());
|
||||
void doFadeInSync(const TimeValue = kHalfSecondPerThirtyTicks, const TimeScale = kThirtyTicksPerSecond, const uint32 = getBlack());
|
||||
void doFadeOutSync(const TimeValue = kOneSecondPerThirtyTicks, const TimeScale = kThirtyTicksPerSecond, bool isBlack = true);
|
||||
void doFadeInSync(const TimeValue = kHalfSecondPerThirtyTicks, const TimeScale = kThirtyTicksPerSecond, bool isBlack = true);
|
||||
|
||||
void setFaderValue(const int32);
|
||||
|
||||
protected:
|
||||
uint32 _fadeTarget;
|
||||
void setFaderValue(const int32);
|
||||
|
||||
private:
|
||||
static uint32 getBlack();
|
||||
bool _isBlack;
|
||||
uint32 fadePixel(uint32 color, int32 percent) const;
|
||||
Graphics::Surface *_screen;
|
||||
};
|
||||
|
||||
// Transitions are faders that range over [0,1000], which makes their
|
||||
|
Loading…
Reference in New Issue
Block a user