Initial commit
This commit is contained in:
164
engines/nancy/misc/specialeffect.cpp
Normal file
164
engines/nancy/misc/specialeffect.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
/* 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.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "engines/nancy/nancy.h"
|
||||
#include "engines/nancy/graphics.h"
|
||||
|
||||
#include "engines/nancy/misc/specialeffect.h"
|
||||
|
||||
namespace Nancy {
|
||||
namespace Misc {
|
||||
|
||||
void SpecialEffect::init() {
|
||||
if (g_nancy->getGameType() <= kGameTypeNancy6) {
|
||||
// nancy2-6 have a fixed number of frames for the effect, which is defined in the SPEC chunk
|
||||
auto *specialEffectData = GetEngineData(SPEC);
|
||||
assert(specialEffectData);
|
||||
|
||||
_numFrames = _type == kBlackout ? specialEffectData->fadeToBlackNumFrames : specialEffectData->crossDissolveNumFrames;
|
||||
_frameTime = _type == kBlackout ? specialEffectData->fadeToBlackFrameTime : _frameTime;
|
||||
|
||||
// We use the type definitions in nancy7, which are 1-indexed
|
||||
++_type;
|
||||
}
|
||||
|
||||
// nancy7 got rid of the SPEC chunk, and the data now contains the total amount of time
|
||||
// that the effect should run for instead.
|
||||
if (_rect.isEmpty()) {
|
||||
if (g_nancy->getGameType() <= kGameTypeNancy6 && _type == kCrossDissolve) {
|
||||
// Earlier games did the whole screen (most easily testable in the nancy3 intro if one moves the scrollbar)
|
||||
_rect = Common::Rect(640, 480);
|
||||
} else {
|
||||
const VIEW *viewportData = (const VIEW *)g_nancy->getEngineData("VIEW");
|
||||
assert(viewportData);
|
||||
|
||||
_rect = viewportData->screenPosition;
|
||||
}
|
||||
}
|
||||
|
||||
_drawSurface.create(_rect.width(), _rect.height(), g_nancy->_graphics->getScreenPixelFormat());
|
||||
moveTo(_rect);
|
||||
setTransparent(false);
|
||||
|
||||
RenderObject::init();
|
||||
}
|
||||
|
||||
void SpecialEffect::updateGraphics() {
|
||||
if (_numFrames) {
|
||||
// Early version with constant number of frames, linear interpolation
|
||||
if (g_nancy->getTotalPlayTime() > _nextFrameTime && _currentFrame < (int)_numFrames && isInitialized()) {
|
||||
++_currentFrame;
|
||||
_nextFrameTime += _frameTime;
|
||||
|
||||
GraphicsManager::crossDissolve(_fadeFrom, _fadeTo, 255 * _currentFrame / _numFrames, _rect, _drawSurface);
|
||||
setVisible(true);
|
||||
}
|
||||
} else {
|
||||
// nancy7+ version, draws as many frames as possible, ease in/out interpolation
|
||||
if (_startTime == 0) {
|
||||
_startTime = g_nancy->getTotalPlayTime();
|
||||
|
||||
// The original code times how long the first frame takes to draw,
|
||||
// divides the total time by that time, and uses the result to
|
||||
// decide how many frames need to be drawn. This results in highly
|
||||
// variable timing depending on the machine the game is played on.
|
||||
// On modern PCs, it even results in a divide by 0 that effectively
|
||||
// stops the special effect from playing. Using the original _totalTime
|
||||
// value results in the effect taking much longer than the developers
|
||||
// intended (as made obvious in the dog scare sequence in the beginning
|
||||
// of nancy7), so we manually shorten the timings to better match what
|
||||
// the developers would've seen when on their machines.
|
||||
_totalTime /= 2;
|
||||
_fadeToBlackTime /= 2;
|
||||
}
|
||||
|
||||
if (g_nancy->getTotalPlayTime() > _startTime + _totalTime && (_type != kThroughBlack || _throughBlackStarted2nd)) {
|
||||
if (_currentFrame == 0) {
|
||||
// Ensure at least one dissolve frame is shown
|
||||
++_currentFrame;
|
||||
GraphicsManager::crossDissolve(_fadeFrom, _fadeTo, 128, _rect, _drawSurface);
|
||||
setVisible(true);
|
||||
}
|
||||
} else {
|
||||
// Use a curve for all fades. Not entirely accurate to the original engine,
|
||||
// since that pre-calculated the number of frames and did some exponent magic on them
|
||||
float alpha = (float)(g_nancy->getTotalPlayTime() - _startTime) / (float)_totalTime;
|
||||
bool start2nd = alpha > 1;
|
||||
alpha = alpha * alpha * (3.0 - 2.0 * alpha);
|
||||
alpha *= 255;
|
||||
GraphicsManager::crossDissolve(_fadeFrom, _fadeTo, alpha, _rect, _drawSurface);
|
||||
setVisible(true);
|
||||
++_currentFrame;
|
||||
|
||||
if (start2nd && _type == kThroughBlack) {
|
||||
_throughBlackStarted2nd = true;
|
||||
_fadeFrom.clear();
|
||||
setVisible(false);
|
||||
g_nancy->_graphics->screenshotScreen(_fadeTo);
|
||||
setVisible(true);
|
||||
_startTime = g_nancy->getTotalPlayTime();
|
||||
_currentFrame = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpecialEffect::onSceneChange() {
|
||||
g_nancy->_graphics->screenshotScreen(_fadeFrom);
|
||||
_drawSurface.rawBlitFrom(_fadeFrom, _rect, Common::Point());
|
||||
}
|
||||
|
||||
void SpecialEffect::afterSceneChange() {
|
||||
if (_fadeFrom.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_type == kCrossDissolve) {
|
||||
g_nancy->_graphics->screenshotScreen(_fadeTo);
|
||||
} else {
|
||||
_fadeTo.create(640, 480, _drawSurface.format);
|
||||
_fadeTo.clear();
|
||||
}
|
||||
|
||||
// Workaround for the way ManagedSurface handles transparency. Both pure black
|
||||
// and pure white appear in scenes with SpecialEffects, and those happen to be
|
||||
// the two default values transBlitFrom uses for transColor. By doing this,
|
||||
// transColor gets set to the one color guaranteed to not appear in any scene,
|
||||
// and transparency works correctly
|
||||
_fadeTo.setTransparentColor(g_nancy->_graphics->getTransColor());
|
||||
|
||||
registerGraphics();
|
||||
_nextFrameTime = g_nancy->getTotalPlayTime() + _frameTime;
|
||||
_fadeToBlackEndTime = g_nancy->getTotalPlayTime() + _totalTime + _fadeToBlackTime;
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
bool SpecialEffect::isDone() const {
|
||||
if (_type == kBlackout) {
|
||||
return g_nancy->getTotalPlayTime() > _fadeToBlackEndTime;
|
||||
} else {
|
||||
bool canFinish = (_type == kThroughBlack) ? _throughBlackStarted2nd : true;
|
||||
return _totalTime ? ((g_nancy->getTotalPlayTime() > _startTime + _totalTime) && (_currentFrame != 0) && canFinish) : (_currentFrame >= (int)_numFrames);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Misc
|
||||
} // End of namespace Nancy
|
||||
Reference in New Issue
Block a user