From da74436aa4d1c25f5120caa75197c2c4d9e0d1bc Mon Sep 17 00:00:00 2001 From: Matthew Hoops Date: Fri, 16 Sep 2011 19:06:22 -0400 Subject: PEGASUS: Implement fader support --- engines/pegasus/fader.cpp | 214 ++++++++++++++++++++++++++++++++++++++++++++++ engines/pegasus/fader.h | 130 ++++++++++++++++++++++++++++ engines/pegasus/module.mk | 1 + engines/pegasus/sound.cpp | 13 +-- engines/pegasus/sound.h | 9 +- engines/pegasus/timers.h | 1 + 6 files changed, 352 insertions(+), 16 deletions(-) create mode 100755 engines/pegasus/fader.cpp create mode 100755 engines/pegasus/fader.h (limited to 'engines/pegasus') diff --git a/engines/pegasus/fader.cpp b/engines/pegasus/fader.cpp new file mode 100755 index 0000000000..c3cfe9d263 --- /dev/null +++ b/engines/pegasus/fader.cpp @@ -0,0 +1,214 @@ +/* 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 "pegasus/fader.h" +#include "pegasus/util.h" + +namespace Pegasus { + +Fader::Fader() { + _currentValue = 0; + _currentFaderMove._numKnots = 0; +} + +void Fader::setFaderValue(const uint32 newValue) { + _currentValue = newValue; +} + +bool Fader::initFaderMove(const FaderMoveSpec &spec) { + bool faderMoves = false; + uint32 value = 0; + + if (spec._numKnots > 0) { + stopFader(); + value = spec._knots[0].knotValue; + TimeValue startTime = spec._knots[0].knotTime; + + if (startTime != 0xffffffff) { + if (spec._numKnots > 1) { + TimeValue stopTime = spec._knots[spec._numKnots - 1].knotTime; + + if (spec._faderScale > 0) { + if (stopTime > startTime) { + for (uint32 i = 1; i < spec._numKnots; ++i) { + if (spec._knots[i - 1].knotValue != spec._knots[i].knotValue) { + faderMoves = true; + break; + } + } + + if (faderMoves) + _currentFaderMove = spec; + } else if (spec._knots[spec._numKnots - 1].knotValue != value) { + value = spec._knots[spec._numKnots - 1].knotValue; + } + } + } + } + } + + setFaderValue(value); + return faderMoves; +} + +void Fader::startFader(const FaderMoveSpec &spec) { + if (initFaderMove(spec)) { + setFlags(0); + setScale(spec._faderScale); + setSegment(spec._knots[0].knotTime, spec._knots[spec._numKnots - 1].knotTime); + setTime(spec._knots[0].knotTime); + start(); + } +} + +void Fader::startFaderSync(const FaderMoveSpec &spec) { + if (initFaderMove(spec)) { + setFlags(0); + setScale(spec._faderScale); + setSegment(spec._knots[0].knotTime, spec._knots[spec._numKnots - 1].knotTime); + setTime(spec._knots[0].knotTime); + start(); + + while (isFading()) + useIdleTime(); + + // Once more, for good measure, to make sure that there are no boundary + // condition problems. + useIdleTime(); + stopFader(); + } +} + +void Fader::loopFader(const FaderMoveSpec &spec) { + if (initFaderMove(spec)) { + setFlags(kLoopTimeBase); + setScale(spec._faderScale); + setSegment(spec._knots[0].knotTime, spec._knots[spec._numKnots - 1].knotTime); + setTime(spec._knots[0].knotTime); + start(); + } +} + +void Fader::stopFader() { + stop(); +} + +void Fader::pauseFader() { + stopFader(); +} + +void Fader::continueFader() { + if (getTime() < getStop()) + start(); +} + +void Fader::timeChanged(const TimeValue newTime) { + if (_currentFaderMove._numKnots != 0) { + uint32 i; + for (i = 0; i < _currentFaderMove._numKnots; i++) + if (_currentFaderMove._knots[i].knotTime > newTime) + break; + + uint32 newValue; + if (i == 0) + newValue = _currentFaderMove._knots[0].knotValue; + else if (i == _currentFaderMove._numKnots) + newValue = _currentFaderMove._knots[i - 1].knotValue; + else + newValue = linearInterp(_currentFaderMove._knots[i - 1].knotTime, _currentFaderMove._knots[i].knotTime, newTime, _currentFaderMove._knots[i - 1].knotValue, _currentFaderMove._knots[i].knotValue); + + if (newValue != _currentValue) + setFaderValue(newValue); + } +} + +void FaderMoveSpec::makeOneKnotFaderSpec(const uint32 knotValue) { + _numKnots = 1; + _knots[0].knotTime = 0; + _knots[0].knotValue = knotValue; +} + +void FaderMoveSpec::makeTwoKnotFaderSpec(const TimeScale faderScale, const TimeValue time1, const uint32 value1, const TimeValue time2, const uint32 value2) { + _numKnots = 2; + _faderScale = faderScale; + _knots[0].knotTime = time1; + _knots[0].knotValue = value1; + _knots[1].knotTime = time2; + _knots[1].knotValue = value2; +} + +void FaderMoveSpec::insertFaderKnot(const TimeValue knotTime, const uint32 knotValue) { + if (_numKnots != kMaxFaderKnots) { + uint32 index; + for (index = 0; index < _numKnots; index++) { + if (knotTime == _knots[index].knotTime) { + _knots[index].knotValue = knotValue; + return; + } else if (knotTime < _knots[index].knotTime) { + break; + } + } + + for (uint32 i = _numKnots; i > index; i--) + _knots[i] = _knots[i - 1]; + + _knots[index].knotTime = knotTime; + _knots[index].knotValue = knotValue; + _numKnots++; + } +} + +void FaderAnimation::setFaderValue(const uint32 newValue) { + if (getFaderValue() != newValue) { + Fader::setFaderValue(newValue); + triggerRedraw(); + } +} + +SoundFader::SoundFader() { + _sound = 0; + _masterVolume = 0xff; +} + +void SoundFader::attachSound(Sound *sound) { + if (!sound && isFading()) + stopFader(); + + _sound = sound; +} + +void SoundFader::setFaderValue(const uint32 newVolume) { + if (_sound) + _sound->setVolume((newVolume * _masterVolume) >> 8); + + _currentValue = newVolume; +} + +void SoundFader::setMasterVolume(const uint16 masterVolume) { + _masterVolume = masterVolume; + setFaderValue(getFaderValue()); +} + +} // End of namespace Pegasus diff --git a/engines/pegasus/fader.h b/engines/pegasus/fader.h new file mode 100755 index 0000000000..5ca1a5c3e9 --- /dev/null +++ b/engines/pegasus/fader.h @@ -0,0 +1,130 @@ +/* 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_FADER_H +#define PEGASUS_FADER_H + +#include "pegasus/elements.h" +#include "pegasus/timers.h" + +namespace Pegasus { + +class Fader; + +class FaderMoveSpec { +friend class Fader; +public: + FaderMoveSpec() { + _faderScale = kDefaultTimeScale; + _numKnots = 0; + } + + FaderMoveSpec(const TimeScale scale) { + _faderScale = scale; + _numKnots = 0; + } + + void setFaderScale(const TimeScale scale) { _faderScale = scale; } + TimeScale getFaderScale() const { return _faderScale; } + + void makeOneKnotFaderSpec(const uint32); + void makeTwoKnotFaderSpec(const TimeScale, const TimeValue, const uint32, const TimeValue, const uint32); + + void insertFaderKnot(const TimeValue, const uint32); + + uint32 getNumKnots() const { return _numKnots; } + uint32 getNthKnotTime(const uint32 index) const { return _knots[index].knotTime; } + uint32 getNthKnotValue(const uint32 index) const { return _knots[index].knotValue; } + +protected: + struct FaderKnot { + TimeValue knotTime; + uint32 knotValue; + }; + + TimeScale _faderScale; + uint32 _numKnots; + + static const uint32 kMaxFaderKnots = 20; + FaderKnot _knots[kMaxFaderKnots]; +}; + +class Fader : private IdlerTimeBase { +public: + Fader(); + virtual ~Fader() {} + + virtual void setFaderValue(const uint32); + uint32 getFaderValue() const { return _currentValue; } + virtual void startFader(const FaderMoveSpec &); + virtual void startFaderSync(const FaderMoveSpec &); + virtual void loopFader(const FaderMoveSpec &); + virtual void stopFader(); + virtual bool isFading() { return isRunning(); } + + void pauseFader(); + void continueFader(); + + void getCurrentFaderMove(FaderMoveSpec &spec) { spec = _currentFaderMove; } + +protected: + bool initFaderMove(const FaderMoveSpec &); + virtual void timeChanged(const TimeValue); + + uint32 _currentValue; + FaderMoveSpec _currentFaderMove; +}; + +class FaderAnimation : public DisplayElement, public Fader { +public: + FaderAnimation(const tDisplayElementID id) : DisplayElement(id) {} + virtual ~FaderAnimation() {} + + void setFaderValue(const uint32); +}; + +class Sound; + +class SoundFader : public Fader { +friend class Sound; +public: + SoundFader(); + virtual ~SoundFader() {} + + void setFaderValue(const uint32); + + void setMasterVolume(const uint16); + uint16 getMasterVolume() const { return _masterVolume; } + +protected: + void attachSound(Sound *); + + Sound *_sound; + uint16 _masterVolume; +}; + +} // End of namespace Pegasus + +#endif diff --git a/engines/pegasus/module.mk b/engines/pegasus/module.mk index 0f697f397e..ca262cbc98 100644 --- a/engines/pegasus/module.mk +++ b/engines/pegasus/module.mk @@ -6,6 +6,7 @@ MODULE_OBJS = \ cursor.o \ detection.o \ elements.o \ + fader.o \ gamestate.o \ graphics.o \ hotspot.o \ diff --git a/engines/pegasus/sound.cpp b/engines/pegasus/sound.cpp index 5db1d90a3c..847106aa4d 100755 --- a/engines/pegasus/sound.cpp +++ b/engines/pegasus/sound.cpp @@ -29,6 +29,7 @@ #include "common/file.h" #include "common/system.h" +#include "pegasus/fader.h" #include "pegasus/sound.h" namespace Pegasus { @@ -36,6 +37,7 @@ namespace Pegasus { Sound::Sound() { _stream = 0; _volume = 0xFF; + _fader = 0; } Sound::~Sound() { @@ -65,18 +67,15 @@ void Sound::initFromQuickTime(const Common::String &fileName) { _stream = Audio::makeQuickTimeStream(fileName); } -#if 0 -// TODO! void Sound::attachFader(SoundFader *fader) { if (_fader) - _fader->attachSound(NULL); + _fader->attachSound(0); _fader = fader; if (_fader) _fader->attachSound(this); } -#endif void Sound::playSound() { if (!isSoundLoaded()) @@ -84,11 +83,8 @@ void Sound::playSound() { stopSound(); -#if 0 - // TODO! if (_fader) setVolume(_fader->getFaderValue()); -#endif g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_handle, _stream, -1, _volume, 0, DisposeAfterUse::NO); } @@ -102,12 +98,9 @@ void Sound::loopSound() { // Create a looping stream Audio::AudioStream *loopStream = new Audio::LoopingAudioStream(_stream, 0, DisposeAfterUse::NO); -#if 0 - // TODO! // Assume that if there is a fader, we're going to fade the sound in. if (_fader) setVolume(0); -#endif g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_handle, loopStream, -1, _volume, 0, DisposeAfterUse::YES); } diff --git a/engines/pegasus/sound.h b/engines/pegasus/sound.h index 99607d432c..f66c3f4250 100755 --- a/engines/pegasus/sound.h +++ b/engines/pegasus/sound.h @@ -35,8 +35,7 @@ namespace Audio { namespace Pegasus { -// TODO! -//class SoundFader; +class SoundFader; // Things you might want to do with sound: // Start it @@ -73,16 +72,14 @@ public: void setVolume(const uint16 volume); bool isPlaying(); - // TODO! - //void attachFader(SoundFader *fader); + void attachFader(SoundFader *fader); protected: Audio::SeekableAudioStream *_stream; Audio::SoundHandle _handle; byte _volume; - // TODO! - //SoundFader *_fader; + SoundFader *_fader; }; } // End of namespace Pegasus diff --git a/engines/pegasus/timers.h b/engines/pegasus/timers.h index 9ce3093820..52f420eb90 100755 --- a/engines/pegasus/timers.h +++ b/engines/pegasus/timers.h @@ -26,6 +26,7 @@ #ifndef PEGASUS_TIMERS_H #define PEGASUS_TIMERS_H +#include "common/list.h" #include "common/rational.h" #include "pegasus/constants.h" -- cgit v1.2.3