diff --git a/audio/audiostream.cpp b/audio/audiostream.cpp index 4dd5d236be1..c413edb73d8 100644 --- a/audio/audiostream.cpp +++ b/audio/audiostream.cpp @@ -98,7 +98,7 @@ LoopingAudioStream::LoopingAudioStream(RewindableAudioStream *stream, uint loops // TODO: Properly indicate error _loops = _completeIterations = 1; } - if (stream->endOfData()) { + if (stream->endOfStream()) { // Apparently this is an empty stream _loops = _completeIterations = 1; } @@ -122,7 +122,7 @@ int LoopingAudioStream::readBuffer(int16 *buffer, const int numSamples) { _loops = _completeIterations = 1; return samplesRead; } - if (_parent->endOfData()) { + if (_parent->endOfStream()) { // Apparently this is an empty stream _loops = _completeIterations = 1; } @@ -134,7 +134,11 @@ int LoopingAudioStream::readBuffer(int16 *buffer, const int numSamples) { } bool LoopingAudioStream::endOfData() const { - return (_loops != 0 && (_completeIterations == _loops)); + return (_loops != 0 && _completeIterations == _loops) || _parent->endOfData(); +} + +bool LoopingAudioStream::endOfStream() const { + return _loops != 0 && _completeIterations == _loops; } AudioStream *makeLoopingAudioStream(RewindableAudioStream *stream, uint loops) { @@ -189,7 +193,7 @@ int SubLoopingAudioStream::readBuffer(int16 *buffer, const int numSamples) { int framesRead = _parent->readBuffer(buffer, framesLeft); _pos = _pos.addFrames(framesRead); - if (framesRead < framesLeft && _parent->endOfData()) { + if (framesRead < framesLeft && _parent->endOfStream()) { // TODO: Proper error indication. _done = true; return framesRead; @@ -216,6 +220,18 @@ int SubLoopingAudioStream::readBuffer(int16 *buffer, const int numSamples) { } } +bool SubLoopingAudioStream::endOfData() const { + // We're out of data if this stream is finished or the parent + // has run out of data for now. + return _done || _parent->endOfData(); +} + +bool SubLoopingAudioStream::endOfStream() const { + // The end of the stream has been reached only when we've gone + // through all the iterations. + return _done; +} + #pragma mark - #pragma mark --- SubSeekableAudioStream --- #pragma mark - @@ -315,18 +331,27 @@ public: virtual int readBuffer(int16 *buffer, const int numSamples); virtual bool isStereo() const { return _stereo; } virtual int getRate() const { return _rate; } + virtual bool endOfData() const { - //Common::StackLock lock(_mutex); - return _queue.empty(); + Common::StackLock lock(_mutex); + return _queue.empty() || _queue.front()._stream->endOfData(); + } + + virtual bool endOfStream() const { + Common::StackLock lock(_mutex); + return _finished && _queue.empty(); } - virtual bool endOfStream() const { return _finished && _queue.empty(); } // Implement the QueuingAudioStream API virtual void queueAudioStream(AudioStream *stream, DisposeAfterUse::Flag disposeAfterUse); - virtual void finish() { _finished = true; } + + virtual void finish() { + Common::StackLock lock(_mutex); + _finished = true; + } uint32 numQueuedStreams() const { - //Common::StackLock lock(_mutex); + Common::StackLock lock(_mutex); return _queue.size(); } }; @@ -356,11 +381,17 @@ int QueuingAudioStreamImpl::readBuffer(int16 *buffer, const int numSamples) { AudioStream *stream = _queue.front()._stream; samplesDecoded += stream->readBuffer(buffer + samplesDecoded, numSamples - samplesDecoded); - if (stream->endOfData()) { + // Done with the stream completely + if (stream->endOfStream()) { StreamHolder tmp = _queue.pop(); if (tmp._disposeAfterUse == DisposeAfterUse::YES) delete stream; + continue; } + + // Done with data but not the stream, bail out + if (stream->endOfData()) + break; } return samplesDecoded; @@ -416,12 +447,14 @@ public: return samplesRead; } - bool endOfData() const { return _parentStream->endOfData() || _samplesRead >= _totalSamples; } + bool endOfData() const { return _parentStream->endOfData() || reachedLimit(); } + bool endOfStream() const { return _parentStream->endOfStream() || reachedLimit(); } bool isStereo() const { return _parentStream->isStereo(); } int getRate() const { return _parentStream->getRate(); } private: int getChannels() const { return isStereo() ? 2 : 1; } + bool reachedLimit() const { return _samplesRead >= _totalSamples; } AudioStream *_parentStream; DisposeAfterUse::Flag _disposeAfterUse; diff --git a/audio/audiostream.h b/audio/audiostream.h index d5d7d0b6c7b..5202a4711cb 100644 --- a/audio/audiostream.h +++ b/audio/audiostream.h @@ -118,6 +118,7 @@ public: int readBuffer(int16 *buffer, const int numSamples); bool endOfData() const; + bool endOfStream() const; bool isStereo() const { return _parent->isStereo(); } int getRate() const { return _parent->getRate(); } @@ -247,7 +248,8 @@ public: DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES); int readBuffer(int16 *buffer, const int numSamples); - bool endOfData() const { return _done; } + bool endOfData() const; + bool endOfStream() const; bool isStereo() const { return _parent->isStereo(); } int getRate() const { return _parent->getRate(); } @@ -287,7 +289,8 @@ public: int getRate() const { return _parent->getRate(); } - bool endOfData() const { return (_pos >= _length) || _parent->endOfStream(); } + bool endOfData() const { return (_pos >= _length) || _parent->endOfData(); } + bool endOfStream() const { return (_pos >= _length) || _parent->endOfStream(); } bool seek(const Timestamp &where); diff --git a/audio/decoders/aac.cpp b/audio/decoders/aac.cpp index 7700bb32155..beabf7bff90 100644 --- a/audio/decoders/aac.cpp +++ b/audio/decoders/aac.cpp @@ -117,6 +117,7 @@ AudioStream *AACDecoder::decodeFrame(Common::SeekableReadStream &stream) { inBufferPos += frameInfo.bytesconsumed; } + audioStream->finish(); return audioStream; } diff --git a/audio/decoders/qdm2.cpp b/audio/decoders/qdm2.cpp index 743ca1cb7d5..97d73b3a039 100644 --- a/audio/decoders/qdm2.cpp +++ b/audio/decoders/qdm2.cpp @@ -2607,6 +2607,7 @@ AudioStream *QDM2Stream::decodeFrame(Common::SeekableReadStream &stream) { while (qdm2_decodeFrame(stream, audioStream)) ; + audioStream->finish(); return audioStream; } diff --git a/audio/decoders/quicktime.cpp b/audio/decoders/quicktime.cpp index 547abd2aa4d..331c850b1a4 100644 --- a/audio/decoders/quicktime.cpp +++ b/audio/decoders/quicktime.cpp @@ -414,8 +414,15 @@ void QuickTimeAudioDecoder::QuickTimeAudioTrack::skipSamples(const Timestamp &le } void QuickTimeAudioDecoder::QuickTimeAudioTrack::findEdit(const Timestamp &position) { - for (_curEdit = 0; _curEdit < _parentTrack->editCount - 1 && position > Timestamp(0, _parentTrack->editList[_curEdit].timeOffset, _decoder->_timeScale); _curEdit++) - ; + // Go through the edits look for where we find out we need to be. As long + // as the position is >= to the edit's start time, it is considered to be in that + // edit. seek() already figured out if we reached the last edit, so we don't need + // to handle that case here. + for (_curEdit = 0; _curEdit < _parentTrack->editCount - 1; _curEdit++) { + Timestamp nextEditTime(0, _parentTrack->editList[_curEdit + 1].timeOffset, _decoder->_timeScale); + if (position < nextEditTime) + break; + } enterNewEdit(position); } diff --git a/backends/platform/sdl/amigaos/amigaos-main.cpp b/backends/platform/sdl/amigaos/amigaos-main.cpp index 0743b3f9a0b..65da6bbf850 100644 --- a/backends/platform/sdl/amigaos/amigaos-main.cpp +++ b/backends/platform/sdl/amigaos/amigaos-main.cpp @@ -30,6 +30,9 @@ int main(int argc, char *argv[]) { + // Set up a stack cookie to avoid crashes due to too few stack set by users + static const char *stack_cookie __attribute__((used)) = "$STACK: 600000"; + // Create our OSystem instance g_system = new OSystem_AmigaOS(); assert(g_system); diff --git a/backends/platform/sdl/amigaos/amigaos.mk b/backends/platform/sdl/amigaos/amigaos.mk index 822468ce638..7f5b10118d9 100644 --- a/backends/platform/sdl/amigaos/amigaos.mk +++ b/backends/platform/sdl/amigaos/amigaos.mk @@ -1,18 +1,18 @@ # Special target to create an AmigaOS snapshot installation -amigaos4dist: $(EXECUTABLE) - mkdir -p $(AMIGAOS4PATH) - mkdir -p $(AMIGAOS4PATH)/themes - mkdir -p $(AMIGAOS4PATH)/extras - $(STRIP) $(EXECUTABLE) -o $(AMIGAOS4PATH)/$(EXECUTABLE) - cp ${srcdir}/icons/residualvm.info $(AMIGAOS4PATH)/$(EXECUTABLE).info - cp $(DIST_FILES_THEMES) $(AMIGAOS4PATH)/themes/ +amigaosdist: $(EXECUTABLE) + mkdir -p $(AMIGAOSPATH) + mkdir -p $(AMIGAOSPATH)/themes + mkdir -p $(AMIGAOSPATH)/extras + $(STRIP) $(EXECUTABLE) -o $(AMIGAOSPATH)/$(EXECUTABLE) + cp ${srcdir}/icons/residualvm.info $(AMIGAOSPATH)/$(EXECUTABLE).info + cp $(DIST_FILES_THEMES) $(AMIGAOSPATH)/themes/ ifdef DIST_FILES_ENGINEDATA - cp $(DIST_FILES_ENGINEDATA) $(AMIGAOS4PATH)/extras/ + cp $(DIST_FILES_ENGINEDATA) $(AMIGAOSPATH)/extras/ endif - cp $(DIST_FILES_DOCS) $(AMIGAOS4PATH) + cp $(DIST_FILES_DOCS) $(AMIGAOSPATH) # Special target to cross create an AmigaOS snapshot installation -amigaos4cross: $(EXECUTABLE) +amigaoscross: $(EXECUTABLE) mkdir -p ResidualVM mkdir -p ResidualVM/themes mkdir -p ResidualVM/extras diff --git a/base/version.cpp b/base/version.cpp index 3c589d91786..405d4643e73 100644 --- a/base/version.cpp +++ b/base/version.cpp @@ -56,6 +56,9 @@ * to properly work in exports (i.e. release tar balls etc.). */ const char *gScummVMVersion = SCUMMVM_VERSION; +#ifdef __amigaos4__ +static const char *version_cookie __attribute__((used)) = "$VER: ScummVM " SCUMMVM_VERSION " (" __DATE__ ", " __TIME__ ")"; +#endif #ifdef __PLAYSTATION2__ const char *gScummVMBuildDate = "Git Master"; /* ScummVM Git Master */ const char *gScummVMVersionDate = SCUMMVM_VERSION " - PlayStation2"; diff --git a/common/config-manager.cpp b/common/config-manager.cpp index fadc903c26c..e0cf23739a0 100644 --- a/common/config-manager.cpp +++ b/common/config-manager.cpp @@ -597,7 +597,7 @@ void ConfigManager::setActiveDomain(const String &domName) { _activeDomain = 0; } else { assert(isValidDomainName(domName)); - _activeDomain = & _gameDomains[domName]; + _activeDomain = &_gameDomains[domName]; } _activeDomainName = domName; } @@ -626,6 +626,10 @@ void ConfigManager::addMiscDomain(const String &domName) { void ConfigManager::removeGameDomain(const String &domName) { assert(!domName.empty()); assert(isValidDomainName(domName)); + if (domName == _activeDomainName) { + _activeDomainName.clear(); + _activeDomain = 0; + } _gameDomains.erase(domName); } @@ -638,6 +642,10 @@ void ConfigManager::removeMiscDomain(const String &domName) { void ConfigManager::renameGameDomain(const String &oldName, const String &newName) { renameDomain(oldName, newName, _gameDomains); + if (_activeDomainName == oldName) { + _activeDomainName = newName; + _activeDomain = &_gameDomains[newName]; + } } void ConfigManager::renameMiscDomain(const String &oldName, const String &newName) { diff --git a/configure b/configure index 3222614824e..ed5dea87e01 100755 --- a/configure +++ b/configure @@ -175,7 +175,7 @@ _as="as" _windres=windres _stagingpath="staging" _win32path="C:/residualvm" -_amigaos4path="Games:ResidualVM" +_amigaospath="Games:ResidualVM" _staticlibpath= _sdlconfig=sdl-config _freetypeconfig=freetype-config @@ -4572,7 +4572,7 @@ WINDRES := $_windres WINDRESFLAGS := $WINDRESFLAGS STAGINGPATH=$_stagingpath WIN32PATH=$_win32path -AMIGAOS4PATH=$_amigaos4path +AMIGAOSPATH=$_amigaospath STATICLIBPATH=$_staticlibpath BACKEND := $_backend diff --git a/engines/advancedDetector.cpp b/engines/advancedDetector.cpp index 7bb88074973..3c1d00d5156 100644 --- a/engines/advancedDetector.cpp +++ b/engines/advancedDetector.cpp @@ -122,7 +122,7 @@ bool cleanupPirated(ADGameDescList &matched) { // We ruled out all variants and now have nothing if (matched.empty()) { - warning("Illegitimate game copy detected. We give no support in such cases %d", matched.size()); + warning("Illegitimate game copy detected. We provide no support in such cases"); return true; } } diff --git a/graphics/pixelformat.h b/graphics/pixelformat.h index 792833a8e3c..00db6702fcb 100644 --- a/graphics/pixelformat.h +++ b/graphics/pixelformat.h @@ -27,6 +27,97 @@ namespace Graphics { +/** Template to expand from an n-bit component to an 8-bit component */ +template +struct ColorComponent { +}; + +template<> +struct ColorComponent<0> { + static inline uint expand(uint value) { + return 0; + } +}; + +template<> +struct ColorComponent<1> { + static inline uint expand(uint value) { + value &= 1; + return value | + (value << 1) | + (value << 2) | + (value << 3) | + (value << 4) | + (value << 5) | + (value << 6) | + (value << 7); + } +}; + +template<> +struct ColorComponent<2> { + static inline uint expand(uint value) { + value &= 3; + return value | + (value << 2) | + (value << 4) | + (value << 6); + } +}; + +template<> +struct ColorComponent<3> { + static inline uint expand(uint value) { + value &= 7; + return (value << 5) | + (value << 2) | + (value >> 1); + } +}; + +template<> +struct ColorComponent<4> { + static inline uint expand(uint value) { + value &= 15; + return value | + (value << 4); + } +}; + +template<> +struct ColorComponent<5> { + static inline uint expand(uint value) { + value &= 31; + return (value << 3) | + (value >> 2); + } +}; + +template<> +struct ColorComponent<6> { + static inline uint expand(uint value) { + value &= 63; + return (value << 2) | + (value >> 4); + } +}; + +template<> +struct ColorComponent<7> { + static inline uint expand(uint value) { + value &= 127; + return (value << 1) | + (value >> 6); + } +}; + +template<> +struct ColorComponent<8> { + static inline uint expand(uint value) { + return value & 255; + } +}; + /** * A pixel format description. * @@ -91,16 +182,16 @@ struct PixelFormat { } inline void colorToRGB(uint32 color, uint8 &r, uint8 &g, uint8 &b) const { - r = ((color >> rShift) << rLoss) & 0xFF; - g = ((color >> gShift) << gLoss) & 0xFF; - b = ((color >> bShift) << bLoss) & 0xFF; + r = expand(rBits(), color >> rShift); + g = expand(gBits(), color >> gShift); + b = expand(bBits(), color >> bShift); } inline void colorToARGB(uint32 color, uint8 &a, uint8 &r, uint8 &g, uint8 &b) const { - a = (aBits() == 0) ? 0xFF : (((color >> aShift) << aLoss) & 0xFF); - r = ((color >> rShift) << rLoss) & 0xFF; - g = ((color >> gShift) << gLoss) & 0xFF; - b = ((color >> bShift) << bLoss) & 0xFF; + a = (aBits() == 0) ? 0xFF : expand(aBits(), color >> aShift); + r = expand(rBits(), color >> rShift); + g = expand(gBits(), color >> gShift); + b = expand(bBits(), color >> bShift); } ////////////////////////////////////////////////////////////////////// @@ -142,6 +233,33 @@ struct PixelFormat { inline uint aMax() const { return (1 << aBits()) - 1; } + + /** Expand a given bit-depth component to a full 8-bit component */ + static inline uint expand(uint bits, uint color) { + switch (bits) { + case 0: + return ColorComponent<0>::expand(color); + case 1: + return ColorComponent<1>::expand(color); + case 2: + return ColorComponent<2>::expand(color); + case 3: + return ColorComponent<3>::expand(color); + case 4: + return ColorComponent<4>::expand(color); + case 5: + return ColorComponent<5>::expand(color); + case 6: + return ColorComponent<6>::expand(color); + case 7: + return ColorComponent<7>::expand(color); + case 8: + return ColorComponent<8>::expand(color); + } + + // Unsupported + return 0; + } }; } // End of namespace Graphics diff --git a/gui/options.cpp b/gui/options.cpp index 90bfe4cc3d2..4f7b5896f5c 100644 --- a/gui/options.cpp +++ b/gui/options.cpp @@ -84,7 +84,7 @@ enum { static const char *savePeriodLabels[] = { _s("Never"), _s("every 5 mins"), _s("every 10 mins"), _s("every 15 mins"), _s("every 30 mins"), 0 }; static const int savePeriodValues[] = { 0, 5 * 60, 10 * 60, 15 * 60, 30 * 60, -1 }; -static const char *outputRateLabels[] = { _s(""), _s("8 kHz"), _s("11kHz"), _s("22 kHz"), _s("44 kHz"), _s("48 kHz"), 0 }; +static const char *outputRateLabels[] = { _s(""), _s("8 kHz"), _s("11 kHz"), _s("22 kHz"), _s("44 kHz"), _s("48 kHz"), 0 }; static const int outputRateValues[] = { 0, 8000, 11025, 22050, 44100, 48000, -1 }; OptionsDialog::OptionsDialog(const Common::String &domain, int x, int y, int w, int h) @@ -890,10 +890,10 @@ void OptionsDialog::addMIDIControls(GuiObject *boss, const Common::String &prefi // SoundFont if (g_system->getOverlayWidth() > 320) - _soundFontButton = new ButtonWidget(boss, prefix + "mcFontButton", _("SoundFont:"), _("SoundFont is supported by some audio cards, Fluidsynth and Timidity"), kChooseSoundFontCmd); + _soundFontButton = new ButtonWidget(boss, prefix + "mcFontButton", _("SoundFont:"), _("SoundFont is supported by some audio cards, FluidSynth and Timidity"), kChooseSoundFontCmd); else - _soundFontButton = new ButtonWidget(boss, prefix + "mcFontButton", _c("SoundFont:", "lowres"), _("SoundFont is supported by some audio cards, Fluidsynth and Timidity"), kChooseSoundFontCmd); - _soundFont = new StaticTextWidget(boss, prefix + "mcFontPath", _c("None", "soundfont"), _("SoundFont is supported by some audio cards, Fluidsynth and Timidity")); + _soundFontButton = new ButtonWidget(boss, prefix + "mcFontButton", _c("SoundFont:", "lowres"), _("SoundFont is supported by some audio cards, FluidSynth and Timidity"), kChooseSoundFontCmd); + _soundFont = new StaticTextWidget(boss, prefix + "mcFontPath", _c("None", "soundfont"), _("SoundFont is supported by some audio cards, FluidSynth and Timidity")); _soundFontClearButton = addClearButton(boss, prefix + "mcFontClearButton", kClearSoundFontCmd); diff --git a/image/codecs/cinepak.cpp b/image/codecs/cinepak.cpp index 8d5dbceb4ad..8464aa3889a 100644 --- a/image/codecs/cinepak.cpp +++ b/image/codecs/cinepak.cpp @@ -52,11 +52,16 @@ CinepakDecoder::CinepakDecoder(int bitsPerPixel) : Codec() { _curFrame.strips = NULL; _y = 0; - if (bitsPerPixel == 8) + if (bitsPerPixel == 8) { _pixelFormat = Graphics::PixelFormat::createFormatCLUT8(); - else + } else { _pixelFormat = g_system->getScreenFormat(); + // Default to a 32bpp format, if in 8bpp mode + if (_pixelFormat.bytesPerPixel == 1) + _pixelFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0); + } + // Create a lookup for the clip function // This dramatically improves the performance of the color conversion _clipTableBuf = new byte[1024]; diff --git a/test/common/rendermode.h b/test/common/rendermode.h index e5e277f16b0..b96ae243a59 100644 --- a/test/common/rendermode.h +++ b/test/common/rendermode.h @@ -49,7 +49,6 @@ class RenderModeTestSuite : public CxxTest::TestSuite { * Notably, the output should not be in mixed case. */ TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("FMTOWNS")), "fmtowns", 7); - TS_ASSERT_DIFFERS(Common::getRenderModeCode(Common::parseRenderMode("FMTOWNS")), "fmtowns"); TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("CGA")), "cga", 3); TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("vga")), "vga", 3); TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("Ega")), "ega", 3); diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index c6171c44500..dce96aae031 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -778,6 +778,31 @@ void VideoDecoder::setEndTime(const Audio::Timestamp &endTime) { } } +void VideoDecoder::setEndFrame(uint frame) { + VideoTrack *track = 0; + + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) { + if ((*it)->getTrackType() == Track::kTrackTypeVideo) { + // We only allow this when one video track is present + if (track) + return; + + track = (VideoTrack *)*it; + } + } + + // If we didn't find a video track, we can't set the final frame (of course) + if (!track) + return; + + Audio::Timestamp time = track->getFrameTime(frame + 1); + + if (time < 0) + return; + + setEndTime(time); +} + VideoDecoder::Track *VideoDecoder::getTrack(uint track) { if (track > _internalTracks.size()) return 0; diff --git a/video/video_decoder.h b/video/video_decoder.h index 2faec0fb3eb..c3879e91447 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -213,6 +213,17 @@ public: */ void setEndTime(const Audio::Timestamp &endTime); + /** + * Set the end frame. + * + * The passed frame will be the last frame to show. + * + * Like seekToFrame(), this only works when one video track is present, + * and that track supports getFrameTime(). This calls setEndTime() + * internally. + */ + void setEndFrame(uint frame); + /** * Get the stop time of the video (if not set, zero) */