diff options
author | Einar Johan Trøan Sømåen | 2012-08-31 13:11:31 +0200 |
---|---|---|
committer | Einar Johan Trøan Sømåen | 2012-08-31 13:11:31 +0200 |
commit | 3fe7f2cbe2b70eaa824b7159d94d40c2280006a3 (patch) | |
tree | ea592da00ad567c75008137f79eeba16c3ba40c4 | |
parent | 246109839b9c196e9181a6f619c15694456b9aec (diff) | |
parent | 10a947a0be80ea8c5c88bd3493a5057b1223ce45 (diff) | |
download | scummvm-rg350-3fe7f2cbe2b70eaa824b7159d94d40c2280006a3.tar.gz scummvm-rg350-3fe7f2cbe2b70eaa824b7159d94d40c2280006a3.tar.bz2 scummvm-rg350-3fe7f2cbe2b70eaa824b7159d94d40c2280006a3.zip |
Merge remote-tracking branch 'origin/master' into wintermute
130 files changed, 10847 insertions, 6594 deletions
@@ -408,6 +408,9 @@ Other contributions French: Thierry Crozat + Galician: + Santiago G. Sanz + German: Simon Sawatzki Lothar Serra Mari @@ -7,6 +7,8 @@ For a more comprehensive changelog of the latest experimental code, see: supported for resolutions bigger than 640x400. The old chooser is still available and used for games without thumbnail support. It is possible to select the old one as default too. + - Rewrote VideoDecoder subsystem. + - Added Galician translation. 1.5.0 (2012-07-27) New Games: diff --git a/audio/audiostream.cpp b/audio/audiostream.cpp index 1c5c435359..6e185702f0 100644 --- a/audio/audiostream.cpp +++ b/audio/audiostream.cpp @@ -386,4 +386,42 @@ Timestamp convertTimeToStreamPos(const Timestamp &where, int rate, bool isStereo return Timestamp(result.secs(), result.numberOfFrames(), result.framerate()); } +/** + * An AudioStream wrapper that cuts off the amount of samples read after a + * given time length is reached. + */ +class LimitingAudioStream : public AudioStream { +public: + LimitingAudioStream(AudioStream *parentStream, const Audio::Timestamp &length, DisposeAfterUse::Flag disposeAfterUse) : + _parentStream(parentStream), _samplesRead(0), _disposeAfterUse(disposeAfterUse), + _totalSamples(length.convertToFramerate(getRate()).totalNumberOfFrames() * getChannels()) {} + + ~LimitingAudioStream() { + if (_disposeAfterUse == DisposeAfterUse::YES) + delete _parentStream; + } + + int readBuffer(int16 *buffer, const int numSamples) { + // Cap us off so we don't read past _totalSamples + int samplesRead = _parentStream->readBuffer(buffer, MIN<int>(numSamples, _totalSamples - _samplesRead)); + _samplesRead += samplesRead; + return samplesRead; + } + + bool endOfData() const { return _parentStream->endOfData() || _samplesRead >= _totalSamples; } + bool isStereo() const { return _parentStream->isStereo(); } + int getRate() const { return _parentStream->getRate(); } + +private: + int getChannels() const { return isStereo() ? 2 : 1; } + + AudioStream *_parentStream; + DisposeAfterUse::Flag _disposeAfterUse; + uint32 _totalSamples, _samplesRead; +}; + +AudioStream *makeLimitingAudioStream(AudioStream *parentStream, const Timestamp &length, DisposeAfterUse::Flag disposeAfterUse) { + return new LimitingAudioStream(parentStream, length, disposeAfterUse); +} + } // End of namespace Audio diff --git a/audio/audiostream.h b/audio/audiostream.h index 801f13d9d9..d6d4a16280 100644 --- a/audio/audiostream.h +++ b/audio/audiostream.h @@ -356,6 +356,16 @@ QueuingAudioStream *makeQueuingAudioStream(int rate, bool stereo); */ Timestamp convertTimeToStreamPos(const Timestamp &where, int rate, bool isStereo); +/** + * Factory function for an AudioStream wrapper that cuts off the amount of samples read after a + * given time length is reached. + * + * @param parentStream The stream to limit + * @param length The time length to limit the stream to + * @param disposeAfterUse Whether the parent stream object should be destroyed on destruction of the returned stream + */ +AudioStream *makeLimitingAudioStream(AudioStream *parentStream, const Timestamp &length, DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES); + } // End of namespace Audio #endif diff --git a/audio/decoders/quicktime.cpp b/audio/decoders/quicktime.cpp index 8874a61c2e..5276cfc530 100644 --- a/audio/decoders/quicktime.cpp +++ b/audio/decoders/quicktime.cpp @@ -62,41 +62,6 @@ private: }; /** - * An AudioStream wrapper that cuts off the amount of samples read after a - * given time length is reached. - */ -class LimitingAudioStream : public AudioStream { -public: - LimitingAudioStream(AudioStream *parentStream, const Audio::Timestamp &length, - DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES) : - _parentStream(parentStream), _samplesRead(0), _disposeAfterUse(disposeAfterUse), - _totalSamples(length.convertToFramerate(getRate()).totalNumberOfFrames() * getChannels()) {} - - ~LimitingAudioStream() { - if (_disposeAfterUse == DisposeAfterUse::YES) - delete _parentStream; - } - - int readBuffer(int16 *buffer, const int numSamples) { - // Cap us off so we don't read past _totalSamples - int samplesRead = _parentStream->readBuffer(buffer, MIN<int>(numSamples, _totalSamples - _samplesRead)); - _samplesRead += samplesRead; - return samplesRead; - } - - bool endOfData() const { return _parentStream->endOfData() || _samplesRead >= _totalSamples; } - bool isStereo() const { return _parentStream->isStereo(); } - int getRate() const { return _parentStream->getRate(); } - -private: - int getChannels() const { return isStereo() ? 2 : 1; } - - AudioStream *_parentStream; - DisposeAfterUse::Flag _disposeAfterUse; - uint32 _totalSamples, _samplesRead; -}; - -/** * An AudioStream wrapper that forces audio to be played in mono. * It currently just ignores the right channel if stereo. */ @@ -263,7 +228,7 @@ void QuickTimeAudioDecoder::QuickTimeAudioTrack::queueAudio(const Timestamp &len _skipSamples = Timestamp(); } - queueStream(new LimitingAudioStream(new SilentAudioStream(getRate(), isStereo()), editLength), editLength); + queueStream(makeLimitingAudioStream(new SilentAudioStream(getRate(), isStereo()), editLength), editLength); _curEdit++; enterNewEdit(nextEditTime); } else { @@ -289,7 +254,7 @@ void QuickTimeAudioDecoder::QuickTimeAudioTrack::queueAudio(const Timestamp &len // we move on to the next edit if (trackPosition >= nextEditTime || _curChunk >= _parentTrack->chunkCount) { chunkLength = nextEditTime.convertToFramerate(getRate()) - getCurrentTrackTime(); - stream = new LimitingAudioStream(stream, chunkLength); + stream = makeLimitingAudioStream(stream, chunkLength); _curEdit++; enterNewEdit(nextEditTime); diff --git a/backends/platform/android/texture.cpp b/backends/platform/android/texture.cpp index 95c96e0d25..b174e93191 100644 --- a/backends/platform/android/texture.cpp +++ b/backends/platform/android/texture.cpp @@ -52,9 +52,6 @@ // Supported GL extensions static bool npot_supported = false; -#ifdef GL_OES_draw_texture -static bool draw_tex_supported = false; -#endif static inline GLfixed xdiv(int numerator, int denominator) { assert(numerator < (1 << 16)); @@ -85,11 +82,6 @@ void GLESBaseTexture::initGLExtensions() { if (token == "GL_ARB_texture_non_power_of_two") npot_supported = true; - -#ifdef GL_OES_draw_texture - if (token == "GL_OES_draw_texture") - draw_tex_supported = true; -#endif } } @@ -180,45 +172,28 @@ void GLESBaseTexture::allocBuffer(GLuint w, GLuint h) { void GLESBaseTexture::drawTexture(GLshort x, GLshort y, GLshort w, GLshort h) { GLCALL(glBindTexture(GL_TEXTURE_2D, _texture_name)); -#ifdef GL_OES_draw_texture - // Great extension, but only works under specific conditions. - // Still a work-in-progress - disabled for now. - if (false && draw_tex_supported && !hasPalette()) { - //GLCALL(glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)); - const GLint crop[4] = { 0, _surface.h, _surface.w, -_surface.h }; + const GLfixed tex_width = xdiv(_surface.w, _texture_width); + const GLfixed tex_height = xdiv(_surface.h, _texture_height); + const GLfixed texcoords[] = { + 0, 0, + tex_width, 0, + 0, tex_height, + tex_width, tex_height, + }; - GLCALL(glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop)); + GLCALL(glTexCoordPointer(2, GL_FIXED, 0, texcoords)); - // Android GLES bug? - GLCALL(glColor4ub(0xff, 0xff, 0xff, 0xff)); + const GLshort vertices[] = { + x, y, + x + w, y, + x, y + h, + x + w, y + h, + }; - GLCALL(glDrawTexiOES(x, y, 0, w, h)); - } else -#endif - { - const GLfixed tex_width = xdiv(_surface.w, _texture_width); - const GLfixed tex_height = xdiv(_surface.h, _texture_height); - const GLfixed texcoords[] = { - 0, 0, - tex_width, 0, - 0, tex_height, - tex_width, tex_height, - }; - - GLCALL(glTexCoordPointer(2, GL_FIXED, 0, texcoords)); - - const GLshort vertices[] = { - x, y, - x + w, y, - x, y + h, - x + w, y + h, - }; - - GLCALL(glVertexPointer(2, GL_SHORT, 0, vertices)); - - assert(ARRAYSIZE(vertices) == ARRAYSIZE(texcoords)); - GLCALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, ARRAYSIZE(vertices) / 2)); - } + GLCALL(glVertexPointer(2, GL_SHORT, 0, vertices)); + + assert(ARRAYSIZE(vertices) == ARRAYSIZE(texcoords)); + GLCALL(glDrawArrays(GL_TRIANGLE_STRIP, 0, ARRAYSIZE(vertices) / 2)); clearDirty(); } diff --git a/common/endian.h b/common/endian.h index 394437ec67..759513efef 100644 --- a/common/endian.h +++ b/common/endian.h @@ -146,6 +146,12 @@ */ #define MKTAG(a0,a1,a2,a3) ((uint32)((a3) | ((a2) << 8) | ((a1) << 16) | ((a0) << 24))) +/** + * A wrapper macro used around two character constants, like 'wb', to + * ensure portability. Typical usage: MKTAG16('w','b'). + */ +#define MKTAG16(a0,a1) ((uint16)((a1) | ((a0) << 8))) + // Functions for reading/writing native integers. // They also transparently handle the need for alignment. diff --git a/common/quicktime.h b/common/quicktime.h index 974502d075..08ca35ad51 100644 --- a/common/quicktime.h +++ b/common/quicktime.h @@ -35,6 +35,7 @@ #include "common/scummsys.h" #include "common/stream.h" #include "common/rational.h" +#include "common/types.h" namespace Common { class MacResManager; diff --git a/common/winexe_pe.cpp b/common/winexe_pe.cpp index 6c0f9c9962..b3c45ffe73 100644 --- a/common/winexe_pe.cpp +++ b/common/winexe_pe.cpp @@ -64,7 +64,7 @@ bool PEResources::loadFromEXE(SeekableReadStream *stream) { if (!stream) return false; - if (stream->readUint16BE() != 'MZ') + if (stream->readUint16BE() != MKTAG16('M', 'Z')) return false; stream->skip(58); diff --git a/common/xmlparser.cpp b/common/xmlparser.cpp index ea3d44cf87..f0b7f1cc81 100644 --- a/common/xmlparser.cpp +++ b/common/xmlparser.cpp @@ -20,15 +20,11 @@ * */ -// FIXME: Avoid using fprintf -#define FORBIDDEN_SYMBOL_EXCEPTION_fprintf -#define FORBIDDEN_SYMBOL_EXCEPTION_stderr - - #include "common/xmlparser.h" #include "common/archive.h" #include "common/fs.h" #include "common/memstream.h" +#include "common/system.h" namespace Common { @@ -123,17 +119,19 @@ bool XMLParser::parserError(const String &errStr) { keyClosing = currentPosition; } - fprintf(stderr, "\n File <%s>, line %d:\n", _fileName.c_str(), lineCount); + Common::String errorMessage = Common::String::format("\n File <%s>, line %d:\n", _fileName.c_str(), lineCount); currentPosition = (keyClosing - keyOpening); _stream->seek(keyOpening, SEEK_SET); while (currentPosition--) - fprintf(stderr, "%c", _stream->readByte()); + errorMessage += (char)_stream->readByte(); + + errorMessage += "\n\nParser error: "; + errorMessage += errStr; + errorMessage += "\n\n"; - fprintf(stderr, "\n\nParser error: "); - fprintf(stderr, "%s", errStr.c_str()); - fprintf(stderr, "\n\n"); + g_system->logMessage(LogMessageType::kError, errorMessage.c_str()); return false; } @@ -97,7 +97,7 @@ _sndio=auto _timidity=auto _zlib=auto _sparkle=auto -_png=no +_png=auto _theoradec=auto _faad=auto _fluidsynth=auto @@ -712,7 +712,7 @@ Usage: $0 [OPTIONS]... Configuration: -h, --help display this help and exit - --backend=BACKEND backend to build (android, bada, dc, dingux, ds, gp2x, gph, + --backend=BACKEND backend to build (android, bada, dc, dingux, ds, gph, iphone, linuxmoto, maemo, n64, null, openpandora, ps2, psp, samsungtv, sdl, webos, wii, wince) [sdl] @@ -2079,8 +2079,9 @@ case $_host_os in DEFINES="$DEFINES -D__PLAYSTATION2__" ;; ps3) - # Force use of SDL from the ps3 toolchain + # Force use of SDL and freetype from the ps3 toolchain _sdlpath="$PS3DEV/portlibs/ppu:$PS3DEV/portlibs/ppu/bin" + _freetypepath="$PS3DEV/portlibs/ppu:$PS3DEV/portlibs/ppu/bin" DEFINES="$DEFINES -DPLAYSTATION3" CXXFLAGS="$CXXFLAGS -mcpu=cell -mminimal-toc -I$PSL1GHT/ppu/include -I$PS3DEV/portlibs/ppu/include" @@ -2202,13 +2203,8 @@ if test -n "$_host"; then bfin*) ;; caanoo) - # This uses the GPH backend. - DEFINES="$DEFINES -DGPH_DEVICE" DEFINES="$DEFINES -DCAANOO" - DEFINES="$DEFINES -DREDUCE_MEMORY_USAGE" - if test "$_debug_build" = yes; then - DEFINES="$DEFINES -DGPH_DEBUG" - else + if test "$_debug_build" = no; then # Use -O3 on the Caanoo for non-debug builds. _optimization_level=-O3 fi @@ -2299,13 +2295,7 @@ if test -n "$_host"; then add_line_to_config_h "#define USE_WII_DI" ;; gp2x) - # This uses the GPH backend. - DEFINES="$DEFINES -DGPH_DEVICE" DEFINES="$DEFINES -DGP2X" - DEFINES="$DEFINES -DREDUCE_MEMORY_USAGE" - if test "$_debug_build" = yes; then - DEFINES="$DEFINES -DGPH_DEBUG" - fi CXXFLAGS="$CXXFLAGS -march=armv4t" ASFLAGS="$ASFLAGS -mfloat-abi=soft" LDFLAGS="$LDFLAGS -static" @@ -2319,13 +2309,7 @@ if test -n "$_host"; then _port_mk="backends/platform/gph/gp2x-bundle.mk" ;; gp2xwiz) - # This uses the GPH backend. - DEFINES="$DEFINES -DGPH_DEVICE" DEFINES="$DEFINES -DGP2XWIZ" - DEFINES="$DEFINES -DREDUCE_MEMORY_USAGE" - if test "$_debug_build" = yes; then - DEFINES="$DEFINES -DGPH_DEBUG" - fi CXXFLAGS="$CXXFLAGS -mcpu=arm926ej-s" CXXFLAGS="$CXXFLAGS -mtune=arm926ej-s" ASFLAGS="$ASFLAGS -mfloat-abi=soft" @@ -2611,9 +2595,14 @@ case $_backend in INCLUDES="$INCLUDES "'-I$(srcdir)/backends/platform/ds/commoninclude' INCLUDES="$INCLUDES "'-Ibackends/platform/ds/arm9/data' ;; - gp2x) - ;; gph) + # On the GPH devices we want fancy themes but do not want the load/save thumbnail grid. + DEFINES="$DEFINES -DDISABLE_SAVELOADCHOOSER_GRID" + DEFINES="$DEFINES -DGPH_DEVICE" + DEFINES="$DEFINES -DREDUCE_MEMORY_USAGE" + if test "$_debug_build" = yes; then + DEFINES="$DEFINES -DGPH_DEBUG" + fi ;; iphone) LIBS="$LIBS -lobjc -framework UIKit -framework CoreGraphics -framework OpenGLES" @@ -2709,7 +2698,7 @@ MODULES="$MODULES backends/platform/$_backend" # Setup SDL specifics for SDL based backends # case $_backend in - dingux | gp2x | gph | linuxmoto | maemo | openpandora | samsungtv | sdl) + dingux | gph | linuxmoto | maemo | openpandora | samsungtv | sdl) find_sdlconfig INCLUDES="$INCLUDES `$_sdlconfig --prefix="$_sdlpath" --cflags`" LIBS="$LIBS `$_sdlconfig --prefix="$_sdlpath" --libs`" @@ -3213,6 +3202,11 @@ fi define_in_config_if_yes "$_png" 'USE_PNG' echo "$_png" +if test `get_engine_build sword25` = yes && test ! "$_png" = yes ; then + echo "...disabling Broken Sword 2.5 engine. PNG is required" + engine_disable sword25 +fi + # # Check for Theora Decoder # @@ -3375,7 +3369,7 @@ if test "$_fluidsynth" = yes ; then esac INCLUDES="$INCLUDES $FLUIDSYNTH_CFLAGS" fi -define_in_config_h_if_yes "$_fluidsynth" 'USE_FLUIDSYNTH' +define_in_config_if_yes "$_fluidsynth" 'USE_FLUIDSYNTH' echo "$_fluidsynth" # diff --git a/devtools/credits.pl b/devtools/credits.pl index 6a4b97b89d..7ce17a9df6 100755 --- a/devtools/credits.pl +++ b/devtools/credits.pl @@ -935,6 +935,9 @@ begin_credits("Credits"); begin_section("French"); add_person("Thierry Crozat", "criezy", ""); end_section(); + begin_section("Galician"); + add_person("Santiago G. Sanz", "sgsanz", ""); + end_section(); begin_section("German"); add_person("Simon Sawatzki", "SimSaw", ""); add_person("Lothar Serra Mari", "Lothar93", ""); diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp index 805fe7d366..5f7780bfe3 100644 --- a/engines/agi/detection.cpp +++ b/engines/agi/detection.cpp @@ -20,9 +20,6 @@ * */ -// FIXME: Avoid using printf -#define FORBIDDEN_SYMBOL_EXCEPTION_printf - #include "base/plugins.h" #include "engines/advancedDetector.h" @@ -491,10 +488,14 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX g_fallbackDesc.desc.gameid = _gameid.c_str(); g_fallbackDesc.desc.extra = _extra.c_str(); - printf("Your game version has been detected using fallback matching as a\n"); - printf("variant of %s (%s).\n", g_fallbackDesc.desc.gameid, g_fallbackDesc.desc.extra); - printf("If this is an original and unmodified version or new made Fanmade game,\n"); - printf("please report any, information previously printed by ScummVM to the team.\n"); + Common::String fallbackWarning; + + fallbackWarning = "Your game version has been detected using fallback matching as a\n"; + fallbackWarning += Common::String::format("variant of %s (%s).\n", g_fallbackDesc.desc.gameid, g_fallbackDesc.desc.extra); + fallbackWarning += "If this is an original and unmodified version or new made Fanmade game,\n"; + fallbackWarning += "please report any, information previously printed by ScummVM to the team.\n"; + + g_system->logMessage(LogMessageType::kWarning, fallbackWarning.c_str()); return (const ADGameDescription *)&g_fallbackDesc; } diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp index 10c01741ae..9176412e0e 100644 --- a/engines/agos/animation.cpp +++ b/engines/agos/animation.cpp @@ -260,9 +260,6 @@ bool MoviePlayerDXA::load() { debug(0, "Playing video %s", videoName.c_str()); CursorMan.showMouse(false); - - _firstFrameOffset = _fileStream->pos(); - return true; } @@ -271,6 +268,10 @@ void MoviePlayerDXA::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) { uint w = getWidth(); const Graphics::Surface *surface = decodeNextFrame(); + + if (!surface) + return; + byte *src = (byte *)surface->pixels; dst += y * pitch + x; @@ -281,7 +282,7 @@ void MoviePlayerDXA::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) { } while (--h); if (hasDirtyPalette()) - setSystemPalette(); + g_system->getPaletteManager()->setPalette(getPalette(), 0, 256); } void MoviePlayerDXA::playVideo() { @@ -302,34 +303,7 @@ void MoviePlayerDXA::stopVideo() { } void MoviePlayerDXA::startSound() { - uint32 offset, size; - - if (getSoundTag() == MKTAG('W','A','V','E')) { - size = _fileStream->readUint32BE(); - - if (_sequenceNum) { - Common::File in; - - _fileStream->seek(size, SEEK_CUR); - - in.open("audio.wav"); - if (!in.isOpen()) { - error("Can't read offset file 'audio.wav'"); - } - - in.seek(_sequenceNum * 8, SEEK_SET); - offset = in.readUint32LE(); - size = in.readUint32LE(); - - in.seek(offset, SEEK_SET); - _bgSoundStream = Audio::makeWAVStream(in.readStream(size), DisposeAfterUse::YES); - in.close(); - } else { - _bgSoundStream = Audio::makeWAVStream(_fileStream->readStream(size), DisposeAfterUse::YES); - } - } else { - _bgSoundStream = Audio::SeekableAudioStream::openStreamFile(baseName); - } + start(); if (_bgSoundStream != NULL) { _vm->_mixer->stopHandle(_bgSound); @@ -344,8 +318,7 @@ void MoviePlayerDXA::nextFrame() { } if (_vm->_interactiveVideo == TYPE_LOOPING && endOfVideo()) { - _fileStream->seek(_firstFrameOffset); - _curFrame = -1; + rewind(); startSound(); } @@ -374,13 +347,15 @@ bool MoviePlayerDXA::processFrame() { copyFrameToBuffer((byte *)screen->pixels, (_vm->_screenWidth - getWidth()) / 2, (_vm->_screenHeight - getHeight()) / 2, screen->pitch); _vm->_system->unlockScreen(); - Common::Rational soundTime(_mixer->getSoundElapsedTime(_bgSound), 1000); - if ((_bgSoundStream == NULL) || ((soundTime * getFrameRate()).toInt() / 1000 < getCurFrame() + 1)) { + uint32 soundTime = _mixer->getSoundElapsedTime(_bgSound); + uint32 nextFrameStartTime = ((Video::VideoDecoder::VideoTrack *)getTrack(0))->getNextFrameStartTime(); + + if ((_bgSoundStream == NULL) || soundTime < nextFrameStartTime) { if (_bgSoundStream && _mixer->isSoundHandleActive(_bgSound)) { - while (_mixer->isSoundHandleActive(_bgSound) && (soundTime * getFrameRate()).toInt() < getCurFrame()) { + while (_mixer->isSoundHandleActive(_bgSound) && soundTime < nextFrameStartTime) { _vm->_system->delayMillis(10); - soundTime = Common::Rational(_mixer->getSoundElapsedTime(_bgSound), 1000); + soundTime = _mixer->getSoundElapsedTime(_bgSound); } // In case the background sound ends prematurely, update // _ticks so that we can still fall back on the no-sound @@ -399,14 +374,35 @@ bool MoviePlayerDXA::processFrame() { return false; } -void MoviePlayerDXA::updateVolume() { - if (g_system->getMixer()->isSoundHandleActive(_bgSound)) - g_system->getMixer()->setChannelVolume(_bgSound, getVolume()); -} +void MoviePlayerDXA::readSoundData(Common::SeekableReadStream *stream) { + uint32 tag = stream->readUint32BE(); + + if (tag == MKTAG('W','A','V','E')) { + uint32 size = stream->readUint32BE(); + + if (_sequenceNum) { + Common::File in; + + stream->skip(size); + + in.open("audio.wav"); + if (!in.isOpen()) { + error("Can't read offset file 'audio.wav'"); + } + + in.seek(_sequenceNum * 8, SEEK_SET); + uint32 offset = in.readUint32LE(); + size = in.readUint32LE(); -void MoviePlayerDXA::updateBalance() { - if (g_system->getMixer()->isSoundHandleActive(_bgSound)) - g_system->getMixer()->setChannelBalance(_bgSound, getBalance()); + in.seek(offset, SEEK_SET); + _bgSoundStream = Audio::makeWAVStream(in.readStream(size), DisposeAfterUse::YES); + in.close(); + } else { + _bgSoundStream = Audio::makeWAVStream(stream->readStream(size), DisposeAfterUse::YES); + } + } else { + _bgSoundStream = Audio::SeekableAudioStream::openStreamFile(baseName); + } } /////////////////////////////////////////////////////////////////////////////// @@ -415,7 +411,7 @@ void MoviePlayerDXA::updateBalance() { MoviePlayerSMK::MoviePlayerSMK(AGOSEngine_Feeble *vm, const char *name) - : MoviePlayer(vm), SmackerDecoder(vm->_mixer) { + : MoviePlayer(vm), SmackerDecoder() { debug(0, "Creating SMK cutscene player"); memset(baseName, 0, sizeof(baseName)); @@ -435,8 +431,6 @@ bool MoviePlayerSMK::load() { CursorMan.showMouse(false); - _firstFrameOffset = _fileStream->pos(); - return true; } @@ -445,6 +439,10 @@ void MoviePlayerSMK::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) { uint w = getWidth(); const Graphics::Surface *surface = decodeNextFrame(); + + if (!surface) + return; + byte *src = (byte *)surface->pixels; dst += y * pitch + x; @@ -455,7 +453,7 @@ void MoviePlayerSMK::copyFrameToBuffer(byte *dst, uint x, uint y, uint pitch) { } while (--h); if (hasDirtyPalette()) - setSystemPalette(); + g_system->getPaletteManager()->setPalette(getPalette(), 0, 256); } void MoviePlayerSMK::playVideo() { @@ -468,6 +466,7 @@ void MoviePlayerSMK::stopVideo() { } void MoviePlayerSMK::startSound() { + start(); } void MoviePlayerSMK::handleNextFrame() { @@ -477,10 +476,8 @@ void MoviePlayerSMK::handleNextFrame() { } void MoviePlayerSMK::nextFrame() { - if (_vm->_interactiveVideo == TYPE_LOOPING && endOfVideo()) { - _fileStream->seek(_firstFrameOffset); - _curFrame = -1; - } + if (_vm->_interactiveVideo == TYPE_LOOPING && endOfVideo()) + rewind(); if (!endOfVideo()) { decodeNextFrame(); @@ -503,7 +500,7 @@ bool MoviePlayerSMK::processFrame() { uint32 waitTime = getTimeToNextFrame(); - if (!waitTime) { + if (!waitTime && !endOfVideoTracks()) { warning("dropped frame %i", getCurFrame()); return false; } diff --git a/engines/agos/animation.h b/engines/agos/animation.h index d1ff074b03..9e31fced6d 100644 --- a/engines/agos/animation.h +++ b/engines/agos/animation.h @@ -67,9 +67,6 @@ protected: virtual void handleNextFrame(); virtual bool processFrame() = 0; virtual void startSound() {} - -protected: - uint32 _firstFrameOffset; }; class MoviePlayerDXA : public MoviePlayer, Video::DXADecoder { @@ -84,9 +81,7 @@ public: virtual void stopVideo(); protected: - // VideoDecoder API - void updateVolume(); - void updateBalance(); + void readSoundData(Common::SeekableReadStream *stream); private: void handleNextFrame(); diff --git a/engines/cine/anim.cpp b/engines/cine/anim.cpp index 410fcca1f3..60168831a1 100644 --- a/engines/cine/anim.cpp +++ b/engines/cine/anim.cpp @@ -682,9 +682,10 @@ void convert8BBP2(byte *dest, byte *source, int16 width, int16 height) { * Load image set * @param resourceName Image set filename * @param idx Target index in animDataTable (-1 if any empty space will do) + * @param frameIndex frame of animation to load (-1 for all frames) * @return The number of the animDataTable entry after the loaded image set (-1 if error) */ -int loadSet(const char *resourceName, int16 idx) { +int loadSet(const char *resourceName, int16 idx, int16 frameIndex =-1 ) { AnimHeader2Struct header2; uint16 numSpriteInAnim; int16 foundFileIdx = findFileInBundle(resourceName); @@ -708,7 +709,17 @@ int loadSet(const char *resourceName, int16 idx) { entry = idx < 0 ? emptyAnimSpace() : idx; assert(entry >= 0); - for (int16 i = 0; i < numSpriteInAnim; i++, entry++) { + int16 startFrame = 0; + int16 endFrame = numSpriteInAnim; + + if(frameIndex>=0) + { + startFrame = frameIndex; + endFrame = frameIndex+1; + ptr += 0x10 * frameIndex; + } + + for (int16 i = startFrame; i < endFrame; i++, entry++) { Common::MemoryReadStream readS(ptr, 0x10); header2.field_0 = readS.readUint32BE(); @@ -767,7 +778,7 @@ int loadSeq(const char *resourceName, int16 idx) { * @return The number of the animDataTable entry after the loaded resource (-1 if error) * @todo Implement loading of all resource types */ -int loadResource(const char *resourceName, int16 idx) { +int loadResource(const char *resourceName, int16 idx, int16 frameIndex) { int result = -1; // Return an error by default if (strstr(resourceName, ".SPL")) { result = loadSpl(resourceName, idx); @@ -778,7 +789,7 @@ int loadResource(const char *resourceName, int16 idx) { } else if (strstr(resourceName, ".ANM")) { result = loadAni(resourceName, idx); } else if (strstr(resourceName, ".SET")) { - result = loadSet(resourceName, idx); + result = loadSet(resourceName, idx, frameIndex); } else if (strstr(resourceName, ".SEQ")) { result = loadSeq(resourceName, idx); } else if (strstr(resourceName, ".H32")) { diff --git a/engines/cine/anim.h b/engines/cine/anim.h index 9c06c260ce..c5130aab82 100644 --- a/engines/cine/anim.h +++ b/engines/cine/anim.h @@ -98,7 +98,7 @@ public: void freeAnimDataTable(); void freeAnimDataRange(byte startIdx, byte numIdx); -int loadResource(const char *resourceName, int16 idx = -1); +int loadResource(const char *resourceName, int16 idx = -1, int16 frameIndex = -1); void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGameFormat saveGameFormat); void generateMask(const byte *sprite, byte *mask, uint16 size, byte transparency); diff --git a/engines/cine/bg_list.cpp b/engines/cine/bg_list.cpp index 693fea3294..36ecf53dea 100644 --- a/engines/cine/bg_list.cpp +++ b/engines/cine/bg_list.cpp @@ -39,9 +39,9 @@ uint32 var8; * @param objIdx Sprite description */ void addToBGList(int16 objIdx) { - renderer->incrustSprite(g_cine->_objectTable[objIdx]); - createBgIncrustListElement(objIdx, 0); + + renderer->incrustSprite(g_cine->_bgIncrustList.back()); } /** @@ -49,9 +49,9 @@ void addToBGList(int16 objIdx) { * @param objIdx Sprite description */ void addSpriteFilledToBGList(int16 objIdx) { - renderer->incrustMask(g_cine->_objectTable[objIdx]); - createBgIncrustListElement(objIdx, 1); + + renderer->incrustMask(g_cine->_bgIncrustList.back()); } /** @@ -103,9 +103,9 @@ void loadBgIncrustFromSave(Common::SeekableReadStream &fHandle) { g_cine->_bgIncrustList.push_back(tmp); if (tmp.param == 0) { - renderer->incrustSprite(g_cine->_objectTable[tmp.objIdx]); + renderer->incrustSprite(tmp); } else { - renderer->incrustMask(g_cine->_objectTable[tmp.objIdx]); + renderer->incrustMask(tmp); } } } diff --git a/engines/cine/cine.cpp b/engines/cine/cine.cpp index 6b94c33c31..bbe2cd4896 100644 --- a/engines/cine/cine.cpp +++ b/engines/cine/cine.cpp @@ -189,6 +189,8 @@ void CineEngine::initialize() { g_cine->_messageTable.clear(); resetObjectTable(); + disableSystemMenu = 1; + var8 = 0; var2 = var3 = var4 = var5 = 0; diff --git a/engines/cine/gfx.cpp b/engines/cine/gfx.cpp index d448f134ff..7a988227f6 100644 --- a/engines/cine/gfx.cpp +++ b/engines/cine/gfx.cpp @@ -113,7 +113,7 @@ FWRenderer::FWRenderer() : _background(NULL), _backupPal(), _cmd(""), assert(_backBuffer); memset(_backBuffer, 0, _screenSize); - memset(_bgName, 0, sizeof(_bgName)); + memset(_bgName, 0, sizeof (_bgName)); } @@ -174,7 +174,8 @@ void FWRenderer::fillSprite(const ObjectStruct &obj, uint8 color) { * @param obj Object info * @param fillColor Sprite color */ -void FWRenderer::incrustMask(const ObjectStruct &obj, uint8 color) { +void FWRenderer::incrustMask(const BGIncrust &incrust, uint8 color) { + const ObjectStruct &obj = g_cine->_objectTable[incrust.objIdx]; const byte *data = g_cine->_animDataTable[obj.frame].data(); int x, y, width, height; @@ -218,7 +219,9 @@ void FWRenderer::drawSprite(const ObjectStruct &obj) { * Draw color sprite on background * @param obj Object info */ -void FWRenderer::incrustSprite(const ObjectStruct &obj) { +void FWRenderer::incrustSprite(const BGIncrust &incrust) { + const ObjectStruct &obj = g_cine->_objectTable[incrust.objIdx]; + const byte *data = g_cine->_animDataTable[obj.frame].data(); const byte *mask = g_cine->_animDataTable[obj.frame].mask(); int x, y, width, height; @@ -246,14 +249,16 @@ void FWRenderer::drawCommand() { unsigned int i; int x = 10, y = _cmdY; - drawPlainBox(x, y, 301, 11, 0); - drawBorder(x - 1, y - 1, 302, 12, 2); + if(disableSystemMenu == 0) { + drawPlainBox(x, y, 301, 11, 0); + drawBorder(x - 1, y - 1, 302, 12, 2); - x += 2; - y += 2; + x += 2; + y += 2; - for (i = 0; i < _cmd.size(); i++) { - x = drawChar(_cmd[i], x, y); + for (i = 0; i < _cmd.size(); i++) { + x = drawChar(_cmd[i], x, y); + } } } @@ -298,10 +303,11 @@ void FWRenderer::drawMessage(const char *str, int x, int y, int width, int color for (i = 0; str[i]; i++, line--) { // Fit line of text into textbox if (!line) { - while (str[i] == ' ') i++; + while (str[i] == ' ') + i++; line = fitLine(str + i, tw, words, cw); - if (str[i + line] != '\0' && str[i + line] != 0x7C && words) { + if ( str[i + line] != '\0' && str[i + line] != 0x7C && words) { space = (tw - cw) / words; extraSpace = (tw - cw) % words; } else { @@ -1119,7 +1125,8 @@ void OSRenderer::clear() { * @param obj Object info * @param fillColor Sprite color */ -void OSRenderer::incrustMask(const ObjectStruct &obj, uint8 color) { +void OSRenderer::incrustMask(const BGIncrust &incrust, uint8 color) { + const ObjectStruct &obj = g_cine->_objectTable[incrust.objIdx]; const byte *data = g_cine->_animDataTable[obj.frame].data(); int x, y, width, height; @@ -1154,15 +1161,16 @@ void OSRenderer::drawSprite(const ObjectStruct &obj) { * Draw color sprite * @param obj Object info */ -void OSRenderer::incrustSprite(const ObjectStruct &obj) { - const byte *data = g_cine->_animDataTable[obj.frame].data(); +void OSRenderer::incrustSprite(const BGIncrust &incrust) { + const ObjectStruct &obj = g_cine->_objectTable[incrust.objIdx]; + const byte *data = g_cine->_animDataTable[incrust.frame].data(); int x, y, width, height, transColor; - x = obj.x; - y = obj.y; + x = incrust.x; + y = incrust.y; transColor = obj.part; - width = g_cine->_animDataTable[obj.frame]._realWidth; - height = g_cine->_animDataTable[obj.frame]._height; + width = g_cine->_animDataTable[incrust.frame]._realWidth; + height = g_cine->_animDataTable[incrust.frame]._height; if (_bgTable[_currentBg].bg) { drawSpriteRaw2(data, transColor, width, height, _bgTable[_currentBg].bg, x, y); @@ -1416,7 +1424,7 @@ void OSRenderer::selectBg(unsigned int idx) { if (_bgTable[idx].bg) { assert(_bgTable[idx].pal.isValid() && !(_bgTable[idx].pal.empty())); - _currentBg = idx; + _currentBg = idx; } else warning("OSRenderer::selectBg(%d) - attempt to select null background", idx); reloadPalette(); @@ -1742,23 +1750,23 @@ void OSRenderer::drawSprite(overlay *overlayPtr, const byte *spritePtr, int16 wi // draw the mask based on next objects in the list Common::List<overlay>::iterator it; - for (it = g_cine->_overlayList.begin(); it != g_cine->_overlayList.end(); ++it) { - if (&(*it) == overlayPtr) { + for (it = g_cine->_overlayList.begin(); it != g_cine->_overlayList.end(); ++it) { + if(&(*it) == overlayPtr) { break; } } - while (it != g_cine->_overlayList.end()) { + while(it != g_cine->_overlayList.end()) { overlay *pCurrentOverlay = &(*it); if ((pCurrentOverlay->type == 5) || ((pCurrentOverlay->type == 21) && (pCurrentOverlay->x == overlayPtr->objIdx))) { AnimData *sprite = &g_cine->_animDataTable[g_cine->_objectTable[it->objIdx].frame]; if (pMask == NULL) { - pMask = new byte[width * height]; + pMask = new byte[width*height]; for (int i = 0; i < height; i++) { for (int j = 0; j < width; j++) { - byte spriteColor = spritePtr[width * i + j]; + byte spriteColor= spritePtr[width * i + j]; pMask[width * i + j] = spriteColor; } } @@ -1769,7 +1777,7 @@ void OSRenderer::drawSprite(overlay *overlayPtr, const byte *spritePtr, int16 wi int inMaskX = (g_cine->_objectTable[it->objIdx].x + i) - x; int inMaskY = (g_cine->_objectTable[it->objIdx].y + j) - y; - if (inMaskX >= 0 && inMaskX < width) { + if (inMaskX >=0 && inMaskX < width) { if (inMaskY >= 0 && inMaskY < height) { if (sprite->_bpp == 1) { if (!sprite->getColor(i, j)) { @@ -1780,23 +1788,27 @@ void OSRenderer::drawSprite(overlay *overlayPtr, const byte *spritePtr, int16 wi } } } - - } it++; } // now, draw with the mask we created - if (pMask) { + if(pMask) { spritePtr = pMask; } + + // ignore transparent color in 1bpp + if (bpp == 1) { + transparentColor = 1; + } + { for (int i = 0; i < height; i++) { byte *destPtr = page + x + y * 320; destPtr += i * 320; for (int j = 0; j < width; j++) { - byte color = *(spritePtr++); + byte color= *(spritePtr++); if ((transparentColor != color) && x + j >= 0 && x + j < 320 && i + y >= 0 && i + y < 200) { *(destPtr++) = color; } else { diff --git a/engines/cine/gfx.h b/engines/cine/gfx.h index 6ff5b08b77..3434cf9fc2 100644 --- a/engines/cine/gfx.h +++ b/engines/cine/gfx.h @@ -27,6 +27,7 @@ #include "common/rect.h" #include "common/stack.h" #include "cine/object.h" +#include "cine/bg_list.h" namespace Cine { @@ -177,8 +178,8 @@ public: void drawFrame(); void setCommand(Common::String cmd); - virtual void incrustMask(const ObjectStruct &obj, uint8 color = 0); - virtual void incrustSprite(const ObjectStruct &obj); + virtual void incrustMask(const BGIncrust &incrust, uint8 color = 0); + virtual void incrustSprite(const BGIncrust &incrust); virtual void loadBg16(const byte *bg, const char *name, unsigned int idx = 0); virtual void loadCt16(const byte *ct, const char *name); @@ -239,8 +240,8 @@ public: void clear(); - void incrustMask(const ObjectStruct &obj, uint8 color = 0); - void incrustSprite(const ObjectStruct &obj); + void incrustMask(const BGIncrust &incrust, uint8 color = 0); + void incrustSprite(const BGIncrust &incrust); void loadBg16(const byte *bg, const char *name, unsigned int idx = 0); void loadCt16(const byte *ct, const char *name); diff --git a/engines/cine/main_loop.cpp b/engines/cine/main_loop.cpp index 971830ce8f..f13f38a45e 100644 --- a/engines/cine/main_loop.cpp +++ b/engines/cine/main_loop.cpp @@ -56,6 +56,12 @@ static void processEvent(Common::Event &event) { case Common::EVENT_RBUTTONDOWN: mouseRight = 1; break; + case Common::EVENT_LBUTTONUP: + mouseLeft = 0; + break; + case Common::EVENT_RBUTTONUP: + mouseRight = 0; + break; case Common::EVENT_MOUSEMOVE: break; case Common::EVENT_KEYDOWN: @@ -115,7 +121,7 @@ static void processEvent(Common::Event &event) { } break; case Common::KEYCODE_F10: - if (!disableSystemMenu && !inMenu) { + if (!inMenu) { g_cine->makeSystemMenu(); } break; @@ -214,8 +220,6 @@ void manageEvents() { g_sound->update(); mouseData.left = mouseLeft; mouseData.right = mouseRight; - mouseLeft = 0; - mouseRight = 0; } void getMouseData(uint16 param, uint16 *pButton, uint16 *pX, uint16 *pY) { @@ -311,6 +315,7 @@ void CineEngine::mainLoop(int bootScriptIdx) { // HACK: Force amount of oxygen left to maximum during Operation Stealth's first arcade sequence. // This makes it possible to pass the arcade sequence for now. // FIXME: Remove the hack and make the first arcade sequence normally playable. + /* if (g_cine->getGameType() == Cine::GType_OS) { Common::String bgName(renderer->getBgName()); // Check if the background is one of the three backgrounds @@ -320,7 +325,7 @@ void CineEngine::mainLoop(int bootScriptIdx) { // Force the amount of oxygen left to the maximum. g_cine->_objectTable[oxygenObjNum].x = maxOxygen; } - } + }*/ // HACK: In Operation Stealth after the first arcade sequence jump player's position to avoid getting stuck. // After the first arcade sequence the player comes up stairs from @@ -379,8 +384,8 @@ void CineEngine::mainLoop(int bootScriptIdx) { playerAction = false; _messageLen <<= 3; - if (_messageLen < 0x800) - _messageLen = 0x800; + if (_messageLen < 800) + _messageLen = 800; do { manageEvents(); diff --git a/engines/cine/saveload.cpp b/engines/cine/saveload.cpp index 223099a587..20952eea52 100644 --- a/engines/cine/saveload.cpp +++ b/engines/cine/saveload.cpp @@ -991,7 +991,7 @@ void CineEngine::makeSave(char *saveFileName) { * at a time. */ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGameFormat saveGameFormat) { - int16 currentAnim, foundFileIdx; + int16 foundFileIdx; char *animName, part[256], name[10]; strcpy(part, currentPartName); @@ -1001,10 +1001,10 @@ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGam const int entrySize = ((saveGameFormat == ANIMSIZE_23) ? 23 : 30); const int fileStartPos = fHandle.pos(); - currentAnim = 0; - while (currentAnim < NUM_MAX_ANIMDATA) { + + for(int resourceIndex=0; resourceIndex<NUM_MAX_ANIMDATA; resourceIndex++) { // Seek to the start of the current animation's entry - fHandle.seek(fileStartPos + currentAnim * entrySize); + fHandle.seek(fileStartPos + resourceIndex * entrySize); // Read in the current animation entry fHandle.readUint16BE(); // width fHandle.readUint16BE(); @@ -1019,7 +1019,7 @@ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGam } foundFileIdx = fHandle.readSint16BE(); - fHandle.readSint16BE(); // frame + int16 frameIndex = fHandle.readSint16BE(); // frame fHandle.read(name, 10); // Handle variables only present in animation entries of size 23 @@ -1029,7 +1029,7 @@ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGam // Don't try to load invalid entries. if (foundFileIdx < 0 || !validPtr) { - currentAnim++; // Jump over the invalid entry + //resourceIndex++; // Jump over the invalid entry continue; } @@ -1041,9 +1041,7 @@ void loadResourcesFromSave(Common::SeekableReadStream &fHandle, enum CineSaveGam animName = g_cine->_partBuffer[foundFileIdx].partName; loadRelatedPalette(animName); // Is this for Future Wars only? - const int16 prevAnim = currentAnim; - currentAnim = loadResource(animName, currentAnim); - assert(currentAnim > prevAnim); // Make sure we advance forward + loadResource(animName, resourceIndex, frameIndex); } loadPart(part); diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp index 66150cc5b2..9cbe3c3fab 100644 --- a/engines/cine/script_fw.cpp +++ b/engines/cine/script_fw.cpp @@ -533,7 +533,6 @@ void RawScript::setData(const FWScriptInfo &info, const byte *data) { * @return Precalculated script labels */ const ScriptVars &RawScript::labels() const { - assert(_data); return _labels; } @@ -687,7 +686,7 @@ const char *FWScript::getNextString() { * @param pos Restored script position */ void FWScript::load(const ScriptVars &labels, const ScriptVars &local, uint16 compare, uint16 pos) { - assert(pos < _script._size); + assert(pos <= _script._size); _labels = labels; _localVars = local; _compare = compare; @@ -705,13 +704,15 @@ void FWScript::load(const ScriptVars &labels, const ScriptVars &local, uint16 co int FWScript::execute() { int ret = 0; - while (!ret) { - _line = _pos; - byte opcode = getNextByte(); - OpFunc handler = _info->opcodeHandler(opcode); + if(_script._size) { + while (!ret) { + _line = _pos; + byte opcode = getNextByte(); + OpFunc handler = _info->opcodeHandler(opcode); - if (handler) { - ret = (this->*handler)(); + if (handler) { + ret = (this->*handler)(); + } } } @@ -1861,7 +1862,7 @@ int FWScript::o1_disableSystemMenu() { byte param = getNextByte(); debugC(5, kCineDebugScript, "Line: %d: disableSystemMenu(%d)", _line, param); - disableSystemMenu = (param != 0); + disableSystemMenu = param; return 0; } diff --git a/engines/cine/various.cpp b/engines/cine/various.cpp index 9b73ae1101..eccd71cf05 100644 --- a/engines/cine/various.cpp +++ b/engines/cine/various.cpp @@ -36,7 +36,7 @@ namespace Cine { -bool disableSystemMenu = false; +int16 disableSystemMenu = 0; bool inMenu; int16 commandVar3[4]; @@ -341,7 +341,7 @@ void CineEngine::makeSystemMenu() { int16 mouseX, mouseY, mouseButton; int16 selectedSave; - if (!disableSystemMenu) { + if (disableSystemMenu != 1) { inMenu = true; do { @@ -544,14 +544,16 @@ int16 buildObjectListCommand(int16 param) { int16 selectSubObject(int16 x, int16 y, int16 param) { int16 listSize = buildObjectListCommand(param); - int16 selectedObject; + int16 selectedObject = -1; bool osExtras = g_cine->getGameType() == Cine::GType_OS; if (!listSize) { return -2; } - selectedObject = makeMenuChoice(objectListCommand, listSize, x, y, 140, osExtras); + if (disableSystemMenu == 0) { + selectedObject = makeMenuChoice(objectListCommand, listSize, x, y, 140, osExtras); + } if (selectedObject == -1) return -1; @@ -691,9 +693,6 @@ int16 makeMenuChoice(const CommandeType commandList[], uint16 height, uint16 X, int16 var_4; SelectionMenu *menu; - if (disableSystemMenu) - return -1; - paramY = (height * 9) + 10; if (X + width > 319) { @@ -810,14 +809,18 @@ void makeActionMenu() { getMouseData(mouseUpdateStatus, &mouseButton, &mouseX, &mouseY); if (g_cine->getGameType() == Cine::GType_OS) { - playerCommand = makeMenuChoice(defaultActionCommand, 6, mouseX, mouseY, 70, true); + if(disableSystemMenu == 0) { + playerCommand = makeMenuChoice(defaultActionCommand, 6, mouseX, mouseY, 70, true); + } if (playerCommand >= 8000) { playerCommand -= 8000; canUseOnObject = canUseOnItemTable[playerCommand]; } } else { - playerCommand = makeMenuChoice(defaultActionCommand, 6, mouseX, mouseY, 70); + if(disableSystemMenu == 0) { + playerCommand = makeMenuChoice(defaultActionCommand, 6, mouseX, mouseY, 70); + } } inMenu = false; diff --git a/engines/cine/various.h b/engines/cine/various.h index 0c1883c323..813619816d 100644 --- a/engines/cine/various.h +++ b/engines/cine/various.h @@ -41,7 +41,7 @@ void makeActionMenu(); void waitPlayerInput(); void setTextWindow(uint16 param1, uint16 param2, uint16 param3, uint16 param4); -extern bool disableSystemMenu; +extern int16 disableSystemMenu; extern bool inMenu; extern CommandeType currentSaveName[10]; diff --git a/engines/lastexpress/data/background.cpp b/engines/lastexpress/data/background.cpp index 3d866c26f9..60379251a3 100644 --- a/engines/lastexpress/data/background.cpp +++ b/engines/lastexpress/data/background.cpp @@ -107,6 +107,7 @@ byte *Background::decodeComponent(Common::SeekableReadStream *in, uint32 inSize, return NULL; // Initialize the decoding + memset(out, 0, outSize * sizeof(byte)); uint32 inPos = 0; uint32 outPos = 0; diff --git a/engines/lastexpress/data/subtitle.cpp b/engines/lastexpress/data/subtitle.cpp index a9a8284588..4d19c02aa7 100644 --- a/engines/lastexpress/data/subtitle.cpp +++ b/engines/lastexpress/data/subtitle.cpp @@ -210,10 +210,10 @@ void SubtitleManager::setTime(uint16 time) { _currentIndex = -1; // Find the appropriate line to show - for (int16 i = 0; i < (int16)_subtitles.size(); i++) { + for (uint i = 0; i < _subtitles.size(); i++) { if ((time >= _subtitles[i]->getTimeStart()) && (time <= _subtitles[i]->getTimeStop())) { // Keep the index of the line to show - _currentIndex = i; + _currentIndex = (int16)i; return; } } @@ -237,7 +237,7 @@ Common::Rect SubtitleManager::draw(Graphics::Surface *surface) { // Draw the current line assert(_currentIndex >= 0 && _currentIndex < (int16)_subtitles.size()); - return _subtitles[_currentIndex]->draw(surface, _font); + return _subtitles[(uint16)_currentIndex]->draw(surface, _font); } } // End of namespace LastExpress diff --git a/engines/lastexpress/debug.cpp b/engines/lastexpress/debug.cpp index f89ad8b80d..db3a3e3962 100644 --- a/engines/lastexpress/debug.cpp +++ b/engines/lastexpress/debug.cpp @@ -85,7 +85,6 @@ Debugger::Debugger(LastExpressEngine *engine) : _engine(engine), _command(NULL), DCmd_Register("entity", WRAP_METHOD(Debugger, cmdEntity)); // Misc - DCmd_Register("loadgame", WRAP_METHOD(Debugger, cmdLoadGame)); DCmd_Register("chapter", WRAP_METHOD(Debugger, cmdSwitchChapter)); DCmd_Register("clear", WRAP_METHOD(Debugger, cmdClear)); @@ -139,6 +138,9 @@ void Debugger::copyCommand(int argc, const char **argv) { for (int i = 0; i < _numParams; i++) { _commandParams[i] = (char *)malloc(strlen(argv[i]) + 1); + if (_commandParams[i] == NULL) + error("[Debugger::copyCommand] Cannot allocate memory for command parameters"); + memset(_commandParams[i], 0, strlen(argv[i]) + 1); strcpy(_commandParams[i], argv[i]); } @@ -152,9 +154,18 @@ void Debugger::callCommand() { (*_command)(_numParams, const_cast<const char **>(_commandParams)); } -void Debugger::loadArchive(ArchiveIndex index) const { - _engine->getResourceManager()->loadArchive(index); - getScenes()->loadSceneDataFile(index); +bool Debugger::loadArchive(int index) { + if (index < 1 || index > 3) { + DebugPrintf("Invalid cd number (was: %d, valid: [1-3])\n", index); + return false; + } + + if (!_engine->getResourceManager()->loadArchive((ArchiveIndex)index)) + return false; + + getScenes()->loadSceneDataFile((ArchiveIndex)index); + + return true; } // Restore loaded archive @@ -233,8 +244,10 @@ bool Debugger::cmdListFiles(int argc, const char **argv) { Common::String filter(const_cast<char *>(argv[1])); // Load the proper archive - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive(getNumber(argv[2]))) + return true; + } Common::ArchiveMemberList list; int count = _engine->getResourceManager()->listMatchingMembers(list, filter); @@ -317,8 +330,10 @@ bool Debugger::cmdShowFrame(int argc, const char **argv) { Common::String filename(const_cast<char *>(argv[1])); filename += ".seq"; - if (argc == 4) - loadArchive((ArchiveIndex)getNumber(argv[3])); + if (argc == 4) { + if (!loadArchive(getNumber(argv[3]))) + return true; + } if (!_engine->getResourceManager()->hasFile(filename)) { DebugPrintf("Cannot find file: %s\n", filename.c_str()); @@ -377,8 +392,10 @@ bool Debugger::cmdShowBg(int argc, const char **argv) { if (argc == 2 || argc == 3) { Common::String filename(const_cast<char *>(argv[1])); - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive(getNumber(argv[2]))) + return true; + } if (!_engine->getResourceManager()->hasFile(filename + ".BG")) { DebugPrintf("Cannot find file: %s\n", (filename + ".BG").c_str()); @@ -430,8 +447,10 @@ bool Debugger::cmdPlaySeq(int argc, const char **argv) { Common::String filename(const_cast<char *>(argv[1])); filename += ".seq"; - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive(getNumber(argv[2]))) + return true; + } if (!_engine->getResourceManager()->hasFile(filename)) { DebugPrintf("Cannot find file: %s\n", filename.c_str()); @@ -505,8 +524,10 @@ bool Debugger::cmdPlaySeq(int argc, const char **argv) { bool Debugger::cmdPlaySnd(int argc, const char **argv) { if (argc == 2 || argc == 3) { - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive(getNumber(argv[2]))) + return true; + } // Add .SND at the end of the filename if needed Common::String name(const_cast<char *>(argv[1])); @@ -520,7 +541,7 @@ bool Debugger::cmdPlaySnd(int argc, const char **argv) { _engine->_system->getMixer()->stopAll(); - _soundStream->load(getArchive(name)); + _soundStream->load(getArchive(name), 16); if (argc == 3) restoreArchive(); @@ -542,8 +563,10 @@ bool Debugger::cmdPlaySbe(int argc, const char **argv) { if (argc == 2 || argc == 3) { Common::String filename(const_cast<char *>(argv[1])); - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive(getNumber(argv[2]))) + return true; + } filename += ".sbe"; @@ -605,8 +628,10 @@ bool Debugger::cmdPlayNis(int argc, const char **argv) { if (argc == 2 || argc == 3) { Common::String name(const_cast<char *>(argv[1])); - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive(getNumber(argv[2]))) + return true; + } // If we got a nis filename, check that the file exists if (name.contains('.') && !_engine->getResourceManager()->hasFile(name)) { @@ -662,8 +687,10 @@ bool Debugger::cmdLoadScene(int argc, const char **argv) { SceneIndex index = (SceneIndex)getNumber(argv[1]); // Check args - if (argc == 3) - loadArchive((ArchiveIndex)getNumber(argv[2])); + if (argc == 3) { + if (!loadArchive(getNumber(argv[2]))) + return true; + } if (index > 2500) { DebugPrintf("Error: invalid index value (0-2500)"); @@ -1091,30 +1118,6 @@ label_error: } /** - * Command: loads a game - * - * @param argc The argument count. - * @param argv The values. - * - * @return true if it was handled, false otherwise - */ -bool Debugger::cmdLoadGame(int argc, const char **argv) { - if (argc == 2) { - int id = getNumber(argv[1]); - - if (id == 0 || id > 6) - goto error; - - getSaveLoad()->loadGame((GameId)(id - 1)); - } else { -error: - DebugPrintf("Syntax: loadgame <id> (id=1-6)\n"); - } - - return true; -} - -/** * Command: switch to a specific chapter * * @param argc The argument count. diff --git a/engines/lastexpress/debug.h b/engines/lastexpress/debug.h index d9ba6f47a1..532cb83717 100644 --- a/engines/lastexpress/debug.h +++ b/engines/lastexpress/debug.h @@ -79,7 +79,6 @@ private: bool cmdShow(int argc, const char **argv); bool cmdEntity(int argc, const char **argv); - bool cmdLoadGame(int argc, const char **argv); bool cmdSwitchChapter(int argc, const char **argv); bool cmdClear(int argc, const char **argv); @@ -87,7 +86,7 @@ private: void copyCommand(int argc, const char **argv); int getNumber(const char *arg) const; - void loadArchive(ArchiveIndex index) const; + bool loadArchive(int index); void restoreArchive() const; Debuglet *_command; diff --git a/engines/lastexpress/entities/abbot.cpp b/engines/lastexpress/entities/abbot.cpp index e0fe429520..406b017d3a 100644 --- a/engines/lastexpress/entities/abbot.cpp +++ b/engines/lastexpress/entities/abbot.cpp @@ -58,10 +58,10 @@ Abbot::Abbot(LastExpressEngine *engine) : Entity(engine, kEntityAbbot) { ADD_CALLBACK_FUNCTION(Abbot, chapter2); ADD_CALLBACK_FUNCTION(Abbot, chapter3); ADD_CALLBACK_FUNCTION(Abbot, chapter3Handler); - ADD_CALLBACK_FUNCTION(Abbot, function19); - ADD_CALLBACK_FUNCTION(Abbot, function20); - ADD_CALLBACK_FUNCTION(Abbot, function21); - ADD_CALLBACK_FUNCTION(Abbot, function22); + ADD_CALLBACK_FUNCTION(Abbot, conversationWithBoutarel); + ADD_CALLBACK_FUNCTION(Abbot, readPaper); + ADD_CALLBACK_FUNCTION(Abbot, goToLunch); + ADD_CALLBACK_FUNCTION(Abbot, haveLunch); ADD_CALLBACK_FUNCTION(Abbot, function23); ADD_CALLBACK_FUNCTION(Abbot, function24); ADD_CALLBACK_FUNCTION(Abbot, function25); @@ -259,7 +259,7 @@ IMPLEMENT_FUNCTION(18, Abbot, chapter3Handler) getData()->entityPosition = kPosition_6470; getData()->location = kLocationInsideCompartment; - setup_function19(); + setup_conversationWithBoutarel(); break; } break; @@ -272,7 +272,7 @@ IMPLEMENT_FUNCTION(18, Abbot, chapter3Handler) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(19, Abbot, function19) +IMPLEMENT_FUNCTION(19, Abbot, conversationWithBoutarel) switch (savepoint.action) { default: break; @@ -311,21 +311,21 @@ IMPLEMENT_FUNCTION(19, Abbot, function19) case 3: getSavePoints()->push(kEntityAbbot, kEntityBoutarel, kAction122288808); - setup_function20(); + setup_readPaper(); break; } } IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(20, Abbot, function20) +IMPLEMENT_FUNCTION(20, Abbot, readPaper) switch (savepoint.action) { default: break; case kActionNone: if (getState()->time > kTime1966500 && getEntities()->isInRestaurant(kEntityBoutarel)) - setup_function21(); + setup_goToLunch(); break; case kActionDefault: @@ -335,7 +335,7 @@ IMPLEMENT_FUNCTION(20, Abbot, function20) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(21, Abbot, function21) +IMPLEMENT_FUNCTION(21, Abbot, goToLunch) switch (savepoint.action) { default: break; @@ -393,7 +393,7 @@ IMPLEMENT_FUNCTION(21, Abbot, function21) break; case 7: - setup_function22(); + setup_haveLunch(); break; } break; @@ -409,7 +409,7 @@ IMPLEMENT_FUNCTION(21, Abbot, function21) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(22, Abbot, function22) +IMPLEMENT_FUNCTION(22, Abbot, haveLunch) switch (savepoint.action) { default: break; @@ -1547,7 +1547,7 @@ IMPLEMENT_FUNCTION(45, Abbot, function45) getData()->car = kCarRedSleeping; getData()->location = kLocationOutsideCompartment; - RESET_ENTITY_STATE(kEntityVerges, Verges, setup_function38); + RESET_ENTITY_STATE(kEntityVerges, Verges, setup_resetState); getEntities()->drawSequenceLeft(kEntityAbbot, "617Ec"); getEntities()->enterCompartment(kEntityAbbot, kObjectCompartmentC, true); diff --git a/engines/lastexpress/entities/abbot.h b/engines/lastexpress/entities/abbot.h index ce52bb68ce..dc3e86db54 100644 --- a/engines/lastexpress/entities/abbot.h +++ b/engines/lastexpress/entities/abbot.h @@ -156,10 +156,10 @@ public: * Handle Chapter 3 events */ DECLARE_FUNCTION(chapter3Handler) - DECLARE_FUNCTION(function19) - DECLARE_FUNCTION(function20) - DECLARE_FUNCTION(function21) - DECLARE_FUNCTION(function22) + DECLARE_FUNCTION(conversationWithBoutarel) + DECLARE_FUNCTION(readPaper) + DECLARE_FUNCTION(goToLunch) + DECLARE_FUNCTION(haveLunch) DECLARE_FUNCTION(function23) DECLARE_FUNCTION(function24) DECLARE_FUNCTION(function25) diff --git a/engines/lastexpress/entities/august.cpp b/engines/lastexpress/entities/august.cpp index 67d810fde2..dbae7bad20 100644 --- a/engines/lastexpress/entities/august.cpp +++ b/engines/lastexpress/entities/august.cpp @@ -3530,7 +3530,7 @@ IMPLEMENT_FUNCTION(69, August, unhookCars) getScenes()->loadSceneFromPosition(kCarRestaurant, 85, 1); getSavePoints()->pushAll(kEntityAugust, kActionProceedChapter5); - RESET_ENTITY_STATE(kEntityVerges, Verges, setup_function42) + RESET_ENTITY_STATE(kEntityVerges, Verges, setup_end) } break; } diff --git a/engines/lastexpress/entities/chapters.cpp b/engines/lastexpress/entities/chapters.cpp index a2f3a3d871..d373432710 100644 --- a/engines/lastexpress/entities/chapters.cpp +++ b/engines/lastexpress/entities/chapters.cpp @@ -1851,7 +1851,7 @@ void Chapters::enterExitHelper(bool isEnteringStation) { callbackAction(); } -void Chapters::playSteam() { +void Chapters::playSteam() const { getSoundQueue()->resetState(); getSound()->playSteam((CityIndex)ENTITY_PARAM(0, 4)); ENTITY_PARAM(0, 2) = 0; diff --git a/engines/lastexpress/entities/chapters.h b/engines/lastexpress/entities/chapters.h index ddb3de3bea..fb52ea3ee4 100644 --- a/engines/lastexpress/entities/chapters.h +++ b/engines/lastexpress/entities/chapters.h @@ -157,7 +157,7 @@ private: bool timeCheckExitStation(TimeValue timeValue, uint ¶meter, byte callback, const char *sequence); void enterExitStation(const SavePoint &savepoint, bool isEnteringStation); void enterExitHelper(bool isEnteringStation); - void playSteam(); + void playSteam() const; }; } // End of namespace LastExpress diff --git a/engines/lastexpress/entities/entity.cpp b/engines/lastexpress/entities/entity.cpp index 2deca291f6..dad5e67392 100644 --- a/engines/lastexpress/entities/entity.cpp +++ b/engines/lastexpress/entities/entity.cpp @@ -26,10 +26,15 @@ #include "lastexpress/game/action.h" #include "lastexpress/game/entities.h" +#include "lastexpress/game/logic.h" #include "lastexpress/game/object.h" #include "lastexpress/game/savegame.h" +#include "lastexpress/game/savepoint.h" +#include "lastexpress/game/state.h" #include "lastexpress/game/scenes.h" +#include "lastexpress/lastexpress.h" + namespace LastExpress { ////////////////////////////////////////////////////////////////////////// @@ -45,12 +50,14 @@ EntityData::EntityCallData::~EntityCallData() { SAFE_DELETE(sequence3); } -void EntityData::EntityCallData::syncString(Common::Serializer &s, Common::String &string, int length) { +void EntityData::EntityCallData::syncString(Common::Serializer &s, Common::String &string, uint length) const { char seqName[13]; memset(&seqName, 0, length); - if (s.isSaving()) strcpy((char *)&seqName, string.c_str()); - s.syncBytes((byte *)&seqName, length); + if (s.isSaving()) + strcpy((char *)&seqName, string.c_str()); + + s.syncBytes((byte *)&seqName, length); if (s.isLoading()) string = seqName; @@ -110,7 +117,7 @@ EntityData::EntityParameters *EntityData::getParameters(uint callback, byte inde return _parameters[callback].parameters[index]; } -int EntityData::getCallback(uint callback) const { +byte EntityData::getCallback(uint callback) const { if (callback >= 16) error("[EntityData::getCallback] Invalid callback value (was: %d, max: 16)", callback); @@ -818,7 +825,7 @@ void Entity::setupIISS(const char *name, uint index, uint param1, uint param2, c // Helper functions ////////////////////////////////////////////////////////////////////////// -bool Entity::updateParameter(uint ¶meter, uint timeType, uint delta) { +bool Entity::updateParameter(uint ¶meter, uint timeType, uint delta) const { if (!parameter) parameter = (uint)(timeType + delta); @@ -830,7 +837,7 @@ bool Entity::updateParameter(uint ¶meter, uint timeType, uint delta) { return true; } -bool Entity::updateParameterTime(TimeValue timeValue, bool check, uint ¶meter, uint delta) { +bool Entity::updateParameterTime(TimeValue timeValue, bool check, uint ¶meter, uint delta) const { if (getState()->time <= timeValue) { if (check || !parameter) parameter = (uint)(getState()->time + delta); @@ -844,7 +851,7 @@ bool Entity::updateParameterTime(TimeValue timeValue, bool check, uint ¶mete return true; } -bool Entity::updateParameterCheck(uint ¶meter, uint timeType, uint delta) { +bool Entity::updateParameterCheck(uint ¶meter, uint timeType, uint delta) const { if (parameter && parameter >= timeType) return false; @@ -854,7 +861,7 @@ bool Entity::updateParameterCheck(uint ¶meter, uint timeType, uint delta) { return true; } -bool Entity::timeCheck(TimeValue timeValue, uint ¶meter, Common::Functor0<void> *function) { +bool Entity::timeCheck(TimeValue timeValue, uint ¶meter, Common::Functor0<void> *function) const { if (getState()->time > timeValue && !parameter) { parameter = 1; (*function)(); @@ -929,14 +936,14 @@ bool Entity::timeCheckCar(TimeValue timeValue, uint ¶meter, byte callback, C return false; } -void Entity::timeCheckSavepoint(TimeValue timeValue, uint ¶meter, EntityIndex entity1, EntityIndex entity2, ActionIndex action) { +void Entity::timeCheckSavepoint(TimeValue timeValue, uint ¶meter, EntityIndex entity1, EntityIndex entity2, ActionIndex action) const { if (getState()->time > timeValue && !parameter) { parameter = 1; getSavePoints()->push(entity1, entity2, action); } } -void Entity::timeCheckObject(TimeValue timeValue, uint ¶meter, ObjectIndex object, ObjectLocation location) { +void Entity::timeCheckObject(TimeValue timeValue, uint ¶meter, ObjectIndex object, ObjectLocation location) const { if (getState()->time > timeValue && !parameter) { parameter = 1; getObjects()->updateLocation2(object, location); diff --git a/engines/lastexpress/entities/entity.h b/engines/lastexpress/entities/entity.h index 3601f34f6f..c67d13db9e 100644 --- a/engines/lastexpress/entities/entity.h +++ b/engines/lastexpress/entities/entity.h @@ -25,13 +25,8 @@ #include "lastexpress/shared.h" -#include "lastexpress/game/logic.h" -#include "lastexpress/game/savepoint.h" -#include "lastexpress/game/state.h" - #include "lastexpress/sound/sound.h" -#include "lastexpress/lastexpress.h" #include "lastexpress/helpers.h" #include "common/array.h" @@ -827,7 +822,7 @@ public: * @param string The string. * @param length Length of the string. */ - void syncString(Common::Serializer &s, Common::String &string, int length); + void syncString(Common::Serializer &s, Common::String &string, uint length) const; // Serializable void saveLoadWithSerializer(Common::Serializer &s); @@ -850,8 +845,8 @@ public: EntityParameters *getCurrentParameters(byte index = 0) { return getParameters(_data.currentCall, index); } EntityCallParameters *getCurrentCallParameters() { return &_parameters[_data.currentCall]; } - int getCallback(uint callback) const; - int getCurrentCallback() { return getCallback(_data.currentCall); } + byte getCallback(uint callback) const; + byte getCurrentCallback() { return getCallback(_data.currentCall); } void setCallback(uint callback, byte index); void setCurrentCallback(uint index) { setCallback(_data.currentCall, index); } @@ -1089,18 +1084,18 @@ protected: // Helper functions ////////////////////////////////////////////////////////////////////////// - bool updateParameter(uint ¶meter, uint timeType, uint delta); - bool updateParameterCheck(uint ¶meter, uint timeType, uint delta); - bool updateParameterTime(TimeValue timeValue, bool check, uint ¶meter, uint delta); + bool updateParameter(uint ¶meter, uint timeType, uint delta) const; + bool updateParameterCheck(uint ¶meter, uint timeType, uint delta) const; + bool updateParameterTime(TimeValue timeValue, bool check, uint ¶meter, uint delta) const; - bool timeCheck(TimeValue timeValue, uint ¶meter, Common::Functor0<void> *function); + bool timeCheck(TimeValue timeValue, uint ¶meter, Common::Functor0<void> *function) const; bool timeCheckCallback(TimeValue timeValue, uint ¶meter, byte callback, Common::Functor0<void> *function); bool timeCheckCallback(TimeValue timeValue, uint ¶meter, byte callback, const char *str, Common::Functor1<const char *, void> *function); bool timeCheckCallback(TimeValue timeValue, uint ¶meter, byte callback, bool check, Common::Functor1<bool, void> *function); bool timeCheckCallbackInventory(TimeValue timeValue, uint ¶meter, byte callback, Common::Functor0<void> *function); bool timeCheckCar(TimeValue timeValue, uint ¶meter, byte callback, Common::Functor0<void> *function); - void timeCheckSavepoint(TimeValue timeValue, uint ¶meter, EntityIndex entity1, EntityIndex entity2, ActionIndex action); - void timeCheckObject(TimeValue timeValue, uint ¶meter, ObjectIndex index, ObjectLocation location); + void timeCheckSavepoint(TimeValue timeValue, uint ¶meter, EntityIndex entity1, EntityIndex entity2, ActionIndex action) const; + void timeCheckObject(TimeValue timeValue, uint ¶meter, ObjectIndex index, ObjectLocation location) const; bool timeCheckCallbackAction(TimeValue timeValue, uint ¶meter); bool timeCheckPlaySoundUpdatePosition(TimeValue timeValue, uint ¶meter, byte callback, const char* sound, EntityPosition position); diff --git a/engines/lastexpress/entities/verges.cpp b/engines/lastexpress/entities/verges.cpp index 867f122d8f..d9ddb0a4d1 100644 --- a/engines/lastexpress/entities/verges.cpp +++ b/engines/lastexpress/entities/verges.cpp @@ -46,40 +46,40 @@ Verges::Verges(LastExpressEngine *engine) : Entity(engine, kEntityVerges) { ADD_CALLBACK_FUNCTION(Verges, callbackActionRestaurantOrSalon); ADD_CALLBACK_FUNCTION(Verges, savegame); ADD_CALLBACK_FUNCTION(Verges, updateEntity); - ADD_CALLBACK_FUNCTION(Verges, function9); - ADD_CALLBACK_FUNCTION(Verges, function10); + ADD_CALLBACK_FUNCTION(Verges, walkBetweenCars); + ADD_CALLBACK_FUNCTION(Verges, makeAnnouncement); ADD_CALLBACK_FUNCTION(Verges, function11); ADD_CALLBACK_FUNCTION(Verges, function12); - ADD_CALLBACK_FUNCTION(Verges, function13); + ADD_CALLBACK_FUNCTION(Verges, baggageCar); ADD_CALLBACK_FUNCTION(Verges, updateFromTime); - ADD_CALLBACK_FUNCTION(Verges, function15); - ADD_CALLBACK_FUNCTION(Verges, function16); - ADD_CALLBACK_FUNCTION(Verges, function17); + ADD_CALLBACK_FUNCTION(Verges, dialog); + ADD_CALLBACK_FUNCTION(Verges, dialog2); + ADD_CALLBACK_FUNCTION(Verges, talkAboutPassengerList); ADD_CALLBACK_FUNCTION(Verges, chapter1); ADD_CALLBACK_FUNCTION(Verges, talkHarem); ADD_CALLBACK_FUNCTION(Verges, talkPassengerList); ADD_CALLBACK_FUNCTION(Verges, talkGendarmes); - ADD_CALLBACK_FUNCTION(Verges, function22); + ADD_CALLBACK_FUNCTION(Verges, askMertensToRelayAugustInvitation); ADD_CALLBACK_FUNCTION(Verges, function23); ADD_CALLBACK_FUNCTION(Verges, policeGettingOffTrain); - ADD_CALLBACK_FUNCTION(Verges, function25); + ADD_CALLBACK_FUNCTION(Verges, policeSearch); ADD_CALLBACK_FUNCTION(Verges, chapter1Handler); ADD_CALLBACK_FUNCTION(Verges, chapter2); ADD_CALLBACK_FUNCTION(Verges, chapter2Handler); ADD_CALLBACK_FUNCTION(Verges, chapter3); ADD_CALLBACK_FUNCTION(Verges, function30); - ADD_CALLBACK_FUNCTION(Verges, function31); + ADD_CALLBACK_FUNCTION(Verges, talkAboutMax); ADD_CALLBACK_FUNCTION(Verges, function32); ADD_CALLBACK_FUNCTION(Verges, function33); ADD_CALLBACK_FUNCTION(Verges, function34); - ADD_CALLBACK_FUNCTION(Verges, function35); + ADD_CALLBACK_FUNCTION(Verges, organizeConcertInvitations); ADD_CALLBACK_FUNCTION(Verges, chapter4); ADD_CALLBACK_FUNCTION(Verges, chapter4Handler); - ADD_CALLBACK_FUNCTION(Verges, function38); + ADD_CALLBACK_FUNCTION(Verges, resetState); ADD_CALLBACK_FUNCTION(Verges, chapter5); ADD_CALLBACK_FUNCTION(Verges, chapter5Handler); - ADD_CALLBACK_FUNCTION(Verges, function41); - ADD_CALLBACK_FUNCTION(Verges, function42); + ADD_CALLBACK_FUNCTION(Verges, askPassengersToStayInCompartments); + ADD_CALLBACK_FUNCTION(Verges, end); } ////////////////////////////////////////////////////////////////////////// @@ -149,7 +149,7 @@ IMPLEMENT_FUNCTION_II(8, Verges, updateEntity, CarIndex, EntityPosition) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_S(9, Verges, function9) +IMPLEMENT_FUNCTION_S(9, Verges, walkBetweenCars) switch (savepoint.action) { default: break; @@ -201,7 +201,7 @@ switch (savepoint.action) { case 3: setCallback(4); - setup_function10(kCarGreenSleeping, kPosition_540, (char *)¶ms->seq1); + setup_makeAnnouncement(kCarGreenSleeping, kPosition_540, (char *)¶ms->seq1); break; case 4: @@ -225,7 +225,7 @@ switch (savepoint.action) { IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_IIS(10, Verges, function10, CarIndex, EntityPosition) +IMPLEMENT_FUNCTION_IIS(10, Verges, makeAnnouncement, CarIndex, EntityPosition) switch (savepoint.action) { default: break; @@ -404,7 +404,7 @@ IMPLEMENT_FUNCTION(12, Verges, function12) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_I(13, Verges, function13, bool) +IMPLEMENT_FUNCTION_I(13, Verges, baggageCar, bool) switch (savepoint.action) { default: break; @@ -449,7 +449,7 @@ IMPLEMENT_FUNCTION_I(14, Verges, updateFromTime, uint32) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_IS(15, Verges, function15, EntityIndex) +IMPLEMENT_FUNCTION_IS(15, Verges, dialog, EntityIndex) switch (savepoint.action) { default: break; @@ -486,7 +486,7 @@ IMPLEMENT_FUNCTION_IS(15, Verges, function15, EntityIndex) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION_ISS(16, Verges, function16, EntityIndex) +IMPLEMENT_FUNCTION_ISS(16, Verges, dialog2, EntityIndex) switch (savepoint.action) { default: break; @@ -526,7 +526,7 @@ IMPLEMENT_FUNCTION_ISS(16, Verges, function16, EntityIndex) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(17, Verges, function17) +IMPLEMENT_FUNCTION(17, Verges, talkAboutPassengerList) switch (savepoint.action) { default: break; @@ -548,7 +548,7 @@ IMPLEMENT_FUNCTION(17, Verges, function17) case 2: setCallback(3); - setup_function15(kEntityMertens, "TRA1291"); + setup_dialog(kEntityMertens, "TRA1291"); break; case 3: @@ -611,7 +611,7 @@ IMPLEMENT_FUNCTION(21, Verges, talkGendarmes) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(22, Verges, function22) +IMPLEMENT_FUNCTION(22, Verges, askMertensToRelayAugustInvitation) switch (savepoint.action) { default: break; @@ -634,10 +634,10 @@ IMPLEMENT_FUNCTION(22, Verges, function22) case 2: if (getEvent(kEventMertensAskTylerCompartment) || getEvent(kEventMertensAskTylerCompartmentD) || getEvent(kEventMertensAugustWaiting)) { setCallback(3); - setup_function16(kEntityMertens, "TRA1200", "TRA1201"); + setup_dialog2(kEntityMertens, "TRA1200", "TRA1201"); } else { setCallback(4); - setup_function16(kEntityMertens, "TRA1200A", "TRA1201"); + setup_dialog2(kEntityMertens, "TRA1200A", "TRA1201"); } break; @@ -714,7 +714,7 @@ IMPLEMENT_FUNCTION(24, Verges, policeGettingOffTrain) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(25, Verges, function25) +IMPLEMENT_FUNCTION(25, Verges, policeSearch) switch (savepoint.action) { default: break; @@ -774,10 +774,10 @@ IMPLEMENT_FUNCTION(25, Verges, function25) if (getData()->car == kCarRedSleeping) { setCallback(6); - setup_function10(kCarGreenSleeping, kPosition_540, "TRA1005"); + setup_makeAnnouncement(kCarGreenSleeping, kPosition_540, "TRA1005"); } else { setCallback(7); - setup_function10(kCarRedSleeping, kPosition_9460, "TRA1006"); + setup_makeAnnouncement(kCarRedSleeping, kPosition_9460, "TRA1006"); } break; } @@ -805,7 +805,7 @@ IMPLEMENT_FUNCTION(25, Verges, function25) getSavePoints()->push(kEntityVerges, kEntityCoudert, kAction168254872); setCallback(4); - setup_function10(kCarRedSleeping, kPosition_9460, "TRA1006"); + setup_makeAnnouncement(kCarRedSleeping, kPosition_9460, "TRA1006"); break; case 4: @@ -838,7 +838,7 @@ IMPLEMENT_FUNCTION(25, Verges, function25) getSavePoints()->push(kEntityVerges, kEntityCoudert, kAction168254872); setCallback(10); - setup_function10(kCarGreenSleeping, kPosition_540, "TRA1006"); + setup_makeAnnouncement(kCarGreenSleeping, kPosition_540, "TRA1006"); break; case 10: @@ -892,14 +892,14 @@ IMPLEMENT_FUNCTION(26, Verges, chapter1Handler) label_callback1: if (getEntities()->isInBaggageCarEntrance(kEntityPlayer)) { setCallback(2); - setup_function13(false); + setup_baggageCar(false); break; } label_callback2: if (ENTITY_PARAM(0, 7)) { setCallback(3); - setup_function25(); + setup_policeSearch(); break; } @@ -907,7 +907,7 @@ label_callback3: if (params->param6) goto label_callback12; - if (Entity::timeCheckCallback(kTimeChapter1, params->param7, 4, "TRA1001", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTimeChapter1, params->param7, 4, "TRA1001", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback4: @@ -923,19 +923,19 @@ label_callback4: } label_callback8: - if (Entity::timeCheckCallback(kTime1107000, CURRENT_PARAM(1, 1), 9, "TRA1001A", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime1107000, CURRENT_PARAM(1, 1), 9, "TRA1001A", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback9: - if (Entity::timeCheckCallback(kTime1134000, CURRENT_PARAM(1, 2), 10, "TRA1002", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime1134000, CURRENT_PARAM(1, 2), 10, "TRA1002", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback10: - if (Entity::timeCheckCallback(kTime1165500, CURRENT_PARAM(1, 3), 11, "TRA1003", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime1165500, CURRENT_PARAM(1, 3), 11, "TRA1003", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback11: - if (Entity::timeCheckCallback(kTime1225800, CURRENT_PARAM(1, 4), 12, "TRA1004", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime1225800, CURRENT_PARAM(1, 4), 12, "TRA1004", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback12: @@ -955,7 +955,7 @@ label_callback13: label_callback14: if (ENTITY_PARAM(0, 3) && !params->param4 && (getState()->time < kTime1134000 || getState()->time > kTime1156500)) { setCallback(15); - setup_function17(); + setup_talkAboutPassengerList(); break; } @@ -963,14 +963,14 @@ label_callback15: if (ENTITY_PARAM(0, 1) && !params->param5) { if (getState()->time < kTime1134000 || getState()->time > kTime1156500) { setCallback(16); - setup_function22(); + setup_askMertensToRelayAugustInvitation(); } } break; case kActionOpenDoor: setCallback(17); - setup_function13(savepoint.param.intValue < 106 ? true : false); + setup_baggageCar(savepoint.param.intValue < 106 ? true : false); break; case kActionDefault: @@ -1006,7 +1006,7 @@ label_callback15: case 6: setCallback(7); - setup_function15(kEntityMertens, "TRA1202"); + setup_dialog(kEntityMertens, "TRA1202"); break; case 7: @@ -1084,11 +1084,11 @@ IMPLEMENT_FUNCTION(28, Verges, chapter2Handler) case kActionNone: if (getEntities()->isInBaggageCarEntrance(kEntityPlayer)) { setCallback(1); - setup_function13(false); + setup_baggageCar(false); } label_callback_1: - if (Entity::timeCheckCallback(kTime1818900, params->param1, 2, "Tra2177", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime1818900, params->param1, 2, "Tra2177", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback_2: @@ -1117,7 +1117,7 @@ label_callback_6: if (ENTITY_PARAM(0, 3)) { setCallback(7); - setup_function17(); + setup_talkAboutPassengerList(); } break; @@ -1130,7 +1130,7 @@ label_callback_6: case kActionOpenDoor: setCallback(8); - setup_function13(savepoint.param.intValue < 106); + setup_baggageCar(savepoint.param.intValue < 106); break; case kActionDefault: @@ -1155,7 +1155,7 @@ label_callback_6: case 4: setCallback(5); - setup_function15(kEntityCoudert, "TRA2100"); + setup_dialog(kEntityCoudert, "TRA2100"); break; case 5: @@ -1177,7 +1177,7 @@ IMPLEMENT_FUNCTION(29, Verges, chapter3) break; case kActionNone: - setup_function23(); + setup_function33(); break; case kActionDefault: @@ -1221,7 +1221,7 @@ IMPLEMENT_FUNCTION_S(30, Verges, function30) case 2: setCallback(3); - setup_function15(kEntityCoudert, (char *)¶ms->seq1); + setup_dialog(kEntityCoudert, (char *)¶ms->seq1); break; case 3: @@ -1238,7 +1238,7 @@ IMPLEMENT_FUNCTION_S(30, Verges, function30) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(31, Verges, function31) +IMPLEMENT_FUNCTION(31, Verges, talkAboutMax) switch (savepoint.action) { default: break; @@ -1260,7 +1260,7 @@ IMPLEMENT_FUNCTION(31, Verges, function31) case 2: setCallback(3); - setup_function15(kEntityCoudert, "TRA3015"); + setup_dialog(kEntityCoudert, "TRA3015"); break; case 3: @@ -1289,7 +1289,7 @@ IMPLEMENT_FUNCTION(32, Verges, function32) if (getState()->time > kTime2263500 && !params->param1) { params->param1 = 1; setCallback(5); - setup_function10(kCarRedSleeping, kPosition_9460, "TRA3006"); + setup_makeAnnouncement(kCarRedSleeping, kPosition_9460, "TRA3006"); break; } break; @@ -1341,7 +1341,7 @@ IMPLEMENT_FUNCTION(32, Verges, function32) case 3: setCallback(4); - setup_function10(kCarGreenSleeping, kPosition_540, "TRA3004"); + setup_makeAnnouncement(kCarGreenSleeping, kPosition_540, "TRA3004"); break; case 4: @@ -1412,7 +1412,7 @@ IMPLEMENT_FUNCTION(33, Verges, function33) getSavePoints()->push(kEntityVerges, kEntityAbbot, kAction192054567); setCallback(6); - setup_function9("Tra3010"); + setup_walkBetweenCars("Tra3010"); break; case 6: @@ -1432,42 +1432,42 @@ IMPLEMENT_FUNCTION(34, Verges, function34) case kActionNone: if (getEntities()->isInBaggageCarEntrance(kEntityPlayer)) { setCallback(1); - setup_function13(false); + setup_baggageCar(false); break; } label_callback_1: if (ENTITY_PARAM(0, 4)) { setCallback(2); - setup_function31(); + setup_talkAboutMax(); break; } label_callback_2: if (ENTITY_PARAM(0, 3)) { setCallback(3); - setup_function17(); + setup_talkAboutPassengerList(); break; } label_callback_3: - if (Entity::timeCheckCallback(kTime1971000, params->param1, 4, "Tra3001", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime1971000, params->param1, 4, "Tra3001", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback_4: - if (Entity::timeCheckCallback(kTime1998000, params->param2, 5, "Tra3010a", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime1998000, params->param2, 5, "Tra3010a", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback_5: - if (Entity::timeCheckCallback(kTime2016000, params->param3, 6, WRAP_SETUP_FUNCTION(Verges, setup_function35))) + if (Entity::timeCheckCallback(kTime2016000, params->param3, 6, WRAP_SETUP_FUNCTION(Verges, setup_organizeConcertInvitations))) break; label_callback_6: - if (Entity::timeCheckCallback(kTime2070000, params->param4, 7, "Tra3002", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime2070000, params->param4, 7, "Tra3002", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback_7: - if (Entity::timeCheckCallback(kTime2142000, params->param5, 8, "Tra3003", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime2142000, params->param5, 8, "Tra3003", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback_8: @@ -1480,7 +1480,7 @@ label_callback_9: case kActionOpenDoor: setCallback(11); - setup_function13(savepoint.param.intValue < 106); + setup_baggageCar(savepoint.param.intValue < 106); break; case kActionCallback: @@ -1520,7 +1520,7 @@ label_callback_9: IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(35, Verges, function35) +IMPLEMENT_FUNCTION(35, Verges, organizeConcertInvitations) switch (savepoint.action) { default: break; @@ -1542,7 +1542,7 @@ IMPLEMENT_FUNCTION(35, Verges, function35) case 2: setCallback(3); - setup_function15(kEntityMertens, "Tra3011A"); + setup_dialog(kEntityMertens, "Tra3011A"); break; case 3: @@ -1554,7 +1554,7 @@ IMPLEMENT_FUNCTION(35, Verges, function35) case 4: setCallback(5); - setup_function15(kEntityMertens, "Tra3011"); + setup_dialog(kEntityMertens, "Tra3011"); break; case 5: @@ -1609,7 +1609,7 @@ IMPLEMENT_FUNCTION(37, Verges, chapter4Handler) case kActionNone: if (getEntities()->isInBaggageCarEntrance(kEntityPlayer)) { setCallback(1); - setup_function13(false); + setup_baggageCar(false); break; } @@ -1617,42 +1617,42 @@ label_callback_1: if (ENTITY_PARAM(0, 6)) { if (ENTITY_PARAM(0, 3)) { setCallback(2); - setup_function17(); + setup_talkAboutPassengerList(); break; } label_callback_2: - if (Entity::timeCheckCallback(kTime2349000, params->param1, 3, "Tra1001", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime2349000, params->param1, 3, "Tra1001", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback_3: - if (Entity::timeCheckCallback(kTime2378700, params->param2, 4, "Tra4001", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime2378700, params->param2, 4, "Tra4001", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback_4: - if (Entity::timeCheckCallback(kTime2403000, params->param3, 5, "Tra1001A", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime2403000, params->param3, 5, "Tra1001A", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback_5: - if (Entity::timeCheckCallback(kTime2414700, params->param4, 6, "Tra4002", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime2414700, params->param4, 6, "Tra4002", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback_6: - if (Entity::timeCheckCallback(kTime2484000, params->param5, 7, "Tra4003", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime2484000, params->param5, 7, "Tra4003", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; label_callback_7: - if (Entity::timeCheckCallback(kTime2511000, params->param6, 8, "Tra4004", WRAP_SETUP_FUNCTION_S(Verges, setup_function9))) + if (Entity::timeCheckCallback(kTime2511000, params->param6, 8, "Tra4004", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars))) break; } label_callback_8: - Entity::timeCheckCallback(kTime2538000, params->param7, 9, "Tra4005", WRAP_SETUP_FUNCTION_S(Verges, setup_function9)); + Entity::timeCheckCallback(kTime2538000, params->param7, 9, "Tra4005", WRAP_SETUP_FUNCTION_S(Verges, setup_walkBetweenCars)); break; case kActionOpenDoor: setCallback(10); - setup_function13(savepoint.param.intValue < 106); + setup_baggageCar(savepoint.param.intValue < 106); break; case kActionDefault: @@ -1697,7 +1697,7 @@ label_callback_8: IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(38, Verges, function38) +IMPLEMENT_FUNCTION(38, Verges, resetState) switch (savepoint.action) { default: break; @@ -1803,14 +1803,14 @@ IMPLEMENT_FUNCTION(40, Verges, chapter5Handler) getAction()->playAnimation(kEventCathFreePassengers); getSavePoints()->pushAll(kEntityVerges, kActionProceedChapter5); getScenes()->loadSceneFromPosition(kCarRedSleeping, 40); - setup_function41(); + setup_askPassengersToStayInCompartments(); } break; } IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(41, Verges, function41) +IMPLEMENT_FUNCTION(41, Verges, askPassengersToStayInCompartments) switch (savepoint.action) { default: break; @@ -1822,7 +1822,7 @@ IMPLEMENT_FUNCTION(41, Verges, function41) getData()->location = kLocationInsideCompartment; setCallback(1); - setup_function10(kCarRedSleeping, kPosition_2000, "Tra5001"); + setup_makeAnnouncement(kCarRedSleeping, kPosition_2000, "Tra5001"); break; case kActionCallback: @@ -1852,7 +1852,7 @@ IMPLEMENT_FUNCTION(41, Verges, function41) break; case 4: - setup_function42(); + setup_end(); break; } break; @@ -1860,7 +1860,7 @@ IMPLEMENT_FUNCTION(41, Verges, function41) IMPLEMENT_FUNCTION_END ////////////////////////////////////////////////////////////////////////// -IMPLEMENT_FUNCTION(42, Verges, function42) +IMPLEMENT_FUNCTION(42, Verges, end) if (savepoint.action == kActionDefault) getEntities()->clearSequences(kEntityVerges); IMPLEMENT_FUNCTION_END @@ -1891,7 +1891,7 @@ void Verges::talk(const SavePoint &savepoint, const char *sound1, const char *so case 2: setCallback(3); - setup_function15(kEntityCoudert, sound1); + setup_dialog(kEntityCoudert, sound1); break; case 3: @@ -1901,7 +1901,7 @@ void Verges::talk(const SavePoint &savepoint, const char *sound1, const char *so case 4: setCallback(5); - setup_function15(kEntityMertens, sound2); + setup_dialog(kEntityMertens, sound2); break; case 5: diff --git a/engines/lastexpress/entities/verges.h b/engines/lastexpress/entities/verges.h index 82381043d3..93cc190d1e 100644 --- a/engines/lastexpress/entities/verges.h +++ b/engines/lastexpress/entities/verges.h @@ -87,11 +87,11 @@ public: */ DECLARE_FUNCTION_2(updateEntity, CarIndex car, EntityPosition entityPosition) - DECLARE_FUNCTION_1(function9, const char *soundName) - DECLARE_FUNCTION_3(function10, CarIndex car, EntityPosition entityPosition, const char *soundName) + DECLARE_FUNCTION_1(walkBetweenCars, const char *soundName) + DECLARE_FUNCTION_3(makeAnnouncement, CarIndex car, EntityPosition entityPosition, const char *soundName) DECLARE_FUNCTION(function11) DECLARE_FUNCTION(function12) - DECLARE_FUNCTION_1(function13, bool) + DECLARE_FUNCTION_1(baggageCar, bool) /** * Updates parameter 2 using time value @@ -100,9 +100,9 @@ public: */ DECLARE_FUNCTION_1(updateFromTime, uint32 time) - DECLARE_FUNCTION_2(function15, EntityIndex entity, const char *soundName) - DECLARE_FUNCTION_3(function16, EntityIndex entityIndex, const char *soundName1, const char *soundName2) - DECLARE_FUNCTION(function17) + DECLARE_FUNCTION_2(dialog, EntityIndex entity, const char *soundName) + DECLARE_FUNCTION_3(dialog2, EntityIndex entityIndex, const char *soundName1, const char *soundName2) + DECLARE_FUNCTION(talkAboutPassengerList) /** * Setup Chapter 1 @@ -112,10 +112,10 @@ public: DECLARE_FUNCTION_NOSETUP(talkHarem) DECLARE_FUNCTION(talkPassengerList) DECLARE_FUNCTION(talkGendarmes) - DECLARE_FUNCTION(function22) + DECLARE_FUNCTION(askMertensToRelayAugustInvitation) DECLARE_FUNCTION(function23) DECLARE_FUNCTION(policeGettingOffTrain) - DECLARE_FUNCTION(function25) + DECLARE_FUNCTION(policeSearch) /** * Handle Chapter 1 events @@ -138,11 +138,11 @@ public: DECLARE_FUNCTION(chapter3) DECLARE_FUNCTION_1(function30, const char *soundName) - DECLARE_FUNCTION(function31) + DECLARE_FUNCTION(talkAboutMax) DECLARE_FUNCTION(function32) DECLARE_FUNCTION(function33) DECLARE_FUNCTION(function34) - DECLARE_FUNCTION(function35) + DECLARE_FUNCTION(organizeConcertInvitations) /** * Setup Chapter 4 @@ -154,7 +154,7 @@ public: */ DECLARE_FUNCTION(chapter4Handler) - DECLARE_FUNCTION(function38) + DECLARE_FUNCTION(resetState) /** * Setup Chapter 5 @@ -166,8 +166,8 @@ public: */ DECLARE_FUNCTION(chapter5Handler) - DECLARE_FUNCTION(function41) - DECLARE_FUNCTION(function42) + DECLARE_FUNCTION(askPassengersToStayInCompartments) + DECLARE_FUNCTION(end) private: void talk(const SavePoint &savepoint, const char *sound1, const char *sound2); diff --git a/engines/lastexpress/fight/fight.cpp b/engines/lastexpress/fight/fight.cpp index b00c1732e7..49a9b85657 100644 --- a/engines/lastexpress/fight/fight.cpp +++ b/engines/lastexpress/fight/fight.cpp @@ -39,10 +39,8 @@ #include "lastexpress/game/state.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/graphics.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" diff --git a/engines/lastexpress/game/action.cpp b/engines/lastexpress/game/action.cpp index 60a309518a..796abf2ce7 100644 --- a/engines/lastexpress/game/action.cpp +++ b/engines/lastexpress/game/action.cpp @@ -394,7 +394,7 @@ Action::Action(LastExpressEngine *engine) : _engine(engine) { } Action::~Action() { - for (int i = 0; i < (int)_actions.size(); i++) + for (uint i = 0; i < _actions.size(); i++) SAFE_DELETE(_actions[i]); _actions.clear(); @@ -421,8 +421,6 @@ SceneIndex Action::processHotspot(const SceneHotspot &hotspot) { // Action 0 IMPLEMENT_ACTION(dummy) error("[Action::action_dummy] Dummy action function called (hotspot action: %d)", hotspot.action); - - return kSceneInvalid; } ////////////////////////////////////////////////////////////////////////// diff --git a/engines/lastexpress/game/beetle.cpp b/engines/lastexpress/game/beetle.cpp index 2a72459697..d7a369ba40 100644 --- a/engines/lastexpress/game/beetle.cpp +++ b/engines/lastexpress/game/beetle.cpp @@ -94,7 +94,7 @@ void Beetle::load() { // Check that all sequences are loaded properly _data->isLoaded = true; - for (int i = 0; i < (int)_data->sequences.size(); i++) { + for (uint i = 0; i < _data->sequences.size(); i++) { if (!_data->sequences[i]->isLoaded()) { _data->isLoaded = false; break; @@ -351,6 +351,9 @@ void Beetle::drawUpdate() { } void Beetle::invertDirection() { + if (!_data) + error("[Beetle::invertDirection] Sequences have not been loaded"); + switch (_data->indexes[_data->offset]) { default: break; diff --git a/engines/lastexpress/game/entities.cpp b/engines/lastexpress/game/entities.cpp index 51db635bed..fafbd7cb64 100644 --- a/engines/lastexpress/game/entities.cpp +++ b/engines/lastexpress/game/entities.cpp @@ -181,7 +181,7 @@ Entities::Entities(LastExpressEngine *engine) : _engine(engine) { Entities::~Entities() { SAFE_DELETE(_header); - for (int i = 0; i < (int)_entities.size(); i++) + for (uint i = 0; i < _entities.size(); i++) SAFE_DELETE(_entities[i]); _entities.clear(); @@ -669,7 +669,7 @@ void Entities::executeCallbacks() { ////////////////////////////////////////////////////////////////////////// // Processing ////////////////////////////////////////////////////////////////////////// -void Entities::incrementDirectionCounter(EntityData::EntityCallData *data) { +void Entities::incrementDirectionCounter(EntityData::EntityCallData *data) const { data->doProcessEntity = false; if (data->direction == kDirectionRight || (data->direction == kDirectionSwitch && data->directionSwitch == kDirectionRight)) diff --git a/engines/lastexpress/game/entities.h b/engines/lastexpress/game/entities.h index a9de7931f0..81aed627aa 100644 --- a/engines/lastexpress/game/entities.h +++ b/engines/lastexpress/game/entities.h @@ -344,7 +344,7 @@ private: uint _positions[_positionsCount]; void executeCallbacks(); - void incrementDirectionCounter(EntityData::EntityCallData *data); + void incrementDirectionCounter(EntityData::EntityCallData *data) const; void processEntity(EntityIndex entity); void drawSequence(EntityIndex entity, const char *sequence, EntityDirection direction) const; diff --git a/engines/lastexpress/game/inventory.cpp b/engines/lastexpress/game/inventory.cpp index 52c00ece31..11e7369ee1 100644 --- a/engines/lastexpress/game/inventory.cpp +++ b/engines/lastexpress/game/inventory.cpp @@ -35,10 +35,8 @@ #include "lastexpress/menu/menu.h" #include "lastexpress/sound/queue.h" -#include "lastexpress/sound/sound.h" #include "lastexpress/graphics.h" -#include "lastexpress/helpers.h" #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" @@ -621,7 +619,7 @@ void Inventory::drawEgg() const { // Blinking egg: we need to blink the egg for delta time, with the blinking getting faster until it's always lit. void Inventory::drawBlinkingEgg(uint ticks) { - uint globalTimer = getGlobalTimer(); + uint globalTimer = (uint)getGlobalTimer(); uint timerValue = (getProgress().jacket == kJacketGreen) ? 450 : 225; if (globalTimer == timerValue || globalTimer == 900) { @@ -655,7 +653,7 @@ void Inventory::drawBlinkingEgg(uint ticks) { } void Inventory::blinkEgg() { - drawItem((CursorStyle)(getMenu()->getGameId() + 39), 608, 448, (_blinkingBrightness == 0) ? -1 : _blinkingBrightness); + drawItem((CursorStyle)(getMenu()->getGameId() + 39), 608, 448, (_blinkingBrightness == 0) ? -1 : (int16)_blinkingBrightness); askForRedraw(); diff --git a/engines/lastexpress/game/logic.cpp b/engines/lastexpress/game/logic.cpp index 1696f100ff..09104d1bf9 100644 --- a/engines/lastexpress/game/logic.cpp +++ b/engines/lastexpress/game/logic.cpp @@ -48,7 +48,6 @@ #include "lastexpress/sound/queue.h" -#include "lastexpress/graphics.h" #include "lastexpress/lastexpress.h" #include "lastexpress/resource.h" diff --git a/engines/lastexpress/game/savegame.cpp b/engines/lastexpress/game/savegame.cpp index 360e99146a..021dc40bb9 100644 --- a/engines/lastexpress/game/savegame.cpp +++ b/engines/lastexpress/game/savegame.cpp @@ -78,7 +78,7 @@ uint32 SavegameStream::read(void *dataPtr, uint32 dataSize) { uint32 SavegameStream::readUncompressed(void *dataPtr, uint32 dataSize) { if ((int32)dataSize > size() - pos()) { - dataSize = size() - pos(); + dataSize = (uint32)(size() - pos()); _eos = true; } memcpy(dataPtr, getData() + pos(), dataSize); @@ -230,7 +230,7 @@ uint32 SavegameStream::writeCompressed(const void *dataPtr, uint32 dataSize) { if (*data != _previousValue || _repeatCount >= 255) { if (_previousValue) { writeBuffer(0xFF, true); - writeBuffer(_repeatCount, true); + writeBuffer((uint8)_repeatCount, true); writeBuffer(_previousValue, true); _previousValue = *data++; @@ -255,7 +255,7 @@ uint32 SavegameStream::writeCompressed(const void *dataPtr, uint32 dataSize) { } writeBuffer(0xFD, true); - writeBuffer(_repeatCount, true); + writeBuffer((uint8)_repeatCount, true); _previousValue = *data++; _valueCount = 1; @@ -348,11 +348,12 @@ uint32 SavegameStream::readCompressed(void *dataPtr, uint32 dataSize) { // Constructors ////////////////////////////////////////////////////////////////////////// -SaveLoad::SaveLoad(LastExpressEngine *engine) : _engine(engine), _savegame(NULL), _gameTicksLastSavegame(0) { +SaveLoad::SaveLoad(LastExpressEngine *engine) : _engine(engine), _savegame(NULL), _gameTicksLastSavegame(0), _entity(kEntityPlayer) { } SaveLoad::~SaveLoad() { clear(true); + _savegame = NULL; // Zero passed pointers _engine = NULL; @@ -481,10 +482,10 @@ void SaveLoad::clear(bool clearStream) { // Save & Load ////////////////////////////////////////////////////////////////////////// -// Load game -void SaveLoad::loadGame(GameId id) { +// Load last saved game +void SaveLoad::loadLastGame() { if (!_savegame) - error("[SaveLoad::loadGame] No savegame stream present"); + error("[SaveLoad::loadLastGame] No savegame stream present"); // Rewind current savegame _savegame->seek(0); @@ -521,7 +522,29 @@ void SaveLoad::loadGame(GameId id) { } // Load a specific game entry -void SaveLoad::loadGame(GameId id, uint32 index) { +void SaveLoad::loadGame(uint32 index) { + if (!_savegame) + error("[SaveLoad::loadLastGame] No savegame stream present"); + + // Rewind current savegame + _savegame->seek(0); + + // Write main header (with selected index) + SavegameMainHeader header; + header.count = index; + header.brightness = getState()->brightness; + header.volume = getState()->volume; + + Common::Serializer ser(NULL, _savegame); + header.saveLoadWithSerializer(ser); + + // TODO + // Go to the entry + // Load the entry + // Get offset (main and entry) + // Write main header again with correct entry offset + // Setup game and start + error("[SaveLoad::loadGame] Not implemented! (only loading the last entry is working for now)"); } @@ -550,7 +573,7 @@ void SaveLoad::saveGame(SavegameType type, EntityIndex entity, uint32 value) { entry.saveLoadWithSerializer(ser); if (!entry.isValid()) { - error("[SaveLoad::saveGame] Invalid entry. This savegame might be corrupted"); + warning("[SaveLoad::saveGame] Invalid entry. This savegame might be corrupted"); _savegame->seek(header.offset); } else if (getState()->time < entry.time || (type == kSavegameTypeTickInterval && getState()->time == entry.time)) { // Not ready to save a game, skipping! @@ -634,6 +657,9 @@ bool SaveLoad::loadMainHeader(Common::InSaveFile *stream, SavegameMainHeader *he // Entries ////////////////////////////////////////////////////////////////////////// uint32 SaveLoad::writeValue(Common::Serializer &ser, const char *name, Common::Functor1<Common::Serializer &, void> *function, uint size) { + if (!_savegame) + error("[SaveLoad::writeValue] Stream not initialized properly"); + debugC(kLastExpressDebugSavegame, "Savegame: Writing %s: %u bytes", name, size); uint32 prevPosition = (uint32)_savegame->pos(); @@ -652,6 +678,9 @@ uint32 SaveLoad::writeValue(Common::Serializer &ser, const char *name, Common::F } uint32 SaveLoad::readValue(Common::Serializer &ser, const char *name, Common::Functor1<Common::Serializer &, void> *function, uint size) { + if (!_savegame) + error("[SaveLoad::readValue] Stream not initialized properly"); + debugC(kLastExpressDebugSavegame, "Savegame: Reading %s: %u bytes", name, size); uint32 prevPosition = (uint32)_savegame->pos(); diff --git a/engines/lastexpress/game/savegame.h b/engines/lastexpress/game/savegame.h index 8656b2ee86..361957227e 100644 --- a/engines/lastexpress/game/savegame.h +++ b/engines/lastexpress/game/savegame.h @@ -153,8 +153,8 @@ public: uint32 init(GameId id, bool resetHeaders); // Save & Load - void loadGame(GameId id); - void loadGame(GameId id, uint32 index); + void loadLastGame(); + void loadGame(uint32 index); void saveGame(SavegameType type, EntityIndex entity, uint32 value); void loadVolumeBrightness(); diff --git a/engines/lastexpress/game/savepoint.cpp b/engines/lastexpress/game/savepoint.cpp index 6b2dfc5930..8d14ec386b 100644 --- a/engines/lastexpress/game/savepoint.cpp +++ b/engines/lastexpress/game/savepoint.cpp @@ -202,7 +202,7 @@ void SavePoints::callAndProcess() { // Misc ////////////////////////////////////////////////////////////////////////// bool SavePoints::updateEntityFromData(const SavePoint &savepoint) { - for (int i = 0; i < (int)_data.size(); i++) { + for (uint i = 0; i < _data.size(); i++) { // Not a data savepoint! if (!_data[i].entity1) @@ -210,7 +210,7 @@ bool SavePoints::updateEntityFromData(const SavePoint &savepoint) { // Found our data! if (_data[i].entity1 == savepoint.entity1 && _data[i].action == savepoint.action) { - debugC(8, kLastExpressDebugLogic, "Update entity from data: entity1=%s, action=%s, param=%d", ENTITY_NAME(_data[i].entity1), ACTION_NAME(_data[i].action), _data[i].param); + debugC(8, kLastExpressDebugLogic, "Update entity from data: entity1=%s, action=%s, param=%u", ENTITY_NAME(_data[i].entity1), ACTION_NAME(_data[i].action), _data[i].param); // the SavePoint param value is the index of the entity call parameter to update getEntities()->get(_data[i].entity1)->getParamData()->updateParameters(_data[i].param); diff --git a/engines/lastexpress/game/scenes.cpp b/engines/lastexpress/game/scenes.cpp index 3cda900757..a2c7226b93 100644 --- a/engines/lastexpress/game/scenes.cpp +++ b/engines/lastexpress/game/scenes.cpp @@ -739,7 +739,7 @@ void SceneManager::resetQueue() { _queue.clear(); } -void SceneManager::setCoordinates(Common::Rect rect) { +void SceneManager::setCoordinates(const Common::Rect &rect) { _flagCoordinates = true; if (_coords.right > rect.right) diff --git a/engines/lastexpress/game/scenes.h b/engines/lastexpress/game/scenes.h index a866c65111..1c7ae85f98 100644 --- a/engines/lastexpress/game/scenes.h +++ b/engines/lastexpress/game/scenes.h @@ -79,7 +79,7 @@ public: void removeAndRedraw(SequenceFrame **frame, bool doRedraw); void resetQueue(); void setCoordinates(SequenceFrame *frame); - void setCoordinates(Common::Rect rect); + void setCoordinates(const Common::Rect &rect); // Helpers SceneIndex getSceneIndexFromPosition(CarIndex car, Position position, int param3 = -1); diff --git a/engines/lastexpress/menu/menu.cpp b/engines/lastexpress/menu/menu.cpp index 6a453aee99..c48e55bb55 100644 --- a/engines/lastexpress/menu/menu.cpp +++ b/engines/lastexpress/menu/menu.cpp @@ -916,13 +916,13 @@ void Menu::startGame() { if (_lastIndex == _index) { setGlobalTimer(0); if (_index) { - getSaveLoad()->loadGame(_gameId); + getSaveLoad()->loadLastGame(); } else { getLogic()->resetState(); getEntities()->setup(true, kEntityPlayer); } } else { - getSaveLoad()->loadGame(_gameId, _index); + getSaveLoad()->loadGame(_index); } } diff --git a/engines/lastexpress/sound/entry.cpp b/engines/lastexpress/sound/entry.cpp index f2a063e45f..3d22657124 100644 --- a/engines/lastexpress/sound/entry.cpp +++ b/engines/lastexpress/sound/entry.cpp @@ -116,10 +116,8 @@ void SoundEntry::close() { } void SoundEntry::play() { - if (!_stream) { + if (!_stream) error("[SoundEntry::play] stream has been disposed"); - return; - } // Prepare sound stream if (!_soundStream) diff --git a/engines/lastexpress/sound/queue.cpp b/engines/lastexpress/sound/queue.cpp index d72acfd8a0..8904b48930 100644 --- a/engines/lastexpress/sound/queue.cpp +++ b/engines/lastexpress/sound/queue.cpp @@ -67,6 +67,8 @@ void SoundQueue::handleTimer() { for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) { SoundEntry *entry = (*i); + if (entry == NULL) + error("[SoundQueue::handleTimer] Invalid entry found in sound queue"); // When the entry has stopped playing, we remove his buffer if (entry->isFinished()) { @@ -123,6 +125,8 @@ void SoundQueue::updateQueue() { for (Common::List<SoundEntry *>::iterator it = _soundList.begin(); it != _soundList.end(); ++it) { SoundEntry *entry = *it; + if (entry == NULL) + error("[SoundQueue::updateQueue] Invalid entry found in sound queue"); // Original removes the entry data from the cache and sets the archive as not loaded // and if the sound data buffer is not full, loads a new entry to be played based on @@ -179,6 +183,8 @@ void SoundQueue::clearQueue() { for (Common::List<SoundEntry *>::iterator i = _soundList.begin(); i != _soundList.end(); ++i) { SoundEntry *entry = (*i); + if (entry == NULL) + error("[SoundQueue::clearQueue] Invalid entry found in sound queue"); // Delete entry entry->close(); diff --git a/engines/mohawk/myst_stacks/dni.cpp b/engines/mohawk/myst_stacks/dni.cpp index cae165ccf0..d103105c2d 100644 --- a/engines/mohawk/myst_stacks/dni.cpp +++ b/engines/mohawk/myst_stacks/dni.cpp @@ -109,7 +109,7 @@ void Dni::o_handPage(uint16 op, uint16 var, uint16 argc, uint16 *argv) { _vm->setMainCursor(kDefaultMystCursor); // Play movie end (atrus leaving) - _vm->_video->setVideoBounds(atrus, Audio::Timestamp(0, 14813, 600), Audio::Timestamp(0xFFFFFFFF)); + _vm->_video->setVideoBounds(atrus, Audio::Timestamp(0, 14813, 600), _vm->_video->getDuration(atrus)); _vm->_video->setVideoLooping(atrus, false); _atrusLeft = true; diff --git a/engines/mohawk/video.cpp b/engines/mohawk/video.cpp index 18d609c513..0ed4f38b53 100644 --- a/engines/mohawk/video.cpp +++ b/engines/mohawk/video.cpp @@ -29,6 +29,7 @@ #include "common/textconsole.h" #include "common/system.h" +#include "graphics/palette.h" #include "graphics/surface.h" #include "video/qt_decoder.h" @@ -43,13 +44,12 @@ void VideoEntry::clear() { loop = false; enabled = false; start = Audio::Timestamp(0, 1); - end = Audio::Timestamp(0xFFFFFFFF, 1); // Largest possible, there is an endOfVideo() check anyway filename.clear(); id = -1; } bool VideoEntry::endOfVideo() { - return !video || video->endOfVideo() || video->getTime() >= (uint)end.msecs(); + return !video || video->endOfVideo(); } VideoManager::VideoManager(MohawkEngine* vm) : _vm(vm) { @@ -207,7 +207,7 @@ bool VideoManager::updateMovies() { // Remove any videos that are over if (_videoStreams[i].endOfVideo()) { if (_videoStreams[i].loop) { - _videoStreams[i]->seekToTime(_videoStreams[i].start); + _videoStreams[i]->seek(_videoStreams[i].start); } else { // Check the video time one last time before deleting it _vm->doVideoTimer(i, true); @@ -239,7 +239,7 @@ bool VideoManager::updateMovies() { frame = convertedFrame; } else if (pixelFormat.bytesPerPixel == 1 && _videoStreams[i]->hasDirtyPalette()) { // Set the palette when running in 8bpp mode only - _videoStreams[i]->setSystemPalette(); + _vm->_system->getPaletteManager()->setPalette(_videoStreams[i]->getPalette(), 0, 256); } // Clip the width/height to make sure we stay on the screen (Myst does this a few times) @@ -394,6 +394,8 @@ VideoHandle VideoManager::createVideoHandle(uint16 id, uint16 x, uint16 y, bool entry.loop = loop; entry.enabled = true; + entry->start(); + // Search for any deleted videos so we can take a formerly used slot for (uint32 i = 0; i < _videoStreams.size(); i++) if (!_videoStreams[i].video) { @@ -430,6 +432,7 @@ VideoHandle VideoManager::createVideoHandle(const Common::String &filename, uint entry->loadStream(file); entry->setVolume(volume); + entry->start(); // Search for any deleted videos so we can take a formerly used slot for (uint32 i = 0; i < _videoStreams.size(); i++) @@ -492,7 +495,7 @@ uint32 VideoManager::getTime(VideoHandle handle) { uint32 VideoManager::getDuration(VideoHandle handle) { assert(handle != NULL_VID_HANDLE); - return _videoStreams[handle]->getDuration(); + return _videoStreams[handle]->getDuration().msecs(); } bool VideoManager::endOfVideo(VideoHandle handle) { @@ -511,14 +514,13 @@ bool VideoManager::isVideoPlaying() { void VideoManager::setVideoBounds(VideoHandle handle, Audio::Timestamp start, Audio::Timestamp end) { assert(handle != NULL_VID_HANDLE); _videoStreams[handle].start = start; - _videoStreams[handle].end = end; - _videoStreams[handle]->seekToTime(start); + _videoStreams[handle]->setEndTime(end); + _videoStreams[handle]->seek(start); } void VideoManager::drawVideoFrame(VideoHandle handle, Audio::Timestamp time) { assert(handle != NULL_VID_HANDLE); - _videoStreams[handle].end = Audio::Timestamp(0xffffffff, 1); - _videoStreams[handle]->seekToTime(time); + _videoStreams[handle]->seek(time); updateMovies(); delete _videoStreams[handle].video; _videoStreams[handle].clear(); @@ -526,7 +528,7 @@ void VideoManager::drawVideoFrame(VideoHandle handle, Audio::Timestamp time) { void VideoManager::seekToTime(VideoHandle handle, Audio::Timestamp time) { assert(handle != NULL_VID_HANDLE); - _videoStreams[handle]->seekToTime(time); + _videoStreams[handle]->seek(time); } void VideoManager::setVideoLooping(VideoHandle handle, bool loop) { diff --git a/engines/mohawk/video.h b/engines/mohawk/video.h index 98bcadfb53..9dddcde09b 100644 --- a/engines/mohawk/video.h +++ b/engines/mohawk/video.h @@ -45,19 +45,19 @@ struct MLSTRecord { struct VideoEntry { // Playback variables - Video::SeekableVideoDecoder *video; + Video::VideoDecoder *video; uint16 x; uint16 y; bool loop; bool enabled; - Audio::Timestamp start, end; + Audio::Timestamp start; // Identification Common::String filename; // External video files int id; // Internal Mohawk files // Helper functions - Video::SeekableVideoDecoder *operator->() const { assert(video); return video; } // TODO: Remove this eventually + Video::VideoDecoder *operator->() const { assert(video); return video; } // TODO: Remove this eventually void clear(); bool endOfVideo(); }; diff --git a/engines/saga/introproc_saga2.cpp b/engines/saga/introproc_saga2.cpp index b6470370af..260eca98e6 100644 --- a/engines/saga/introproc_saga2.cpp +++ b/engines/saga/introproc_saga2.cpp @@ -32,6 +32,7 @@ #include "common/keyboard.h" #include "common/system.h" #include "common/textconsole.h" +#include "graphics/palette.h" #include "graphics/surface.h" #include "video/smk_decoder.h" @@ -92,7 +93,7 @@ int Scene::FTA2EndProc(FTA2Endings whichEnding) { } void Scene::playMovie(const char *filename) { - Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(_vm->_mixer); + Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(); if (!smkDecoder->loadFile(filename)) return; @@ -101,6 +102,8 @@ void Scene::playMovie(const char *filename) { uint16 y = (g_system->getHeight() - smkDecoder->getHeight()) / 2; bool skipVideo = false; + smkDecoder->start(); + while (!_vm->shouldQuit() && !smkDecoder->endOfVideo() && !skipVideo) { if (smkDecoder->needsUpdate()) { const Graphics::Surface *frame = smkDecoder->decodeNextFrame(); @@ -108,7 +111,7 @@ void Scene::playMovie(const char *filename) { _vm->_system->copyRectToScreen(frame->pixels, frame->pitch, x, y, frame->w, frame->h); if (smkDecoder->hasDirtyPalette()) - smkDecoder->setSystemPalette(); + _vm->_system->getPaletteManager()->setPalette(smkDecoder->getPalette(), 0, 256); _vm->_system->updateScreen(); } diff --git a/engines/saga/shorten.cpp b/engines/saga/shorten.cpp index 5efc8d1f67..69c27b6a6b 100644 --- a/engines/saga/shorten.cpp +++ b/engines/saga/shorten.cpp @@ -519,9 +519,6 @@ byte *loadShortenFromStream(Common::ReadStream &stream, int &size, int &rate, by if (maxLPC > 0) free(lpc); - if (size > 0) - free(unpackedBuffer); - delete gReader; return unpackedBuffer; } diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index 564bbbbd79..1889d53480 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -250,20 +250,18 @@ void Console::postEnter() { #endif if (_videoFile.hasSuffix(".seq")) { - SeqDecoder *seqDecoder = new SeqDecoder(); - seqDecoder->setFrameDelay(_videoFrameDelay); - videoDecoder = seqDecoder; + videoDecoder = new SEQDecoder(_videoFrameDelay); #ifdef ENABLE_SCI32 } else if (_videoFile.hasSuffix(".vmd")) { - videoDecoder = new Video::VMDDecoder(g_system->getMixer()); + videoDecoder = new Video::AdvancedVMDDecoder(); } else if (_videoFile.hasSuffix(".rbt")) { - videoDecoder = new RobotDecoder(g_system->getMixer(), _engine->getPlatform() == Common::kPlatformMacintosh); + videoDecoder = new RobotDecoder(_engine->getPlatform() == Common::kPlatformMacintosh); } else if (_videoFile.hasSuffix(".duk")) { duckMode = true; - videoDecoder = new Video::AviDecoder(g_system->getMixer()); + videoDecoder = new Video::AVIDecoder(); #endif } else if (_videoFile.hasSuffix(".avi")) { - videoDecoder = new Video::AviDecoder(g_system->getMixer()); + videoDecoder = new Video::AVIDecoder(); } else { warning("Unrecognized video type"); } diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp index 685b3c0bd3..8b3afeef99 100644 --- a/engines/sci/engine/kgraphics32.cpp +++ b/engines/sci/engine/kgraphics32.cpp @@ -771,20 +771,23 @@ reg_t kRemapColors32(EngineState *s, int argc, reg_t *argv) { } break; case 3: { // remap to gray - // Example call: QFG4 room 490 (Baba Yaga's hut) - params are color 253, 75% and 0 + // Example call: QFG4 room 490 (Baba Yaga's hut) - params are color 253, 75% and 0. + // In this room, it's used for the cloud before Baba Yaga appears. int16 color = argv[1].toSint16(); int16 percent = argv[2].toSint16(); // 0 - 100 - uint16 unk3 = (argc >= 4) ? argv[3].toUint16() : 0; - warning("kRemapColors: RemapToGray color %d by %d percent (unk3 = %d)", color, percent, unk3); - // TODO + if (argc >= 4) + warning("RemapToGray called with 4 parameters, unknown parameter is %d", argv[3].toUint16()); + g_sci->_gfxPalette->setRemappingPercentGray(color, percent); } break; case 4: { // remap to percent gray - //int16 unk1 = argv[1].toSint16(); - //uint16 unk2 = argv[2].toUint16(); - //uint16 unk3 = argv[3].toUint16(); - //uint16 unk4 = (argc >= 5) ? argv[4].toUint16() : 0; - kStub(s, argc, argv); + // Example call: QFG4 rooms 530/535 (swamp) - params are 253, 100%, 200 + int16 color = argv[1].toSint16(); + int16 percent = argv[2].toSint16(); // 0 - 100 + // argv[3] is unknown (a number, e.g. 200) - start color, perhaps? + if (argc >= 5) + warning("RemapToGrayPercent called with 5 parameters, unknown parameter is %d", argv[4].toUint16()); + g_sci->_gfxPalette->setRemappingPercentGray(color, percent); } break; case 5: { // don't map to range diff --git a/engines/sci/engine/kmath.cpp b/engines/sci/engine/kmath.cpp index a643fbe37a..4b8fadbb84 100644 --- a/engines/sci/engine/kmath.cpp +++ b/engines/sci/engine/kmath.cpp @@ -84,27 +84,10 @@ reg_t kSqrt(EngineState *s, int argc, reg_t *argv) { * accurate. */ uint16 kGetAngleWorker(int16 x1, int16 y1, int16 x2, int16 y2) { - // TODO: This has been implemented based on behavior observed with a test - // program created with SCI Studio. However, the return values have subtle - // differences from the original, which uses custom implementation of atan(). - // The differences in the return values are the cause of bug #3540976 - // and perhaps bug #3037267 as well. - // The results of this function match the expected results of SCI0, but not - // SCI1 (hence the bug in Longbow). We need to find the point in history - // when this function was changed. - - // HACK: Return the expected value for Longbow, scene 150 (bug #3540976). - // This is a temporary solution, till the function returns the expected - // results. - if (g_sci->getGameId() == GID_LONGBOW && g_sci->getEngineState()->currentRoomNumber() == 150) { - if (x1 == 207 && y1 == 88 && x2 == 107 && y2 == 184) - return 226; - } - -#if 0 - // A simpler atan2-based implementation - return (int16)(360 - atan2((double)(x1 - x2), (double)(y1 - y2)) * 57.2958) % 360; -#endif + // SCI1 games (QFG2 and newer) use a simple atan implementation. SCI0 games + // use a somewhat less accurate calculation (below). + if (getSciVersion() >= SCI_VERSION_1_EGA_ONLY) + return (int16)(360 - atan2((double)(x1 - x2), (double)(y1 - y2)) * 57.2958) % 360; int16 xRel = x2 - x1; int16 yRel = y1 - y2; // y-axis is mirrored. diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp index cb2a763da9..6bf9aff2fe 100644 --- a/engines/sci/engine/kvideo.cpp +++ b/engines/sci/engine/kvideo.cpp @@ -50,6 +50,8 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) { if (!videoDecoder) return; + videoDecoder->start(); + byte *scaleBuffer = 0; byte bytesPerPixel = videoDecoder->getPixelFormat().bytesPerPixel; uint16 width = videoDecoder->getWidth(); @@ -162,9 +164,8 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { } else { // DOS SEQ // SEQ's are called with no subops, just the string and delay - SeqDecoder *seqDecoder = new SeqDecoder(); - seqDecoder->setFrameDelay(argv[1].toUint16()); // Time between frames in ticks - videoDecoder = seqDecoder; + // Time is specified as ticks + videoDecoder = new SEQDecoder(argv[1].toUint16()); if (!videoDecoder->loadFile(filename)) { warning("Failed to open movie file %s", filename.c_str()); @@ -190,7 +191,7 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { switch (argv[0].toUint16()) { case 0: { Common::String filename = s->_segMan->getString(argv[1]); - videoDecoder = new Video::AviDecoder(g_system->getMixer()); + videoDecoder = new Video::AVIDecoder(); if (filename.equalsIgnoreCase("gk2a.avi")) { // HACK: Switch to 16bpp graphics for Indeo3. @@ -252,6 +253,7 @@ reg_t kRobot(EngineState *s, int argc, reg_t *argv) { int16 y = argv[5].toUint16(); warning("kRobot(init), id %d, obj %04x:%04x, flag %d, x=%d, y=%d", id, PRINT_REG(obj), flag, x, y); g_sci->_robotDecoder->load(id); + g_sci->_robotDecoder->start(); g_sci->_robotDecoder->setPos(x, y); } break; @@ -267,13 +269,13 @@ reg_t kRobot(EngineState *s, int argc, reg_t *argv) { warning("kRobot(%d)", subop); break; case 8: // sync - //if (false) { // debug: automatically skip all robot videos - if ((uint32)g_sci->_robotDecoder->getCurFrame() != g_sci->_robotDecoder->getFrameCount() - 1) { - writeSelector(s->_segMan, argv[1], SELECTOR(signal), NULL_REG); - } else { + //if (true) { // debug: automatically skip all robot videos + if (g_sci->_robotDecoder->endOfVideo()) { g_sci->_robotDecoder->close(); // Signal the engine scripts that the video is done writeSelector(s->_segMan, argv[1], SELECTOR(signal), SIGNAL_REG); + } else { + writeSelector(s->_segMan, argv[1], SELECTOR(signal), NULL_REG); } break; default: @@ -348,7 +350,7 @@ reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv) { break; } case 6: // Play - videoDecoder = new Video::VMDDecoder(g_system->getMixer()); + videoDecoder = new Video::AdvancedVMDDecoder(); if (s->_videoState.fileName.empty()) { // Happens in Lighthouse @@ -406,7 +408,7 @@ reg_t kPlayDuck(EngineState *s, int argc, reg_t *argv) { s->_videoState.reset(); s->_videoState.fileName = Common::String::format("%d.duk", argv[1].toUint16()); - videoDecoder = new Video::AviDecoder(g_system->getMixer()); + videoDecoder = new Video::AVIDecoder(); if (!videoDecoder->loadFile(s->_videoState.fileName)) { warning("Could not open Duck %s", s->_videoState.fileName.c_str()); diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index a4c2355e8f..9fa0368784 100644 --- a/engines/sci/engine/workarounds.cpp +++ b/engines/sci/engine/workarounds.cpp @@ -399,7 +399,7 @@ const SciWorkaroundEntry kUnLoad_workarounds[] = { { GID_LSL6, 740, 740, 0, "showCartoon", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // during ending, 4 additional parameters are passed by accident { GID_LSL6HIRES, 130, 130, 0, "recruitLarryScr", "changeState", -1, 0, { WORKAROUND_IGNORE, 0 } }, // during intro, a 3rd parameter is passed by accident { GID_SQ1, 43, 303, 0, "slotGuy", "dispose", -1, 0, { WORKAROUND_IGNORE, 0 } }, // when leaving ulence flats bar, parameter 1 is not passed - script error - { GID_QFG4, 770, 110, 0, "dreamer", "dispose", -1, 0, { WORKAROUND_IGNORE, 0 } }, // during the dream sequence, a 3rd parameter is passed by accident + { GID_QFG4, -1, 110, 0, "dreamer", "dispose", -1, 0, { WORKAROUND_IGNORE, 0 } }, // during the dream sequence, a 3rd parameter is passed by accident SCI_WORKAROUNDENTRY_TERMINATOR }; diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index 0098728e5d..968014c032 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -28,6 +28,7 @@ #include "common/system.h" #include "common/textconsole.h" #include "engines/engine.h" +#include "graphics/palette.h" #include "graphics/surface.h" #include "sci/sci.h" @@ -488,7 +489,7 @@ void GfxFrameout::showVideo() { uint16 y = videoDecoder->getPos().y; if (videoDecoder->hasDirtyPalette()) - videoDecoder->setSystemPalette(); + g_system->getPaletteManager()->setPalette(videoDecoder->getPalette(), 0, 256); while (!g_engine->shouldQuit() && !videoDecoder->endOfVideo() && !skipVideo) { if (videoDecoder->needsUpdate()) { @@ -497,7 +498,7 @@ void GfxFrameout::showVideo() { g_system->copyRectToScreen(frame->pixels, frame->pitch, x, y, frame->w, frame->h); if (videoDecoder->hasDirtyPalette()) - videoDecoder->setSystemPalette(); + g_system->getPaletteManager()->setPalette(videoDecoder->getPalette(), 0, 256); g_system->updateScreen(); } @@ -728,7 +729,9 @@ void GfxFrameout::kernelFrameout() { g_sci->_gfxCompare->setNSRect(itemEntry->object, nsRect); } - // FIXME: When does this happen, and why? + // Don't attempt to draw sprites that are outside the visible + // screen area. An example is the random people walking in + // Jackson Square in GK1. if (itemEntry->celRect.bottom < 0 || itemEntry->celRect.top >= _screen->getDisplayHeight() || itemEntry->celRect.right < 0 || itemEntry->celRect.left >= _screen->getDisplayWidth()) continue; diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp index 68104b0ac8..53d69cdcca 100644 --- a/engines/sci/graphics/palette.cpp +++ b/engines/sci/graphics/palette.cpp @@ -375,6 +375,27 @@ void GfxPalette::setRemappingPercent(byte color, byte percent) { _remappingType[color] = kRemappingByPercent; } +void GfxPalette::setRemappingPercentGray(byte color, byte percent) { + _remapOn = true; + + // We need to defer the setup of the remapping table every time the screen + // palette is changed, so that kernelFindColor() can find the correct + // colors. Set it once here, in case the palette stays the same and update + // it on each palette change by copySysPaletteToScreen(). + _remappingPercentToSet = percent; + + // Note: This is not what the original does, but the results are the same visually + for (int i = 0; i < 256; i++) { + byte rComponent = _sysPalette.colors[i].r * _remappingPercentToSet * 0.30 / 100; + byte gComponent = _sysPalette.colors[i].g * _remappingPercentToSet * 0.59 / 100; + byte bComponent = _sysPalette.colors[i].b * _remappingPercentToSet * 0.11 / 100; + byte luminosity = rComponent + gComponent + bComponent; + _remappingByPercent[i] = kernelFindColor(luminosity, luminosity, luminosity); + } + + _remappingType[color] = kRemappingByPercent; +} + void GfxPalette::setRemappingRange(byte color, byte from, byte to, byte base) { _remapOn = true; diff --git a/engines/sci/graphics/palette.h b/engines/sci/graphics/palette.h index 9898315897..e974781d49 100644 --- a/engines/sci/graphics/palette.h +++ b/engines/sci/graphics/palette.h @@ -61,6 +61,7 @@ public: void resetRemapping(); void setRemappingPercent(byte color, byte percent); + void setRemappingPercentGray(byte color, byte percent); void setRemappingRange(byte color, byte from, byte to, byte base); bool isRemapped(byte color) const { return _remapOn && (_remappingType[color] != kRemappingNone); diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index d43a9d06fc..42ae00b525 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -632,7 +632,7 @@ void SciEngine::initGraphics() { _gfxPaint = _gfxPaint32; _gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache, _gfxScreen); _gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxScreen, _gfxText32); - _robotDecoder = new RobotDecoder(g_system->getMixer(), getPlatform() == Common::kPlatformMacintosh); + _robotDecoder = new RobotDecoder(getPlatform() == Common::kPlatformMacintosh); _gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxCache, _gfxScreen, _gfxPalette, _gfxPaint32); } else { #endif diff --git a/engines/sci/sound/audio.cpp b/engines/sci/sound/audio.cpp index 123dd21894..528bb51393 100644 --- a/engines/sci/sound/audio.cpp +++ b/engines/sci/sound/audio.cpp @@ -67,7 +67,8 @@ int AudioPlayer::startAudio(uint16 module, uint32 number) { if (audioStream) { _wPlayFlag = false; - _mixer->playStream(Audio::Mixer::kSpeechSoundType, &_audioHandle, audioStream); + Audio::Mixer::SoundType soundType = (module == 65535) ? Audio::Mixer::kSFXSoundType : Audio::Mixer::kSpeechSoundType; + _mixer->playStream(soundType, &_audioHandle, audioStream); return sampleLen; } else { // Don't throw a warning in this case. getAudioStream() already has. Some games diff --git a/engines/sci/sound/soundcmd.cpp b/engines/sci/sound/soundcmd.cpp index cbb5cab4fe..5d32f40f18 100644 --- a/engines/sci/sound/soundcmd.cpp +++ b/engines/sci/sound/soundcmd.cpp @@ -96,7 +96,7 @@ void SoundCommandParser::initSoundResource(MusicEntry *newSound) { if (_useDigitalSFX || !newSound->soundRes) { int sampleLen; newSound->pStreamAud = _audio->getAudioStream(newSound->resourceId, 65535, &sampleLen); - newSound->soundType = Audio::Mixer::kSpeechSoundType; + newSound->soundType = Audio::Mixer::kSFXSoundType; } } @@ -367,29 +367,36 @@ reg_t SoundCommandParser::kDoSoundFade(int argc, reg_t *argv, reg_t acc) { case 4: // SCI01+ case 5: // SCI1+ (SCI1 late sound scheme), with fade and continue - musicSlot->fadeTo = CLIP<uint16>(argv[1].toUint16(), 0, MUSIC_VOLUME_MAX); - // Check if the song is already at the requested volume. If it is, don't - // perform any fading. Happens for example during the intro of Longbow. - if (musicSlot->fadeTo == musicSlot->volume) - return acc; - - // sometimes we get objects in that position, fix it up (ffs. workarounds) - if (!argv[1].getSegment()) - musicSlot->fadeStep = volume > musicSlot->fadeTo ? -argv[3].toUint16() : argv[3].toUint16(); - else - musicSlot->fadeStep = volume > musicSlot->fadeTo ? -5 : 5; - musicSlot->fadeTickerStep = argv[2].toUint16() * 16667 / _music->soundGetTempo(); - musicSlot->fadeTicker = 0; - if (argc == 5) { // TODO: We currently treat this argument as a boolean, but may // have to handle different non-zero values differently. (e.g., - // some KQ6 scripts pass 3 here) - musicSlot->stopAfterFading = (argv[4].toUint16() != 0); + // some KQ6 scripts pass 3 here). + // There is a script bug in KQ6, room 460 (the room with the flying + // books). An object is passed here, which should not be treated as + // a true flag. Fixes bugs #3555404 and #3291115. + musicSlot->stopAfterFading = (argv[4].isNumber() && argv[4].toUint16() != 0); } else { musicSlot->stopAfterFading = false; } + musicSlot->fadeTo = CLIP<uint16>(argv[1].toUint16(), 0, MUSIC_VOLUME_MAX); + // Check if the song is already at the requested volume. If it is, don't + // perform any fading. Happens for example during the intro of Longbow. + if (musicSlot->fadeTo != musicSlot->volume) { + // sometimes we get objects in that position, fix it up (ffs. workarounds) + if (!argv[1].getSegment()) + musicSlot->fadeStep = volume > musicSlot->fadeTo ? -argv[3].toUint16() : argv[3].toUint16(); + else + musicSlot->fadeStep = volume > musicSlot->fadeTo ? -5 : 5; + musicSlot->fadeTickerStep = argv[2].toUint16() * 16667 / _music->soundGetTempo(); + } else { + // Stop the music, if requested. Fixes bug #3555404. + if (musicSlot->stopAfterFading) + processStopSound(obj, false); + } + + musicSlot->fadeTicker = 0; + // WORKAROUND/HACK: In the labyrinth in KQ6, when falling in the pit and // lighting the lantern, the game scripts perform a fade in of the game // music, but set it to stop after fading. Remove that flag here. This is diff --git a/engines/sci/video/robot_decoder.cpp b/engines/sci/video/robot_decoder.cpp index ebcfac6054..608c77136f 100644 --- a/engines/sci/video/robot_decoder.cpp +++ b/engines/sci/video/robot_decoder.cpp @@ -22,11 +22,13 @@ #include "common/archive.h" #include "common/stream.h" +#include "common/substream.h" #include "common/system.h" #include "common/textconsole.h" #include "common/util.h" #include "graphics/surface.h" +#include "audio/audiostream.h" #include "audio/decoders/raw.h" #include "sci/resource.h" @@ -63,57 +65,26 @@ namespace Sci { // our graphics engine, it looks just like a part of the room. A RBT can move // around the screen and go behind other objects. (...) -#ifdef ENABLE_SCI32 - -enum robotPalTypes { +enum RobotPalTypes { kRobotPalVariable = 0, kRobotPalConstant = 1 }; -RobotDecoder::RobotDecoder(Audio::Mixer *mixer, bool isBigEndian) { - _surface = 0; - _width = 0; - _height = 0; +RobotDecoder::RobotDecoder(bool isBigEndian) { _fileStream = 0; - _audioStream = 0; - _dirtyPalette = false; _pos = Common::Point(0, 0); - _mixer = mixer; _isBigEndian = isBigEndian; + _frameTotalSize = 0; } RobotDecoder::~RobotDecoder() { close(); } -bool RobotDecoder::load(GuiResourceId id) { - // TODO: RAMA's robot 1003 cannot be played (shown at the menu screen) - - // its drawn at odd coordinates. SV can't play it either (along with some - // others), so it must be some new functionality added in RAMA's robot - // videos. Skip it for now. - if (g_sci->getGameId() == GID_RAMA && id == 1003) - return false; - - // TODO: The robot video in the Lighthouse demo gets stuck - if (g_sci->getGameId() == GID_LIGHTHOUSE && id == 16) - return false; - - Common::String fileName = Common::String::format("%d.rbt", id); - Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(fileName); - - if (!stream) { - warning("Unable to open robot file %s", fileName.c_str()); - return false; - } - - return loadStream(stream); -} - bool RobotDecoder::loadStream(Common::SeekableReadStream *stream) { close(); _fileStream = new Common::SeekableSubReadStreamEndian(stream, 0, stream->size(), _isBigEndian, DisposeAfterUse::YES); - _surface = new Graphics::Surface(); readHeaderChunk(); @@ -125,131 +96,60 @@ bool RobotDecoder::loadStream(Common::SeekableReadStream *stream) { if (_header.version < 4 || _header.version > 6) error("Unknown robot version: %d", _header.version); - if (_header.hasSound) { - _audioStream = Audio::makeQueuingAudioStream(11025, false); - _mixer->playStream(Audio::Mixer::kMusicSoundType, &_audioHandle, _audioStream, -1, getVolume(), getBalance()); - } + RobotVideoTrack *videoTrack = new RobotVideoTrack(_header.frameCount); + addTrack(videoTrack); - readPaletteChunk(_header.paletteDataSize); - readFrameSizesChunk(); - calculateVideoDimensions(); - _surface->create(_width, _height, Graphics::PixelFormat::createFormatCLUT8()); + if (_header.hasSound) + addTrack(new RobotAudioTrack()); + videoTrack->readPaletteChunk(_fileStream, _header.paletteDataSize); + readFrameSizesChunk(); + videoTrack->calculateVideoDimensions(_fileStream, _frameTotalSize); return true; } -void RobotDecoder::readHeaderChunk() { - // Header (60 bytes) - _fileStream->skip(6); - _header.version = _fileStream->readUint16(); - _header.audioChunkSize = _fileStream->readUint16(); - _header.audioSilenceSize = _fileStream->readUint16(); - _fileStream->skip(2); - _header.frameCount = _fileStream->readUint16(); - _header.paletteDataSize = _fileStream->readUint16(); - _header.unkChunkDataSize = _fileStream->readUint16(); - _fileStream->skip(5); - _header.hasSound = _fileStream->readByte(); - _fileStream->skip(34); - - // Some videos (e.g. robot 1305 in Phantasmagoria and - // robot 184 in Lighthouse) have an unknown chunk before - // the palette chunk (probably used for sound preloading). - // Skip it here. - if (_header.unkChunkDataSize) - _fileStream->skip(_header.unkChunkDataSize); -} - -void RobotDecoder::readPaletteChunk(uint16 chunkSize) { - byte *paletteData = new byte[chunkSize]; - _fileStream->read(paletteData, chunkSize); - - // SCI1.1 palette - byte palFormat = paletteData[32]; - uint16 palColorStart = paletteData[25]; - uint16 palColorCount = READ_SCI11ENDIAN_UINT16(paletteData + 29); +bool RobotDecoder::load(GuiResourceId id) { + // TODO: RAMA's robot 1003 cannot be played (shown at the menu screen) - + // its drawn at odd coordinates. SV can't play it either (along with some + // others), so it must be some new functionality added in RAMA's robot + // videos. Skip it for now. + if (g_sci->getGameId() == GID_RAMA && id == 1003) + return false; + + // TODO: The robot video in the Lighthouse demo gets stuck + if (g_sci->getGameId() == GID_LIGHTHOUSE && id == 16) + return false; - int palOffset = 37; - memset(_palette, 0, 256 * 3); + Common::String fileName = Common::String::format("%d.rbt", id); + Common::SeekableReadStream *stream = SearchMan.createReadStreamForMember(fileName); - for (uint16 colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) { - if (palFormat == kRobotPalVariable) - palOffset++; - _palette[colorNo * 3 + 0] = paletteData[palOffset++]; - _palette[colorNo * 3 + 1] = paletteData[palOffset++]; - _palette[colorNo * 3 + 2] = paletteData[palOffset++]; + if (!stream) { + warning("Unable to open robot file %s", fileName.c_str()); + return false; } - _dirtyPalette = true; - delete[] paletteData; + return loadStream(stream); } +void RobotDecoder::close() { + VideoDecoder::close(); -void RobotDecoder::readFrameSizesChunk() { - // The robot video file contains 2 tables, with one entry for each frame: - // - A table containing the size of the image in each video frame - // - A table containing the total size of each video frame. - // In v5 robots, the tables contain 16-bit integers, whereas in v6 robots, - // they contain 32-bit integers. - - _frameTotalSize = new uint32[_header.frameCount]; - - // TODO: The table reading code can probably be removed once the - // audio chunk size is figured out (check the TODO inside processNextFrame()) -#if 0 - // We don't need any of the two tables to play the video, so we ignore - // both of them. - uint16 wordSize = _header.version == 6 ? 4 : 2; - _fileStream->skip(_header.frameCount * wordSize * 2); -#else - switch (_header.version) { - case 4: - case 5: // sizes are 16-bit integers - // Skip table with frame image sizes, as we don't need it - _fileStream->skip(_header.frameCount * 2); - for (int i = 0; i < _header.frameCount; ++i) - _frameTotalSize[i] = _fileStream->readUint16(); - break; - case 6: // sizes are 32-bit integers - // Skip table with frame image sizes, as we don't need it - _fileStream->skip(_header.frameCount * 4); - for (int i = 0; i < _header.frameCount; ++i) - _frameTotalSize[i] = _fileStream->readUint32(); - break; - default: - error("Can't yet handle index table for robot version %d", _header.version); - } -#endif - - // 2 more unknown tables - _fileStream->skip(1024 + 512); + delete _fileStream; + _fileStream = 0; - // Pad to nearest 2 kilobytes - uint32 curPos = _fileStream->pos(); - if (curPos & 0x7ff) - _fileStream->seek((curPos & ~0x7ff) + 2048); + delete[] _frameTotalSize; + _frameTotalSize = 0; } -void RobotDecoder::calculateVideoDimensions() { - // This is an O(n) operation, as each frame has a different size. - // We need to know the actual frame size to have a constant video size. - uint32 pos = _fileStream->pos(); - - for (uint32 curFrame = 0; curFrame < _header.frameCount; curFrame++) { - _fileStream->skip(4); - uint16 frameWidth = _fileStream->readUint16(); - uint16 frameHeight = _fileStream->readUint16(); - if (frameWidth > _width) - _width = frameWidth; - if (frameHeight > _height) - _height = frameHeight; - _fileStream->skip(_frameTotalSize[curFrame] - 8); - } +void RobotDecoder::readNextPacket() { + // Get our track + RobotVideoTrack *videoTrack = (RobotVideoTrack *)getTrack(0); + videoTrack->increaseCurFrame(); + Graphics::Surface *surface = videoTrack->getSurface(); - _fileStream->seek(pos); -} + if (videoTrack->endOfTrack()) + return; -const Graphics::Surface *RobotDecoder::decodeNextFrame() { // Read frame image header (24 bytes) _fileStream->skip(3); byte frameScale = _fileStream->readByte(); @@ -258,23 +158,28 @@ const Graphics::Surface *RobotDecoder::decodeNextFrame() { _fileStream->skip(4); // unknown, almost always 0 uint16 frameX = _fileStream->readUint16(); uint16 frameY = _fileStream->readUint16(); + // TODO: In v4 robot files, frameX and frameY have a different meaning. // Set them both to 0 for v4 for now, so that robots in PQ:SWAT show up // correctly. if (_header.version == 4) frameX = frameY = 0; + uint16 compressedSize = _fileStream->readUint16(); uint16 frameFragments = _fileStream->readUint16(); _fileStream->skip(4); // unknown uint32 decompressedSize = frameWidth * frameHeight * frameScale / 100; + // FIXME: A frame's height + position can go off limits... why? With the // following, we cut the contents to fit the frame - uint16 scaledHeight = CLIP<uint16>(decompressedSize / frameWidth, 0, _height - frameY); + uint16 scaledHeight = CLIP<uint16>(decompressedSize / frameWidth, 0, surface->h - frameY); + // FIXME: Same goes for the frame's width + position. In this case, we // modify the position to fit the contents on screen. - if (frameWidth + frameX > _width) - frameX = _width - frameWidth; - assert (frameWidth + frameX <= _width && scaledHeight + frameY <= _height); + if (frameWidth + frameX > surface->w) + frameX = surface->w - frameWidth; + + assert(frameWidth + frameX <= surface->w && scaledHeight + frameY <= surface->h); DecompressorLZS lzs; byte *decompressedFrame = new byte[decompressedSize]; @@ -305,24 +210,23 @@ const Graphics::Surface *RobotDecoder::decodeNextFrame() { // Copy over the decompressed frame byte *inFrame = decompressedFrame; - byte *outFrame = (byte *)_surface->pixels; + byte *outFrame = (byte *)surface->pixels; // Black out the surface - memset(outFrame, 0, _width * _height); + memset(outFrame, 0, surface->w * surface->h); // Move to the correct y coordinate - outFrame += _width * frameY; + outFrame += surface->w * frameY; for (uint16 y = 0; y < scaledHeight; y++) { memcpy(outFrame + frameX, inFrame, frameWidth); inFrame += frameWidth; - outFrame += _width; + outFrame += surface->w; } delete[] decompressedFrame; - // +1 because we start with frame number -1 - uint32 audioChunkSize = _frameTotalSize[_curFrame + 1] - (24 + compressedSize); + uint32 audioChunkSize = _frameTotalSize[videoTrack->getCurFrame()] - (24 + compressedSize); // TODO: The audio chunk size below is usually correct, but there are some // exceptions (e.g. robot 4902 in Phantasmagoria, towards its end) @@ -337,51 +241,166 @@ const Graphics::Surface *RobotDecoder::decodeNextFrame() { // Queue the next audio frame // FIXME: For some reason, there are audio hiccups/gaps if (_header.hasSound) { - _fileStream->skip(8); // header - _audioStream->queueBuffer(g_sci->_audio->getDecodedRobotAudioFrame(_fileStream, audioChunkSize - 8), - (audioChunkSize - 8) * 2, DisposeAfterUse::NO, - Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN); + RobotAudioTrack *audioTrack = (RobotAudioTrack *)getTrack(1); + _fileStream->skip(8); // header + audioChunkSize -= 8; + audioTrack->queueBuffer(g_sci->_audio->getDecodedRobotAudioFrame(_fileStream, audioChunkSize), audioChunkSize * 2); } else { _fileStream->skip(audioChunkSize); - } - - if (_curFrame == -1) - _startTime = g_system->getMillis(); + } +} - _curFrame++; +void RobotDecoder::readHeaderChunk() { + // Header (60 bytes) + _fileStream->skip(6); + _header.version = _fileStream->readUint16(); + _header.audioChunkSize = _fileStream->readUint16(); + _header.audioSilenceSize = _fileStream->readUint16(); + _fileStream->skip(2); + _header.frameCount = _fileStream->readUint16(); + _header.paletteDataSize = _fileStream->readUint16(); + _header.unkChunkDataSize = _fileStream->readUint16(); + _fileStream->skip(5); + _header.hasSound = _fileStream->readByte(); + _fileStream->skip(34); - return _surface; + // Some videos (e.g. robot 1305 in Phantasmagoria and + // robot 184 in Lighthouse) have an unknown chunk before + // the palette chunk (probably used for sound preloading). + // Skip it here. + if (_header.unkChunkDataSize) + _fileStream->skip(_header.unkChunkDataSize); } -void RobotDecoder::close() { - if (!_fileStream) - return; +void RobotDecoder::readFrameSizesChunk() { + // The robot video file contains 2 tables, with one entry for each frame: + // - A table containing the size of the image in each video frame + // - A table containing the total size of each video frame. + // In v5 robots, the tables contain 16-bit integers, whereas in v6 robots, + // they contain 32-bit integers. - delete _fileStream; - _fileStream = 0; + _frameTotalSize = new uint32[_header.frameCount]; + // TODO: The table reading code can probably be removed once the + // audio chunk size is figured out (check the TODO inside processNextFrame()) +#if 0 + // We don't need any of the two tables to play the video, so we ignore + // both of them. + uint16 wordSize = _header.version == 6 ? 4 : 2; + _fileStream->skip(_header.frameCount * wordSize * 2); +#else + switch (_header.version) { + case 4: + case 5: // sizes are 16-bit integers + // Skip table with frame image sizes, as we don't need it + _fileStream->skip(_header.frameCount * 2); + for (int i = 0; i < _header.frameCount; ++i) + _frameTotalSize[i] = _fileStream->readUint16(); + break; + case 6: // sizes are 32-bit integers + // Skip table with frame image sizes, as we don't need it + _fileStream->skip(_header.frameCount * 4); + for (int i = 0; i < _header.frameCount; ++i) + _frameTotalSize[i] = _fileStream->readUint32(); + break; + default: + error("Can't yet handle index table for robot version %d", _header.version); + } +#endif + + // 2 more unknown tables + _fileStream->skip(1024 + 512); + + // Pad to nearest 2 kilobytes + uint32 curPos = _fileStream->pos(); + if (curPos & 0x7ff) + _fileStream->seek((curPos & ~0x7ff) + 2048); +} + +RobotDecoder::RobotVideoTrack::RobotVideoTrack(int frameCount) : _frameCount(frameCount) { + _surface = new Graphics::Surface(); + _curFrame = -1; + _dirtyPalette = false; +} + +RobotDecoder::RobotVideoTrack::~RobotVideoTrack() { _surface->free(); delete _surface; - _surface = 0; +} - if (_header.hasSound) { - _mixer->stopHandle(_audioHandle); - //delete _audioStream; _audioStream = 0; +uint16 RobotDecoder::RobotVideoTrack::getWidth() const { + return _surface->w; +} + +uint16 RobotDecoder::RobotVideoTrack::getHeight() const { + return _surface->h; +} + +Graphics::PixelFormat RobotDecoder::RobotVideoTrack::getPixelFormat() const { + return _surface->format; +} + +void RobotDecoder::RobotVideoTrack::readPaletteChunk(Common::SeekableSubReadStreamEndian *stream, uint16 chunkSize) { + byte *paletteData = new byte[chunkSize]; + stream->read(paletteData, chunkSize); + + // SCI1.1 palette + byte palFormat = paletteData[32]; + uint16 palColorStart = paletteData[25]; + uint16 palColorCount = READ_SCI11ENDIAN_UINT16(paletteData + 29); + + int palOffset = 37; + memset(_palette, 0, 256 * 3); + + for (uint16 colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) { + if (palFormat == kRobotPalVariable) + palOffset++; + _palette[colorNo * 3 + 0] = paletteData[palOffset++]; + _palette[colorNo * 3 + 1] = paletteData[palOffset++]; + _palette[colorNo * 3 + 2] = paletteData[palOffset++]; } - reset(); + _dirtyPalette = true; + delete[] paletteData; } -void RobotDecoder::updateVolume() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) - g_system->getMixer()->setChannelVolume(_audioHandle, getVolume()); +void RobotDecoder::RobotVideoTrack::calculateVideoDimensions(Common::SeekableSubReadStreamEndian *stream, uint32 *frameSizes) { + // This is an O(n) operation, as each frame has a different size. + // We need to know the actual frame size to have a constant video size. + uint32 pos = stream->pos(); + + uint16 width = 0, height = 0; + + for (int curFrame = 0; curFrame < _frameCount; curFrame++) { + stream->skip(4); + uint16 frameWidth = stream->readUint16(); + uint16 frameHeight = stream->readUint16(); + if (frameWidth > width) + width = frameWidth; + if (frameHeight > height) + height = frameHeight; + stream->skip(frameSizes[curFrame] - 8); + } + + stream->seek(pos); + + _surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); } -void RobotDecoder::updateBalance() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) - g_system->getMixer()->setChannelBalance(_audioHandle, getBalance()); +RobotDecoder::RobotAudioTrack::RobotAudioTrack() { + _audioStream = Audio::makeQueuingAudioStream(11025, false); } -#endif +RobotDecoder::RobotAudioTrack::~RobotAudioTrack() { + delete _audioStream; +} + +void RobotDecoder::RobotAudioTrack::queueBuffer(byte *buffer, int size) { + _audioStream->queueBuffer(buffer, size, DisposeAfterUse::YES, Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN); +} + +Audio::AudioStream *RobotDecoder::RobotAudioTrack::getAudioStream() const { + return _audioStream; +} } // End of namespace Sci diff --git a/engines/sci/video/robot_decoder.h b/engines/sci/video/robot_decoder.h index e9cefe7d91..ebc3262939 100644 --- a/engines/sci/video/robot_decoder.h +++ b/engines/sci/video/robot_decoder.h @@ -25,84 +25,103 @@ #include "common/rational.h" #include "common/rect.h" -#include "common/stream.h" -#include "common/substream.h" -#include "audio/audiostream.h" -#include "audio/mixer.h" -#include "graphics/pixelformat.h" #include "video/video_decoder.h" -namespace Sci { +namespace Audio { +class QueuingAudioStream; +} -#ifdef ENABLE_SCI32 - -struct RobotHeader { - // 6 bytes, identifier bytes - uint16 version; - uint16 audioChunkSize; - uint16 audioSilenceSize; - // 2 bytes, unknown - uint16 frameCount; - uint16 paletteDataSize; - uint16 unkChunkDataSize; - // 5 bytes, unknown - byte hasSound; - // 34 bytes, unknown -}; +namespace Common { +class SeekableSubReadStreamEndian; +} + +namespace Sci { -class RobotDecoder : public Video::FixedRateVideoDecoder { +class RobotDecoder : public Video::VideoDecoder { public: - RobotDecoder(Audio::Mixer *mixer, bool isBigEndian); + RobotDecoder(bool isBigEndian); virtual ~RobotDecoder(); bool loadStream(Common::SeekableReadStream *stream); bool load(GuiResourceId id); void close(); - - bool isVideoLoaded() const { return _fileStream != 0; } - uint16 getWidth() const { return _width; } - uint16 getHeight() const { return _height; } - uint32 getFrameCount() const { return _header.frameCount; } - const Graphics::Surface *decodeNextFrame(); - Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } - const byte *getPalette() { _dirtyPalette = false; return _palette; } - bool hasDirtyPalette() const { return _dirtyPalette; } + void setPos(uint16 x, uint16 y) { _pos = Common::Point(x, y); } Common::Point getPos() const { return _pos; } protected: - // VideoDecoder API - void updateVolume(); - void updateBalance(); - - // FixedRateVideoDecoder API - Common::Rational getFrameRate() const { return Common::Rational(60, 10); } - + void readNextPacket(); + private: + class RobotVideoTrack : public FixedRateVideoTrack { + public: + RobotVideoTrack(int frameCount); + ~RobotVideoTrack(); + + uint16 getWidth() const; + uint16 getHeight() const; + Graphics::PixelFormat getPixelFormat() const; + int getCurFrame() const { return _curFrame; } + int getFrameCount() const { return _frameCount; } + const Graphics::Surface *decodeNextFrame() { return _surface; } + const byte *getPalette() const { _dirtyPalette = false; return _palette; } + bool hasDirtyPalette() const { return _dirtyPalette; } + + void readPaletteChunk(Common::SeekableSubReadStreamEndian *stream, uint16 chunkSize); + void calculateVideoDimensions(Common::SeekableSubReadStreamEndian *stream, uint32 *frameSizes); + Graphics::Surface *getSurface() { return _surface; } + void increaseCurFrame() { _curFrame++; } + + protected: + Common::Rational getFrameRate() const { return Common::Rational(60, 10); } + + private: + int _frameCount; + int _curFrame; + byte _palette[256 * 3]; + mutable bool _dirtyPalette; + Graphics::Surface *_surface; + }; + + class RobotAudioTrack : public AudioTrack { + public: + RobotAudioTrack(); + ~RobotAudioTrack(); + + Audio::Mixer::SoundType getSoundType() const { return Audio::Mixer::kMusicSoundType; } + + void queueBuffer(byte *buffer, int size); + + protected: + Audio::AudioStream *getAudioStream() const; + + private: + Audio::QueuingAudioStream *_audioStream; + }; + + struct RobotHeader { + // 6 bytes, identifier bytes + uint16 version; + uint16 audioChunkSize; + uint16 audioSilenceSize; + // 2 bytes, unknown + uint16 frameCount; + uint16 paletteDataSize; + uint16 unkChunkDataSize; + // 5 bytes, unknown + byte hasSound; + // 34 bytes, unknown + } _header; + void readHeaderChunk(); - void readPaletteChunk(uint16 chunkSize); void readFrameSizesChunk(); - void calculateVideoDimensions(); - - void freeData(); - RobotHeader _header; Common::Point _pos; bool _isBigEndian; + uint32 *_frameTotalSize; Common::SeekableSubReadStreamEndian *_fileStream; - - uint16 _width; - uint16 _height; - uint32 *_frameTotalSize; - byte _palette[256 * 3]; - bool _dirtyPalette; - Graphics::Surface *_surface; - Audio::QueuingAudioStream *_audioStream; - Audio::SoundHandle _audioHandle; - Audio::Mixer *_mixer; }; -#endif } // End of namespace Sci diff --git a/engines/sci/video/seq_decoder.cpp b/engines/sci/video/seq_decoder.cpp index abd64911a7..a7b6346eca 100644 --- a/engines/sci/video/seq_decoder.cpp +++ b/engines/sci/video/seq_decoder.cpp @@ -41,33 +41,44 @@ enum seqFrameTypes { kSeqFrameDiff = 1 }; -SeqDecoder::SeqDecoder() { - _fileStream = 0; - _surface = 0; - _dirtyPalette = false; +SEQDecoder::SEQDecoder(uint frameDelay) : _frameDelay(frameDelay) { } -SeqDecoder::~SeqDecoder() { +SEQDecoder::~SEQDecoder() { close(); } -bool SeqDecoder::loadStream(Common::SeekableReadStream *stream) { +bool SEQDecoder::loadStream(Common::SeekableReadStream *stream) { close(); + addTrack(new SEQVideoTrack(stream, _frameDelay)); + + return true; +} + +SEQDecoder::SEQVideoTrack::SEQVideoTrack(Common::SeekableReadStream *stream, uint frameDelay) { + assert(stream); + assert(frameDelay != 0); _fileStream = stream; + _frameDelay = frameDelay; + _curFrame = -1; + _surface = new Graphics::Surface(); _surface->create(SEQ_SCREEN_WIDTH, SEQ_SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8()); _frameCount = _fileStream->readUint16LE(); - // Set palette - int paletteChunkSize = _fileStream->readUint32LE(); - readPaletteChunk(paletteChunkSize); + // Set initial palette + readPaletteChunk(_fileStream->readUint32LE()); +} - return true; +SEQDecoder::SEQVideoTrack::~SEQVideoTrack() { + delete _fileStream; + _surface->free(); + delete _surface; } -void SeqDecoder::readPaletteChunk(uint16 chunkSize) { +void SEQDecoder::SEQVideoTrack::readPaletteChunk(uint16 chunkSize) { byte *paletteData = new byte[chunkSize]; _fileStream->read(paletteData, chunkSize); @@ -91,23 +102,7 @@ void SeqDecoder::readPaletteChunk(uint16 chunkSize) { delete[] paletteData; } -void SeqDecoder::close() { - if (!_fileStream) - return; - - _frameDelay = 0; - - delete _fileStream; - _fileStream = 0; - - _surface->free(); - delete _surface; - _surface = 0; - - reset(); -} - -const Graphics::Surface *SeqDecoder::decodeNextFrame() { +const Graphics::Surface *SEQDecoder::SEQVideoTrack::decodeNextFrame() { int16 frameWidth = _fileStream->readUint16LE(); int16 frameHeight = _fileStream->readUint16LE(); int16 frameLeft = _fileStream->readUint16LE(); @@ -142,9 +137,6 @@ const Graphics::Surface *SeqDecoder::decodeNextFrame() { delete[] buf; } - if (_curFrame == -1) - _startTime = g_system->getMillis(); - _curFrame++; return _surface; } @@ -159,7 +151,7 @@ const Graphics::Surface *SeqDecoder::decodeNextFrame() { } \ memcpy(dest + writeRow * SEQ_SCREEN_WIDTH + writeCol, litData + litPos, n); -bool SeqDecoder::decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey) { +bool SEQDecoder::SEQVideoTrack::decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey) { int writeRow = 0; int writeCol = left; int litPos = 0; @@ -237,4 +229,9 @@ bool SeqDecoder::decodeFrame(byte *rleData, int rleSize, byte *litData, int litS return true; } +const byte *SEQDecoder::SEQVideoTrack::getPalette() const { + _dirtyPalette = false; + return _palette; +} + } // End of namespace Sci diff --git a/engines/sci/video/seq_decoder.h b/engines/sci/video/seq_decoder.h index 800a3c9024..890f349feb 100644 --- a/engines/sci/video/seq_decoder.h +++ b/engines/sci/video/seq_decoder.h @@ -40,44 +40,49 @@ namespace Sci { /** * Implementation of the Sierra SEQ decoder, used in KQ6 DOS floppy/CD and GK1 DOS */ -class SeqDecoder : public Video::FixedRateVideoDecoder { +class SEQDecoder : public Video::VideoDecoder { public: - SeqDecoder(); - virtual ~SeqDecoder(); + SEQDecoder(uint frameDelay); + virtual ~SEQDecoder(); bool loadStream(Common::SeekableReadStream *stream); - void close(); - - void setFrameDelay(int frameDelay) { _frameDelay = frameDelay; } - - bool isVideoLoaded() const { return _fileStream != 0; } - uint16 getWidth() const { return SEQ_SCREEN_WIDTH; } - uint16 getHeight() const { return SEQ_SCREEN_HEIGHT; } - uint32 getFrameCount() const { return _frameCount; } - const Graphics::Surface *decodeNextFrame(); - Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } - const byte *getPalette() { _dirtyPalette = false; return _palette; } - bool hasDirtyPalette() const { return _dirtyPalette; } - -protected: - Common::Rational getFrameRate() const { assert(_frameDelay); return Common::Rational(60, _frameDelay); } private: - enum { - SEQ_SCREEN_WIDTH = 320, - SEQ_SCREEN_HEIGHT = 200 + class SEQVideoTrack : public FixedRateVideoTrack { + public: + SEQVideoTrack(Common::SeekableReadStream *stream, uint frameDelay); + ~SEQVideoTrack(); + + uint16 getWidth() const { return SEQ_SCREEN_WIDTH; } + uint16 getHeight() const { return SEQ_SCREEN_HEIGHT; } + Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } + int getCurFrame() const { return _curFrame; } + int getFrameCount() const { return _frameCount; } + const Graphics::Surface *decodeNextFrame(); + const byte *getPalette() const; + bool hasDirtyPalette() const { return _dirtyPalette; } + + protected: + Common::Rational getFrameRate() const { return Common::Rational(60, _frameDelay); } + + private: + enum { + SEQ_SCREEN_WIDTH = 320, + SEQ_SCREEN_HEIGHT = 200 + }; + + void readPaletteChunk(uint16 chunkSize); + bool decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey); + + Common::SeekableReadStream *_fileStream; + int _curFrame, _frameCount; + byte _palette[256 * 3]; + mutable bool _dirtyPalette; + Graphics::Surface *_surface; + uint _frameDelay; }; - void readPaletteChunk(uint16 chunkSize); - bool decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey); - - uint16 _width, _height; - uint16 _frameDelay; - Common::SeekableReadStream *_fileStream; - byte _palette[256 * 3]; - bool _dirtyPalette; - uint32 _frameCount; - Graphics::Surface *_surface; + uint _frameDelay; }; } // End of namespace Sci diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp index 87305921c9..5404c7f8b1 100644 --- a/engines/scumm/detection.cpp +++ b/engines/scumm/detection.cpp @@ -20,9 +20,6 @@ * */ -// FIXME: Avoid using printf -#define FORBIDDEN_SYMBOL_EXCEPTION_printf - #include "base/plugins.h" #include "common/archive.h" @@ -1066,15 +1063,19 @@ Common::Error ScummMetaEngine::createInstance(OSystem *syst, Engine **engine) co // unknown MD5, or with a medium debug level in case of a known MD5 (for // debugging purposes). if (!findInMD5Table(res.md5.c_str())) { - printf("Your game version appears to be unknown. If this is *NOT* a fan-modified\n"); - printf("version (in particular, not a fan-made translation), please, report the\n"); - printf("following data to the ScummVM team along with name of the game you tried\n"); - printf("to add and its version/language/etc.:\n"); + Common::String md5Warning; + + md5Warning = "Your game version appears to be unknown. If this is *NOT* a fan-modified\n"; + md5Warning += "version (in particular, not a fan-made translation), please, report the\n"; + md5Warning += "following data to the ScummVM team along with name of the game you tried\n"; + md5Warning += "to add and its version/language/etc.:\n"; - printf(" SCUMM gameid '%s', file '%s', MD5 '%s'\n\n", + md5Warning += Common::String::format(" SCUMM gameid '%s', file '%s', MD5 '%s'\n\n", res.game.gameid, generateFilenameForDetection(res.fp.pattern, res.fp.genMethod).c_str(), res.md5.c_str()); + + g_system->logMessage(LogMessageType::kWarning, md5Warning.c_str()); } else { debug(1, "Using MD5 '%s'", res.md5.c_str()); } diff --git a/engines/scumm/he/animation_he.cpp b/engines/scumm/he/animation_he.cpp index 40e99c26a8..be17a3b305 100644 --- a/engines/scumm/he/animation_he.cpp +++ b/engines/scumm/he/animation_he.cpp @@ -40,7 +40,7 @@ MoviePlayer::MoviePlayer(ScummEngine_v90he *vm, Audio::Mixer *mixer) : _vm(vm) { _video = new Video::BinkDecoder(); else #endif - _video = new Video::SmackerDecoder(mixer); + _video = new Video::SmackerDecoder(); _flags = 0; _wizResNum = 0; @@ -61,11 +61,16 @@ int MoviePlayer::load(const char *filename, int flags, int image) { if (_video->isVideoLoaded()) _video->close(); + // Ensure that Bink will use our PixelFormat + _video->setDefaultHighColorFormat(g_system->getScreenFormat()); + if (!_video->loadFile(filename)) { warning("Failed to load video file %s", filename); return -1; } + _video->start(); + debug(1, "Playing video %s", filename); if (flags & 2) diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp index ddafd964eb..f7add4eed2 100644 --- a/engines/sword1/animation.cpp +++ b/engines/sword1/animation.cpp @@ -37,6 +37,7 @@ #include "gui/message.h" +#include "video/dxa_decoder.h" #include "video/psx_decoder.h" #include "video/smk_decoder.h" @@ -96,9 +97,8 @@ static const char *const sequenceListPSX[20] = { // Basic movie player /////////////////////////////////////////////////////////////////////////////// -MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Video::VideoDecoder *decoder, DecoderType decoderType) - : _vm(vm), _textMan(textMan), _resMan(resMan), _snd(snd), _bgSoundHandle(bgSoundHandle), _system(system) { - _bgSoundStream = NULL; +MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, OSystem *system, Video::VideoDecoder *decoder, DecoderType decoderType) + : _vm(vm), _textMan(textMan), _resMan(resMan), _system(system) { _decoderType = decoderType; _decoder = decoder; @@ -107,7 +107,6 @@ MoviePlayer::MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, Audio:: } MoviePlayer::~MoviePlayer() { - delete _bgSoundHandle; delete _decoder; } @@ -116,16 +115,12 @@ MoviePlayer::~MoviePlayer() { * @param id the id of the file */ bool MoviePlayer::load(uint32 id) { - Common::File f; Common::String filename; - if (_decoderType == kVideoDecoderDXA) - _bgSoundStream = Audio::SeekableAudioStream::openStreamFile(sequenceList[id]); - else - _bgSoundStream = NULL; - if (SwordEngine::_systemVars.showText) { + Common::File f; filename = Common::String::format("%s.txt", sequenceList[id]); + if (f.open(filename)) { Common::String line; int lineNo = 0; @@ -169,7 +164,6 @@ bool MoviePlayer::load(uint32 id) { _movieTexts.push_back(MovieText(startFrame, endFrame, ptr, color)); lastEnd = endFrame; } - f.close(); } } @@ -189,6 +183,7 @@ bool MoviePlayer::load(uint32 id) { // Need to load here in case it fails in which case we'd need // to go back to paletted mode if (_decoder->loadFile(filename)) { + _decoder->start(); return true; } else { initGraphics(g_system->getWidth(), g_system->getHeight(), true); @@ -197,30 +192,27 @@ bool MoviePlayer::load(uint32 id) { break; } - return _decoder->loadFile(filename.c_str()); -} + if (!_decoder->loadFile(filename)) + return false; -void MoviePlayer::play() { - if (_bgSoundStream) - _snd->playStream(Audio::Mixer::kSFXSoundType, _bgSoundHandle, _bgSoundStream); + // For DXA, also add the external sound file + if (_decoderType == kVideoDecoderDXA) + _decoder->addStreamFileTrack(sequenceList[id]); - bool terminated = false; + _decoder->start(); + return true; +} +void MoviePlayer::play() { _textX = 0; _textY = 0; - terminated = !playVideo(); - - if (terminated) - _snd->stopHandle(*_bgSoundHandle); + playVideo(); _textMan->releaseText(2, false); _movieTexts.clear(); - while (_snd->isSoundHandleActive(*_bgSoundHandle)) - _system->delayMillis(100); - // It's tempting to call _screen->fullRefresh() here to restore the old // palette. However, that causes glitches with DXA movies, where the // previous location would be momentarily drawn, before switching to @@ -320,7 +312,7 @@ bool MoviePlayer::playVideo() { } if (_decoder->hasDirtyPalette()) { - _decoder->setSystemPalette(); + _vm->_system->getPaletteManager()->setPalette(_decoder->getPalette(), 0, 256); if (!_movieTexts.empty()) { // Look for the best color indexes to use to display the subtitles @@ -506,24 +498,12 @@ void MoviePlayer::drawFramePSX(const Graphics::Surface *frame) { scaledFrame.free(); } -DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle) - : _mixer(mixer), _bgSoundHandle(bgSoundHandle) { -} - -uint32 DXADecoderWithSound::getTime() const { - if (_mixer->isSoundHandleActive(*_bgSoundHandle)) - return _mixer->getSoundElapsedTime(*_bgSoundHandle); - - return DXADecoder::getTime(); -} - /////////////////////////////////////////////////////////////////////////////// // Factory function for creating the appropriate cutscene player /////////////////////////////////////////////////////////////////////////////// -MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::Mixer *snd, OSystem *system) { +MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *resMan, OSystem *system) { Common::String filename; - Audio::SoundHandle *bgSoundHandle = new Audio::SoundHandle; // For the PSX version, we'll try the PlayStation stream files if (vm->isPsx()) { @@ -534,7 +514,7 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan * #ifdef USE_RGB_COLOR // All BS1 PSX videos run the videos at 2x speed Video::VideoDecoder *psxDecoder = new Video::PSXStreamDecoder(Video::PSXStreamDecoder::kCD2x); - return new MoviePlayer(vm, textMan, resMan, snd, system, bgSoundHandle, psxDecoder, kVideoDecoderPSX); + return new MoviePlayer(vm, textMan, resMan, system, psxDecoder, kVideoDecoderPSX); #else GUI::MessageDialog dialog(Common::String::format(_("PSX stream cutscene '%s' cannot be played in paletted mode"), filename.c_str()), _("OK")); dialog.runModal(); @@ -546,20 +526,20 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan * filename = Common::String::format("%s.smk", sequenceList[id]); if (Common::File::exists(filename)) { - Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(snd); - return new MoviePlayer(vm, textMan, resMan, snd, system, bgSoundHandle, smkDecoder, kVideoDecoderSMK); + Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(); + return new MoviePlayer(vm, textMan, resMan, system, smkDecoder, kVideoDecoderSMK); } filename = Common::String::format("%s.dxa", sequenceList[id]); if (Common::File::exists(filename)) { #ifdef USE_ZLIB - DXADecoderWithSound *dxaDecoder = new DXADecoderWithSound(snd, bgSoundHandle); - return new MoviePlayer(vm, textMan, resMan, snd, system, bgSoundHandle, dxaDecoder, kVideoDecoderDXA); + Video::VideoDecoder *dxaDecoder = new Video::DXADecoder(); + return new MoviePlayer(vm, textMan, resMan, system, dxaDecoder, kVideoDecoderDXA); #else GUI::MessageDialog dialog(_("DXA cutscenes found but ScummVM has been built without zlib support"), _("OK")); dialog.runModal(); - return NULL; + return 0; #endif } @@ -569,7 +549,7 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan * if (Common::File::exists(filename)) { GUI::MessageDialog dialog(_("MPEG2 cutscenes are no longer supported"), _("OK")); dialog.runModal(); - return NULL; + return 0; } if (!vm->isPsx() || scumm_stricmp(sequenceList[id], "enddemo") != 0) { @@ -578,7 +558,7 @@ MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan * dialog.runModal(); } - return NULL; + return 0; } } // End of namespace Sword1 diff --git a/engines/sword1/animation.h b/engines/sword1/animation.h index c2ed86a1a3..d0c61f5eb3 100644 --- a/engines/sword1/animation.h +++ b/engines/sword1/animation.h @@ -23,16 +23,19 @@ #ifndef SWORD1_ANIMATION_H #define SWORD1_ANIMATION_H -#include "video/dxa_decoder.h" -#include "video/video_decoder.h" - #include "common/list.h" -#include "audio/audiostream.h" - #include "sword1/screen.h" #include "sword1/sound.h" +namespace Graphics { +struct Surface; +} + +namespace Video { +class VideoDecoder; +} + namespace Sword1 { enum DecoderType { @@ -55,21 +58,9 @@ public: } }; -class DXADecoderWithSound : public Video::DXADecoder { -public: - DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle); - ~DXADecoderWithSound() {} - - uint32 getTime() const; - -private: - Audio::Mixer *_mixer; - Audio::SoundHandle *_bgSoundHandle; -}; - class MoviePlayer { public: - MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Video::VideoDecoder *decoder, DecoderType decoderType); + MoviePlayer(SwordEngine *vm, Text *textMan, ResMan *resMan, OSystem *system, Video::VideoDecoder *decoder, DecoderType decoderType); virtual ~MoviePlayer(); bool load(uint32 id); void play(); @@ -78,7 +69,6 @@ protected: SwordEngine *_vm; Text *_textMan; ResMan *_resMan; - Audio::Mixer *_snd; OSystem *_system; Common::List<MovieText> _movieTexts; int _textX, _textY, _textWidth, _textHeight; @@ -88,8 +78,6 @@ protected: DecoderType _decoderType; Video::VideoDecoder *_decoder; - Audio::SoundHandle *_bgSoundHandle; - Audio::AudioStream *_bgSoundStream; bool playVideo(); void performPostProcessing(byte *screen); @@ -100,7 +88,7 @@ protected: void convertColor(byte r, byte g, byte b, float &h, float &s, float &v); }; -MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *resMan, Audio::Mixer *snd, OSystem *system); +MoviePlayer *makeMoviePlayer(uint32 id, SwordEngine *vm, Text *textMan, ResMan *resMan, OSystem *system); } // End of namespace Sword1 diff --git a/engines/sword1/logic.cpp b/engines/sword1/logic.cpp index 8e04861edf..757d768780 100644 --- a/engines/sword1/logic.cpp +++ b/engines/sword1/logic.cpp @@ -959,7 +959,7 @@ int Logic::fnPlaySequence(Object *cpt, int32 id, int32 sequenceId, int32 d, int3 // meantime, we don't want any looping sound effects still playing. _sound->quitScreen(); - MoviePlayer *player = makeMoviePlayer(sequenceId, _vm, _textMan, _resMan, _mixer, _system); + MoviePlayer *player = makeMoviePlayer(sequenceId, _vm, _textMan, _resMan, _system); if (player) { _screen->clearScreen(); if (player->load(sequenceId)) diff --git a/engines/sword2/animation.cpp b/engines/sword2/animation.cpp index 5e3f8929e9..00260f789a 100644 --- a/engines/sword2/animation.cpp +++ b/engines/sword2/animation.cpp @@ -38,8 +38,11 @@ #include "sword2/screen.h" #include "sword2/animation.h" +#include "graphics/palette.h" + #include "gui/message.h" +#include "video/dxa_decoder.h" #include "video/smk_decoder.h" #include "video/psx_decoder.h" @@ -51,9 +54,8 @@ namespace Sword2 { // Basic movie player /////////////////////////////////////////////////////////////////////////////// -MoviePlayer::MoviePlayer(Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Video::VideoDecoder *decoder, DecoderType decoderType) - : _vm(vm), _snd(snd), _bgSoundHandle(bgSoundHandle), _system(system) { - _bgSoundStream = NULL; +MoviePlayer::MoviePlayer(Sword2Engine *vm, OSystem *system, Video::VideoDecoder *decoder, DecoderType decoderType) + : _vm(vm), _system(system) { _decoderType = decoderType; _decoder = decoder; @@ -62,7 +64,6 @@ MoviePlayer::MoviePlayer(Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, A } MoviePlayer::~MoviePlayer() { - delete _bgSoundHandle; delete _decoder; } @@ -75,11 +76,6 @@ bool MoviePlayer::load(const char *name) { if (_vm->shouldQuit()) return false; - if (_decoderType == kVideoDecoderDXA) - _bgSoundStream = Audio::SeekableAudioStream::openStreamFile(name); - else - _bgSoundStream = NULL; - _textSurface = NULL; Common::String filename; @@ -99,6 +95,7 @@ bool MoviePlayer::load(const char *name) { // Need to load here in case it fails in which case we'd need // to go back to paletted mode if (_decoder->loadFile(filename)) { + _decoder->start(); return true; } else { initGraphics(640, 480, true); @@ -106,7 +103,15 @@ bool MoviePlayer::load(const char *name) { } } - return _decoder->loadFile(filename.c_str()); + if (!_decoder->loadFile(filename)) + return false; + + // For DXA, also add the external sound file + if (_decoderType == kVideoDecoderDXA) + _decoder->addStreamFileTrack(name); + + _decoder->start(); + return true; } void MoviePlayer::play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadIn, uint32 leadOut) { @@ -122,24 +127,15 @@ void MoviePlayer::play(MovieText *movieTexts, uint32 numMovieTexts, uint32 leadI if (leadIn) _vm->_sound->playMovieSound(leadIn, kLeadInSound); - if (_bgSoundStream) - _snd->playStream(Audio::Mixer::kSFXSoundType, _bgSoundHandle, _bgSoundStream); - - bool terminated = false; - - terminated = !playVideo(); + bool terminated = !playVideo(); closeTextObject(_currentMovieText, NULL, 0); if (terminated) { - _snd->stopHandle(*_bgSoundHandle); _vm->_sound->stopMovieSounds(); _vm->_sound->stopSpeech(); } - while (_snd->isSoundHandleActive(*_bgSoundHandle)) - _system->delayMillis(100); - if (_decoderType == kVideoDecoderPSX) { // Need to jump back to paletted color initGraphics(640, 480, true); @@ -336,7 +332,7 @@ bool MoviePlayer::playVideo() { } if (_decoder->hasDirtyPalette()) { - _decoder->setSystemPalette(); + _vm->_system->getPaletteManager()->setPalette(_decoder->getPalette(), 0, 256); uint32 maxWeight = 0; uint32 minWeight = 0xFFFFFFFF; @@ -406,31 +402,19 @@ void MoviePlayer::drawFramePSX(const Graphics::Surface *frame) { scaledFrame.free(); } -DXADecoderWithSound::DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle) - : _mixer(mixer), _bgSoundHandle(bgSoundHandle) { -} - -uint32 DXADecoderWithSound::getTime() const { - if (_mixer->isSoundHandleActive(*_bgSoundHandle)) - return _mixer->getSoundElapsedTime(*_bgSoundHandle); - - return DXADecoder::getTime(); -} - /////////////////////////////////////////////////////////////////////////////// // Factory function for creating the appropriate cutscene player /////////////////////////////////////////////////////////////////////////////// -MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, uint32 frameCount) { +MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, OSystem *system, uint32 frameCount) { Common::String filename; - Audio::SoundHandle *bgSoundHandle = new Audio::SoundHandle; filename = Common::String::format("%s.str", name); if (Common::File::exists(filename)) { #ifdef USE_RGB_COLOR Video::VideoDecoder *psxDecoder = new Video::PSXStreamDecoder(Video::PSXStreamDecoder::kCD2x, frameCount); - return new MoviePlayer(vm, snd, system, bgSoundHandle, psxDecoder, kVideoDecoderPSX); + return new MoviePlayer(vm, system, psxDecoder, kVideoDecoderPSX); #else GUI::MessageDialog dialog(_("PSX cutscenes found but ScummVM has been built without RGB color support"), _("OK")); dialog.runModal(); @@ -441,16 +425,16 @@ MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *s filename = Common::String::format("%s.smk", name); if (Common::File::exists(filename)) { - Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(snd); - return new MoviePlayer(vm, snd, system, bgSoundHandle, smkDecoder, kVideoDecoderSMK); + Video::SmackerDecoder *smkDecoder = new Video::SmackerDecoder(); + return new MoviePlayer(vm, system, smkDecoder, kVideoDecoderSMK); } filename = Common::String::format("%s.dxa", name); if (Common::File::exists(filename)) { #ifdef USE_ZLIB - DXADecoderWithSound *dxaDecoder = new DXADecoderWithSound(snd, bgSoundHandle); - return new MoviePlayer(vm, snd, system, bgSoundHandle, dxaDecoder, kVideoDecoderDXA); + Video::DXADecoder *dxaDecoder = new Video::DXADecoder(); + return new MoviePlayer(vm, system, dxaDecoder, kVideoDecoderDXA); #else GUI::MessageDialog dialog(_("DXA cutscenes found but ScummVM has been built without zlib support"), _("OK")); dialog.runModal(); diff --git a/engines/sword2/animation.h b/engines/sword2/animation.h index 3d5c42b7f7..b2a243b2ca 100644 --- a/engines/sword2/animation.h +++ b/engines/sword2/animation.h @@ -25,12 +25,16 @@ #ifndef SWORD2_ANIMATION_H #define SWORD2_ANIMATION_H -#include "video/dxa_decoder.h" -#include "video/video_decoder.h" -#include "audio/mixer.h" - #include "sword2/screen.h" +namespace Graphics { +struct Surface; +} + +namespace Video { +class VideoDecoder; +} + namespace Sword2 { enum DecoderType { @@ -55,20 +59,9 @@ struct MovieText { } }; -class DXADecoderWithSound : public Video::DXADecoder { -public: - DXADecoderWithSound(Audio::Mixer *mixer, Audio::SoundHandle *bgSoundHandle); - ~DXADecoderWithSound() {} - - uint32 getTime() const; -private: - Audio::Mixer *_mixer; - Audio::SoundHandle *_bgSoundHandle; -}; - class MoviePlayer { public: - MoviePlayer(Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, Audio::SoundHandle *bgSoundHandle, Video::VideoDecoder *decoder, DecoderType decoderType); + MoviePlayer(Sword2Engine *vm, OSystem *system, Video::VideoDecoder *decoder, DecoderType decoderType); virtual ~MoviePlayer(); bool load(const char *name); @@ -76,7 +69,6 @@ public: protected: Sword2Engine *_vm; - Audio::Mixer *_snd; OSystem *_system; MovieText *_movieTexts; uint32 _numMovieTexts; @@ -87,8 +79,6 @@ protected: DecoderType _decoderType; Video::VideoDecoder *_decoder; - Audio::SoundHandle *_bgSoundHandle; - Audio::AudioStream *_bgSoundStream; uint32 _leadOut; int _leadOutFrame; @@ -105,7 +95,7 @@ protected: uint32 getWhiteColor(); }; -MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, Audio::Mixer *snd, OSystem *system, uint32 frameCount); +MoviePlayer *makeMoviePlayer(const char *name, Sword2Engine *vm, OSystem *system, uint32 frameCount); } // End of namespace Sword2 diff --git a/engines/sword2/function.cpp b/engines/sword2/function.cpp index 836b252d6c..07fcaa094b 100644 --- a/engines/sword2/function.cpp +++ b/engines/sword2/function.cpp @@ -2139,7 +2139,7 @@ int32 Logic::fnPlaySequence(int32 *params) { uint32 frameCount = Sword2Engine::isPsx() ? params[1] : 0; - _moviePlayer = makeMoviePlayer(filename, _vm, _vm->_mixer, _vm->_system, frameCount); + _moviePlayer = makeMoviePlayer(filename, _vm, _vm->_system, frameCount); if (_moviePlayer && _moviePlayer->load(filename)) { _moviePlayer->play(_sequenceTextList, _sequenceTextLines, _smackerLeadIn, _smackerLeadOut); diff --git a/engines/sword25/fmv/movieplayer.cpp b/engines/sword25/fmv/movieplayer.cpp index 9ee13b4b6d..a95532ec65 100644 --- a/engines/sword25/fmv/movieplayer.cpp +++ b/engines/sword25/fmv/movieplayer.cpp @@ -61,6 +61,7 @@ bool MoviePlayer::loadMovie(const Common::String &filename, uint z) { // Get the file and load it into the decoder Common::SeekableReadStream *in = Kernel::getInstance()->getPackage()->getStream(filename); _decoder.loadStream(in); + _decoder.start(); GraphicEngine *pGfx = Kernel::getInstance()->getGfx(); diff --git a/engines/sword25/fmv/movieplayer.h b/engines/sword25/fmv/movieplayer.h index 1d256e56ba..2f5614b505 100644 --- a/engines/sword25/fmv/movieplayer.h +++ b/engines/sword25/fmv/movieplayer.h @@ -39,7 +39,7 @@ #include "sword25/gfx/bitmap.h" #ifdef USE_THEORADEC -#include "sword25/fmv/theora_decoder.h" +#include "video/theora_decoder.h" #endif #define THEORA_INDIRECT_RENDERING @@ -141,7 +141,7 @@ private: #ifdef USE_THEORADEC - TheoraDecoder _decoder; + Video::TheoraDecoder _decoder; Graphics::Surface *_backSurface; int _outX, _outY; diff --git a/engines/sword25/fmv/theora_decoder.cpp b/engines/sword25/fmv/theora_decoder.cpp deleted file mode 100644 index d38f5a26cf..0000000000 --- a/engines/sword25/fmv/theora_decoder.cpp +++ /dev/null @@ -1,565 +0,0 @@ -/* 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 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. - * - */ - -/* - * Source is based on the player example from libvorbis package, - * available at: http://svn.xiph.org/trunk/theora/examples/player_example.c - * - * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. - * - * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 - * by the Xiph.Org Foundation and contributors http://www.xiph.org/ - * - */ - -#include "sword25/fmv/theora_decoder.h" - -#ifdef USE_THEORADEC -#include "common/system.h" -#include "common/textconsole.h" -#include "common/util.h" -#include "graphics/yuv_to_rgb.h" -#include "audio/decoders/raw.h" -#include "sword25/kernel/common.h" - -namespace Sword25 { - -#define AUDIOFD_FRAGSIZE 10240 - -static double rint(double v) { - return floor(v + 0.5); -} - -TheoraDecoder::TheoraDecoder(Audio::Mixer::SoundType soundType) { - _fileStream = 0; - - _theoraPacket = 0; - _vorbisPacket = 0; - _theoraDecode = 0; - _theoraSetup = 0; - _nextFrameStartTime = 0.0; - - _soundType = soundType; - _audStream = 0; - _audHandle = new Audio::SoundHandle(); - - ogg_sync_init(&_oggSync); - - _curFrame = -1; - _audiobuf = (ogg_int16_t *)malloc(AUDIOFD_FRAGSIZE * sizeof(ogg_int16_t)); - - reset(); -} - -TheoraDecoder::~TheoraDecoder() { - close(); - delete _fileStream; - delete _audHandle; - free(_audiobuf); -} - -void TheoraDecoder::queuePage(ogg_page *page) { - if (_theoraPacket) - ogg_stream_pagein(&_theoraOut, page); - - if (_vorbisPacket) - ogg_stream_pagein(&_vorbisOut, page); -} - -int TheoraDecoder::bufferData() { - char *buffer = ogg_sync_buffer(&_oggSync, 4096); - int bytes = _fileStream->read(buffer, 4096); - - ogg_sync_wrote(&_oggSync, bytes); - - return bytes; -} - -bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) { - close(); - - _endOfAudio = false; - _endOfVideo = false; - _fileStream = stream; - - // start up Ogg stream synchronization layer - ogg_sync_init(&_oggSync); - - // init supporting Vorbis structures needed in header parsing - vorbis_info_init(&_vorbisInfo); - vorbis_comment_init(&_vorbisComment); - - // init supporting Theora structures needed in header parsing - th_comment_init(&_theoraComment); - th_info_init(&_theoraInfo); - - // Ogg file open; parse the headers - // Only interested in Vorbis/Theora streams - bool foundHeader = false; - while (!foundHeader) { - int ret = bufferData(); - - if (ret == 0) - break; - - while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) { - ogg_stream_state test; - - // is this a mandated initial header? If not, stop parsing - if (!ogg_page_bos(&_oggPage)) { - // don't leak the page; get it into the appropriate stream - queuePage(&_oggPage); - foundHeader = true; - break; - } - - ogg_stream_init(&test, ogg_page_serialno(&_oggPage)); - ogg_stream_pagein(&test, &_oggPage); - ogg_stream_packetout(&test, &_oggPacket); - - // identify the codec: try theora - if (!_theoraPacket && th_decode_headerin(&_theoraInfo, &_theoraComment, &_theoraSetup, &_oggPacket) >= 0) { - // it is theora - memcpy(&_theoraOut, &test, sizeof(test)); - _theoraPacket = 1; - } else if (!_vorbisPacket && vorbis_synthesis_headerin(&_vorbisInfo, &_vorbisComment, &_oggPacket) >= 0) { - // it is vorbis - memcpy(&_vorbisOut, &test, sizeof(test)); - _vorbisPacket = 1; - } else { - // whatever it is, we don't care about it - ogg_stream_clear(&test); - } - } - // fall through to non-bos page parsing - } - - // we're expecting more header packets. - while ((_theoraPacket && _theoraPacket < 3) || (_vorbisPacket && _vorbisPacket < 3)) { - int ret; - - // look for further theora headers - while (_theoraPacket && (_theoraPacket < 3) && (ret = ogg_stream_packetout(&_theoraOut, &_oggPacket))) { - if (ret < 0) - error("Error parsing Theora stream headers; corrupt stream?"); - - if (!th_decode_headerin(&_theoraInfo, &_theoraComment, &_theoraSetup, &_oggPacket)) - error("Error parsing Theora stream headers; corrupt stream?"); - - _theoraPacket++; - } - - // look for more vorbis header packets - while (_vorbisPacket && (_vorbisPacket < 3) && (ret = ogg_stream_packetout(&_vorbisOut, &_oggPacket))) { - if (ret < 0) - error("Error parsing Vorbis stream headers; corrupt stream?"); - - if (vorbis_synthesis_headerin(&_vorbisInfo, &_vorbisComment, &_oggPacket)) - error("Error parsing Vorbis stream headers; corrupt stream?"); - - _vorbisPacket++; - - if (_vorbisPacket == 3) - break; - } - - // The header pages/packets will arrive before anything else we - // care about, or the stream is not obeying spec - - if (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) { - queuePage(&_oggPage); // demux into the appropriate stream - } else { - ret = bufferData(); // someone needs more data - - if (ret == 0) - error("End of file while searching for codec headers."); - } - } - - // and now we have it all. initialize decoders - if (_theoraPacket) { - _theoraDecode = th_decode_alloc(&_theoraInfo, _theoraSetup); - debugN(1, "Ogg logical stream %lx is Theora %dx%d %.02f fps", - _theoraOut.serialno, _theoraInfo.pic_width, _theoraInfo.pic_height, - (double)_theoraInfo.fps_numerator / _theoraInfo.fps_denominator); - - switch (_theoraInfo.pixel_fmt) { - case TH_PF_420: - debug(1, " 4:2:0 video"); - break; - case TH_PF_422: - debug(1, " 4:2:2 video"); - break; - case TH_PF_444: - debug(1, " 4:4:4 video"); - break; - case TH_PF_RSVD: - default: - debug(1, " video\n (UNKNOWN Chroma sampling!)"); - break; - } - - if (_theoraInfo.pic_width != _theoraInfo.frame_width || _theoraInfo.pic_height != _theoraInfo.frame_height) - debug(1, " Frame content is %dx%d with offset (%d,%d).", - _theoraInfo.frame_width, _theoraInfo.frame_height, _theoraInfo.pic_x, _theoraInfo.pic_y); - - switch (_theoraInfo.colorspace){ - case TH_CS_UNSPECIFIED: - /* nothing to report */ - break; - case TH_CS_ITU_REC_470M: - debug(1, " encoder specified ITU Rec 470M (NTSC) color."); - break; - case TH_CS_ITU_REC_470BG: - debug(1, " encoder specified ITU Rec 470BG (PAL) color."); - break; - default: - debug(1, "warning: encoder specified unknown colorspace (%d).", _theoraInfo.colorspace); - break; - } - - debug(1, "Encoded by %s", _theoraComment.vendor); - if (_theoraComment.comments) { - debug(1, "theora comment header:"); - for (int i = 0; i < _theoraComment.comments; i++) { - if (_theoraComment.user_comments[i]) { - int len = _theoraComment.comment_lengths[i]; - char *value = (char *)malloc(len + 1); - if (value) { - memcpy(value, _theoraComment.user_comments[i], len); - value[len] = '\0'; - debug(1, "\t%s", value); - free(value); - } - } - } - } - - th_decode_ctl(_theoraDecode, TH_DECCTL_GET_PPLEVEL_MAX, &_ppLevelMax, sizeof(_ppLevelMax)); - _ppLevel = _ppLevelMax; - th_decode_ctl(_theoraDecode, TH_DECCTL_SET_PPLEVEL, &_ppLevel, sizeof(_ppLevel)); - _ppInc = 0; - } else { - // tear down the partial theora setup - th_info_clear(&_theoraInfo); - th_comment_clear(&_theoraComment); - } - - th_setup_free(_theoraSetup); - _theoraSetup = 0; - - if (_vorbisPacket) { - vorbis_synthesis_init(&_vorbisDSP, &_vorbisInfo); - vorbis_block_init(&_vorbisDSP, &_vorbisBlock); - debug(3, "Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.", - _vorbisOut.serialno, _vorbisInfo.channels, _vorbisInfo.rate); - - _audStream = Audio::makeQueuingAudioStream(_vorbisInfo.rate, _vorbisInfo.channels); - - // Get enough audio data to start us off - while (_audStream->numQueuedStreams() == 0) { - // Queue more data - bufferData(); - while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) - queuePage(&_oggPage); - - queueAudio(); - } - - if (_audStream) - g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, _audHandle, _audStream, -1, getVolume(), getBalance()); - } else { - // tear down the partial vorbis setup - vorbis_info_clear(&_vorbisInfo); - vorbis_comment_clear(&_vorbisComment); - _endOfAudio = true; - } - - _surface.create(_theoraInfo.frame_width, _theoraInfo.frame_height, g_system->getScreenFormat()); - - // Set up a display surface - _displaySurface.pixels = _surface.getBasePtr(_theoraInfo.pic_x, _theoraInfo.pic_y); - _displaySurface.w = _theoraInfo.pic_width; - _displaySurface.h = _theoraInfo.pic_height; - _displaySurface.format = _surface.format; - _displaySurface.pitch = _surface.pitch; - - // Set the frame rate - _frameRate = Common::Rational(_theoraInfo.fps_numerator, _theoraInfo.fps_denominator); - - return true; -} - -void TheoraDecoder::close() { - if (_vorbisPacket) { - ogg_stream_clear(&_vorbisOut); - vorbis_block_clear(&_vorbisBlock); - vorbis_dsp_clear(&_vorbisDSP); - vorbis_comment_clear(&_vorbisComment); - vorbis_info_clear(&_vorbisInfo); - - g_system->getMixer()->stopHandle(*_audHandle); - - _audStream = 0; - _vorbisPacket = false; - } - if (_theoraPacket) { - ogg_stream_clear(&_theoraOut); - th_decode_free(_theoraDecode); - th_comment_clear(&_theoraComment); - th_info_clear(&_theoraInfo); - _theoraDecode = 0; - _theoraPacket = false; - } - - if (!_fileStream) - return; - - ogg_sync_clear(&_oggSync); - - delete _fileStream; - _fileStream = 0; - - _surface.free(); - _displaySurface.pixels = 0; - _displaySurface.free(); - - reset(); -} - -const Graphics::Surface *TheoraDecoder::decodeNextFrame() { - // First, let's get our frame - while (_theoraPacket) { - // theora is one in, one out... - if (ogg_stream_packetout(&_theoraOut, &_oggPacket) > 0) { - - if (_ppInc) { - _ppLevel += _ppInc; - th_decode_ctl(_theoraDecode, TH_DECCTL_SET_PPLEVEL, &_ppLevel, sizeof(_ppLevel)); - _ppInc = 0; - } - - if (th_decode_packetin(_theoraDecode, &_oggPacket, NULL) == 0) { - _curFrame++; - - // Convert YUV data to RGB data - th_ycbcr_buffer yuv; - th_decode_ycbcr_out(_theoraDecode, yuv); - translateYUVtoRGBA(yuv); - - if (_curFrame == 0) - _startTime = g_system->getMillis(); - - double time = th_granule_time(_theoraDecode, _oggPacket.granulepos); - - // We need to calculate when the next frame should be shown - // This is all in floating point because that's what the Ogg code gives us - // Ogg is a lossy container format, so it doesn't always list the time to the - // next frame. In such cases, we need to calculate it ourselves. - if (time == -1.0) - _nextFrameStartTime += _frameRate.getInverse().toDouble(); - else - _nextFrameStartTime = time; - - // break out - break; - } - } else { - // If we can't get any more frames, we're done. - if (_theoraOut.e_o_s || _fileStream->eos()) { - _endOfVideo = true; - break; - } - - // Queue more data - bufferData(); - while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) - queuePage(&_oggPage); - } - - // Update audio if we can - queueAudio(); - } - - // Force at least some audio to be buffered - // TODO: 5 is very arbitrary. We probably should do something like QuickTime does. - while (!_endOfAudio && _audStream->numQueuedStreams() < 5) { - bufferData(); - while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) - queuePage(&_oggPage); - - bool queuedAudio = queueAudio(); - if ((_vorbisOut.e_o_s || _fileStream->eos()) && !queuedAudio) { - _endOfAudio = true; - break; - } - } - - return &_displaySurface; -} - -bool TheoraDecoder::queueAudio() { - if (!_audStream) - return false; - - // An audio buffer should have been allocated (either in the constructor or after queuing the current buffer) - if (!_audiobuf) { - warning("[TheoraDecoder::queueAudio] Invalid audio buffer"); - return false; - } - - bool queuedAudio = false; - - for (;;) { - float **pcm; - - // if there's pending, decoded audio, grab it - int ret = vorbis_synthesis_pcmout(&_vorbisDSP, &pcm); - if (ret > 0) { - int count = _audiobufFill / 2; - int maxsamples = ((AUDIOFD_FRAGSIZE - _audiobufFill) / _vorbisInfo.channels) >> 1; - int i; - for (i = 0; i < ret && i < maxsamples; i++) - for (int j = 0; j < _vorbisInfo.channels; j++) { - int val = CLIP((int)rint(pcm[j][i] * 32767.f), -32768, 32767); - _audiobuf[count++] = val; - } - - vorbis_synthesis_read(&_vorbisDSP, i); - _audiobufFill += (i * _vorbisInfo.channels) << 1; - - if (_audiobufFill == AUDIOFD_FRAGSIZE) { - byte flags = Audio::FLAG_16BITS | Audio::FLAG_STEREO; -#ifdef SCUMM_LITTLE_ENDIAN - flags |= Audio::FLAG_LITTLE_ENDIAN; -#endif - _audStream->queueBuffer((byte *)_audiobuf, AUDIOFD_FRAGSIZE, DisposeAfterUse::NO, flags); - - // The audio mixer is now responsible for the old audio buffer. - // We need to create a new one. - _audiobuf = (ogg_int16_t *)malloc(AUDIOFD_FRAGSIZE * sizeof(ogg_int16_t)); - if (!_audiobuf) { - warning("[TheoraDecoder::queueAudio] Cannot allocate memory for audio buffer"); - return false; - } - - _audiobufFill = 0; - queuedAudio = true; - } - } else { - // no pending audio; is there a pending packet to decode? - if (ogg_stream_packetout(&_vorbisOut, &_oggPacket) > 0) { - if (vorbis_synthesis(&_vorbisBlock, &_oggPacket) == 0) // test for success! - vorbis_synthesis_blockin(&_vorbisDSP, &_vorbisBlock); - } else // we've buffered all we have, break out for now - return queuedAudio; - } - } - - // Unreachable - return false; -} - -void TheoraDecoder::reset() { - VideoDecoder::reset(); - - // FIXME: This does a rewind() instead of a reset()! - - if (_fileStream) - _fileStream->seek(0); - - _audiobufFill = 0; - _audiobufReady = false; - - _curFrame = -1; - - _theoraPacket = 0; - _vorbisPacket = 0; -} - -bool TheoraDecoder::endOfVideo() const { - return !isVideoLoaded() || (_endOfVideo && (!_audStream || (_audStream->endOfData() && _endOfAudio))); -} - -uint32 TheoraDecoder::getTimeToNextFrame() const { - if (endOfVideo() || _curFrame < 0) - return 0; - - uint32 elapsedTime = getTime(); - uint32 nextFrameStartTime = (uint32)(_nextFrameStartTime * 1000); - - if (nextFrameStartTime <= elapsedTime) - return 0; - - return nextFrameStartTime - elapsedTime; -} - -uint32 TheoraDecoder::getTime() const { - if (_audStream) - return g_system->getMixer()->getSoundElapsedTime(*_audHandle); - - return VideoDecoder::getTime(); -} - -void TheoraDecoder::pauseVideoIntern(bool pause) { - if (_audStream) - g_system->getMixer()->pauseHandle(*_audHandle, pause); -} - -enum TheoraYUVBuffers { - kBufferY = 0, - kBufferU = 1, - kBufferV = 2 -}; - -void TheoraDecoder::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer) { - // Width and height of all buffers have to be divisible by 2. - assert((YUVBuffer[kBufferY].width & 1) == 0); - assert((YUVBuffer[kBufferY].height & 1) == 0); - assert((YUVBuffer[kBufferU].width & 1) == 0); - assert((YUVBuffer[kBufferV].width & 1) == 0); - - // UV images have to have a quarter of the Y image resolution - assert(YUVBuffer[kBufferU].width == YUVBuffer[kBufferY].width >> 1); - assert(YUVBuffer[kBufferV].width == YUVBuffer[kBufferY].width >> 1); - assert(YUVBuffer[kBufferU].height == YUVBuffer[kBufferY].height >> 1); - assert(YUVBuffer[kBufferV].height == YUVBuffer[kBufferY].height >> 1); - - Graphics::convertYUV420ToRGB(&_surface, YUVBuffer[kBufferY].data, YUVBuffer[kBufferU].data, YUVBuffer[kBufferV].data, YUVBuffer[kBufferY].width, YUVBuffer[kBufferY].height, YUVBuffer[kBufferY].stride, YUVBuffer[kBufferU].stride); -} - -void TheoraDecoder::updateVolume() { - if (g_system->getMixer()->isSoundHandleActive(*_audHandle)) - g_system->getMixer()->setChannelVolume(*_audHandle, getVolume()); -} - -void TheoraDecoder::updateBalance() { - if (g_system->getMixer()->isSoundHandleActive(*_audHandle)) - g_system->getMixer()->setChannelBalance(*_audHandle, getBalance()); -} - -} // End of namespace Sword25 - -#endif diff --git a/engines/sword25/fmv/theora_decoder.h b/engines/sword25/fmv/theora_decoder.h deleted file mode 100644 index 739040024f..0000000000 --- a/engines/sword25/fmv/theora_decoder.h +++ /dev/null @@ -1,144 +0,0 @@ -/* 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 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 SWORD25_THEORADECODER_H -#define SWORD25_THEORADECODER_H - -#include "common/scummsys.h" // for USE_THEORADEC - -#ifdef USE_THEORADEC - -#include "common/rational.h" -#include "video/video_decoder.h" -#include "audio/audiostream.h" -#include "audio/mixer.h" -#include "graphics/pixelformat.h" -#include "graphics/surface.h" - -#include <theora/theoradec.h> -#include <vorbis/codec.h> - -namespace Common { -class SeekableReadStream; -} - -namespace Sword25 { - -/** - * - * Decoder for Theora videos. - * Video decoder used in engines: - * - sword25 - */ -class TheoraDecoder : public Video::VideoDecoder { -public: - TheoraDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kMusicSoundType); - virtual ~TheoraDecoder(); - - /** - * Load a video file - * @param stream the stream to load - */ - bool loadStream(Common::SeekableReadStream *stream); - void close(); - void reset(); - - /** - * Decode the next frame and return the frame's surface - * @note the return surface should *not* be freed - * @note this may return 0, in which case the last frame should be kept on screen - */ - const Graphics::Surface *decodeNextFrame(); - - bool isVideoLoaded() const { return _fileStream != 0; } - uint16 getWidth() const { return _displaySurface.w; } - uint16 getHeight() const { return _displaySurface.h; } - - uint32 getFrameCount() const { - // It is not possible to get frame count easily - // I.e. seeking is required - assert(0); - return 0; - } - - Graphics::PixelFormat getPixelFormat() const { return _displaySurface.format; } - uint32 getTime() const; - uint32 getTimeToNextFrame() const; - - bool endOfVideo() const; - -protected: - // VideoDecoder API - void updateVolume(); - void updateBalance(); - void pauseVideoIntern(bool pause); - -private: - void queuePage(ogg_page *page); - bool queueAudio(); - int bufferData(); - void translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer); - - Common::SeekableReadStream *_fileStream; - Graphics::Surface _surface; - Graphics::Surface _displaySurface; - Common::Rational _frameRate; - double _nextFrameStartTime; - bool _endOfVideo; - bool _endOfAudio; - - Audio::Mixer::SoundType _soundType; - Audio::SoundHandle *_audHandle; - Audio::QueuingAudioStream *_audStream; - - ogg_sync_state _oggSync; - ogg_page _oggPage; - ogg_packet _oggPacket; - ogg_stream_state _vorbisOut; - ogg_stream_state _theoraOut; - th_info _theoraInfo; - th_comment _theoraComment; - th_dec_ctx *_theoraDecode; - th_setup_info *_theoraSetup; - vorbis_info _vorbisInfo; - vorbis_dsp_state _vorbisDSP; - vorbis_block _vorbisBlock; - vorbis_comment _vorbisComment; - - int _theoraPacket; - int _vorbisPacket; - - int _ppLevelMax; - int _ppLevel; - int _ppInc; - - // single audio fragment audio buffering - int _audiobufFill; - bool _audiobufReady; - ogg_int16_t *_audiobuf; -}; - -} // End of namespace Sword25 - -#endif - -#endif diff --git a/engines/sword25/module.mk b/engines/sword25/module.mk index 302120c500..e24a221244 100644 --- a/engines/sword25/module.mk +++ b/engines/sword25/module.mk @@ -85,11 +85,6 @@ MODULE_OBJS := \ util/pluto/pluto.o \ util/pluto/plzio.o -ifdef USE_THEORADEC -MODULE_OBJS += \ - fmv/theora_decoder.o -endif - # This module can be built as a plugin ifeq ($(ENABLE_SWORD25), DYNAMIC_PLUGIN) PLUGIN := 1 diff --git a/engines/sword25/sfx/soundengine.cpp b/engines/sword25/sfx/soundengine.cpp index 78b2db19eb..69fae3dc4e 100644 --- a/engines/sword25/sfx/soundengine.cpp +++ b/engines/sword25/sfx/soundengine.cpp @@ -239,16 +239,20 @@ void SoundEngine::setSoundVolume(uint handle, float volume) { debugC(1, kDebugSound, "SoundEngine::setSoundVolume(%d, %f)", handle, volume); SndHandle* sndHandle = findHandle(handle); - if (sndHandle != NULL) + if (sndHandle != NULL) { + sndHandle->volume = volume; _mixer->setChannelVolume(sndHandle->handle, (byte)(volume * 255)); + } } void SoundEngine::setSoundPanning(uint handle, float pan) { debugC(1, kDebugSound, "SoundEngine::setSoundPanning(%d, %f)", handle, pan); SndHandle* sndHandle = findHandle(handle); - if (sndHandle != NULL) + if (sndHandle != NULL) { + sndHandle->pan = pan; _mixer->setChannelBalance(sndHandle->handle, (int8)(pan * 127)); + } } void SoundEngine::pauseSound(uint handle) { @@ -324,13 +328,16 @@ bool SoundEngine::canLoadResource(const Common::String &fileName) { return fname.hasSuffix(".ogg"); } - - bool SoundEngine::persist(OutputPersistenceBlock &writer) { +bool SoundEngine::persist(OutputPersistenceBlock &writer) { writer.write(_maxHandleId); for (uint i = 0; i < SOUND_HANDLES; i++) { writer.write(_handles[i].id); + // Don't restart sounds which already finished playing. + if (_handles[i].type != kFreeHandle && !_mixer->isSoundHandleActive(_handles[i].handle)) + _handles[i].type = kFreeHandle; + writer.writeString(_handles[i].fileName); writer.write((int)_handles[i].sndType); writer.write(_handles[i].volume); @@ -374,7 +381,8 @@ bool SoundEngine::unpersist(InputPersistenceBlock &reader) { reader.read(layer); if (reader.isGood()) { - playSoundEx(fileName, (SOUND_TYPES)sndType, volume, pan, loop, loopStart, loopEnd, layer, i); + if (sndType != kFreeHandle) + playSoundEx(fileName, (SOUND_TYPES)sndType, volume, pan, loop, loopStart, loopEnd, layer, i); } else return false; } diff --git a/engines/sword25/util/pluto/pluto.cpp b/engines/sword25/util/pluto/pluto.cpp index d645e5ed2a..b7f5e30340 100644 --- a/engines/sword25/util/pluto/pluto.cpp +++ b/engines/sword25/util/pluto/pluto.cpp @@ -895,10 +895,10 @@ static void unpersistnumber(UnpersistInfo *upi) static void unpersiststring(UnpersistInfo *upi) { /* perms reftbl sptbl ref */ - int length; + size_t length; char* string; lua_checkstack(upi->L, 1); - verify(LIF(Z,read)(&upi->zio, &length, sizeof(int)) == 0); + verify(LIF(Z,read)(&upi->zio, &length, sizeof(size_t)) == 0); string = pdep_newvector(upi->L, length, char); verify(LIF(Z,read)(&upi->zio, string, length) == 0); lua_pushlstring(upi->L, string, length); diff --git a/engines/toon/movie.cpp b/engines/toon/movie.cpp index 93e41adf57..8c85e20f7c 100644 --- a/engines/toon/movie.cpp +++ b/engines/toon/movie.cpp @@ -25,6 +25,7 @@ #include "common/keyboard.h" #include "common/stream.h" #include "common/system.h" +#include "graphics/palette.h" #include "graphics/surface.h" #include "toon/audio.h" @@ -33,6 +34,10 @@ namespace Toon { +ToonstruckSmackerDecoder::ToonstruckSmackerDecoder() : Video::SmackerDecoder() { + _lowRes = false; +} + void ToonstruckSmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize) { debugC(6, kDebugMovie, "handleAudioTrack(%d, %d, %d)", track, chunkSize, unpackedSize); @@ -40,33 +45,21 @@ void ToonstruckSmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, ui /* uint16 width = */ _fileStream->readUint16LE(); uint16 height = _fileStream->readUint16LE(); _lowRes = (height == getHeight() / 2); - } else + } else { Video::SmackerDecoder::handleAudioTrack(track, chunkSize, unpackedSize); + } } -bool ToonstruckSmackerDecoder::loadFile(const Common::String &filename) { - debugC(1, kDebugMovie, "loadFile(%s)", filename.c_str()); +bool ToonstruckSmackerDecoder::loadStream(Common::SeekableReadStream *stream) { + if (!Video::SmackerDecoder::loadStream(stream)) + return false; _lowRes = false; - - if (Video::SmackerDecoder::loadFile(filename)) { - if (_surface->h == 200) { - if (_surface) { - _surface->free(); - delete _surface; - } - _surface = new Graphics::Surface(); - _surface->create(640, 400, Graphics::PixelFormat::createFormatCLUT8()); - _header.flags = 4; - } - - return true; - } - return false; + return true; } -ToonstruckSmackerDecoder::ToonstruckSmackerDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : Video::SmackerDecoder(mixer, soundType) { - _lowRes = false; +Video::SmackerDecoder::SmackerVideoTrack *ToonstruckSmackerDecoder::createVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, uint32 flags, uint32 signature) const { + return Video::SmackerDecoder::createVideoTrack(width, height, frameCount, frameRate, (height == 200) ? 4 : flags, signature); } // decoder is deallocated with Movie destruction i.e. new ToonstruckSmackerDecoder is needed @@ -103,6 +96,9 @@ void Movie::play(const Common::String &video, int32 flags) { bool Movie::playVideo(bool isFirstIntroVideo) { debugC(1, kDebugMovie, "playVideo(isFirstIntroVideo: %d)", isFirstIntroVideo); + + _decoder->start(); + while (!_vm->shouldQuit() && !_decoder->endOfVideo()) { if (_decoder->needsUpdate()) { const Graphics::Surface *frame = _decoder->decodeNextFrame(); @@ -131,7 +127,7 @@ bool Movie::playVideo(bool isFirstIntroVideo) { } } } - _decoder->setSystemPalette(); + _vm->_system->getPaletteManager()->setPalette(_decoder->getPalette(), 0, 256); _vm->_system->updateScreen(); } diff --git a/engines/toon/movie.h b/engines/toon/movie.h index 2cd33302f2..e795182cba 100644 --- a/engines/toon/movie.h +++ b/engines/toon/movie.h @@ -30,13 +30,17 @@ namespace Toon { class ToonstruckSmackerDecoder : public Video::SmackerDecoder { public: - ToonstruckSmackerDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType); - virtual ~ToonstruckSmackerDecoder() {} - void handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize); - bool loadFile(const Common::String &filename); + ToonstruckSmackerDecoder(); + + bool loadStream(Common::SeekableReadStream *stream); bool isLowRes() { return _lowRes; } + protected: - bool _lowRes; + void handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize); + SmackerVideoTrack *createVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, uint32 flags, uint32 signature) const; + +private: + bool _lowRes; }; class Movie { diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp index ee427652d8..9fd8415676 100644 --- a/engines/toon/toon.cpp +++ b/engines/toon/toon.cpp @@ -51,7 +51,7 @@ void ToonEngine::init() { _currentScriptRegion = 0; _resources = new Resources(this); _animationManager = new AnimationManager(this); - _moviePlayer = new Movie(this, new ToonstruckSmackerDecoder(_mixer)); + _moviePlayer = new Movie(this, new ToonstruckSmackerDecoder()); _hotspots = new Hotspots(this); _mainSurface = new Graphics::Surface(); diff --git a/engines/tucker/sequences.cpp b/engines/tucker/sequences.cpp index 775fd6f1a0..16c4f4f6f0 100644 --- a/engines/tucker/sequences.cpp +++ b/engines/tucker/sequences.cpp @@ -28,6 +28,7 @@ #include "audio/decoders/wave.h" #include "graphics/palette.h" +#include "graphics/surface.h" #include "tucker/tucker.h" #include "tucker/graphics.h" @@ -749,6 +750,7 @@ void AnimationSequencePlayer::openAnimation(int index, const char *fileName) { _seqNum = 1; return; } + _flicPlayer[index].start(); _flicPlayer[index].decodeNextFrame(); if (index == 0) { getRGBPalette(index); @@ -801,7 +803,7 @@ void AnimationSequencePlayer::playIntroSeq19_20() { if (_flicPlayer[0].getCurFrame() >= 115) { surface = _flicPlayer[1].decodeNextFrame(); if (_flicPlayer[1].endOfVideo()) - _flicPlayer[1].reset(); + _flicPlayer[1].rewind(); } bool framesLeft = decodeNextAnimationFrame(0, false); diff --git a/graphics/decoders/bmp.cpp b/graphics/decoders/bmp.cpp index 5f764e1bd3..f15d4e2519 100644 --- a/graphics/decoders/bmp.cpp +++ b/graphics/decoders/bmp.cpp @@ -82,7 +82,7 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { /* uint16 planes = */ stream.readUint16LE(); uint16 bitsPerPixel = stream.readUint16LE(); - if (bitsPerPixel != 8 && bitsPerPixel != 24) { + if (bitsPerPixel != 8 && bitsPerPixel != 24 && bitsPerPixel != 32) { warning("%dbpp bitmaps not supported", bitsPerPixel); return false; } @@ -119,8 +119,8 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8(); - // BGRA for 24bpp - if (bitsPerPixel == 24) + // BGRA for 24bpp and 32 bpp + if (bitsPerPixel == 24 || bitsPerPixel == 32) format = Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0); _surface = new Graphics::Surface(); @@ -136,7 +136,7 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { stream.read(dst + (height - i - 1) * width, width); stream.skip(extraDataLength); } - } else { + } else if (bitsPerPixel == 24) { byte *dst = (byte *)_surface->pixels + (height - 1) * _surface->pitch; for (int32 i = 0; i < height; i++) { @@ -153,6 +153,27 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { stream.skip(extraDataLength); dst -= _surface->pitch * 2; } + } else { // 32 bpp + byte *dst = (byte *)_surface->pixels + (height - 1) * _surface->pitch; + + for (int32 i = 0; i < height; i++) { + for (uint32 j = 0; j < width; j++) { + byte b = stream.readByte(); + byte g = stream.readByte(); + byte r = stream.readByte(); + // Ignore the last byte, as in v3 it is unused + // and should thus NOT be used as alpha. + // ref: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376%28v=vs.85%29.aspx + stream.readByte(); + uint32 color = format.RGBToColor(r, g, b); + + *((uint32 *)dst) = color; + dst += format.bytesPerPixel; + } + + stream.skip(extraDataLength); + dst -= _surface->pitch * 2; + } } return true; diff --git a/graphics/decoders/png.cpp b/graphics/decoders/png.cpp index 492c69779f..bfaab6dc35 100644 --- a/graphics/decoders/png.cpp +++ b/graphics/decoders/png.cpp @@ -20,86 +20,25 @@ * */ +// Since we need to work with libpng here, we need to allow all symbols +// to avoid compilation issues. +#define FORBIDDEN_SYMBOL_ALLOW_ALL +#include "common/scummsys.h" + +#ifdef USE_PNG +#include <png.h> +#endif + #include "graphics/decoders/png.h" #include "graphics/pixelformat.h" #include "graphics/surface.h" -#include "common/endian.h" -#include "common/memstream.h" #include "common/stream.h" -#include "common/types.h" -#include "common/util.h" -#include "common/zlib.h" - -// PNG decoder, based on the W3C specs: -// http://www.w3.org/TR/PNG/ -// Parts of the code have been adapted from LodePNG, by Lode Vandevenne: -// http://members.gamedev.net/lode/projects/LodePNG/ - -/* -LodePNG version 20101211 - -Copyright (c) 2005-2010 Lode Vandevenne - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*/ namespace Graphics { -enum PNGChunks { - // == Critical chunks ===================================================== - kChunkIHDR = MKTAG('I','H','D','R'), // Image header - kChunkIDAT = MKTAG('I','D','A','T'), // Image data - kChunkPLTE = MKTAG('P','L','T','E'), // Palette - kChunkIEND = MKTAG('I','E','N','D'), // Image trailer - // == Ancillary chunks ==================================================== - kChunktRNS = MKTAG('t','R','N','S') // Transparency - // All of the other ancillary chunks are ignored. They're added here for - // reference only. - // cHRM - Primary chromacities and white point - // gAMA - Image gamma - // iCCP - Embedded ICC profile - // sBIT - Significant bits - // sRGB - Standard RGB color space - // tEXT - Textual data - // sTXt - Compressed textual data - // iTXt - International textual data - // bKGD - Background color - // hIST - Image histogram - // pHYs - Physical pixel dimensions - // sPLT - Suggested palette - // tIME - Image last-modification time -}; - -// Refer to http://www.w3.org/TR/PNG/#9Filters -enum PNGFilters { - kFilterNone = 0, - kFilterSub = 1, - kFilterUp = 2, - kFilterAverage = 3, - kFilterPaeth = 4 -}; - -PNGDecoder::PNGDecoder() : _compressedBuffer(0), _compressedBufferSize(0), - _transparentColorSpecified(false), _outputSurface(0), _paletteEntries(0) { +PNGDecoder::PNGDecoder() : _outputSurface(0), _palette(0), _paletteColorCount(0) { } PNGDecoder::~PNGDecoder() { @@ -112,14 +51,41 @@ void PNGDecoder::destroy() { delete _outputSurface; _outputSurface = 0; } + delete[] _palette; + _palette = NULL; +} + +#ifdef USE_PNG +// libpng-error-handling: +void pngError(png_structp pngptr, png_const_charp errorMsg) { + error("%s", errorMsg); +} - _paletteEntries = 0; +void pngWarning(png_structp pngptr, png_const_charp warningMsg) { + warning("%s", warningMsg); } +// libpng-I/O-helper: +void pngReadFromStream(png_structp pngPtr, png_bytep data, png_size_t length) { + void *readIOptr = png_get_io_ptr(pngPtr); + Common::SeekableReadStream *stream = (Common::SeekableReadStream *)readIOptr; + stream->read(data, length); +} +#endif + +/* + * This code is based on Broken Sword 2.5 engine + * + * Copyright (c) Malte Thiesen, Daniel Queteschiner and Michael Elsdoerfer + * + * Licensed under GNU GPL v2 + * + */ + bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { +#ifdef USE_PNG destroy(); - uint32 chunkLength = 0, chunkType = 0; _stream = &stream; // First, check the PNG signature @@ -132,374 +98,143 @@ bool PNGDecoder::loadStream(Common::SeekableReadStream &stream) { return false; } - // Start reading chunks till we reach an IEND chunk - while (chunkType != kChunkIEND) { - // The chunk length does not include the type or CRC bytes - chunkLength = _stream->readUint32BE(); - chunkType = _stream->readUint32BE(); - - switch (chunkType) { - case kChunkIHDR: - readHeaderChunk(); - break; - case kChunkIDAT: - if (_compressedBufferSize == 0) { - _compressedBufferSize += chunkLength; - _compressedBuffer = (byte *)malloc(_compressedBufferSize); - _stream->read(_compressedBuffer, chunkLength); - } else { - // Expand the buffer - uint32 prevSize = _compressedBufferSize; - _compressedBufferSize += chunkLength; - byte *tmp = new byte[prevSize]; - memcpy(tmp, _compressedBuffer, prevSize); - free(_compressedBuffer); - _compressedBuffer = (byte *)malloc(_compressedBufferSize); - memcpy(_compressedBuffer, tmp, prevSize); - delete[] tmp; - _stream->read(_compressedBuffer + prevSize, chunkLength); - } - break; - case kChunkPLTE: // only available in indexed PNGs - if (_header.colorType != kIndexed) - error("A palette chunk has been found in a non-indexed PNG file"); - if (chunkLength % 3 != 0) - error("Palette chunk not divisible by 3"); - - _paletteEntries = chunkLength / 3; - _stream->read(_palette, _paletteEntries * 3); - memset(_paletteTransparency, 0xff, sizeof(_paletteTransparency)); - break; - case kChunkIEND: - // End of stream - break; - case kChunktRNS: - readTransparencyChunk(chunkLength); - break; - default: - // Skip the chunk content - _stream->skip(chunkLength); - break; - } - - if (chunkType != kChunkIEND) - _stream->skip(4); // skip the chunk CRC checksum + // The following is based on the guide provided in: + //http://www.libpng.org/pub/png/libpng-1.2.5-manual.html#section-3 + //http://www.libpng.org/pub/png/libpng-1.4.0-manual.pdf + // along with the png-loading code used in the sword25-engine. + png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!pngPtr) { + delete _stream; + return false; + } + png_infop infoPtr = png_create_info_struct(pngPtr); + if (!infoPtr) { + png_destroy_read_struct(&pngPtr, NULL, NULL); + delete _stream; + return false; + } + png_infop endInfo = png_create_info_struct(pngPtr); + if (!endInfo) { + png_destroy_read_struct(&pngPtr, &infoPtr, NULL); + delete _stream; + return false; } - // We no longer need the file stream, thus close it here - _stream = 0; + png_set_error_fn(pngPtr, NULL, pngError, pngWarning); + // TODO: The manual says errors should be handled via setjmp - // Unpack the compressed buffer - Common::MemoryReadStream *compData = new Common::MemoryReadStream(_compressedBuffer, _compressedBufferSize, DisposeAfterUse::YES); - _imageData = Common::wrapCompressedReadStream(compData); + png_set_read_fn(pngPtr, _stream, pngReadFromStream); + png_set_crc_action(pngPtr, PNG_CRC_DEFAULT, PNG_CRC_WARN_USE); + // We already verified the PNG-header + png_set_sig_bytes(pngPtr, 8); - // Construct the final image - constructImage(); + // Read PNG header + png_read_info(pngPtr, infoPtr); - // Close the uncompressed stream, which will also delete the memory stream, - // and thus the original compressed buffer - delete _imageData; + // No handling for unknown chunks yet. + int bitDepth, colorType, width, height, interlaceType; + png_uint_32 w, h; + png_get_IHDR(pngPtr, infoPtr, &w, &h, &bitDepth, &colorType, &interlaceType, NULL, NULL); + width = w; + height = h; - return true; -} - -/** - * Paeth predictor, used by PNG filter type 4 - * The parameters are of signed 16-bit integers, but should come - * from unsigned chars. The integers are only needed to make - * the paeth calculation correct. - * - * Taken from lodePNG, with a slight patch: - * http://www.atalasoft.com/cs/blogs/stevehawley/archive/2010/02/23/libpng-you-re-doing-it-wrong.aspx - */ -byte PNGDecoder::paethPredictor(int16 a, int16 b, int16 c) { - int16 pa = ABS<int16>(b - c); - int16 pb = ABS<int16>(a - c); - int16 pc = ABS<int16>(a + b - c - c); - - if (pa <= MIN<int16>(pb, pc)) - return (byte)a; - else if (pb <= pc) - return (byte)b; - else - return (byte)c; -} + // Allocate memory for the final image data. + // To keep memory framentation low this happens before allocating memory for temporary image data. + _outputSurface = new Graphics::Surface(); -/** - * Unfilters a filtered PNG scan line. - * PNG filters are defined in: http://www.w3.org/TR/PNG/#9Filters - * Note that filters are always applied to bytes - * - * Taken from lodePNG - */ -void PNGDecoder::unfilterScanLine(byte *dest, const byte *scanLine, const byte *prevLine, uint16 byteWidth, byte filterType, uint16 length) { - uint16 i; - - switch (filterType) { - case kFilterNone: // no change - for (i = 0; i < length; i++) - dest[i] = scanLine[i]; - break; - case kFilterSub: // add the bytes to the left - for (i = 0; i < byteWidth; i++) - dest[i] = scanLine[i]; - for (i = byteWidth; i < length; i++) - dest[i] = scanLine[i] + dest[i - byteWidth]; - break; - case kFilterUp: // add the bytes of the above scanline - if (prevLine) { - for (i = 0; i < length; i++) - dest[i] = scanLine[i] + prevLine[i]; - } else { - for (i = 0; i < length; i++) - dest[i] = scanLine[i]; + // Images of all color formats except PNG_COLOR_TYPE_PALETTE + // will be transformed into ARGB images + if (colorType == PNG_COLOR_TYPE_PALETTE && !png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) { + int numPalette = 0; + png_colorp palette = NULL; + uint32 success = png_get_PLTE(pngPtr, infoPtr, &palette, &numPalette); + if (success != PNG_INFO_PLTE) { + png_destroy_read_struct(&pngPtr, &infoPtr, NULL); + return false; } - break; - case kFilterAverage: // average value of the left and top left - if (prevLine) { - for (i = 0; i < byteWidth; i++) - dest[i] = scanLine[i] + prevLine[i] / 2; - for (i = byteWidth; i < length; i++) - dest[i] = scanLine[i] + ((dest[i - byteWidth] + prevLine[i]) / 2); - } else { - for (i = 0; i < byteWidth; i++) - dest[i] = scanLine[i]; - for (i = byteWidth; i < length; i++) - dest[i] = scanLine[i] + dest[i - byteWidth] / 2; + _paletteColorCount = numPalette; + _palette = new byte[_paletteColorCount * 3]; + for (int i = 0; i < _paletteColorCount; i++) { + _palette[(i * 3)] = palette[i].red; + _palette[(i * 3) + 1] = palette[i].green; + _palette[(i * 3) + 2] = palette[i].blue; + } - break; - case kFilterPaeth: // Paeth filter: http://www.w3.org/TR/PNG/#9Filter-type-4-Paeth - if (prevLine) { - for(i = 0; i < byteWidth; i++) - dest[i] = (scanLine[i] + prevLine[i]); // paethPredictor(0, prevLine[i], 0) is always prevLine[i] - for(i = byteWidth; i < length; i++) - dest[i] = (scanLine[i] + paethPredictor(dest[i - byteWidth], prevLine[i], prevLine[i - byteWidth])); - } else { - for(i = 0; i < byteWidth; i++) - dest[i] = scanLine[i]; - for(i = byteWidth; i < length; i++) - dest[i] = (scanLine[i] + dest[i - byteWidth]); // paethPredictor(dest[i - byteWidth], 0, 0) is always dest[i - byteWidth] + _outputSurface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); + png_set_packing(pngPtr); + } else { + _outputSurface->create(width, height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)); + if (!_outputSurface->pixels) { + error("Could not allocate memory for output image."); } - break; - default: - error("Unknown line filter"); + if (bitDepth == 16) + png_set_strip_16(pngPtr); + if (bitDepth < 8) + png_set_expand(pngPtr); + if (png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS)) + png_set_expand(pngPtr); + if (colorType == PNG_COLOR_TYPE_GRAY || + colorType == PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(pngPtr); + + // PNGs are Big-Endian: +#ifdef SCUMM_LITTLE_ENDIAN + png_set_bgr(pngPtr); + png_set_swap_alpha(pngPtr); + if (colorType != PNG_COLOR_TYPE_RGB_ALPHA) + png_set_filler(pngPtr, 0xff, PNG_FILLER_BEFORE); +#else + if (colorType != PNG_COLOR_TYPE_RGB_ALPHA) + png_set_filler(pngPtr, 0xff, PNG_FILLER_AFTER); +#endif + } -} + // After the transformations have been registered, the image data is read again. + png_read_update_info(pngPtr, infoPtr); + png_get_IHDR(pngPtr, infoPtr, &w, &h, &bitDepth, &colorType, NULL, NULL, NULL); + width = w; + height = h; -int PNGDecoder::getBytesPerPixel() const { - return (getNumColorChannels() * _header.bitDepth + 7) / 8; -} + if (interlaceType == PNG_INTERLACE_NONE) { + // PNGs without interlacing can simply be read row by row. + for (int i = 0; i < height; i++) { + png_read_row(pngPtr, (png_bytep)_outputSurface->getBasePtr(0, i), NULL); + } + } else { + // PNGs with interlacing require us to allocate an auxillary + // buffer with pointers to all row starts. -void PNGDecoder::constructImage() { - assert (_header.bitDepth != 0); - - int bytesPerPixel = getBytesPerPixel(); - int pitch = bytesPerPixel * _header.width; - byte *unfilteredSurface = new byte[pitch * _header.height]; - byte *dest = unfilteredSurface; - uint16 scanLineWidth = (_header.width * getNumColorChannels() * _header.bitDepth + 7) / 8; - byte *scanLine = new byte[scanLineWidth]; - byte *prevLine = 0; - - switch(_header.interlaceType) { - case kNonInterlaced: - for (uint16 y = 0; y < _header.height; y++) { - byte filterType = _imageData->readByte(); - _imageData->read(scanLine, scanLineWidth); - unfilterScanLine(dest, scanLine, prevLine, bytesPerPixel, filterType, scanLineWidth); - prevLine = dest; - dest += pitch; + // Allocate row pointer buffer + png_bytep *rowPtr = new png_bytep[height]; + if (!rowPtr) { + error("Could not allocate memory for row pointers."); } - break; - case kInterlaced: - // Theoretically, this shouldn't be needed, as interlacing is only - // useful for web images. Interlaced PNG images require more complex - // handling, so unless having support for such images is needed, there - // is no reason to add support for them. - error("TODO: Support for interlaced PNG images"); - break; - } - delete[] scanLine; + // Initialize row pointers + for (int i = 0; i < height; i++) + rowPtr[i] = (png_bytep)_outputSurface->getBasePtr(0, i); - constructOutput(unfilteredSurface); - delete[] unfilteredSurface; -} + // Read image data + png_read_image(pngPtr, rowPtr); -Graphics::PixelFormat PNGDecoder::findPixelFormat() const { - // Try to find the best pixel format based on what we have here - // Which is basically 8bpp for paletted non-transparent - // and 32bpp for everything else - - switch (_header.colorType) { - case kIndexed: - if (!_transparentColorSpecified) - return Graphics::PixelFormat::createFormatCLUT8(); - // fall through - case kGrayScale: - case kTrueColor: - case kGrayScaleWithAlpha: - case kTrueColorWithAlpha: - // We'll go with standard RGBA 32-bit - return Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0); + // Free row pointer buffer + delete[] rowPtr; } - error("Unknown PNG color type"); - return Graphics::PixelFormat(); -} + // Read additional data at the end. + png_read_end(pngPtr, NULL); -void PNGDecoder::constructOutput(const byte *surface) { - _outputSurface = new Graphics::Surface(); - _outputSurface->create(_header.width, _header.height, findPixelFormat()); - - const byte *src = surface; - byte a = 0xFF; - int bytesPerPixel = getBytesPerPixel(); - - if (_header.colorType != kIndexed) { - if (_header.colorType == kTrueColor || - _header.colorType == kTrueColorWithAlpha) { - if (bytesPerPixel != 3 && bytesPerPixel != 4) - error("Unsupported truecolor PNG format"); - } else if (_header.colorType == kGrayScale || - _header.colorType == kGrayScaleWithAlpha) { - if (bytesPerPixel != 1 && bytesPerPixel != 2) - error("Unsupported grayscale PNG format"); - } - - for (uint16 i = 0; i < _outputSurface->h; i++) { - for (uint16 j = 0; j < _outputSurface->w; j++) { - uint32 result = 0; - - switch (bytesPerPixel) { - case 1: // Grayscale - if (_transparentColorSpecified) - a = (src[0] == _transparentColor[0]) ? 0 : 0xFF; - result = _outputSurface->format.ARGBToColor(a, src[0], src[0], src[0]); - break; - case 2: // Grayscale + alpha - result = _outputSurface->format.ARGBToColor(src[1], src[0], src[0], src[0]); - break; - case 3: // RGB - if (_transparentColorSpecified) { - bool isTransparentColor = (src[0] == _transparentColor[0] && - src[1] == _transparentColor[1] && - src[2] == _transparentColor[2]); - a = isTransparentColor ? 0 : 0xFF; - } - - result = _outputSurface->format.ARGBToColor(a, src[0], src[1], src[2]); - break; - case 4: // RGBA - result = _outputSurface->format.ARGBToColor(src[3], src[0], src[1], src[2]); - break; - } - - *((uint32 *)_outputSurface->getBasePtr(j, i)) = result; - src += bytesPerPixel; - } - } - } else { - uint32 mask = (0xff >> (8 - _header.bitDepth)) << (8 - _header.bitDepth); - - // Convert the indexed surface to the target pixel format - for (uint16 i = 0; i < _outputSurface->h; i++) { - int data = 0; - int bitCount = 8; - const byte *src1 = src; - - for (uint16 j = 0; j < _outputSurface->w; j++) { - if (bitCount == 8) { - data = *src; - src++; - } - - byte index = (data & mask) >> (8 - _header.bitDepth); - data = (data << _header.bitDepth) & 0xff; - bitCount -= _header.bitDepth; - - if (bitCount == 0) - bitCount = 8; - - if (_transparentColorSpecified) { - byte r = _palette[index * 3 + 0]; - byte g = _palette[index * 3 + 1]; - byte b = _palette[index * 3 + 2]; - a = _paletteTransparency[index]; - *((uint32 *)_outputSurface->getBasePtr(j, i)) = _outputSurface->format.ARGBToColor(a, r, g, b); - } else { - *((byte *)_outputSurface->getBasePtr(j, i)) = index; - } - } - - src = src1 + _outputSurface->w; - } - } -} + // Destroy libpng structures + png_destroy_read_struct(&pngPtr, &infoPtr, NULL); -void PNGDecoder::readHeaderChunk() { - _header.width = _stream->readUint32BE(); - _header.height = _stream->readUint32BE(); - _header.bitDepth = _stream->readByte(); - if (_header.bitDepth > 8) - error("Only PNGs with a bit depth of 1-8 bits are supported (i.e. PNG24)"); - _header.colorType = (PNGColorType)_stream->readByte(); - _header.compressionMethod = _stream->readByte(); - // Compression methods: http://www.w3.org/TR/PNG/#10Compression - // Only compression method 0 (deflate) is documented and supported - if (_header.compressionMethod != 0) - error("Unknown PNG compression method: %d", _header.compressionMethod); - _header.filterMethod = _stream->readByte(); - // Filter methods: http://www.w3.org/TR/PNG/#9Filters - // Only filter method 0 is documented and supported - if (_header.filterMethod != 0) - error("Unknown PNG filter method: %d", _header.filterMethod); - _header.interlaceType = (PNGInterlaceType)_stream->readByte(); -} - -byte PNGDecoder::getNumColorChannels() const { - switch (_header.colorType) { - case kGrayScale: - return 1; // Gray - case kTrueColor: - return 3; // RGB - case kIndexed: - return 1; // Indexed - case kGrayScaleWithAlpha: - return 2; // Gray + Alpha - case kTrueColorWithAlpha: - return 4; // RGBA - default: - error("Unknown color type"); - } -} + // We no longer need the file stream, thus close it here + _stream = 0; -void PNGDecoder::readTransparencyChunk(uint32 chunkLength) { - _transparentColorSpecified = true; - - switch(_header.colorType) { - case kGrayScale: - _transparentColor[0] = _stream->readUint16BE(); - _transparentColor[1] = _transparentColor[0]; - _transparentColor[2] = _transparentColor[0]; - break; - case kTrueColor: - _transparentColor[0] = _stream->readUint16BE(); - _transparentColor[1] = _stream->readUint16BE(); - _transparentColor[2] = _stream->readUint16BE(); - break; - case kIndexed: - _stream->read(_paletteTransparency, chunkLength); - - // A transparency chunk may have less entries - // than the palette entries. The remaining ones - // are unmodified (set to 255). Check here: - // http://www.w3.org/TR/PNG/#11tRNS - break; - default: - error("Transparency chunk found in a PNG that has a separate transparency channel"); - } + return true; +#else + return false; +#endif } } // End of Graphics namespace diff --git a/graphics/decoders/png.h b/graphics/decoders/png.h index ca204f6dd3..e52ddabd7d 100644 --- a/graphics/decoders/png.h +++ b/graphics/decoders/png.h @@ -24,33 +24,12 @@ * PNG decoder used in engines: * - sword25 * Dependencies: - * - zlib + * - libpng */ #ifndef GRAPHICS_PNG_H #define GRAPHICS_PNG_H -// PNG decoder, based on the W3C specs: -// http://www.w3.org/TR/PNG/ -// Parts of the code have been adapted from LodePNG, by Lode Vandevenne: -// http://members.gamedev.net/lode/projects/LodePNG/ - -// All the numbers are BE: http://www.w3.org/TR/PNG/#7Integers-and-byte-order - -// Note: At the moment, this decoder only supports non-interlaced images, and -// does not support truecolor/grayscale images with 16bit depth. -// -// Theoretically, interlaced images shouldn't be needed for games, as -// interlacing is only useful for images in websites. -// -// PNG images with 16bit depth (i.e. 48bit images) are quite rare, and can -// theoretically contain more than 16.7 millions of colors (the so-called "deep -// color" representation). In essence, each of the R, G, B and A components in -// them is specified with 2 bytes, instead of 1. However, the PNG specification -// always refers to color components with 1 byte each, so this part of the spec -// is a bit unclear. For now, these won't be supported, until a suitable sample -// is found. - #include "common/scummsys.h" #include "common/textconsole.h" #include "graphics/decoders/image_decoder.h" @@ -73,62 +52,13 @@ public: void destroy(); const Graphics::Surface *getSurface() const { return _outputSurface; } const byte *getPalette() const { return _palette; } - uint16 getPaletteColorCount() const { return _paletteEntries; } - + uint16 getPaletteColorCount() const { return _paletteColorCount; } private: - enum PNGColorType { - kGrayScale = 0, // bit depths: 1, 2, 4, 8, 16 - kTrueColor = 2, // bit depths: 8, 16 - kIndexed = 3, // bit depths: 1, 2, 4, 8 - kGrayScaleWithAlpha = 4, // bit depths: 8, 16 - kTrueColorWithAlpha = 6 // bit depths: 8, 16 - }; - - enum PNGInterlaceType { - kNonInterlaced = 0, - kInterlaced = 1 - }; - - struct PNGHeader { - uint32 width; - uint32 height; - byte bitDepth; - PNGColorType colorType; - byte compressionMethod; - byte filterMethod; - PNGInterlaceType interlaceType; - }; - - void readHeaderChunk(); - byte getNumColorChannels() const; - - void readPaletteChunk(); - void readTransparencyChunk(uint32 chunkLength); - - void constructImage(); - void unfilterScanLine(byte *dest, const byte *scanLine, const byte *prevLine, uint16 byteWidth, byte filterType, uint16 length); - byte paethPredictor(int16 a, int16 b, int16 c); - - // The original file stream Common::SeekableReadStream *_stream; - // The unzipped image data stream - Common::SeekableReadStream *_imageData; - - PNGHeader _header; - - byte _palette[256 * 3]; // RGB - byte _paletteTransparency[256]; - uint16 _paletteEntries; - uint16 _transparentColor[3]; - bool _transparentColorSpecified; - - byte *_compressedBuffer; - uint32 _compressedBufferSize; + byte *_palette; + uint16 _paletteColorCount; Graphics::Surface *_outputSurface; - Graphics::PixelFormat findPixelFormat() const; - int getBytesPerPixel() const; - void constructOutput(const byte *surface); }; } // End of namespace Graphics diff --git a/graphics/decoders/tga.cpp b/graphics/decoders/tga.cpp new file mode 100644 index 0000000000..0b2318e127 --- /dev/null +++ b/graphics/decoders/tga.cpp @@ -0,0 +1,424 @@ +/* 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 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. + */ + +/* Based on code from xoreos https://github.com/DrMcCoy/xoreos/ + * relicensed under GPLv2+ with permission from DrMcCoy and clone2727 + */ + +#include "common/util.h" +#include "common/stream.h" +#include "common/textconsole.h" +#include "common/error.h" + +#include "graphics/decoders/tga.h" + +namespace Graphics { + +TGADecoder::TGADecoder() { + _colorMapSize = 0; + _colorMapOrigin = 0; + _colorMapLength = 0; + _colorMapEntryLength = 0; + _colorMap = NULL; +} + +TGADecoder::~TGADecoder() { + destroy(); +} + +void TGADecoder::destroy() { + _surface.free(); + delete[] _colorMap; +} + +bool TGADecoder::loadStream(Common::SeekableReadStream &tga) { + byte imageType, pixelDepth; + bool success; + success = readHeader(tga, imageType, pixelDepth); + if (success) { + switch (imageType) { + case TYPE_BW: + case TYPE_TRUECOLOR: + success = readData(tga, imageType, pixelDepth); + break; + case TYPE_RLE_BW: + case TYPE_RLE_TRUECOLOR: + case TYPE_RLE_CMAP: + success = readDataRLE(tga, imageType, pixelDepth); + break; + case TYPE_CMAP: + success = readDataColorMapped(tga, imageType, pixelDepth); + break; + default: + success = false; + break; + } + } + if (tga.err() || !success) { + warning("Failed reading TGA-file"); + return false; + } + return success; +} + +bool TGADecoder::readHeader(Common::SeekableReadStream &tga, byte &imageType, byte &pixelDepth) { + if (!tga.seek(0)) { + warning("Failed reading TGA-file"); + return false; + } + + // TGAs have an optional "id" string in the header + uint32 idLength = tga.readByte(); + + // Number of colors in the color map / palette + int hasColorMap = tga.readByte(); + + // Image type. See header for numeric constants + imageType = tga.readByte(); + + switch (imageType) { + case TYPE_CMAP: + case TYPE_TRUECOLOR: + case TYPE_BW: + case TYPE_RLE_CMAP: + case TYPE_RLE_TRUECOLOR: + case TYPE_RLE_BW: + break; + default: + warning("Unsupported image type: %d", imageType); + return false; + } + + // Color map specifications + if (hasColorMap == 0) { + tga.skip(5); + } else { + _colorMapOrigin = tga.readUint16LE(); + _colorMapLength = tga.readUint16LE(); + _colorMapEntryLength = tga.readByte(); + } + // Origin-defintions + tga.skip(2 + 2); + + // Image dimensions + _surface.w = tga.readUint16LE(); + _surface.h = tga.readUint16LE(); + + // Bits per pixel + pixelDepth = tga.readByte(); + _surface.format.bytesPerPixel = pixelDepth / 8; + + // Image descriptor + byte imgDesc = tga.readByte(); + int attributeBits = imgDesc & 0x0F; + assert((imgDesc & 0x10) == 0); + _originTop = (imgDesc & 0x20); + + // Interleaving is not handled at this point + //int interleave = (imgDesc & 0xC); + if (imageType == TYPE_CMAP || imageType == TYPE_RLE_CMAP) { + if (pixelDepth == 8) { + _format = PixelFormat::createFormatCLUT8(); + } else { + warning("Unsupported index-depth: %d", pixelDepth); + return false; + } + } else if (imageType == TYPE_TRUECOLOR || imageType == TYPE_RLE_TRUECOLOR) { + if (pixelDepth == 24) { + _format = PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0); + } else if (pixelDepth == 32) { + _format = PixelFormat(4, 8, 8, 8, attributeBits, 16, 8, 0, 24); + } else if (pixelDepth == 16 && imageType == TYPE_TRUECOLOR) { + // 16bpp TGA is ARGB1555 + _format = PixelFormat(2, 5, 5, 5, attributeBits, 10, 5, 0, 15); + } else { + warning("Unsupported pixel depth: %d, %d", imageType, pixelDepth); + return false; + } + } else if (imageType == TYPE_BW || TYPE_RLE_BW) { + if (pixelDepth == 8) { + _format = PixelFormat(4, 8, 8, 8, 0, 16, 8, 0, 0); + } else { + warning("Unsupported pixel depth: %d, %d", imageType, pixelDepth); + return false; + } + + } else { + warning("Unsupported image type: %d", imageType); + return false; + } + + // Skip the id string + tga.skip(idLength); + + if (hasColorMap) { + return readColorMap(tga, imageType, pixelDepth); + } + return true; +} + +bool TGADecoder::readColorMap(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth) { + _colorMap = new byte[3 * _colorMapLength]; + for (int i = 0; i < _colorMapLength * 3; i += 3) { + byte r, g, b; + if (_colorMapEntryLength == 32) { + byte a; + PixelFormat format(4, 8, 8, 8, 0, 16, 8, 0, 24); + uint32 color = tga.readUint32LE(); + format.colorToARGB(color, a, r, g, b); + } else if (_colorMapEntryLength == 24) { + r = tga.readByte(); + g = tga.readByte(); + b = tga.readByte(); + } else if (_colorMapEntryLength == 16) { + byte a; + PixelFormat format(2, 5, 5, 5, 0, 10, 5, 0, 15); + uint16 color = tga.readUint16LE(); + format.colorToARGB(color, a, r, g, b); + } else { + warning("Unsupported image type: %d", imageType); + r = g = b = 0; + } +#ifdef SCUMM_LITTLE_ENDIAN + _colorMap[i] = r; + _colorMap[i + 1] = g; + _colorMap[i + 2] = b; +#else + _colorMap[i] = b; + _colorMap[i + 1] = g; + _colorMap[i + 2] = r; +#endif + } + return true; +} + +// Additional information found from http://paulbourke.net/dataformats/tga/ +// With some details from the link referenced in the header. +bool TGADecoder::readData(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth) { + // TrueColor + if (imageType == TYPE_TRUECOLOR) { + _surface.create(_surface.w, _surface.h, _format); + + if (pixelDepth == 16) { + for (int i = 0; i < _surface.h; i++) { + uint16 *dst; + if (!_originTop) { + dst = (uint16 *)_surface.getBasePtr(0, _surface.h - i - 1); + } else { + dst = (uint16 *)_surface.getBasePtr(0, i); + } + for (int j = 0; j < _surface.w; j++) { + *dst++ = tga.readUint16LE(); + } + } + } else if (pixelDepth == 32) { + for (int i = 0; i < _surface.h; i++) { + uint32 *dst; + if (!_originTop) { + dst = (uint32 *)_surface.getBasePtr(0, _surface.h - i - 1); + } else { + dst = (uint32 *)_surface.getBasePtr(0, i); + } + for (int j = 0; j < _surface.w; j++) { + *dst++ = tga.readUint32LE(); + } + } + } else if (pixelDepth == 24) { + for (int i = 0; i < _surface.h; i++) { + byte *dst; + if (!_originTop) { + dst = (byte *)_surface.getBasePtr(0, _surface.h - i - 1); + } else { + dst = (byte *)_surface.getBasePtr(0, i); + } + for (int j = 0; j < _surface.w; j++) { + byte r = tga.readByte(); + byte g = tga.readByte(); + byte b = tga.readByte(); +#ifdef SCUMM_LITTLE_ENDIAN + *dst++ = r; + *dst++ = g; + *dst++ = b; +#else + *dst++ = b; + *dst++ = g; + *dst++ = r; +#endif + } + } + } + // Black/White + } else if (imageType == TYPE_BW) { + _surface.create(_surface.w, _surface.h, _format); + + byte *data = (byte *)_surface.pixels; + uint32 count = _surface.w * _surface.h; + + while (count-- > 0) { + byte g = tga.readByte(); + *data++ = g; + *data++ = g; + *data++ = g; + *data++ = g; + } + } + return true; +} + +bool TGADecoder::readDataColorMapped(Common::SeekableReadStream &tga, byte imageType, byte indexDepth) { + // Color-mapped + if (imageType == TYPE_CMAP) { + _surface.create(_surface.w, _surface.h, _format); + if (indexDepth == 8) { + for (int i = 0; i < _surface.h; i++) { + byte *dst; + if (!_originTop) { + dst = (byte *)_surface.getBasePtr(0, _surface.h - i - 1); + } else { + dst = (byte *)_surface.getBasePtr(0, i); + } + for (int j = 0; j < _surface.w; j++) { + byte index = tga.readByte(); + *dst++ = index; + } + } + } else if (indexDepth == 16) { + warning("16 bit indexes not supported"); + return false; + } + } else { + return false; + } + return true; +} + +bool TGADecoder::readDataRLE(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth) { + // RLE-TrueColor / RLE-Black/White + if (imageType == TYPE_RLE_TRUECOLOR || imageType == TYPE_RLE_BW || imageType == TYPE_RLE_CMAP) { + _surface.create(_surface.w, _surface.h, _format); + uint32 count = _surface.w * _surface.h; + byte *data = (byte *)_surface.pixels; + + while (count > 0) { + uint32 header = tga.readByte(); + byte type = (header & 0x80) >> 7; + uint32 rleCount = (header & 0x7F) + 1; + + // RLE-packet + if (type == 1) { + if (pixelDepth == 32 && imageType == TYPE_RLE_TRUECOLOR) { + uint32 color = tga.readUint32LE(); + while (rleCount-- > 0) { + *((uint32 *)data) = color; + data += 4; + count--; + } + } else if (pixelDepth == 24 && imageType == TYPE_RLE_TRUECOLOR) { + byte r = tga.readByte(); + byte g = tga.readByte(); + byte b = tga.readByte(); + while (rleCount-- > 0) { +#ifdef SCUMM_LITTLE_ENDIAN + *data++ = r; + *data++ = g; + *data++ = b; +#else + *data++ = b; + *data++ = g; + *data++ = r; +#endif + count--; + } + } else if (pixelDepth == 8 && imageType == TYPE_RLE_BW) { + byte color = tga.readByte(); + while (rleCount-- > 0) { + *data++ = color; + *data++ = color; + *data++ = color; + *data++ = color; + count--; + } + } else if (pixelDepth == 8 && imageType == TYPE_RLE_CMAP) { + byte index = tga.readByte(); + while (rleCount-- > 0) { + *data++ = index; + count--; + } + } else { + warning("Unhandled pixel-depth for image-type 10"); + return false; + } + // Raw-packet + } else if (type == 0) { + if (pixelDepth == 32 && imageType == TYPE_RLE_TRUECOLOR) { + while (rleCount-- > 0) { + uint32 color = tga.readUint32LE(); + *((uint32 *)data) = color; + data += 4; + count--; + } + } else if (pixelDepth == 24 && imageType == TYPE_RLE_TRUECOLOR) { + while (rleCount-- > 0) { + byte r = tga.readByte(); + byte g = tga.readByte(); + byte b = tga.readByte(); +#ifdef SCUMM_LITTLE_ENDIAN + *data++ = r; + *data++ = g; + *data++ = b; +#else + *data++ = b; + *data++ = g; + *data++ = r; +#endif + count--; + } + } else if (pixelDepth == 8 && imageType == TYPE_RLE_BW) { + while (rleCount-- > 0) { + byte color = tga.readByte(); + *data++ = color; + *data++ = color; + *data++ = color; + *data++ = color; + count--; + } + } else if (pixelDepth == 8 && imageType == TYPE_RLE_CMAP) { + while (rleCount-- > 0) { + byte index = tga.readByte(); + *data++ = index; + count--; + } + } else { + warning("Unhandled pixel-depth for image-type 10"); + return false; + } + } else { + warning("Unknown header for RLE-packet %d", type); + return false; + } + } + } else { + return false; + } + return true; +} + +} // End of namespace Graphics diff --git a/graphics/decoders/tga.h b/graphics/decoders/tga.h new file mode 100644 index 0000000000..dfdc5a4da9 --- /dev/null +++ b/graphics/decoders/tga.h @@ -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. + * + * 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. + */ + +/* Based on code from eos https://github.com/DrMcCoy/xoreos/ + * relicensed under GPLv2+ with permission from DrMcCoy and clone2727 + */ + +/* + * TGA decoder used in engines: + * - none + */ + +#ifndef GRAPHICS_DECODERS_TGA_H +#define GRAPHICS_DECODERS_TGA_H + +#include "graphics/surface.h" +#include "graphics/decoders/image_decoder.h" + +namespace Common { +class SeekableReadStream; +} + +namespace Graphics { + +/** TarGa image-decoder + * The following variations of TGA are supported: + * - Type 1 - Color-mapped images in 16/24/32 bpp with 8 bit indexes + * - Type 2 - 16/24/32 bpp Top AND Bottom origined. + * - Type 3 - Black/White images, 8bpp. + * - Type 9 - RLE-encoded color-mapped images. (8 bit indexes only) + * - Type 10 - RLE-encoded TrueColor, 24/32bpp. + * - Type 11 - RLE-encoded Black/White, 8bpp. + * + * No images are returned with a palette, instead they are converted + * to 16 bpp for Type 1, or 32 bpp for Black/White-images. + */ +class TGADecoder : public ImageDecoder { +public: + TGADecoder(); + virtual ~TGADecoder(); + virtual void destroy(); + virtual const Surface *getSurface() const { return &_surface; } + virtual const byte *getPalette() const { return _colorMap; } + virtual uint16 getPaletteColorCount() const { return _colorMapLength; } + virtual bool loadStream(Common::SeekableReadStream &stream); +private: + // Format-spec from: + //http://www.ludorg.net/amnesia/TGA_File_Format_Spec.html + enum { + TYPE_CMAP = 1, + TYPE_TRUECOLOR = 2, + TYPE_BW = 3, + TYPE_RLE_CMAP = 9, + TYPE_RLE_TRUECOLOR = 10, + TYPE_RLE_BW = 11 + }; + + // Color-map: + bool _colorMapSize; + byte *_colorMap; + int16 _colorMapOrigin; + int16 _colorMapLength; + byte _colorMapEntryLength; + + // Origin may be at the top, or bottom + bool _originTop; + + PixelFormat _format; + Surface _surface; + // Loading helpers + bool readHeader(Common::SeekableReadStream &tga, byte &imageType, byte &pixelDepth); + bool readData(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth); + bool readDataColorMapped(Common::SeekableReadStream &tga, byte imageType, byte indexDepth); + bool readDataRLE(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth); + bool readColorMap(Common::SeekableReadStream &tga, byte imageType, byte pixelDepth); +}; + +} // End of namespace Graphics + +#endif // GRAPHICS_DECODERS_TGA_H diff --git a/graphics/module.mk b/graphics/module.mk index 281f904b38..e67efd2cf5 100644 --- a/graphics/module.mk +++ b/graphics/module.mk @@ -26,7 +26,8 @@ MODULE_OBJS := \ decoders/bmp.o \ decoders/jpeg.o \ decoders/pict.o \ - decoders/png.o + decoders/png.o \ + decoders/tga.o ifdef USE_SCALERS MODULE_OBJS += \ diff --git a/gui/credits.h b/gui/credits.h index 34c6f21026..fdde2da821 100644 --- a/gui/credits.h +++ b/gui/credits.h @@ -476,6 +476,9 @@ static const char *credits[] = { "C1""French", "C0""Thierry Crozat", "", +"C1""Galician", +"C0""Santiago G. Sanz", +"", "C1""German", "C0""Simon Sawatzki", "C0""Lothar Serra Mari", diff --git a/gui/saveload-dialog.cpp b/gui/saveload-dialog.cpp index d1a66dc28a..850dfcc78f 100644 --- a/gui/saveload-dialog.cpp +++ b/gui/saveload-dialog.cpp @@ -535,7 +535,7 @@ const Common::String &SaveLoadChooserGrid::getResultString() const { } void SaveLoadChooserGrid::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { - if (cmd <= _entriesPerPage) { + if (cmd <= _entriesPerPage && cmd + _curPage * _entriesPerPage <= _saveList.size()) { const SaveStateDescriptor &desc = _saveList[cmd - 1 + _curPage * _entriesPerPage]; if (_saveMode) { diff --git a/gui/themes/translations.dat b/gui/themes/translations.dat Binary files differindex cabad0c0c4..1c3abf84a8 100644 --- a/gui/themes/translations.dat +++ b/gui/themes/translations.dat diff --git a/po/ca_ES.po b/po/ca_ES.po index 3e8ade3923..da2586a2af 100644 --- a/po/ca_ES.po +++ b/po/ca_ES.po @@ -5,10 +5,10 @@ # msgid "" msgstr "" -"Project-Id-Version: ScummVM 1.3.0svn\n" +"Project-Id-Version: ScummVM 1.6.0git\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2012-08-12 14:57+0200\n" -"PO-Revision-Date: 2011-10-04 20:51+0100\n" +"POT-Creation-Date: 2012-08-27 15:46+0200\n" +"PO-Revision-Date: 2012-08-26 20:32+0100\n" "Last-Translator: Jordi Vilalta Prat <jvprat@jvprat.com>\n" "Language-Team: Catalan <scummvm-devel@lists.sf.net>\n" "Language: Catalan\n" @@ -45,7 +45,7 @@ msgstr "Amunt" #: gui/browser.cpp:69 gui/chooser.cpp:45 gui/KeysDialog.cpp:43 #: gui/launcher.cpp:345 gui/massadd.cpp:94 gui/options.cpp:1228 #: gui/saveload-dialog.cpp:207 gui/saveload-dialog.cpp:267 -#: gui/saveload-dialog.cpp:516 gui/saveload-dialog.cpp:843 +#: gui/saveload-dialog.cpp:516 gui/saveload-dialog.cpp:847 #: gui/themebrowser.cpp:54 engines/engine.cpp:442 #: engines/scumm/dialogs.cpp:190 engines/sword1/control.cpp:865 #: engines/parallaction/saveload.cpp:274 backends/platform/wii/options.cpp:48 @@ -78,7 +78,6 @@ msgid "Remap keys" msgstr "Assigna les tecles" #: gui/gui-manager.cpp:129 base/main.cpp:307 -#, fuzzy msgid "Toggle FullScreen" msgstr "Commuta la pantalla completa" @@ -92,15 +91,15 @@ msgstr "Assigna" #: gui/KeysDialog.cpp:42 gui/launcher.cpp:346 gui/launcher.cpp:1001 #: gui/launcher.cpp:1005 gui/massadd.cpp:91 gui/options.cpp:1229 -#: gui/saveload-dialog.cpp:844 engines/engine.cpp:361 engines/engine.cpp:372 +#: gui/saveload-dialog.cpp:848 engines/engine.cpp:361 engines/engine.cpp:372 #: engines/scumm/dialogs.cpp:192 engines/scumm/scumm.cpp:1775 -#: engines/agos/animation.cpp:561 engines/groovie/script.cpp:420 +#: engines/agos/animation.cpp:558 engines/groovie/script.cpp:420 #: engines/sky/compact.cpp:131 engines/sky/compact.cpp:141 -#: engines/sword1/animation.cpp:539 engines/sword1/animation.cpp:560 -#: engines/sword1/animation.cpp:570 engines/sword1/animation.cpp:577 +#: engines/sword1/animation.cpp:519 engines/sword1/animation.cpp:540 +#: engines/sword1/animation.cpp:550 engines/sword1/animation.cpp:557 #: engines/sword1/control.cpp:865 engines/sword1/logic.cpp:1633 -#: engines/sword2/animation.cpp:435 engines/sword2/animation.cpp:455 -#: engines/sword2/animation.cpp:465 engines/sword2/animation.cpp:474 +#: engines/sword2/animation.cpp:419 engines/sword2/animation.cpp:439 +#: engines/sword2/animation.cpp:449 engines/sword2/animation.cpp:458 #: engines/parallaction/saveload.cpp:274 backends/platform/wii/options.cpp:47 #: backends/platform/wince/CELauncherDialog.cpp:54 msgid "OK" @@ -194,9 +193,8 @@ msgid "Platform:" msgstr "Platafor.:" #: gui/launcher.cpp:231 -#, fuzzy msgid "Engine" -msgstr "Examina" +msgstr "Motor" #: gui/launcher.cpp:239 gui/options.cpp:1062 gui/options.cpp:1079 msgid "Graphics" @@ -934,11 +932,11 @@ msgstr "" #: gui/saveload-dialog.cpp:158 msgid "List view" -msgstr "" +msgstr "Vista de llistat" #: gui/saveload-dialog.cpp:159 msgid "Grid view" -msgstr "" +msgstr "Vista de quadrícula" #: gui/saveload-dialog.cpp:202 gui/saveload-dialog.cpp:350 msgid "No date saved" @@ -960,15 +958,15 @@ msgstr "Suprimeix" msgid "Do you really want to delete this savegame?" msgstr "Realment voleu suprimir aquesta partida?" -#: gui/saveload-dialog.cpp:375 gui/saveload-dialog.cpp:796 +#: gui/saveload-dialog.cpp:375 gui/saveload-dialog.cpp:800 msgid "Date: " msgstr "Data: " -#: gui/saveload-dialog.cpp:379 gui/saveload-dialog.cpp:802 +#: gui/saveload-dialog.cpp:379 gui/saveload-dialog.cpp:806 msgid "Time: " msgstr "Hora: " -#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:810 +#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:814 msgid "Playtime: " msgstr "Temps de joc: " @@ -978,31 +976,28 @@ msgstr "Partida sense títol" #: gui/saveload-dialog.cpp:517 msgid "Next" -msgstr "" +msgstr "Següent" #: gui/saveload-dialog.cpp:520 msgid "Prev" -msgstr "" +msgstr "Anterior" -#: gui/saveload-dialog.cpp:684 -#, fuzzy +#: gui/saveload-dialog.cpp:688 msgid "New Save" -msgstr "Desa" +msgstr "Nova partida desada" -#: gui/saveload-dialog.cpp:684 -#, fuzzy +#: gui/saveload-dialog.cpp:688 msgid "Create a new save game" -msgstr "No s'ha pogut desar l'estat del joc" +msgstr "Crea una nova partida desada" -#: gui/saveload-dialog.cpp:789 -#, fuzzy +#: gui/saveload-dialog.cpp:793 msgid "Name: " -msgstr "Nom:" +msgstr "Nom: " -#: gui/saveload-dialog.cpp:861 +#: gui/saveload-dialog.cpp:865 #, c-format msgid "Enter a description for slot %d:" -msgstr "" +msgstr "Entreu la descripció per l'espai %d:" #: gui/themebrowser.cpp:44 msgid "Select a Theme" @@ -1206,13 +1201,13 @@ msgstr "" "la informació bàsica i les instruccions sobre com obtenir més assistència." #: engines/dialogs.cpp:228 -#, fuzzy, c-format +#, c-format msgid "" "Gamestate save failed (%s)! Please consult the README for basic information, " "and for instructions on how to obtain further assistance." msgstr "" -"Aquest motor no ofereix ajuda dins el joc. Consulteu el fitxer README per a " -"la informació bàsica i les instruccions sobre com obtenir més assistència." +"No s'ha pogut desar la partida (%s)! Consulteu el fitxer README per a la " +"informació bàsica i les instruccions sobre com obtenir més assistència." #: engines/dialogs.cpp:301 engines/mohawk/dialogs.cpp:109 #: engines/mohawk/dialogs.cpp:174 @@ -1273,13 +1268,13 @@ msgstr "" "Consulteu el fitxer README per a més detalls." #: engines/engine.cpp:426 -#, fuzzy, c-format +#, c-format msgid "" "Gamestate load failed (%s)! Please consult the README for basic information, " "and for instructions on how to obtain further assistance." msgstr "" -"Aquest motor no ofereix ajuda dins el joc. Consulteu el fitxer README per a " -"la informació bàsica i les instruccions sobre com obtenir més assistència." +"No s'ha pogut carregar la partida (%s)! Consulteu el fitxer README per a la " +"informació bàsica i les instruccions sobre com obtenir més assistència." #: engines/engine.cpp:439 msgid "" @@ -1295,15 +1290,16 @@ msgstr "" msgid "Start anyway" msgstr "Inicia de totes maneres" -#: engines/agi/detection.cpp:145 engines/dreamweb/detection.cpp:47 +#: engines/agi/detection.cpp:142 engines/dreamweb/detection.cpp:47 #: engines/sci/detection.cpp:390 msgid "Use original save/load screens" -msgstr "" +msgstr "Utilitza les pantalles originals de desat/càrrega" -#: engines/agi/detection.cpp:146 engines/dreamweb/detection.cpp:48 +#: engines/agi/detection.cpp:143 engines/dreamweb/detection.cpp:48 #: engines/sci/detection.cpp:391 msgid "Use the original save/load screens, instead of the ScummVM ones" msgstr "" +"Utilitza les pantalles originals de desat/càrrega, en lloc de les de ScummVM" #: engines/agi/saveload.cpp:816 engines/sci/engine/kfile.cpp:838 msgid "Restore game:" @@ -1314,68 +1310,71 @@ msgid "Restore" msgstr "Restaura" #: engines/dreamweb/detection.cpp:57 -#, fuzzy msgid "Use bright palette mode" -msgstr "Element superior dret" +msgstr "Utilitza el mode de paleta brillant" #: engines/dreamweb/detection.cpp:58 msgid "Display graphics using the game's bright palette" -msgstr "" +msgstr "Mostra els gràfics utilitzant la paleta brillant del joc" #: engines/sci/detection.cpp:370 msgid "EGA undithering" msgstr "Elimina el tramat d'EGA" #: engines/sci/detection.cpp:371 -#, fuzzy msgid "Enable undithering in EGA games" -msgstr "Activa l'eliminació del tramat en els jocs EGA que ho suportin" +msgstr "Activa l'eliminació del tramat en els jocs EGA" #: engines/sci/detection.cpp:380 -#, fuzzy msgid "Prefer digital sound effects" -msgstr "Volum dels sons d'efectes especials" +msgstr "Prefereix efectes de so digitals" #: engines/sci/detection.cpp:381 msgid "Prefer digital sound effects instead of synthesized ones" -msgstr "" +msgstr "Prefereix els efectes de so digitals en lloc dels sintetitzats" #: engines/sci/detection.cpp:400 msgid "Use IMF/Yamaha FB-01 for MIDI output" -msgstr "" +msgstr "Utilitza IMF/Yamaha FB-01 per la sortida MIDI" #: engines/sci/detection.cpp:401 msgid "" "Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI " "output" msgstr "" +"Utilitza una tarja IBM Music Feature o un mòdul sintetitzador Yamaha FB-01 " +"FM per la sortida MIDI" #: engines/sci/detection.cpp:411 msgid "Use CD audio" -msgstr "" +msgstr "Utilitza l'àudio del CD" #: engines/sci/detection.cpp:412 msgid "Use CD audio instead of in-game audio, if available" msgstr "" +"Utilitza l'àudio del CD en lloc de l'àudio intern del joc, si està disponible" #: engines/sci/detection.cpp:422 msgid "Use Windows cursors" -msgstr "" +msgstr "Utilitza els cursors de Windows" #: engines/sci/detection.cpp:423 msgid "" "Use the Windows cursors (smaller and monochrome) instead of the DOS ones" msgstr "" +"Utilitza els cursors de Windows (més petits i en blanc i negre) en lloc dels " +"de DOS" #: engines/sci/detection.cpp:433 -#, fuzzy msgid "Use silver cursors" -msgstr "Cursor normal" +msgstr "Utilitza cursors platejats" #: engines/sci/detection.cpp:434 msgid "" "Use the alternate set of silver cursors, instead of the normal golden ones" msgstr "" +"Utilitza el conjunt alternatiu de cursors platejats, en lloc dels normals " +"daurats" #: engines/scumm/dialogs.cpp:175 #, c-format @@ -1493,24 +1492,23 @@ msgstr "Veus i sub." #: engines/scumm/dialogs.cpp:653 msgid "Select a Proficiency Level." -msgstr "" +msgstr "Seleccioneu el nivell de competència." #: engines/scumm/dialogs.cpp:655 msgid "Refer to your Loom(TM) manual for help." -msgstr "" +msgstr "Consulteu el manual de Loom(TM) per ajuda." #: engines/scumm/dialogs.cpp:658 -#, fuzzy msgid "Standard" -msgstr "Estàndard (16bpp)" +msgstr "Estàndard" #: engines/scumm/dialogs.cpp:659 msgid "Practice" -msgstr "" +msgstr "Pràctica" #: engines/scumm/dialogs.cpp:660 msgid "Expert" -msgstr "" +msgstr "Expert" #: engines/scumm/help.cpp:73 msgid "Common keyboard commands:" @@ -2103,7 +2101,7 @@ msgstr "~M~enú Principal" msgid "~W~ater Effect Enabled" msgstr "~E~fecte de l'aigua activat" -#: engines/agos/animation.cpp:560 +#: engines/agos/animation.cpp:557 #, c-format msgid "Cutscene file '%s' not found!" msgstr "No s'ha trobat el fitxer d'escena '%s'!" @@ -2129,118 +2127,109 @@ msgstr "No s'ha pogut desar l'estat del joc" #. Malcolm makes a joke. #: engines/kyra/detection.cpp:62 msgid "Studio audience" -msgstr "" +msgstr "Públic" #: engines/kyra/detection.cpp:63 msgid "Enable studio audience" -msgstr "" +msgstr "Activa el públic" #. I18N: This option allows the user to skip text and cutscenes. #: engines/kyra/detection.cpp:73 msgid "Skip support" -msgstr "" +msgstr "Suport per saltar text i escenes" #: engines/kyra/detection.cpp:74 msgid "Allow text and cutscenes to be skipped" -msgstr "" +msgstr "Permet que se saltin textos i escenes" #. I18N: Helium mode makes people sound like they've inhaled Helium. #: engines/kyra/detection.cpp:84 msgid "Helium mode" -msgstr "" +msgstr "Mode heli" #: engines/kyra/detection.cpp:85 -#, fuzzy msgid "Enable helium mode" -msgstr "Activa el Mode Roland GS" +msgstr "Activa el mode heli" #. I18N: When enabled, this option makes scrolling smoother when #. changing from one screen to another. #: engines/kyra/detection.cpp:99 msgid "Smooth scrolling" -msgstr "" +msgstr "Desplaçament suau" #: engines/kyra/detection.cpp:100 msgid "Enable smooth scrolling when walking" -msgstr "" +msgstr "Activa el desplaçament suau al caminar" #. I18N: When enabled, this option changes the cursor when it floats to the #. edge of the screen to a directional arrow. The player can then click to #. walk towards that direction. #: engines/kyra/detection.cpp:112 -#, fuzzy msgid "Floating cursors" -msgstr "Cursor normal" +msgstr "Cursor flotant" #: engines/kyra/detection.cpp:113 msgid "Enable floating cursors" -msgstr "" +msgstr "Activa els cursors flotants" #. I18N: HP stands for Hit Points #: engines/kyra/detection.cpp:127 msgid "HP bar graphs" -msgstr "" +msgstr "Barra gràfica de PI" #: engines/kyra/detection.cpp:128 msgid "Enable hit point bar graphs" -msgstr "" +msgstr "Activa la barra gràfica dels punts d'impacte" #: engines/kyra/lol.cpp:478 msgid "Attack 1" -msgstr "" +msgstr "Atac 1" #: engines/kyra/lol.cpp:479 msgid "Attack 2" -msgstr "" +msgstr "Atac 2" #: engines/kyra/lol.cpp:480 msgid "Attack 3" -msgstr "" +msgstr "Atac 3" #: engines/kyra/lol.cpp:481 msgid "Move Forward" -msgstr "" +msgstr "Mou endavant" #: engines/kyra/lol.cpp:482 msgid "Move Back" -msgstr "" +msgstr "Mou enrere" #: engines/kyra/lol.cpp:483 msgid "Slide Left" -msgstr "" +msgstr "Mou a l'esquerra" #: engines/kyra/lol.cpp:484 -#, fuzzy msgid "Slide Right" -msgstr "Dreta" +msgstr "Mou a la dreta" #: engines/kyra/lol.cpp:485 -#, fuzzy msgid "Turn Left" -msgstr "Apaga" +msgstr "Gira a l'esquerra" #: engines/kyra/lol.cpp:486 -#, fuzzy msgid "Turn Right" -msgstr "Cursor Dreta" +msgstr "Gira a la dreta" #: engines/kyra/lol.cpp:487 -#, fuzzy msgid "Rest" -msgstr "Restaura" +msgstr "Descansa" #: engines/kyra/lol.cpp:488 -#, fuzzy msgid "Options" -msgstr "~O~pcions" +msgstr "Opcions" #: engines/kyra/lol.cpp:489 -#, fuzzy msgid "Choose Spell" -msgstr "Escull" +msgstr "Escull l'encanteri" #: engines/kyra/sound_midi.cpp:475 -#, fuzzy msgid "" "You appear to be using a General MIDI device,\n" "but your game only supports Roland MT32 MIDI.\n" @@ -2256,11 +2245,11 @@ msgstr "" #: engines/queen/queen.cpp:59 msgid "Alternative intro" -msgstr "" +msgstr "Introducció alternativa" #: engines/queen/queen.cpp:60 msgid "Use an alternative game intro (CD version only)" -msgstr "" +msgstr "Utilitza una introducció del joc alternativa (només per la versió CD)" #: engines/sky/compact.cpp:130 msgid "" @@ -2280,28 +2269,29 @@ msgstr "" #: engines/sky/detection.cpp:44 msgid "Floppy intro" -msgstr "" +msgstr "Introducció de disquets" #: engines/sky/detection.cpp:45 msgid "Use the floppy version's intro (CD version only)" msgstr "" +"Utilitza la introducció de la versió de disquets (només per a la versió CD)" -#: engines/sword1/animation.cpp:539 +#: engines/sword1/animation.cpp:519 #, c-format msgid "PSX stream cutscene '%s' cannot be played in paletted mode" -msgstr "" +msgstr "L'escena '%s' de PSX no es pot reproduir en mode paleta" -#: engines/sword1/animation.cpp:560 engines/sword2/animation.cpp:455 +#: engines/sword1/animation.cpp:540 engines/sword2/animation.cpp:439 msgid "DXA cutscenes found but ScummVM has been built without zlib support" msgstr "" "S'han trobat escenes en DXA, però s'ha compilat el ScummVM sense suport de " "zlib" -#: engines/sword1/animation.cpp:570 engines/sword2/animation.cpp:465 +#: engines/sword1/animation.cpp:550 engines/sword2/animation.cpp:449 msgid "MPEG2 cutscenes are no longer supported" msgstr "Les escenes MPEG2 ja no estan suportades" -#: engines/sword1/animation.cpp:576 engines/sword2/animation.cpp:473 +#: engines/sword1/animation.cpp:556 engines/sword2/animation.cpp:457 #, c-format msgid "Cutscene '%s' not found" msgstr "No s'ha trobat l'escena '%s'" @@ -2345,32 +2335,33 @@ msgstr "Mantingues el nou" msgid "This is the end of the Broken Sword 1 Demo" msgstr "Aquest és el final de la Demo del Broken Sword 1" -#: engines/sword2/animation.cpp:435 -#, fuzzy +#: engines/sword2/animation.cpp:419 msgid "" "PSX cutscenes found but ScummVM has been built without RGB color support" msgstr "" -"S'han trobat escenes en DXA, però s'ha compilat el ScummVM sense suport de " -"zlib" +"S'han trobat escenes de PSX, però s'ha compilat el ScummVM sense suport de " +"color RGB" #: engines/sword2/sword2.cpp:79 msgid "Show object labels" -msgstr "" +msgstr "Mostra les etiquetes dels objectes" #: engines/sword2/sword2.cpp:80 msgid "Show labels for objects on mouse hover" -msgstr "" +msgstr "Mostra etiquetes al posar el ratolí sobre els objectes" #: engines/teenagent/resources.cpp:68 msgid "" "You're missing the 'teenagent.dat' file. Get it from the ScummVM website" -msgstr "" +msgstr "Us falta el fitxer 'teenagent.dat'. Obteniu-lo a la pàgina de ScummVM" #: engines/teenagent/resources.cpp:89 msgid "" "The teenagent.dat file is compressed and zlib hasn't been included in this " "executable. Please decompress it" msgstr "" +"El fitxer teenagent.dat està comprimit però aquest executable no conté zlib. " +"Descomprimiu-lo, si us plau." #: engines/parallaction/saveload.cpp:133 #, c-format @@ -2512,9 +2503,8 @@ msgid "Keymap:" msgstr "Assignacions de teclat:" #: backends/keymapper/remap-dialog.cpp:66 -#, fuzzy msgid " (Effective)" -msgstr " (Actiu)" +msgstr " (Efectiu)" #: backends/keymapper/remap-dialog.cpp:106 msgid " (Active)" @@ -2522,7 +2512,7 @@ msgstr " (Actiu)" #: backends/keymapper/remap-dialog.cpp:106 msgid " (Blocked)" -msgstr "" +msgstr " (Bloquejat)" #: backends/keymapper/remap-dialog.cpp:119 msgid " (Global)" @@ -2626,7 +2616,7 @@ msgstr "Mode Touchpad desactivat." #: backends/platform/maemo/maemo.cpp:209 msgid "Click Mode" -msgstr "" +msgstr "Mode clic" #: backends/platform/maemo/maemo.cpp:215 #: backends/platform/symbian/src/SymbianActions.cpp:42 @@ -2637,9 +2627,8 @@ msgid "Left Click" msgstr "Clic esquerre" #: backends/platform/maemo/maemo.cpp:218 -#, fuzzy msgid "Middle Click" -msgstr "Element mig esquerre" +msgstr "Clic central" #: backends/platform/maemo/maemo.cpp:221 #: backends/platform/symbian/src/SymbianActions.cpp:43 @@ -3114,20 +3103,3 @@ msgstr "Clicat activat" #: backends/events/maemosdl/maemosdl-events.cpp:192 msgid "Clicking Disabled" msgstr "Clicat desactivat" - -#~ msgid "Hercules Green" -#~ msgstr "Hercules Verd" - -#~ msgid "Hercules Amber" -#~ msgstr "Hercules Àmbar" - -#~ msgctxt "lowres" -#~ msgid "Hercules Green" -#~ msgstr "Hercules Verd" - -#~ msgctxt "lowres" -#~ msgid "Hercules Amber" -#~ msgstr "Hercules Àmbar" - -#~ msgid "Save game failed!" -#~ msgstr "No s'ha pogut desar la partida!" diff --git a/po/gl_ES.po b/po/gl_ES.po new file mode 100644 index 0000000000..d08867b717 --- /dev/null +++ b/po/gl_ES.po @@ -0,0 +1,3092 @@ +# LANGUAGE translation for ScummVM. +# Copyright (C) YEAR ScummVM Team +# This file is distributed under the same license as the ScummVM package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: ScummVM 1.6.0git\n" +"Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" +"POT-Creation-Date: 2012-08-12 14:57+0200\n" +"PO-Revision-Date: 2012-08-15 13:33+0100\n" +"Last-Translator: Santiago G. Sanz <s.sanz@uvigo.es>\n" +"Language-Team: \n" +"Language: Galego\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=iso-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" + +#: gui/about.cpp:91 +#, c-format +msgid "(built on %s)" +msgstr "(compilado o %s)" + +#: gui/about.cpp:98 +msgid "Features compiled in:" +msgstr "Funcionalidades compiladas:" + +#: gui/about.cpp:107 +msgid "Available engines:" +msgstr "Motores dispoñibles:" + +#: gui/browser.cpp:66 +msgid "Go up" +msgstr "Arriba" + +#: gui/browser.cpp:66 gui/browser.cpp:68 +msgid "Go to previous directory level" +msgstr "Ir ao directorio superior" + +#: gui/browser.cpp:68 +msgctxt "lowres" +msgid "Go up" +msgstr "Arriba" + +#: gui/browser.cpp:69 gui/chooser.cpp:45 gui/KeysDialog.cpp:43 +#: gui/launcher.cpp:345 gui/massadd.cpp:94 gui/options.cpp:1228 +#: gui/saveload-dialog.cpp:207 gui/saveload-dialog.cpp:267 +#: gui/saveload-dialog.cpp:516 gui/saveload-dialog.cpp:843 +#: gui/themebrowser.cpp:54 engines/engine.cpp:442 +#: engines/scumm/dialogs.cpp:190 engines/sword1/control.cpp:865 +#: engines/parallaction/saveload.cpp:274 backends/platform/wii/options.cpp:48 +#: backends/events/default/default-events.cpp:191 +#: backends/events/default/default-events.cpp:213 +msgid "Cancel" +msgstr "Cancelar" + +#: gui/browser.cpp:70 gui/chooser.cpp:46 gui/themebrowser.cpp:55 +msgid "Choose" +msgstr "Elexir" + +#: gui/gui-manager.cpp:115 engines/scumm/help.cpp:125 +#: engines/scumm/help.cpp:140 engines/scumm/help.cpp:165 +#: engines/scumm/help.cpp:191 engines/scumm/help.cpp:209 +#: backends/keymapper/remap-dialog.cpp:52 +msgid "Close" +msgstr "Pechar" + +#: gui/gui-manager.cpp:118 +msgid "Mouse click" +msgstr "Premer co rato" + +#: gui/gui-manager.cpp:122 base/main.cpp:300 +msgid "Display keyboard" +msgstr "Mostrar teclado" + +#: gui/gui-manager.cpp:126 base/main.cpp:304 +msgid "Remap keys" +msgstr "Asignar teclas" + +#: gui/gui-manager.cpp:129 base/main.cpp:307 +msgid "Toggle FullScreen" +msgstr "Activar/desactivar pantalla completa" + +#: gui/KeysDialog.h:36 gui/KeysDialog.cpp:145 +msgid "Choose an action to map" +msgstr "Elixe unha acción para asignala" + +#: gui/KeysDialog.cpp:41 +msgid "Map" +msgstr "Asignar" + +#: gui/KeysDialog.cpp:42 gui/launcher.cpp:346 gui/launcher.cpp:1001 +#: gui/launcher.cpp:1005 gui/massadd.cpp:91 gui/options.cpp:1229 +#: gui/saveload-dialog.cpp:844 engines/engine.cpp:361 engines/engine.cpp:372 +#: engines/scumm/dialogs.cpp:192 engines/scumm/scumm.cpp:1775 +#: engines/agos/animation.cpp:561 engines/groovie/script.cpp:420 +#: engines/sky/compact.cpp:131 engines/sky/compact.cpp:141 +#: engines/sword1/animation.cpp:539 engines/sword1/animation.cpp:560 +#: engines/sword1/animation.cpp:570 engines/sword1/animation.cpp:577 +#: engines/sword1/control.cpp:865 engines/sword1/logic.cpp:1633 +#: engines/sword2/animation.cpp:435 engines/sword2/animation.cpp:455 +#: engines/sword2/animation.cpp:465 engines/sword2/animation.cpp:474 +#: engines/parallaction/saveload.cpp:274 backends/platform/wii/options.cpp:47 +#: backends/platform/wince/CELauncherDialog.cpp:54 +msgid "OK" +msgstr "Aceptar" + +#: gui/KeysDialog.cpp:49 +msgid "Select an action and click 'Map'" +msgstr "Selecciona unha acción e preme en Asignar" + +#: gui/KeysDialog.cpp:80 gui/KeysDialog.cpp:102 gui/KeysDialog.cpp:141 +#, c-format +msgid "Associated key : %s" +msgstr "Tecla asociada: %s" + +#: gui/KeysDialog.cpp:82 gui/KeysDialog.cpp:104 gui/KeysDialog.cpp:143 +#, c-format +msgid "Associated key : none" +msgstr "Tecla asociada: ningunha" + +#: gui/KeysDialog.cpp:90 +msgid "Please select an action" +msgstr "Selecciona unha acción" + +#: gui/KeysDialog.cpp:106 +msgid "Press the key to associate" +msgstr "Preme a tecla para asociala" + +#: gui/launcher.cpp:187 +msgid "Game" +msgstr "Xogo" + +#: gui/launcher.cpp:191 +msgid "ID:" +msgstr "ID:" + +#: gui/launcher.cpp:191 gui/launcher.cpp:193 gui/launcher.cpp:194 +msgid "" +"Short game identifier used for referring to savegames and running the game " +"from the command line" +msgstr "" +"Identificador curto do xogo para os ficheiros de gardado e a execución do " +"xogo dende a liña de comandos" + +#: gui/launcher.cpp:193 +msgctxt "lowres" +msgid "ID:" +msgstr "ID:" + +#: gui/launcher.cpp:198 +msgid "Name:" +msgstr "Nome:" + +#: gui/launcher.cpp:198 gui/launcher.cpp:200 gui/launcher.cpp:201 +msgid "Full title of the game" +msgstr "Título completo do xogo" + +#: gui/launcher.cpp:200 +msgctxt "lowres" +msgid "Name:" +msgstr "Nome:" + +#: gui/launcher.cpp:204 +msgid "Language:" +msgstr "Idioma:" + +#: gui/launcher.cpp:204 gui/launcher.cpp:205 +msgid "" +"Language of the game. This will not turn your Spanish game version into " +"English" +msgstr "Idioma do xogo. Non converterá a versión galega do xogo en inglesa" + +#: gui/launcher.cpp:206 gui/launcher.cpp:220 gui/options.cpp:80 +#: gui/options.cpp:730 gui/options.cpp:743 gui/options.cpp:1199 +#: audio/null.cpp:40 +msgid "<default>" +msgstr "<por defecto>" + +#: gui/launcher.cpp:216 +msgid "Platform:" +msgstr "Plataforma:" + +#: gui/launcher.cpp:216 gui/launcher.cpp:218 gui/launcher.cpp:219 +msgid "Platform the game was originally designed for" +msgstr "Plataforma para a que se desenvolvera o xogo inicialmente" + +#: gui/launcher.cpp:218 +msgctxt "lowres" +msgid "Platform:" +msgstr "Plataforma:" + +#: gui/launcher.cpp:231 +msgid "Engine" +msgstr "Motor" + +#: gui/launcher.cpp:239 gui/options.cpp:1062 gui/options.cpp:1079 +msgid "Graphics" +msgstr "Gráficos" + +#: gui/launcher.cpp:239 gui/options.cpp:1062 gui/options.cpp:1079 +msgid "GFX" +msgstr "Efectos gráficos" + +#: gui/launcher.cpp:242 +msgid "Override global graphic settings" +msgstr "Anular a configuración dos gráficos" + +#: gui/launcher.cpp:244 +msgctxt "lowres" +msgid "Override global graphic settings" +msgstr "Anular a configuración dos gráficos" + +#: gui/launcher.cpp:251 gui/options.cpp:1085 +msgid "Audio" +msgstr "Son" + +#: gui/launcher.cpp:254 +msgid "Override global audio settings" +msgstr "Anular a configuración do son" + +#: gui/launcher.cpp:256 +msgctxt "lowres" +msgid "Override global audio settings" +msgstr "Anular a configuración do son" + +#: gui/launcher.cpp:265 gui/options.cpp:1090 +msgid "Volume" +msgstr "Volume" + +#: gui/launcher.cpp:267 gui/options.cpp:1092 +msgctxt "lowres" +msgid "Volume" +msgstr "Volume" + +#: gui/launcher.cpp:270 +msgid "Override global volume settings" +msgstr "Anular a configuración do volume" + +#: gui/launcher.cpp:272 +msgctxt "lowres" +msgid "Override global volume settings" +msgstr "Anular a configuración do volume" + +#: gui/launcher.cpp:280 gui/options.cpp:1100 +msgid "MIDI" +msgstr "MIDI" + +#: gui/launcher.cpp:283 +msgid "Override global MIDI settings" +msgstr "Anular a configuración de MIDI" + +#: gui/launcher.cpp:285 +msgctxt "lowres" +msgid "Override global MIDI settings" +msgstr "Anular a configuración de MIDI" + +#: gui/launcher.cpp:294 gui/options.cpp:1106 +msgid "MT-32" +msgstr "MT-32" + +#: gui/launcher.cpp:297 +msgid "Override global MT-32 settings" +msgstr "Anular a configuración de MT-32" + +#: gui/launcher.cpp:299 +msgctxt "lowres" +msgid "Override global MT-32 settings" +msgstr "Anular a configuración de MT-32" + +#: gui/launcher.cpp:308 gui/options.cpp:1113 +msgid "Paths" +msgstr "Camiños" + +#: gui/launcher.cpp:310 gui/options.cpp:1115 +msgctxt "lowres" +msgid "Paths" +msgstr "Camiños" + +#: gui/launcher.cpp:317 +msgid "Game Path:" +msgstr "Camiño do xogo:" + +#: gui/launcher.cpp:319 +msgctxt "lowres" +msgid "Game Path:" +msgstr "Camiño do xogo:" + +#: gui/launcher.cpp:324 gui/options.cpp:1139 +msgid "Extra Path:" +msgstr "Camiño adicional:" + +#: gui/launcher.cpp:324 gui/launcher.cpp:326 gui/launcher.cpp:327 +msgid "Specifies path to additional data used the game" +msgstr "Especifica o camiño dos datos adicionais usados no xogo" + +#: gui/launcher.cpp:326 gui/options.cpp:1141 +msgctxt "lowres" +msgid "Extra Path:" +msgstr "Camiño adicional:" + +#: gui/launcher.cpp:333 gui/options.cpp:1123 +msgid "Save Path:" +msgstr "Camiño de gardado:" + +#: gui/launcher.cpp:333 gui/launcher.cpp:335 gui/launcher.cpp:336 +#: gui/options.cpp:1123 gui/options.cpp:1125 gui/options.cpp:1126 +msgid "Specifies where your savegames are put" +msgstr "Especifica o lugar dos ficheiros de gardado" + +#: gui/launcher.cpp:335 gui/options.cpp:1125 +msgctxt "lowres" +msgid "Save Path:" +msgstr "Camiño de gardado:" + +#: gui/launcher.cpp:354 gui/launcher.cpp:453 gui/launcher.cpp:511 +#: gui/launcher.cpp:565 gui/options.cpp:1134 gui/options.cpp:1142 +#: gui/options.cpp:1151 gui/options.cpp:1258 gui/options.cpp:1264 +#: gui/options.cpp:1272 gui/options.cpp:1302 gui/options.cpp:1308 +#: gui/options.cpp:1315 gui/options.cpp:1408 gui/options.cpp:1411 +#: gui/options.cpp:1423 +msgctxt "path" +msgid "None" +msgstr "Ningún" + +#: gui/launcher.cpp:359 gui/launcher.cpp:459 gui/launcher.cpp:569 +#: gui/options.cpp:1252 gui/options.cpp:1296 gui/options.cpp:1414 +#: backends/platform/wii/options.cpp:56 +msgid "Default" +msgstr "Predefinido" + +#: gui/launcher.cpp:504 gui/options.cpp:1417 +msgid "Select SoundFont" +msgstr "Seleccionar SoundFont" + +#: gui/launcher.cpp:523 gui/launcher.cpp:677 +msgid "Select directory with game data" +msgstr "Selecciona un directorio con datos de xogo" + +#: gui/launcher.cpp:541 +msgid "Select additional game directory" +msgstr "Selecciona un directorio con datos adicionais" + +#: gui/launcher.cpp:553 +msgid "Select directory for saved games" +msgstr "Selecciona un directorio para ficheiros de gardado" + +#: gui/launcher.cpp:580 +msgid "This game ID is already taken. Please choose another one." +msgstr "Este ID de xogo xa está en uso. Selecciona outro." + +#: gui/launcher.cpp:621 engines/dialogs.cpp:110 +msgid "~Q~uit" +msgstr "~S~aír" + +#: gui/launcher.cpp:621 backends/platform/sdl/macosx/appmenu_osx.mm:96 +msgid "Quit ScummVM" +msgstr "Saír de ScummVM" + +#: gui/launcher.cpp:622 +msgid "A~b~out..." +msgstr "Ace~r~ca de..." + +#: gui/launcher.cpp:622 backends/platform/sdl/macosx/appmenu_osx.mm:70 +msgid "About ScummVM" +msgstr "Acerca de ScummVM" + +#: gui/launcher.cpp:623 +msgid "~O~ptions..." +msgstr "~O~pcións..." + +#: gui/launcher.cpp:623 +msgid "Change global ScummVM options" +msgstr "Cambiar as opcións de ScummVM" + +#: gui/launcher.cpp:625 +msgid "~S~tart" +msgstr "~I~niciar" + +#: gui/launcher.cpp:625 +msgid "Start selected game" +msgstr "Iniciar o xogo seleccionado" + +#: gui/launcher.cpp:628 +msgid "~L~oad..." +msgstr "~C~argar..." + +#: gui/launcher.cpp:628 +msgid "Load savegame for selected game" +msgstr "Cargar partida do xogo seleccionado" + +#: gui/launcher.cpp:633 gui/launcher.cpp:1120 +msgid "~A~dd Game..." +msgstr "Eng~a~dir xogo..." + +#: gui/launcher.cpp:633 gui/launcher.cpp:640 +msgid "Hold Shift for Mass Add" +msgstr "Manter premido MAIÚS para engadir en masa" + +#: gui/launcher.cpp:635 +msgid "~E~dit Game..." +msgstr "~E~ditar xogo..." + +#: gui/launcher.cpp:635 gui/launcher.cpp:642 +msgid "Change game options" +msgstr "Cambiar as opcións do xogo" + +#: gui/launcher.cpp:637 +msgid "~R~emove Game" +msgstr "Elimina~r~ xogo" + +#: gui/launcher.cpp:637 gui/launcher.cpp:644 +msgid "Remove game from the list. The game data files stay intact" +msgstr "Eliminar o xogo da lista. Os ficheiros de datos non se modifican" + +#: gui/launcher.cpp:640 gui/launcher.cpp:1120 +msgctxt "lowres" +msgid "~A~dd Game..." +msgstr "Eng~a~dir xogo..." + +#: gui/launcher.cpp:642 +msgctxt "lowres" +msgid "~E~dit Game..." +msgstr "~E~ditar xogo..." + +#: gui/launcher.cpp:644 +msgctxt "lowres" +msgid "~R~emove Game" +msgstr "Elimina~r~ xogo" + +#: gui/launcher.cpp:652 +msgid "Search in game list" +msgstr "Buscar na lista de xogos" + +#: gui/launcher.cpp:656 gui/launcher.cpp:1167 +msgid "Search:" +msgstr "Buscar:" + +#: gui/launcher.cpp:680 engines/dialogs.cpp:114 engines/mohawk/myst.cpp:245 +#: engines/mohawk/riven.cpp:716 engines/cruise/menu.cpp:214 +msgid "Load game:" +msgstr "Cargar partida:" + +#: gui/launcher.cpp:680 engines/dialogs.cpp:114 engines/scumm/dialogs.cpp:188 +#: engines/mohawk/myst.cpp:245 engines/mohawk/riven.cpp:716 +#: engines/cruise/menu.cpp:214 backends/platform/wince/CEActionsPocket.cpp:267 +#: backends/platform/wince/CEActionsSmartphone.cpp:231 +msgid "Load" +msgstr "Cargar" + +#: gui/launcher.cpp:788 +msgid "" +"Do you really want to run the mass game detector? This could potentially add " +"a huge number of games." +msgstr "" +"Queres executar o detector de xogos en masa? É posible que se engada un gran " +"número de xogos." + +#: gui/launcher.cpp:789 gui/launcher.cpp:937 +#: backends/events/symbiansdl/symbiansdl-events.cpp:184 +#: backends/platform/wince/CEActionsPocket.cpp:326 +#: backends/platform/wince/CEActionsSmartphone.cpp:287 +#: backends/platform/wince/CELauncherDialog.cpp:83 +msgid "Yes" +msgstr "Si" + +#: gui/launcher.cpp:789 gui/launcher.cpp:937 +#: backends/events/symbiansdl/symbiansdl-events.cpp:184 +#: backends/platform/wince/CEActionsPocket.cpp:326 +#: backends/platform/wince/CEActionsSmartphone.cpp:287 +#: backends/platform/wince/CELauncherDialog.cpp:83 +msgid "No" +msgstr "Non" + +#: gui/launcher.cpp:837 +msgid "ScummVM couldn't open the specified directory!" +msgstr "ScummVM non foi quen de abrir o directorio!" + +#: gui/launcher.cpp:849 +msgid "ScummVM could not find any game in the specified directory!" +msgstr "ScummVM non foi quen de atopar xogos no directorio!" + +#: gui/launcher.cpp:863 +msgid "Pick the game:" +msgstr "Elixe o xogo:" + +#: gui/launcher.cpp:937 +msgid "Do you really want to remove this game configuration?" +msgstr "Seguro que queres eliminar esta configuración de xogo?" + +#: gui/launcher.cpp:1001 +msgid "This game does not support loading games from the launcher." +msgstr "O xogo non permite cargar partidas dende o iniciador." + +#: gui/launcher.cpp:1005 +msgid "ScummVM could not find any engine capable of running the selected game!" +msgstr "ScummVM non foi quen de atopar un motor para executar o xogo!" + +#: gui/launcher.cpp:1119 +msgctxt "lowres" +msgid "Mass Add..." +msgstr "Engadir en masa..." + +#: gui/launcher.cpp:1119 +msgid "Mass Add..." +msgstr "Engadir en masa..." + +#: gui/massadd.cpp:78 gui/massadd.cpp:81 +msgid "... progress ..." +msgstr "...progreso..." + +#: gui/massadd.cpp:258 +msgid "Scan complete!" +msgstr "Análise finalizada!" + +#: gui/massadd.cpp:261 +#, c-format +msgid "Discovered %d new games, ignored %d previously added games." +msgstr "%d xogos novos atopados; %d xogos xa engadidos ignorados." + +#: gui/massadd.cpp:265 +#, c-format +msgid "Scanned %d directories ..." +msgstr "%d directorios analizados..." + +#: gui/massadd.cpp:268 +#, c-format +msgid "Discovered %d new games, ignored %d previously added games ..." +msgstr "%d xogos novos atopados; %d xogos xa engadidos ignorados..." + +#: gui/options.cpp:78 +msgid "Never" +msgstr "Nunca" + +#: gui/options.cpp:78 +msgid "every 5 mins" +msgstr "cada 5 min" + +#: gui/options.cpp:78 +msgid "every 10 mins" +msgstr "cada 10 min" + +#: gui/options.cpp:78 +msgid "every 15 mins" +msgstr "cada 15 min" + +#: gui/options.cpp:78 +msgid "every 30 mins" +msgstr "cada 30 min" + +#: gui/options.cpp:80 +msgid "8 kHz" +msgstr "8 kHz" + +#: gui/options.cpp:80 +msgid "11kHz" +msgstr "11 kHz" + +#: gui/options.cpp:80 +msgid "22 kHz" +msgstr "22 kHz" + +#: gui/options.cpp:80 +msgid "44 kHz" +msgstr "44 kHz" + +#: gui/options.cpp:80 +msgid "48 kHz" +msgstr "48 kHz" + +#: gui/options.cpp:248 gui/options.cpp:474 gui/options.cpp:575 +#: gui/options.cpp:644 gui/options.cpp:852 +msgctxt "soundfont" +msgid "None" +msgstr "Ningunha" + +#: gui/options.cpp:382 +msgid "Failed to apply some of the graphic options changes:" +msgstr "Erro ao aplicar os cambios na configuración dos gráficos:" + +#: gui/options.cpp:394 +msgid "the video mode could not be changed." +msgstr "non se puido cambiar o modo de vídeo." + +#: gui/options.cpp:400 +msgid "the fullscreen setting could not be changed" +msgstr "non se puido cambiar a configuración de pantalla completa." + +#: gui/options.cpp:406 +msgid "the aspect ratio setting could not be changed" +msgstr "non se puido cambiar a proporción." + +#: gui/options.cpp:727 +msgid "Graphics mode:" +msgstr "Modo de gráficos:" + +#: gui/options.cpp:741 +msgid "Render mode:" +msgstr "Modo de procesamento:" + +#: gui/options.cpp:741 gui/options.cpp:742 +msgid "Special dithering modes supported by some games" +msgstr "Modos de interpolación de cores compatibles con algúns xogos" + +#: gui/options.cpp:753 +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2236 +#: backends/graphics/openglsdl/openglsdl-graphics.cpp:472 +msgid "Fullscreen mode" +msgstr "Pantalla completa" + +#: gui/options.cpp:756 +msgid "Aspect ratio correction" +msgstr "Corrección de proporción" + +#: gui/options.cpp:756 +msgid "Correct aspect ratio for 320x200 games" +msgstr "Corrixir a proporción para os xogos en 320x200" + +#: gui/options.cpp:764 +msgid "Preferred Device:" +msgstr "Dispositivo preferido:" + +#: gui/options.cpp:764 +msgid "Music Device:" +msgstr "Dispositivo de música:" + +#: gui/options.cpp:764 gui/options.cpp:766 +msgid "Specifies preferred sound device or sound card emulator" +msgstr "Especifica o dispositivo ou emulador de tarxeta de son preferido" + +#: gui/options.cpp:764 gui/options.cpp:766 gui/options.cpp:767 +msgid "Specifies output sound device or sound card emulator" +msgstr "Especifica o dispositivo ou emulador de tarxeta de son de saída" + +#: gui/options.cpp:766 +msgctxt "lowres" +msgid "Preferred Dev.:" +msgstr "Disp. preferido:" + +#: gui/options.cpp:766 +msgctxt "lowres" +msgid "Music Device:" +msgstr "Disp. música:" + +#: gui/options.cpp:793 +msgid "AdLib emulator:" +msgstr "Emulador de AdLib:" + +#: gui/options.cpp:793 gui/options.cpp:794 +msgid "AdLib is used for music in many games" +msgstr "Moitos xogos empregan AdLib para a música" + +#: gui/options.cpp:804 +msgid "Output rate:" +msgstr "Taxa de saída:" + +#: gui/options.cpp:804 gui/options.cpp:805 +msgid "" +"Higher value specifies better sound quality but may be not supported by your " +"soundcard" +msgstr "" +"A maior valor, maior calidade do son, mais talvez non sexa compatible coa " +"tarxeta" + +#: gui/options.cpp:815 +msgid "GM Device:" +msgstr "Dispositivo de GM:" + +#: gui/options.cpp:815 +msgid "Specifies default sound device for General MIDI output" +msgstr "" +"Especifica o dispositivo de son por defecto para a saída de General MIDI" + +#: gui/options.cpp:826 +msgid "Don't use General MIDI music" +msgstr "Non empregar música en General MIDI" + +#: gui/options.cpp:837 gui/options.cpp:899 +msgid "Use first available device" +msgstr "Empregar o primeiro dispositivo dispoñible" + +#: gui/options.cpp:849 +msgid "SoundFont:" +msgstr "SoundFont:" + +#: gui/options.cpp:849 gui/options.cpp:851 gui/options.cpp:852 +msgid "SoundFont is supported by some audio cards, Fluidsynth and Timidity" +msgstr "" +"SoundFont é compatible con algunhas tarxetas de son, Fluidsynth e Timidity" + +#: gui/options.cpp:851 +msgctxt "lowres" +msgid "SoundFont:" +msgstr "SoundFont:" + +#: gui/options.cpp:857 +msgid "Mixed AdLib/MIDI mode" +msgstr "Modo AdLib/MIDI mixto" + +#: gui/options.cpp:857 +msgid "Use both MIDI and AdLib sound generation" +msgstr "Empregar xeración de son MIDI e máis AdLib" + +#: gui/options.cpp:860 +msgid "MIDI gain:" +msgstr "Ganancia de MIDI:" + +#: gui/options.cpp:870 +msgid "MT-32 Device:" +msgstr "Dispositivo de MT-32:" + +#: gui/options.cpp:870 +msgid "Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output" +msgstr "" +"Especifica o dispositivo por defecto para a saída de Roland MT-32/LAPC1/" +"CM32l/CM64" + +#: gui/options.cpp:875 +msgid "True Roland MT-32 (disable GM emulation)" +msgstr "Roland MT-32 verdadeiro (sen emulación de GM)" + +#: gui/options.cpp:875 gui/options.cpp:877 +msgid "" +"Check if you want to use your real hardware Roland-compatible sound device " +"connected to your computer" +msgstr "" +"Marcar para empregar o hardware compatible con Roland conectado ao sistema" + +#: gui/options.cpp:877 +msgctxt "lowres" +msgid "True Roland MT-32 (no GM emulation)" +msgstr "Roland MT-32 (sen emulación de GM)" + +#: gui/options.cpp:880 +msgid "Enable Roland GS Mode" +msgstr "Activar modo Roland GS" + +#: gui/options.cpp:880 +msgid "Turns off General MIDI mapping for games with Roland MT-32 soundtrack" +msgstr "Desactiva o General MIDI para os xogos con música en Roland MT-32" + +#: gui/options.cpp:889 +msgid "Don't use Roland MT-32 music" +msgstr "Non empregar música en Roland MT-32" + +#: gui/options.cpp:916 +msgid "Text and Speech:" +msgstr "Texto e voz:" + +#: gui/options.cpp:920 gui/options.cpp:930 +msgid "Speech" +msgstr "Voz" + +#: gui/options.cpp:921 gui/options.cpp:931 +msgid "Subtitles" +msgstr "Subtítulos" + +#: gui/options.cpp:922 +msgid "Both" +msgstr "Ambos" + +#: gui/options.cpp:924 +msgid "Subtitle speed:" +msgstr "Velocidade dos subtítulos:" + +#: gui/options.cpp:926 +msgctxt "lowres" +msgid "Text and Speech:" +msgstr "Texto e voz:" + +#: gui/options.cpp:930 +msgid "Spch" +msgstr "Voz" + +#: gui/options.cpp:931 +msgid "Subs" +msgstr "Subs" + +#: gui/options.cpp:932 +msgctxt "lowres" +msgid "Both" +msgstr "Ambos" + +#: gui/options.cpp:932 +msgid "Show subtitles and play speech" +msgstr "Mostrar os subtítulos e reproducir as voces" + +#: gui/options.cpp:934 +msgctxt "lowres" +msgid "Subtitle speed:" +msgstr "Velocidade subs:" + +#: gui/options.cpp:950 +msgid "Music volume:" +msgstr "Volume de música:" + +#: gui/options.cpp:952 +msgctxt "lowres" +msgid "Music volume:" +msgstr "Volume música:" + +#: gui/options.cpp:959 +msgid "Mute All" +msgstr "Silenciar todo" + +#: gui/options.cpp:962 +msgid "SFX volume:" +msgstr "Volume de efectos:" + +#: gui/options.cpp:962 gui/options.cpp:964 gui/options.cpp:965 +msgid "Special sound effects volume" +msgstr "Volume dos efectos de son" + +#: gui/options.cpp:964 +msgctxt "lowres" +msgid "SFX volume:" +msgstr "Volume efectos:" + +#: gui/options.cpp:972 +msgid "Speech volume:" +msgstr "Volume de voz:" + +#: gui/options.cpp:974 +msgctxt "lowres" +msgid "Speech volume:" +msgstr "Volume voz:" + +#: gui/options.cpp:1131 +msgid "Theme Path:" +msgstr "Camiño do tema:" + +#: gui/options.cpp:1133 +msgctxt "lowres" +msgid "Theme Path:" +msgstr "Camiño tema:" + +#: gui/options.cpp:1139 gui/options.cpp:1141 gui/options.cpp:1142 +msgid "Specifies path to additional data used by all games or ScummVM" +msgstr "" +"Especificar o camiño dos datos adicionais de todos os xogos ou de ScummVM" + +#: gui/options.cpp:1148 +msgid "Plugins Path:" +msgstr "Camiño dos complementos:" + +#: gui/options.cpp:1150 +msgctxt "lowres" +msgid "Plugins Path:" +msgstr "Camiño complementos:" + +#: gui/options.cpp:1159 +msgid "Misc" +msgstr "Misc." + +#: gui/options.cpp:1161 +msgctxt "lowres" +msgid "Misc" +msgstr "Misc." + +#: gui/options.cpp:1163 +msgid "Theme:" +msgstr "Tema:" + +#: gui/options.cpp:1167 +msgid "GUI Renderer:" +msgstr "Procesamento da interfaz:" + +#: gui/options.cpp:1179 +msgid "Autosave:" +msgstr "Autogardado:" + +#: gui/options.cpp:1181 +msgctxt "lowres" +msgid "Autosave:" +msgstr "Autogardado:" + +#: gui/options.cpp:1189 +msgid "Keys" +msgstr "Teclas" + +#: gui/options.cpp:1196 +msgid "GUI Language:" +msgstr "Idioma de interfaz:" + +#: gui/options.cpp:1196 +msgid "Language of ScummVM GUI" +msgstr "Idioma da interfaz de ScummVM" + +#: gui/options.cpp:1347 +msgid "You have to restart ScummVM before your changes will take effect." +msgstr "Debes reiniciar ScummVM para que os cambios teñan efecto." + +#: gui/options.cpp:1360 +msgid "Select directory for savegames" +msgstr "Seleccionar directorio para ficheiros de gardado" + +#: gui/options.cpp:1367 +msgid "The chosen directory cannot be written to. Please select another one." +msgstr "Non é posible escribir no directorio elixido. Selecciona outro." + +#: gui/options.cpp:1376 +msgid "Select directory for GUI themes" +msgstr "Seleccionar directorio para temas de interfaz" + +#: gui/options.cpp:1386 +msgid "Select directory for extra files" +msgstr "Seleccionar directorio para ficheiros adicionais" + +#: gui/options.cpp:1397 +msgid "Select directory for plugins" +msgstr "Seleccionar directorio para complementos" + +#: gui/options.cpp:1450 +msgid "" +"The theme you selected does not support your current language. If you want " +"to use this theme you need to switch to another language first." +msgstr "" +"O tema seleccionado non é compatible co idioma actual. Para empregar o tema, " +"deberás cambiar antes o idioma da interfaz." + +#: gui/saveload-dialog.cpp:158 +msgid "List view" +msgstr "Lista" + +#: gui/saveload-dialog.cpp:159 +msgid "Grid view" +msgstr "Grade" + +#: gui/saveload-dialog.cpp:202 gui/saveload-dialog.cpp:350 +msgid "No date saved" +msgstr "Non hai data gardada" + +#: gui/saveload-dialog.cpp:203 gui/saveload-dialog.cpp:351 +msgid "No time saved" +msgstr "Non hai hora gardada" + +#: gui/saveload-dialog.cpp:204 gui/saveload-dialog.cpp:352 +msgid "No playtime saved" +msgstr "Non hai tempo de xogo gardado" + +#: gui/saveload-dialog.cpp:211 gui/saveload-dialog.cpp:267 +msgid "Delete" +msgstr "Eliminar" + +#: gui/saveload-dialog.cpp:266 +msgid "Do you really want to delete this savegame?" +msgstr "Seguro que queres eliminar esta partida?" + +#: gui/saveload-dialog.cpp:375 gui/saveload-dialog.cpp:796 +msgid "Date: " +msgstr "Data:" + +#: gui/saveload-dialog.cpp:379 gui/saveload-dialog.cpp:802 +msgid "Time: " +msgstr "Hora:" + +#: gui/saveload-dialog.cpp:385 gui/saveload-dialog.cpp:810 +msgid "Playtime: " +msgstr "Tempo de xogo:" + +#: gui/saveload-dialog.cpp:398 gui/saveload-dialog.cpp:465 +msgid "Untitled savestate" +msgstr "Partida sen título" + +#: gui/saveload-dialog.cpp:517 +msgid "Next" +msgstr "Seg." + +#: gui/saveload-dialog.cpp:520 +msgid "Prev" +msgstr "Ant." + +#: gui/saveload-dialog.cpp:684 +msgid "New Save" +msgstr "Novo ficheiro" + +#: gui/saveload-dialog.cpp:684 +msgid "Create a new save game" +msgstr "Crea un novo ficheiro de gardado" + +#: gui/saveload-dialog.cpp:789 +msgid "Name: " +msgstr "Nome:" + +#: gui/saveload-dialog.cpp:861 +#, c-format +msgid "Enter a description for slot %d:" +msgstr "Introduce unha descrición para o espazo %d:" + +#: gui/themebrowser.cpp:44 +msgid "Select a Theme" +msgstr "Seleccionar tema" + +#: gui/ThemeEngine.cpp:337 +msgid "Disabled GFX" +msgstr "Efectos gráficos desactivados" + +#: gui/ThemeEngine.cpp:337 +msgctxt "lowres" +msgid "Disabled GFX" +msgstr "Efectos desactivados" + +#: gui/ThemeEngine.cpp:338 +msgid "Standard Renderer (16bpp)" +msgstr "Procesamento estándar (16 bpp)" + +#: gui/ThemeEngine.cpp:338 +msgid "Standard (16bpp)" +msgstr "Estándar (16 bpp)" + +#: gui/ThemeEngine.cpp:340 +msgid "Antialiased Renderer (16bpp)" +msgstr "Procesamento antidistorsión (16 bpp)" + +#: gui/ThemeEngine.cpp:340 +msgid "Antialiased (16bpp)" +msgstr "Antidistorsión (16 bpp)" + +#: gui/widget.cpp:322 gui/widget.cpp:324 gui/widget.cpp:330 gui/widget.cpp:332 +msgid "Clear value" +msgstr "Limpar valor" + +#: base/main.cpp:209 +#, c-format +msgid "Engine does not support debug level '%s'" +msgstr "O motor non é compatible co nivel de depuración %s" + +#: base/main.cpp:287 +msgid "Menu" +msgstr "Menú" + +#: base/main.cpp:290 backends/platform/symbian/src/SymbianActions.cpp:45 +#: backends/platform/wince/CEActionsPocket.cpp:45 +#: backends/platform/wince/CEActionsSmartphone.cpp:46 +msgid "Skip" +msgstr "Omitir" + +#: base/main.cpp:293 backends/platform/symbian/src/SymbianActions.cpp:50 +#: backends/platform/wince/CEActionsPocket.cpp:42 +msgid "Pause" +msgstr "Pausa" + +#: base/main.cpp:296 +msgid "Skip line" +msgstr "Omitir liña" + +#: base/main.cpp:467 +msgid "Error running game:" +msgstr "Erro de execución do xogo:" + +#: base/main.cpp:491 +msgid "Could not find any engine capable of running the selected game" +msgstr "Non se puido atopar un motor para executar o xogo seleccionado" + +#: common/error.cpp:38 +msgid "No error" +msgstr "Non hai erros" + +#: common/error.cpp:40 +msgid "Game data not found" +msgstr "Non se atoparon datos de xogo" + +#: common/error.cpp:42 +msgid "Game id not supported" +msgstr "ID de xogo non compatible" + +#: common/error.cpp:44 +msgid "Unsupported color mode" +msgstr "Modo de color non compatible" + +#: common/error.cpp:47 +msgid "Read permission denied" +msgstr "Permiso de lectura denegado" + +#: common/error.cpp:49 +msgid "Write permission denied" +msgstr "Permiso de escritura denegado" + +#: common/error.cpp:52 +msgid "Path does not exist" +msgstr "O camiño non existe" + +#: common/error.cpp:54 +msgid "Path not a directory" +msgstr "O camiño non é un directorio" + +#: common/error.cpp:56 +msgid "Path not a file" +msgstr "O camiño non é un ficheiro" + +#: common/error.cpp:59 +msgid "Cannot create file" +msgstr "Erro ao crear o ficheiro" + +#: common/error.cpp:61 +msgid "Reading data failed" +msgstr "Erro ao ler os datos" + +#: common/error.cpp:63 +msgid "Writing data failed" +msgstr "Erro ao escribir os datos" + +#: common/error.cpp:66 +msgid "Could not find suitable engine plugin" +msgstr "Non se atopou un complemento axeitado para o motor" + +#: common/error.cpp:68 +msgid "Engine plugin does not support save states" +msgstr "O complemento do motor non é compatible cos ficheiros de gardado" + +#: common/error.cpp:71 +msgid "User canceled" +msgstr "Usuario cancelado" + +#: common/error.cpp:75 +msgid "Unknown error" +msgstr "Erro descoñecido" + +#: engines/advancedDetector.cpp:316 +#, c-format +msgid "The game in '%s' seems to be unknown." +msgstr "O xogo de %s semella ser descoñecido." + +#: engines/advancedDetector.cpp:317 +msgid "Please, report the following data to the ScummVM team along with name" +msgstr "Facilita esta información ao equipo de ScummVM, xunto co nome" + +#: engines/advancedDetector.cpp:319 +msgid "of the game you tried to add and its version/language/etc.:" +msgstr "do xogo que tentaches engadir, xunto coa versión, lingua, etc.:" + +#: engines/dialogs.cpp:84 +msgid "~R~esume" +msgstr "~R~etomar" + +#: engines/dialogs.cpp:86 +msgid "~L~oad" +msgstr "~C~argar" + +#: engines/dialogs.cpp:90 +msgid "~S~ave" +msgstr "~G~ardar" + +#: engines/dialogs.cpp:94 +msgid "~O~ptions" +msgstr "~O~pcións" + +#: engines/dialogs.cpp:99 +msgid "~H~elp" +msgstr "~A~xuda" + +#: engines/dialogs.cpp:101 +msgid "~A~bout" +msgstr "Acerca ~d~e" + +#: engines/dialogs.cpp:104 engines/dialogs.cpp:180 +msgid "~R~eturn to Launcher" +msgstr "~V~olver ao Iniciador" + +#: engines/dialogs.cpp:106 engines/dialogs.cpp:182 +msgctxt "lowres" +msgid "~R~eturn to Launcher" +msgstr "~V~olver ao Iniciador" + +#: engines/dialogs.cpp:115 engines/agi/saveload.cpp:803 +#: engines/cruise/menu.cpp:212 engines/sci/engine/kfile.cpp:742 +msgid "Save game:" +msgstr "Gardar partida:" + +#: engines/dialogs.cpp:115 engines/agi/saveload.cpp:803 +#: engines/scumm/dialogs.cpp:187 engines/cruise/menu.cpp:212 +#: engines/sci/engine/kfile.cpp:742 +#: backends/platform/symbian/src/SymbianActions.cpp:44 +#: backends/platform/wince/CEActionsPocket.cpp:43 +#: backends/platform/wince/CEActionsPocket.cpp:267 +#: backends/platform/wince/CEActionsSmartphone.cpp:45 +#: backends/platform/wince/CEActionsSmartphone.cpp:231 +msgid "Save" +msgstr "Gardar" + +#: engines/dialogs.cpp:144 +msgid "" +"Sorry, this engine does not currently provide in-game help. Please consult " +"the README for basic information, and for instructions on how to obtain " +"further assistance." +msgstr "" +"Este motor non ofrece axuda no xogo actualmente. Consulta o ficheiro README " +"para obter información básica e máis instrucións para acadar asistencia " +"adicional." + +#: engines/dialogs.cpp:228 +#, c-format +msgid "" +"Gamestate save failed (%s)! Please consult the README for basic information, " +"and for instructions on how to obtain further assistance." +msgstr "" +"Erro ao gardar (%s)! Consulta o ficheiro README para obter información " +"básica e máis instrucións para acadar asistencia adicional." + +#: engines/dialogs.cpp:301 engines/mohawk/dialogs.cpp:109 +#: engines/mohawk/dialogs.cpp:174 +msgid "~O~K" +msgstr "~A~ceptar" + +#: engines/dialogs.cpp:302 engines/mohawk/dialogs.cpp:110 +#: engines/mohawk/dialogs.cpp:175 +msgid "~C~ancel" +msgstr "~C~ancelar" + +#: engines/dialogs.cpp:305 +msgid "~K~eys" +msgstr "~T~eclas" + +#: engines/engine.cpp:235 +msgid "Could not initialize color format." +msgstr "Non se puido iniciar o formato de cor." + +#: engines/engine.cpp:243 +msgid "Could not switch to video mode: '" +msgstr "Non se puido cambiar ao modo de vídeo: '" + +#: engines/engine.cpp:252 +msgid "Could not apply aspect ratio setting." +msgstr "Non se puido aplicar a configuración de proporción." + +#: engines/engine.cpp:257 +msgid "Could not apply fullscreen setting." +msgstr "Non se puido aplicar a configuración de pantalla completa." + +#: engines/engine.cpp:357 +msgid "" +"You appear to be playing this game directly\n" +"from the CD. This is known to cause problems,\n" +"and it is therefore recommended that you copy\n" +"the data files to your hard disk instead.\n" +"See the README file for details." +msgstr "" +"Semella que estás a xogar directamente\n" +"dende o CD. Temos constancia de que causa,\n" +"problemas. Por iso, recomendámosche copiar\n" +"os ficheiros de datos ao disco duro. Consulta\n" +"o ficheiro README para obter máis información." + +#: engines/engine.cpp:368 +msgid "" +"This game has audio tracks in its disk. These\n" +"tracks need to be ripped from the disk using\n" +"an appropriate CD audio extracting tool in\n" +"order to listen to the game's music.\n" +"See the README file for details." +msgstr "" +"O xogo ten pistas de son no disco. Debes\n" +"extraelas por medio dunha ferramenta\n" +"axeitada para poder escoitar a música\n" +"do xogo. Consulta o ficheiro README\n" +"para obter máis información." + +#: engines/engine.cpp:426 +#, c-format +msgid "" +"Gamestate load failed (%s)! Please consult the README for basic information, " +"and for instructions on how to obtain further assistance." +msgstr "" +"Erro ao cargar (%s)! Consulta o ficheiro README para obter información " +"básica e máis instrucións para acadar asistencia adicional." + +#: engines/engine.cpp:439 +msgid "" +"WARNING: The game you are about to start is not yet fully supported by " +"ScummVM. As such, it is likely to be unstable, and any saves you make might " +"not work in future versions of ScummVM." +msgstr "" +"Ollo: o xogo que vas iniciar non é aínda totalmente compatible con ScummVM. " +"Por iso, talvez sexa inestable e os ficheiros de gardado talvez non " +"funcionen en futuras versións de ScummVM." + +#: engines/engine.cpp:442 +msgid "Start anyway" +msgstr "Iniciar de todos os xeitos" + +#: engines/agi/detection.cpp:145 engines/dreamweb/detection.cpp:47 +#: engines/sci/detection.cpp:390 +msgid "Use original save/load screens" +msgstr "Empregar pantallas orixinais de gardado e carga" + +#: engines/agi/detection.cpp:146 engines/dreamweb/detection.cpp:48 +#: engines/sci/detection.cpp:391 +msgid "Use the original save/load screens, instead of the ScummVM ones" +msgstr "" +"Empregar as pantallas orixinais de gardado e carga, no canto das de ScummVM" + +#: engines/agi/saveload.cpp:816 engines/sci/engine/kfile.cpp:838 +msgid "Restore game:" +msgstr "Restaurar xogo:" + +#: engines/agi/saveload.cpp:816 engines/sci/engine/kfile.cpp:838 +msgid "Restore" +msgstr "Restaurar" + +#: engines/dreamweb/detection.cpp:57 +msgid "Use bright palette mode" +msgstr "Empregar modo de paleta intensa" + +#: engines/dreamweb/detection.cpp:58 +msgid "Display graphics using the game's bright palette" +msgstr "Mostrar os gráficos coa paletta intensa do xogo" + +#: engines/sci/detection.cpp:370 +msgid "EGA undithering" +msgstr "Non interpolación EGA" + +#: engines/sci/detection.cpp:371 +msgid "Enable undithering in EGA games" +msgstr "Activar a non interpolación nos xogos en EGA" + +#: engines/sci/detection.cpp:380 +msgid "Prefer digital sound effects" +msgstr "Preferir efectos de son dixitais" + +#: engines/sci/detection.cpp:381 +msgid "Prefer digital sound effects instead of synthesized ones" +msgstr "Dar preferencia aos efectos de son dixitais no canto dos sintéticos" + +#: engines/sci/detection.cpp:400 +msgid "Use IMF/Yamaha FB-01 for MIDI output" +msgstr "Empregar IMF/Yamaha FB-01 para a saída de MIDI" + +#: engines/sci/detection.cpp:401 +msgid "" +"Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI " +"output" +msgstr "" +"Empregar unha tarxeta IBM Music Feature ou un módulo de sintetizador Yamaha " +"FB-01 FM para a saída de MIDI" + +#: engines/sci/detection.cpp:411 +msgid "Use CD audio" +msgstr "Empregar son de CD" + +#: engines/sci/detection.cpp:412 +msgid "Use CD audio instead of in-game audio, if available" +msgstr "Empregar son de CD no canto do do xogo, de ser o caso" + +#: engines/sci/detection.cpp:422 +msgid "Use Windows cursors" +msgstr "Empregar cursores de Windows" + +#: engines/sci/detection.cpp:423 +msgid "" +"Use the Windows cursors (smaller and monochrome) instead of the DOS ones" +msgstr "" +"Empregar os cursores de Windows (máis pequenos e monocromos) no canto dos de " +"DOS" + +#: engines/sci/detection.cpp:433 +msgid "Use silver cursors" +msgstr "Empregar cursores prateados" + +#: engines/sci/detection.cpp:434 +msgid "" +"Use the alternate set of silver cursors, instead of the normal golden ones" +msgstr "" +"Empregar o xogo de cursores prateados alternativo, no canto dos dourados " +"normais" + +#: engines/scumm/dialogs.cpp:175 +#, c-format +msgid "Insert Disk %c and Press Button to Continue." +msgstr "Insire o disco %c e preme o botón para continuar." + +#: engines/scumm/dialogs.cpp:176 +#, c-format +msgid "Unable to Find %s, (%c%d) Press Button." +msgstr "Non se puido atopar %s, (%c%d). Preme o botón." + +#: engines/scumm/dialogs.cpp:177 +#, c-format +msgid "Error reading disk %c, (%c%d) Press Button." +msgstr "Erro ao ler o disco %c, (%c%d). Preme o botón." + +#: engines/scumm/dialogs.cpp:178 +msgid "Game Paused. Press SPACE to Continue." +msgstr "Xogo en pausa. Pulsa a barra espazadora para continuar." + +#. I18N: You may specify 'Yes' symbol at the end of the line, like this: +#. "Moechten Sie wirklich neu starten? (J/N)J" +#. Will react to J as 'Yes' +#: engines/scumm/dialogs.cpp:182 +msgid "Are you sure you want to restart? (Y/N)" +msgstr "Seguro que queres reiniciar? (S/N)S" + +#. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment +#: engines/scumm/dialogs.cpp:184 +msgid "Are you sure you want to quit? (Y/N)" +msgstr "Seguro que queres saír? (S/N)S" + +#: engines/scumm/dialogs.cpp:189 +msgid "Play" +msgstr "Xogar" + +#: engines/scumm/dialogs.cpp:191 engines/scumm/help.cpp:82 +#: engines/scumm/help.cpp:84 +#: backends/platform/symbian/src/SymbianActions.cpp:52 +#: backends/platform/wince/CEActionsPocket.cpp:44 +#: backends/platform/wince/CEActionsSmartphone.cpp:52 +#: backends/events/default/default-events.cpp:213 +msgid "Quit" +msgstr "Saír" + +#: engines/scumm/dialogs.cpp:193 +msgid "Insert save/load game disk" +msgstr "Inserir disco de gardado/carga" + +#: engines/scumm/dialogs.cpp:194 +msgid "You must enter a name" +msgstr "Debes introducir un nome" + +#: engines/scumm/dialogs.cpp:195 +msgid "The game was NOT saved (disk full?)" +msgstr "Non se puido gardar a partida (disco cheo?)" + +#: engines/scumm/dialogs.cpp:196 +msgid "The game was NOT loaded" +msgstr "Non se puido cargar a partida" + +#: engines/scumm/dialogs.cpp:197 +#, c-format +msgid "Saving '%s'" +msgstr "Gardando %s" + +#: engines/scumm/dialogs.cpp:198 +#, c-format +msgid "Loading '%s'" +msgstr "Cargando %s" + +#: engines/scumm/dialogs.cpp:199 +msgid "Name your SAVE game" +msgstr "Introduce un nome para a partida gardada" + +#: engines/scumm/dialogs.cpp:200 +msgid "Select a game to LOAD" +msgstr "Selecciona unha partida para cargala" + +#: engines/scumm/dialogs.cpp:201 +msgid "Game title)" +msgstr "Título)" + +#. I18N: Previous page button +#: engines/scumm/dialogs.cpp:287 +msgid "~P~revious" +msgstr "~A~nterior" + +#. I18N: Next page button +#: engines/scumm/dialogs.cpp:289 +msgid "~N~ext" +msgstr "~S~eguinte" + +#: engines/scumm/dialogs.cpp:290 +#: backends/platform/ds/arm9/source/dsoptions.cpp:56 +msgid "~C~lose" +msgstr "~P~echar" + +#: engines/scumm/dialogs.cpp:597 +msgid "Speech Only" +msgstr "Só voz" + +#: engines/scumm/dialogs.cpp:598 +msgid "Speech and Subtitles" +msgstr "Voz e subtítulos" + +#: engines/scumm/dialogs.cpp:599 +msgid "Subtitles Only" +msgstr "Só subtítulos" + +#: engines/scumm/dialogs.cpp:607 +msgctxt "lowres" +msgid "Speech & Subs" +msgstr "Voz e subs" + +#: engines/scumm/dialogs.cpp:653 +msgid "Select a Proficiency Level." +msgstr "Selecciona un nivel de habilidade." + +#: engines/scumm/dialogs.cpp:655 +msgid "Refer to your Loom(TM) manual for help." +msgstr "Consulta o manual de Loom(TM) para obter axuda." + +#: engines/scumm/dialogs.cpp:658 +msgid "Standard" +msgstr "Estándar" + +#: engines/scumm/dialogs.cpp:659 +msgid "Practice" +msgstr "Práctica" + +#: engines/scumm/dialogs.cpp:660 +msgid "Expert" +msgstr "Experto" + +#: engines/scumm/help.cpp:73 +msgid "Common keyboard commands:" +msgstr "Comandos de teclado comúns:" + +#: engines/scumm/help.cpp:74 +msgid "Save / Load dialog" +msgstr "Gardar/cargar diálogo" + +#: engines/scumm/help.cpp:76 +msgid "Skip line of text" +msgstr "Omitir liña de texto" + +#: engines/scumm/help.cpp:77 +msgid "Esc" +msgstr "ESC" + +#: engines/scumm/help.cpp:77 +msgid "Skip cutscene" +msgstr "Omitir secuencia" + +#: engines/scumm/help.cpp:78 +msgid "Space" +msgstr "Barra espazadora" + +#: engines/scumm/help.cpp:78 +msgid "Pause game" +msgstr "Pausar xogo" + +#: engines/scumm/help.cpp:79 engines/scumm/help.cpp:84 +#: engines/scumm/help.cpp:95 engines/scumm/help.cpp:96 +#: engines/scumm/help.cpp:97 engines/scumm/help.cpp:98 +#: engines/scumm/help.cpp:99 engines/scumm/help.cpp:100 +#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102 +msgid "Ctrl" +msgstr "CTRL" + +#: engines/scumm/help.cpp:79 +msgid "Load game state 1-10" +msgstr "Cargar partida 1-10" + +#: engines/scumm/help.cpp:80 engines/scumm/help.cpp:84 +#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:100 +#: engines/scumm/help.cpp:101 engines/scumm/help.cpp:102 +msgid "Alt" +msgstr "ALT" + +#: engines/scumm/help.cpp:80 +msgid "Save game state 1-10" +msgstr "Gardar partida 1-10" + +#: engines/scumm/help.cpp:86 engines/scumm/help.cpp:89 +msgid "Enter" +msgstr "INTRO" + +#: engines/scumm/help.cpp:86 +msgid "Toggle fullscreen" +msgstr "Activar/desactivar pantalla completa" + +#: engines/scumm/help.cpp:87 +msgid "Music volume up / down" +msgstr "Subir/baixar volume de música" + +#: engines/scumm/help.cpp:88 +msgid "Text speed slower / faster" +msgstr "Acelerar/frear texto" + +#: engines/scumm/help.cpp:89 +msgid "Simulate left mouse button" +msgstr "Simular botón primario do rato" + +#: engines/scumm/help.cpp:90 +msgid "Tab" +msgstr "TAB" + +#: engines/scumm/help.cpp:90 +msgid "Simulate right mouse button" +msgstr "Simular botón secundario do rato" + +#: engines/scumm/help.cpp:93 +msgid "Special keyboard commands:" +msgstr "Comandos de teclado especiais:" + +#: engines/scumm/help.cpp:94 +msgid "Show / Hide console" +msgstr "Mostrar/ocultar consola" + +#: engines/scumm/help.cpp:95 +msgid "Start the debugger" +msgstr "Iniciar o depurador" + +#: engines/scumm/help.cpp:96 +msgid "Show memory consumption" +msgstr "Mostrar consumo de memoria" + +#: engines/scumm/help.cpp:97 +msgid "Run in fast mode (*)" +msgstr "Executar en modo rápido (*)" + +#: engines/scumm/help.cpp:98 +msgid "Run in really fast mode (*)" +msgstr "Executar en modo moi rápido (*)" + +#: engines/scumm/help.cpp:99 +msgid "Toggle mouse capture" +msgstr "Activar/desactivar captura de rato" + +#: engines/scumm/help.cpp:100 +msgid "Switch between graphics filters" +msgstr "Cambiar filtro de gráficos" + +#: engines/scumm/help.cpp:101 +msgid "Increase / Decrease scale factor" +msgstr "Aumentar/reducir factor de escala" + +#: engines/scumm/help.cpp:102 +msgid "Toggle aspect-ratio correction" +msgstr "Activar/desactivar corrección de proporción" + +#: engines/scumm/help.cpp:107 +msgid "* Note that using ctrl-f and" +msgstr "* Nota: non recomendamos" + +#: engines/scumm/help.cpp:108 +msgid " ctrl-g are not recommended" +msgstr " empregar CTRL-F nin CTRL-G," + +#: engines/scumm/help.cpp:109 +msgid " since they may cause crashes" +msgstr " xa que poden provocar bloqueos" + +#: engines/scumm/help.cpp:110 +msgid " or incorrect game behavior." +msgstr " ou outros erros no xogo." + +#: engines/scumm/help.cpp:114 +msgid "Spinning drafts on the keyboard:" +msgstr "Tecer feitizos co teclado:" + +#: engines/scumm/help.cpp:116 +msgid "Main game controls:" +msgstr "Controis principais de xogo:" + +#: engines/scumm/help.cpp:121 engines/scumm/help.cpp:136 +#: engines/scumm/help.cpp:161 +msgid "Push" +msgstr "Empuxar" + +#: engines/scumm/help.cpp:122 engines/scumm/help.cpp:137 +#: engines/scumm/help.cpp:162 +msgid "Pull" +msgstr "Tirar de" + +#: engines/scumm/help.cpp:123 engines/scumm/help.cpp:138 +#: engines/scumm/help.cpp:163 engines/scumm/help.cpp:197 +#: engines/scumm/help.cpp:207 +msgid "Give" +msgstr "Dar" + +#: engines/scumm/help.cpp:124 engines/scumm/help.cpp:139 +#: engines/scumm/help.cpp:164 engines/scumm/help.cpp:190 +#: engines/scumm/help.cpp:208 +msgid "Open" +msgstr "Abrir" + +#: engines/scumm/help.cpp:126 +msgid "Go to" +msgstr "Ir a" + +#: engines/scumm/help.cpp:127 +msgid "Get" +msgstr "Coller" + +#: engines/scumm/help.cpp:128 engines/scumm/help.cpp:152 +#: engines/scumm/help.cpp:170 engines/scumm/help.cpp:198 +#: engines/scumm/help.cpp:213 engines/scumm/help.cpp:224 +#: engines/scumm/help.cpp:250 +msgid "Use" +msgstr "Usar" + +#: engines/scumm/help.cpp:129 engines/scumm/help.cpp:141 +msgid "Read" +msgstr "Ler" + +#: engines/scumm/help.cpp:130 engines/scumm/help.cpp:147 +msgid "New kid" +msgstr "Rapaz" + +#: engines/scumm/help.cpp:131 engines/scumm/help.cpp:153 +#: engines/scumm/help.cpp:171 +msgid "Turn on" +msgstr "Acender" + +#: engines/scumm/help.cpp:132 engines/scumm/help.cpp:154 +#: engines/scumm/help.cpp:172 +msgid "Turn off" +msgstr "Apagar" + +#: engines/scumm/help.cpp:142 engines/scumm/help.cpp:167 +#: engines/scumm/help.cpp:194 +msgid "Walk to" +msgstr "Ir a" + +#: engines/scumm/help.cpp:143 engines/scumm/help.cpp:168 +#: engines/scumm/help.cpp:195 engines/scumm/help.cpp:210 +#: engines/scumm/help.cpp:227 +msgid "Pick up" +msgstr "Coller" + +#: engines/scumm/help.cpp:144 engines/scumm/help.cpp:169 +msgid "What is" +msgstr "Que é" + +#: engines/scumm/help.cpp:146 +msgid "Unlock" +msgstr "Despechar" + +#: engines/scumm/help.cpp:149 +msgid "Put on" +msgstr "Poñer" + +#: engines/scumm/help.cpp:150 +msgid "Take off" +msgstr "Quitar" + +#: engines/scumm/help.cpp:156 +msgid "Fix" +msgstr "Reparar" + +#: engines/scumm/help.cpp:158 +msgid "Switch" +msgstr "Cambiar" + +#: engines/scumm/help.cpp:166 engines/scumm/help.cpp:228 +msgid "Look" +msgstr "Mirar" + +#: engines/scumm/help.cpp:173 engines/scumm/help.cpp:223 +msgid "Talk" +msgstr "Falar" + +#: engines/scumm/help.cpp:174 +msgid "Travel" +msgstr "Viaxar" + +#: engines/scumm/help.cpp:175 +msgid "To Henry / To Indy" +msgstr "A Henry / A Indy" + +#. I18N: These are different musical notes +#: engines/scumm/help.cpp:179 +msgid "play C minor on distaff" +msgstr "tocar do menor no bastón" + +#: engines/scumm/help.cpp:180 +msgid "play D on distaff" +msgstr "tocar re no bastón" + +#: engines/scumm/help.cpp:181 +msgid "play E on distaff" +msgstr "tocar mi no bastón" + +#: engines/scumm/help.cpp:182 +msgid "play F on distaff" +msgstr "tocar fa no bastón" + +#: engines/scumm/help.cpp:183 +msgid "play G on distaff" +msgstr "tocar sol no bastón" + +#: engines/scumm/help.cpp:184 +msgid "play A on distaff" +msgstr "tocar la no bastón" + +#: engines/scumm/help.cpp:185 +msgid "play B on distaff" +msgstr "tocar si no bastón" + +#: engines/scumm/help.cpp:186 +msgid "play C major on distaff" +msgstr "tocar do maior no bastón" + +#: engines/scumm/help.cpp:192 engines/scumm/help.cpp:214 +msgid "puSh" +msgstr "Empurrar" + +#: engines/scumm/help.cpp:193 engines/scumm/help.cpp:215 +msgid "pull (Yank)" +msgstr "Tirar de" + +#: engines/scumm/help.cpp:196 engines/scumm/help.cpp:212 +#: engines/scumm/help.cpp:248 +msgid "Talk to" +msgstr "Falar con" + +#: engines/scumm/help.cpp:199 engines/scumm/help.cpp:211 +msgid "Look at" +msgstr "Mirar" + +#: engines/scumm/help.cpp:200 +msgid "turn oN" +msgstr "Acender" + +#: engines/scumm/help.cpp:201 +msgid "turn oFf" +msgstr "Apagar" + +#: engines/scumm/help.cpp:217 +msgid "KeyUp" +msgstr "Arriba" + +#: engines/scumm/help.cpp:217 +msgid "Highlight prev dialogue" +msgstr "Destacar diálogo anterior" + +#: engines/scumm/help.cpp:218 +msgid "KeyDown" +msgstr "Abaixo" + +#: engines/scumm/help.cpp:218 +msgid "Highlight next dialogue" +msgstr "Destacar diálogo seguinte" + +#: engines/scumm/help.cpp:222 +msgid "Walk" +msgstr "Ir a" + +#: engines/scumm/help.cpp:225 engines/scumm/help.cpp:234 +#: engines/scumm/help.cpp:241 engines/scumm/help.cpp:249 +msgid "Inventory" +msgstr "Inventario" + +#: engines/scumm/help.cpp:226 +msgid "Object" +msgstr "Obxecto" + +#: engines/scumm/help.cpp:229 +msgid "Black and White / Color" +msgstr "Branco e negro/cor" + +#: engines/scumm/help.cpp:232 +msgid "Eyes" +msgstr "Ollos" + +#: engines/scumm/help.cpp:233 +msgid "Tongue" +msgstr "Lingua" + +#: engines/scumm/help.cpp:235 +msgid "Punch" +msgstr "Bater a" + +#: engines/scumm/help.cpp:236 +msgid "Kick" +msgstr "Patear a" + +#: engines/scumm/help.cpp:239 engines/scumm/help.cpp:247 +msgid "Examine" +msgstr "Examinar" + +#: engines/scumm/help.cpp:240 +msgid "Regular cursor" +msgstr "Cursor normal" + +#. I18N: Comm is a communication device +#: engines/scumm/help.cpp:243 +msgid "Comm" +msgstr "Comunicador" + +#: engines/scumm/help.cpp:246 +msgid "Save / Load / Options" +msgstr "Gardar/cargar/opcións" + +#: engines/scumm/help.cpp:255 +msgid "Other game controls:" +msgstr "Outros controis de xogo:" + +#: engines/scumm/help.cpp:257 engines/scumm/help.cpp:267 +msgid "Inventory:" +msgstr "Inventario:" + +#: engines/scumm/help.cpp:258 engines/scumm/help.cpp:274 +msgid "Scroll list up" +msgstr "Subir lista" + +#: engines/scumm/help.cpp:259 engines/scumm/help.cpp:275 +msgid "Scroll list down" +msgstr "Baixar lista" + +#: engines/scumm/help.cpp:260 engines/scumm/help.cpp:268 +msgid "Upper left item" +msgstr "Obxecto esquerdo arriba" + +#: engines/scumm/help.cpp:261 engines/scumm/help.cpp:270 +msgid "Lower left item" +msgstr "Obxecto esquerdo abaixo" + +#: engines/scumm/help.cpp:262 engines/scumm/help.cpp:271 +msgid "Upper right item" +msgstr "Obxecto dereito arriba" + +#: engines/scumm/help.cpp:263 engines/scumm/help.cpp:273 +msgid "Lower right item" +msgstr "Obxecto dereito abaixo" + +#: engines/scumm/help.cpp:269 +msgid "Middle left item" +msgstr "Obxecto esquerdo medio" + +#: engines/scumm/help.cpp:272 +msgid "Middle right item" +msgstr "Obxecto dereito medio" + +#: engines/scumm/help.cpp:279 engines/scumm/help.cpp:284 +msgid "Switching characters:" +msgstr "Cambiar caracteres:" + +#: engines/scumm/help.cpp:281 +msgid "Second kid" +msgstr "Rapaz 2" + +#: engines/scumm/help.cpp:282 +msgid "Third kid" +msgstr "Rapaz 3" + +#: engines/scumm/help.cpp:294 +msgid "Fighting controls (numpad):" +msgstr "Controis de combate (teclado numérico):" + +#: engines/scumm/help.cpp:295 engines/scumm/help.cpp:296 +#: engines/scumm/help.cpp:297 +msgid "Step back" +msgstr "Paso atrás" + +#: engines/scumm/help.cpp:298 +msgid "Block high" +msgstr "Bloqueo alto" + +#: engines/scumm/help.cpp:299 +msgid "Block middle" +msgstr "Bloqueo medio" + +#: engines/scumm/help.cpp:300 +msgid "Block low" +msgstr "Bloqueo baixo" + +#: engines/scumm/help.cpp:301 +msgid "Punch high" +msgstr "Puñazo alto" + +#: engines/scumm/help.cpp:302 +msgid "Punch middle" +msgstr "Puñazo medio" + +#: engines/scumm/help.cpp:303 +msgid "Punch low" +msgstr "Puñazo baixo" + +#: engines/scumm/help.cpp:306 +msgid "These are for Indy on left." +msgstr "Son para Indy na esquerda." + +#: engines/scumm/help.cpp:307 +msgid "When Indy is on the right," +msgstr "Se está na dereita," + +#: engines/scumm/help.cpp:308 +msgid "7, 4, and 1 are switched with" +msgstr "7, 4 e 1 cámbianse por" + +#: engines/scumm/help.cpp:309 +msgid "9, 6, and 3, respectively." +msgstr "9, 6 e 3 respectivamente." + +#: engines/scumm/help.cpp:316 +msgid "Biplane controls (numpad):" +msgstr "Controis de biplano (teclado numérico):" + +#: engines/scumm/help.cpp:317 +msgid "Fly to upper left" +msgstr "Voar á esquerda arriba" + +#: engines/scumm/help.cpp:318 +msgid "Fly to left" +msgstr "Voar á esquerda" + +#: engines/scumm/help.cpp:319 +msgid "Fly to lower left" +msgstr "Voar á esquerda abaixo" + +#: engines/scumm/help.cpp:320 +msgid "Fly upwards" +msgstr "Voar arriba" + +#: engines/scumm/help.cpp:321 +msgid "Fly straight" +msgstr "Voar recto" + +#: engines/scumm/help.cpp:322 +msgid "Fly down" +msgstr "Voar abaixo" + +#: engines/scumm/help.cpp:323 +msgid "Fly to upper right" +msgstr "Voar á dereita arriba" + +#: engines/scumm/help.cpp:324 +msgid "Fly to right" +msgstr "Voar á dereita" + +#: engines/scumm/help.cpp:325 +msgid "Fly to lower right" +msgstr "Voar á dereita abaixo" + +#: engines/scumm/scumm.cpp:1773 +#, c-format +msgid "" +"Native MIDI support requires the Roland Upgrade from LucasArts,\n" +"but %s is missing. Using AdLib instead." +msgstr "" +"A compatibilidade nativa con MIDI precisa a actualización de Roland\n" +"de LucasArts, mais falla %s. Empregarase AdLib." + +#: engines/scumm/scumm.cpp:2278 engines/agos/saveload.cpp:220 +#, c-format +msgid "" +"Failed to save game state to file:\n" +"\n" +"%s" +msgstr "" +"Erro ao gardar a partida no ficheiro:\n" +"\n" +"%s" + +#: engines/scumm/scumm.cpp:2285 engines/agos/saveload.cpp:185 +#, c-format +msgid "" +"Failed to load game state from file:\n" +"\n" +"%s" +msgstr "" +"Erro ao cargar a partida do ficheiro:\n" +"\n" +"%s" + +#: engines/scumm/scumm.cpp:2297 engines/agos/saveload.cpp:228 +#, c-format +msgid "" +"Successfully saved game state in file:\n" +"\n" +"%s" +msgstr "" +"Partida gardada con éxito no ficheiro:\n" +"\n" +"%s" + +#: engines/scumm/scumm.cpp:2512 +msgid "" +"Usually, Maniac Mansion would start now. But ScummVM doesn't do that yet. To " +"play it, go to 'Add Game' in the ScummVM start menu and select the 'Maniac' " +"directory inside the Tentacle game directory." +msgstr "" +"Maniac Mansion tería que empezar agora. Porén, ScummVM aínda non é quen de " +"facelo. Para xogar, vai a Engadir xogo no menú de inicio de ScummVM e " +"selecciona o directorio Maniac que está dentro do directorio Tentacle." + +#. I18N: Option for fast scene switching +#: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:171 +msgid "~Z~ip Mode Activated" +msgstr "Modo ~c~omprimido activado" + +#: engines/mohawk/dialogs.cpp:93 +msgid "~T~ransitions Enabled" +msgstr "~T~ransicións activadas" + +#. I18N: Drop book page +#: engines/mohawk/dialogs.cpp:95 +msgid "~D~rop Page" +msgstr "~D~eixar folla" + +#: engines/mohawk/dialogs.cpp:99 +msgid "~S~how Map" +msgstr "Mo~s~trar mapa" + +#: engines/mohawk/dialogs.cpp:105 +msgid "~M~ain Menu" +msgstr "~M~enú principal" + +#: engines/mohawk/dialogs.cpp:172 +msgid "~W~ater Effect Enabled" +msgstr "Efecto de ~a~uga activado" + +#: engines/agos/animation.cpp:560 +#, c-format +msgid "Cutscene file '%s' not found!" +msgstr "Non se atopou o ficheiro de secuencia %s!" + +#: engines/gob/inter_playtoons.cpp:256 engines/gob/inter_v2.cpp:1287 +#: engines/tinsel/saveload.cpp:532 +msgid "Failed to load game state from file." +msgstr "Erro ao cargar a partida do ficheiro." + +#: engines/gob/inter_v2.cpp:1357 engines/tinsel/saveload.cpp:545 +msgid "Failed to save game state to file." +msgstr "Erro ao gardar a partida no ficheiro." + +#: engines/gob/inter_v5.cpp:107 +msgid "Failed to delete file." +msgstr "Erro ao eliminar o ficheiro." + +#: engines/groovie/script.cpp:420 +msgid "Failed to save game" +msgstr "Erro ao gardar a partida" + +#. I18N: Studio audience adds an applause and cheering sounds whenever +#. Malcolm makes a joke. +#: engines/kyra/detection.cpp:62 +msgid "Studio audience" +msgstr "Público do estudio" + +#: engines/kyra/detection.cpp:63 +msgid "Enable studio audience" +msgstr "Activar o público do estudio" + +#. I18N: This option allows the user to skip text and cutscenes. +#: engines/kyra/detection.cpp:73 +msgid "Skip support" +msgstr "Omisións" + +#: engines/kyra/detection.cpp:74 +msgid "Allow text and cutscenes to be skipped" +msgstr "Permitir a omisión do texto e das secuencias" + +#. I18N: Helium mode makes people sound like they've inhaled Helium. +#: engines/kyra/detection.cpp:84 +msgid "Helium mode" +msgstr "Modo helio" + +#: engines/kyra/detection.cpp:85 +msgid "Enable helium mode" +msgstr "Activar o modo helio" + +#. I18N: When enabled, this option makes scrolling smoother when +#. changing from one screen to another. +#: engines/kyra/detection.cpp:99 +msgid "Smooth scrolling" +msgstr "Desprazamento suave" + +#: engines/kyra/detection.cpp:100 +msgid "Enable smooth scrolling when walking" +msgstr "Activar o desprazamento suave ao camiñar" + +#. I18N: When enabled, this option changes the cursor when it floats to the +#. edge of the screen to a directional arrow. The player can then click to +#. walk towards that direction. +#: engines/kyra/detection.cpp:112 +msgid "Floating cursors" +msgstr "Cursores flotantes" + +#: engines/kyra/detection.cpp:113 +msgid "Enable floating cursors" +msgstr "Activar cursores flotantes" + +#. I18N: HP stands for Hit Points +#: engines/kyra/detection.cpp:127 +msgid "HP bar graphs" +msgstr "Barras de vida" + +#: engines/kyra/detection.cpp:128 +msgid "Enable hit point bar graphs" +msgstr "Activar barras de vida" + +#: engines/kyra/lol.cpp:478 +msgid "Attack 1" +msgstr "Ataque 1" + +#: engines/kyra/lol.cpp:479 +msgid "Attack 2" +msgstr "Ataque 2" + +#: engines/kyra/lol.cpp:480 +msgid "Attack 3" +msgstr "Ataque 3" + +#: engines/kyra/lol.cpp:481 +msgid "Move Forward" +msgstr "Mover cara diante" + +#: engines/kyra/lol.cpp:482 +msgid "Move Back" +msgstr "Mover cara atrás" + +#: engines/kyra/lol.cpp:483 +msgid "Slide Left" +msgstr "Esvarar á esquerda" + +#: engines/kyra/lol.cpp:484 +msgid "Slide Right" +msgstr "Esvarar á dereita" + +#: engines/kyra/lol.cpp:485 +msgid "Turn Left" +msgstr "Xirar á esquerda" + +#: engines/kyra/lol.cpp:486 +msgid "Turn Right" +msgstr "Xirar á dereita" + +#: engines/kyra/lol.cpp:487 +msgid "Rest" +msgstr "Parar" + +#: engines/kyra/lol.cpp:488 +msgid "Options" +msgstr "Opcións" + +#: engines/kyra/lol.cpp:489 +msgid "Choose Spell" +msgstr "Elixir feitizo" + +#: engines/kyra/sound_midi.cpp:475 +msgid "" +"You appear to be using a General MIDI device,\n" +"but your game only supports Roland MT32 MIDI.\n" +"We try to map the Roland MT32 instruments to\n" +"General MIDI ones. It is still possible that\n" +"some tracks sound incorrect." +msgstr "" +"Semella que estás a empregar un dispositivo,\n" +"de General MIDI, maix o xogo só e compatible con\n" +"Roland MT32 MIDI. Tentamos asignar os instrumentos\n" +"aos de General MIDI. No entanto, existe a posibilidade\n" +"de que algunhas pistas non soen correctamente." + +#: engines/queen/queen.cpp:59 +msgid "Alternative intro" +msgstr "Intro alternativa" + +#: engines/queen/queen.cpp:60 +msgid "Use an alternative game intro (CD version only)" +msgstr "Empregar unha introdución alternativa para o xogo (só versión en CD)" + +#: engines/sky/compact.cpp:130 +msgid "" +"Unable to find \"sky.cpt\" file!\n" +"Please download it from www.scummvm.org" +msgstr "" +"O ficheiro sky.cpt non se atopa!\n" +"Descárgao dende www.scummvm.org" + +#: engines/sky/compact.cpp:141 +msgid "" +"The \"sky.cpt\" file has an incorrect size.\n" +"Please (re)download it from www.scummvm.org" +msgstr "" +"O ficheiro sky.cpt ten un tamaño incorrecto.\n" +"Descárgao (de novo) dende www.scummvm.org" + +#: engines/sky/detection.cpp:44 +msgid "Floppy intro" +msgstr "Intro de disquete" + +#: engines/sky/detection.cpp:45 +msgid "Use the floppy version's intro (CD version only)" +msgstr "Empregar a introdución da versión en disquete (só versión en CD)" + +#: engines/sword1/animation.cpp:539 +#, c-format +msgid "PSX stream cutscene '%s' cannot be played in paletted mode" +msgstr "Non se pode reproducir a secuencia %s de PSX neste modo gráfico" + +#: engines/sword1/animation.cpp:560 engines/sword2/animation.cpp:455 +msgid "DXA cutscenes found but ScummVM has been built without zlib support" +msgstr "" +"Atopáronse secuencias de DXA. No entanto, esta versión de ScummVM non é " +"compatible con zlib" + +#: engines/sword1/animation.cpp:570 engines/sword2/animation.cpp:465 +msgid "MPEG2 cutscenes are no longer supported" +msgstr "Xa non hai compatibilidade coas secuencias en MPEG2" + +#: engines/sword1/animation.cpp:576 engines/sword2/animation.cpp:473 +#, c-format +msgid "Cutscene '%s' not found" +msgstr "Non se atopou a secuencia %s" + +#: engines/sword1/control.cpp:863 +msgid "" +"ScummVM found that you have old savefiles for Broken Sword 1 that should be " +"converted.\n" +"The old save game format is no longer supported, so you will not be able to " +"load your games if you don't convert them.\n" +"\n" +"Press OK to convert them now, otherwise you will be asked again the next " +"time you start the game.\n" +msgstr "" +"ScummVM atopou ficheiros de gardado vellos de Broken Sword 1 que deberían " +"ser convertidos.\n" +"O formato vello xa non é compatible, de xeito que non poderás cargar as " +"partidas se non os convertes.\n" +"\n" +"Preme Aceptar para convertilos. Se non, volverás ver esta mensaxe a próxima " +"vez que inicies o xogo.\n" + +#: engines/sword1/control.cpp:1232 +#, c-format +msgid "" +"Target new save game already exists!\n" +"Would you like to keep the old save game (%s) or the new one (%s)?\n" +msgstr "" +"Xa existe unha partida con ese nome!\n" +"Queres conservar a vella (%s) ou a nova (%s)?\n" + +#: engines/sword1/control.cpp:1235 +msgid "Keep the old one" +msgstr "Conservar a vella" + +#: engines/sword1/control.cpp:1235 +msgid "Keep the new one" +msgstr "Conservar a nova" + +#: engines/sword1/logic.cpp:1633 +msgid "This is the end of the Broken Sword 1 Demo" +msgstr "Aquí remata a demo de Broken Sword 1" + +#: engines/sword2/animation.cpp:435 +msgid "" +"PSX cutscenes found but ScummVM has been built without RGB color support" +msgstr "" +"Atopáronse secuencias de PSX. No entanto, a versión de ScummVM non é " +"compatible con cores RGB" + +#: engines/sword2/sword2.cpp:79 +msgid "Show object labels" +msgstr "Mostrar etiquetas" + +#: engines/sword2/sword2.cpp:80 +msgid "Show labels for objects on mouse hover" +msgstr "Mostrar as etiquetas dos obxectos ao apuntar co rato" + +#: engines/teenagent/resources.cpp:68 +msgid "" +"You're missing the 'teenagent.dat' file. Get it from the ScummVM website" +msgstr "" +"Falta o ficheiro teenagent.dat. Descárgao dende o sitio web de ScummVM." + +#: engines/teenagent/resources.cpp:89 +msgid "" +"The teenagent.dat file is compressed and zlib hasn't been included in this " +"executable. Please decompress it" +msgstr "" +"O ficheiro teenagent.dat está comprimido e zlib non foi incluído neste " +"executable. Descomprime o ficheiro" + +#: engines/parallaction/saveload.cpp:133 +#, c-format +msgid "" +"Can't save game in slot %i\n" +"\n" +msgstr "" +"Non se pode gardar a partida no espazo %i\n" +"\n" + +#: engines/parallaction/saveload.cpp:204 +msgid "Loading game..." +msgstr "Cargando..." + +#: engines/parallaction/saveload.cpp:219 +msgid "Saving game..." +msgstr "Gardando..." + +#: engines/parallaction/saveload.cpp:272 +msgid "" +"ScummVM found that you have old savefiles for Nippon Safes that should be " +"renamed.\n" +"The old names are no longer supported, so you will not be able to load your " +"games if you don't convert them.\n" +"\n" +"Press OK to convert them now, otherwise you will be asked next time.\n" +msgstr "" +"ScummVM atopou ficheiros de gardado vellos de Nippon Safes que deberían ser " +"renomeados.\n" +"Os nomes vellos xa non son compatibles, de xeito que non poderás cargar as " +"partidas se non os cambias.\n" +"\n" +"Preme Aceptar para cambialos. Se non, volverás ver esta mensaxe a próxima " +"vez que inicies o xogo.\n" + +#: engines/parallaction/saveload.cpp:319 +msgid "ScummVM successfully converted all your savefiles." +msgstr "ScummVM converteu correctamente todos os ficheiros de gardado." + +#: engines/parallaction/saveload.cpp:321 +msgid "" +"ScummVM printed some warnings in your console window and can't guarantee all " +"your files have been converted.\n" +"\n" +"Please report to the team." +msgstr "" +"ScummVM imprimiu avisos na ventá da consola. Non se pode garantir a " +"conversión de todos os ficheiros.\n" +"\n" +"Contacta co equipo de ScummVM." + +#: audio/fmopl.cpp:49 +msgid "MAME OPL emulator" +msgstr "Emulador de OPL de MAME" + +#: audio/fmopl.cpp:51 +msgid "DOSBox OPL emulator" +msgstr "Emulador de OPL de DOSBox" + +#: audio/mididrv.cpp:209 +#, c-format +msgid "" +"The selected audio device '%s' was not found (e.g. might be turned off or " +"disconnected)." +msgstr "" +"Non se atopou o dispositivo de son seleccionado (%s). Talvez estea apagado " +"ou desconectado." + +#: audio/mididrv.cpp:209 audio/mididrv.cpp:221 audio/mididrv.cpp:257 +#: audio/mididrv.cpp:272 +msgid "Attempting to fall back to the next available device..." +msgstr "Intentando pasar ao seguinte dispositivo dispoñible..." + +#: audio/mididrv.cpp:221 +#, c-format +msgid "" +"The selected audio device '%s' cannot be used. See log file for more " +"information." +msgstr "" +"Non se pode empregar o dispositivo de son seleccionado (%s). Consulta o " +"rexistro para obter máis información." + +#: audio/mididrv.cpp:257 +#, c-format +msgid "" +"The preferred audio device '%s' was not found (e.g. might be turned off or " +"disconnected)." +msgstr "" +"Non se atopou o dispositivo de son preferido (%s). Talvez estea apagado ou " +"desconectado." + +#: audio/mididrv.cpp:272 +#, c-format +msgid "" +"The preferred audio device '%s' cannot be used. See log file for more " +"information." +msgstr "" +"Non se pode empregar o dispositivo de son preferido (%s). Consulta o " +"rexistro para obter máis información." + +#: audio/null.h:43 +msgid "No music" +msgstr "Sen música" + +#: audio/mods/paula.cpp:189 +msgid "Amiga Audio Emulator" +msgstr "Emulador de Amiga Audio" + +#: audio/softsynth/adlib.cpp:1593 +msgid "AdLib Emulator" +msgstr "Emulador de AdLib" + +#: audio/softsynth/appleiigs.cpp:33 +msgid "Apple II GS Emulator (NOT IMPLEMENTED)" +msgstr "Emulador de Apple II GS (non implementado)" + +#: audio/softsynth/sid.cpp:1430 +msgid "C64 Audio Emulator" +msgstr "Emulador de C64 Audio" + +#: audio/softsynth/mt32.cpp:293 +msgid "Initializing MT-32 Emulator" +msgstr "Iniciando emulador de MT-32" + +#: audio/softsynth/mt32.cpp:512 +msgid "MT-32 Emulator" +msgstr "Emulador de MT-32" + +#: audio/softsynth/pcspk.cpp:139 +msgid "PC Speaker Emulator" +msgstr "Emulador de altofalante de PC" + +#: audio/softsynth/pcspk.cpp:158 +msgid "IBM PCjr Emulator" +msgstr "Emulador de IBM PCjr" + +#: backends/keymapper/remap-dialog.cpp:47 +msgid "Keymap:" +msgstr "Asignación de teclas:" + +#: backends/keymapper/remap-dialog.cpp:66 +msgid " (Effective)" +msgstr " (Efectiva)" + +#: backends/keymapper/remap-dialog.cpp:106 +msgid " (Active)" +msgstr " (Activa)" + +#: backends/keymapper/remap-dialog.cpp:106 +msgid " (Blocked)" +msgstr " (Bloqueada)" + +#: backends/keymapper/remap-dialog.cpp:119 +msgid " (Global)" +msgstr " (Global)" + +#: backends/keymapper/remap-dialog.cpp:127 +msgid " (Game)" +msgstr " (Xogo)" + +#: backends/midi/windows.cpp:164 +msgid "Windows MIDI" +msgstr "Windows MIDI" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:57 +msgid "ScummVM Main Menu" +msgstr "Menú principal de ScummVM" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:63 +msgid "~L~eft handed mode" +msgstr "Modo para ~z~urdos" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:64 +msgid "~I~ndy fight controls" +msgstr "Controis de combate de ~I~ndy" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:65 +msgid "Show mouse cursor" +msgstr "Mostrar cursor do rato" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:66 +msgid "Snap to edges" +msgstr "Axustar ás marxes" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:68 +msgid "Touch X Offset" +msgstr "Corrección táctil X" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:75 +msgid "Touch Y Offset" +msgstr "Corrección táctil Y" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:87 +msgid "Use laptop trackpad-style cursor control" +msgstr "Empregar control de cursor por trackpad" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:88 +msgid "Tap for left click, double tap right click" +msgstr "Tocar unha vez, premer co botón primario; dúas veces, botón secundario" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:90 +msgid "Sensitivity" +msgstr "Sensibilidade" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:99 +msgid "Initial top screen scale:" +msgstr "Escala da pantalla inicial:" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:105 +msgid "Main screen scaling:" +msgstr "Escala da pantalla principal:" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:107 +msgid "Hardware scale (fast, but low quality)" +msgstr "Escala por hardware (rápida, mais baixa calidade)" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:108 +msgid "Software scale (good quality, but slower)" +msgstr "Escala por software (boa calidade, mais lenta)" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:109 +msgid "Unscaled (you must scroll left and right)" +msgstr "Sen escala (deberás desprazar á esquerda e á dereita)" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:111 +msgid "Brightness:" +msgstr "Luminosidade:" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:121 +msgid "High quality audio (slower) (reboot)" +msgstr "Son de alta calidade (máis lento) (reiniciar)" + +#: backends/platform/ds/arm9/source/dsoptions.cpp:122 +msgid "Disable power off" +msgstr "Desactivar apagado" + +#: backends/platform/iphone/osys_events.cpp:300 +msgid "Mouse-click-and-drag mode enabled." +msgstr "Modo premer e arrastrar activado." + +#: backends/platform/iphone/osys_events.cpp:302 +msgid "Mouse-click-and-drag mode disabled." +msgstr "Modo premer e arrastrar desactivado." + +#: backends/platform/iphone/osys_events.cpp:313 +msgid "Touchpad mode enabled." +msgstr "Modo panel táctil activado." + +#: backends/platform/iphone/osys_events.cpp:315 +msgid "Touchpad mode disabled." +msgstr "Modo panel táctil desactivado." + +#: backends/platform/maemo/maemo.cpp:209 +msgid "Click Mode" +msgstr "Modo rato" + +#: backends/platform/maemo/maemo.cpp:215 +#: backends/platform/symbian/src/SymbianActions.cpp:42 +#: backends/platform/wince/CEActionsPocket.cpp:60 +#: backends/platform/wince/CEActionsSmartphone.cpp:43 +#: backends/platform/bada/form.cpp:281 +msgid "Left Click" +msgstr "Botón primario" + +#: backends/platform/maemo/maemo.cpp:218 +msgid "Middle Click" +msgstr "Botón central" + +#: backends/platform/maemo/maemo.cpp:221 +#: backends/platform/symbian/src/SymbianActions.cpp:43 +#: backends/platform/wince/CEActionsSmartphone.cpp:44 +#: backends/platform/bada/form.cpp:273 +msgid "Right Click" +msgstr "Botón secundario" + +#: backends/platform/sdl/macosx/appmenu_osx.mm:78 +msgid "Hide ScummVM" +msgstr "Ocultar ScummVM" + +#: backends/platform/sdl/macosx/appmenu_osx.mm:83 +msgid "Hide Others" +msgstr "Ocultar outros" + +#: backends/platform/sdl/macosx/appmenu_osx.mm:88 +msgid "Show All" +msgstr "Mostrar todo" + +#: backends/platform/sdl/macosx/appmenu_osx.mm:110 +#: backends/platform/sdl/macosx/appmenu_osx.mm:121 +msgid "Window" +msgstr "Ventá" + +#: backends/platform/sdl/macosx/appmenu_osx.mm:115 +msgid "Minimize" +msgstr "Minimizar" + +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:45 +msgid "Normal (no scaling)" +msgstr "Normal (sen escala)" + +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:64 +msgctxt "lowres" +msgid "Normal (no scaling)" +msgstr "Normal (sen escala)" + +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2135 +#: backends/graphics/openglsdl/openglsdl-graphics.cpp:533 +msgid "Enabled aspect ratio correction" +msgstr "Corrección de proporción activada" + +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2141 +#: backends/graphics/openglsdl/openglsdl-graphics.cpp:538 +msgid "Disabled aspect ratio correction" +msgstr "Corrección de proporción desactivada" + +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2196 +msgid "Active graphics filter:" +msgstr "Filtro de gráficos activo:" + +#: backends/graphics/surfacesdl/surfacesdl-graphics.cpp:2238 +#: backends/graphics/openglsdl/openglsdl-graphics.cpp:477 +msgid "Windowed mode" +msgstr "Modo en ventá" + +#: backends/graphics/opengl/opengl-graphics.cpp:135 +msgid "OpenGL Normal" +msgstr "OpenGL Normal" + +#: backends/graphics/opengl/opengl-graphics.cpp:136 +msgid "OpenGL Conserve" +msgstr "OpenGL Conserve" + +#: backends/graphics/opengl/opengl-graphics.cpp:137 +msgid "OpenGL Original" +msgstr "OpenGL Original" + +#: backends/graphics/openglsdl/openglsdl-graphics.cpp:415 +msgid "Current display mode" +msgstr "Modo de visualización actual" + +#: backends/graphics/openglsdl/openglsdl-graphics.cpp:428 +msgid "Current scale" +msgstr "Escala actual" + +#: backends/graphics/openglsdl/openglsdl-graphics.cpp:558 +msgid "Active filter mode: Linear" +msgstr "Modo de filtro activo: lineal" + +#: backends/graphics/openglsdl/openglsdl-graphics.cpp:560 +msgid "Active filter mode: Nearest" +msgstr "Modo de filtro activo: máis próximo" + +#: backends/platform/symbian/src/SymbianActions.cpp:38 +#: backends/platform/wince/CEActionsSmartphone.cpp:39 +msgid "Up" +msgstr "Arriba" + +#: backends/platform/symbian/src/SymbianActions.cpp:39 +#: backends/platform/wince/CEActionsSmartphone.cpp:40 +msgid "Down" +msgstr "Abaixo" + +#: backends/platform/symbian/src/SymbianActions.cpp:40 +#: backends/platform/wince/CEActionsSmartphone.cpp:41 +msgid "Left" +msgstr "Esquerda" + +#: backends/platform/symbian/src/SymbianActions.cpp:41 +#: backends/platform/wince/CEActionsSmartphone.cpp:42 +msgid "Right" +msgstr "Dereita" + +#: backends/platform/symbian/src/SymbianActions.cpp:46 +#: backends/platform/wince/CEActionsSmartphone.cpp:47 +msgid "Zone" +msgstr "Zona" + +#: backends/platform/symbian/src/SymbianActions.cpp:47 +#: backends/platform/wince/CEActionsPocket.cpp:54 +#: backends/platform/wince/CEActionsSmartphone.cpp:48 +msgid "Multi Function" +msgstr "Multifunción" + +#: backends/platform/symbian/src/SymbianActions.cpp:48 +msgid "Swap character" +msgstr "Cambiar carácter" + +#: backends/platform/symbian/src/SymbianActions.cpp:49 +msgid "Skip text" +msgstr "Omitir texto" + +#: backends/platform/symbian/src/SymbianActions.cpp:51 +msgid "Fast mode" +msgstr "Modo rápido" + +#: backends/platform/symbian/src/SymbianActions.cpp:53 +msgid "Debugger" +msgstr "Depurador" + +#: backends/platform/symbian/src/SymbianActions.cpp:54 +msgid "Global menu" +msgstr "Menú global" + +#: backends/platform/symbian/src/SymbianActions.cpp:55 +msgid "Virtual keyboard" +msgstr "Teclado virtual" + +#: backends/platform/symbian/src/SymbianActions.cpp:56 +msgid "Key mapper" +msgstr "Asignador de teclas" + +#: backends/events/symbiansdl/symbiansdl-events.cpp:184 +msgid "Do you want to quit ?" +msgstr "Queres saír?" + +#: backends/platform/wii/options.cpp:51 +msgid "Video" +msgstr "Vídeo" + +#: backends/platform/wii/options.cpp:54 +msgid "Current video mode:" +msgstr "Modo de vídeo actual:" + +#: backends/platform/wii/options.cpp:56 +msgid "Double-strike" +msgstr "Dobre" + +#: backends/platform/wii/options.cpp:60 +msgid "Horizontal underscan:" +msgstr "Marxe horizontal:" + +#: backends/platform/wii/options.cpp:66 +msgid "Vertical underscan:" +msgstr "Marxe vertical:" + +#: backends/platform/wii/options.cpp:71 +msgid "Input" +msgstr "Entrada" + +#: backends/platform/wii/options.cpp:74 +msgid "GC Pad sensitivity:" +msgstr "Sensibilidade do mando de GC:" + +#: backends/platform/wii/options.cpp:80 +msgid "GC Pad acceleration:" +msgstr "Aceleración do mando de GC:" + +#: backends/platform/wii/options.cpp:86 +msgid "DVD" +msgstr "DVD" + +#: backends/platform/wii/options.cpp:89 backends/platform/wii/options.cpp:101 +msgid "Status:" +msgstr "Estado:" + +#: backends/platform/wii/options.cpp:90 backends/platform/wii/options.cpp:102 +msgid "Unknown" +msgstr "Descoñecido" + +#: backends/platform/wii/options.cpp:93 +msgid "Mount DVD" +msgstr "Montar DVD" + +#: backends/platform/wii/options.cpp:94 +msgid "Unmount DVD" +msgstr "Desmontar DVD" + +#: backends/platform/wii/options.cpp:98 +msgid "SMB" +msgstr "SMB" + +#: backends/platform/wii/options.cpp:106 +msgid "Server:" +msgstr "Servidor:" + +#: backends/platform/wii/options.cpp:110 +msgid "Share:" +msgstr "Disco compartido:" + +#: backends/platform/wii/options.cpp:114 +msgid "Username:" +msgstr "Nome de usuario:" + +#: backends/platform/wii/options.cpp:118 +msgid "Password:" +msgstr "Contrasinal:" + +#: backends/platform/wii/options.cpp:121 +msgid "Init network" +msgstr "Conectar á rede" + +#: backends/platform/wii/options.cpp:123 +msgid "Mount SMB" +msgstr "Montar SMB" + +#: backends/platform/wii/options.cpp:124 +msgid "Unmount SMB" +msgstr "Desmontar SMB" + +#: backends/platform/wii/options.cpp:143 +msgid "DVD Mounted successfully" +msgstr "DVD montado con éxito" + +#: backends/platform/wii/options.cpp:146 +msgid "Error while mounting the DVD" +msgstr "Erro ao montar o DVD" + +#: backends/platform/wii/options.cpp:148 +msgid "DVD not mounted" +msgstr "DVD non montado" + +#: backends/platform/wii/options.cpp:161 +msgid "Network up, share mounted" +msgstr "Conexión á rede, disco montado" + +#: backends/platform/wii/options.cpp:163 +msgid "Network up" +msgstr "Conexión á rede" + +#: backends/platform/wii/options.cpp:166 +msgid ", error while mounting the share" +msgstr ", erro ao montar o disco" + +#: backends/platform/wii/options.cpp:168 +msgid ", share not mounted" +msgstr ", disco non montado" + +#: backends/platform/wii/options.cpp:174 +msgid "Network down" +msgstr "Non hai conexión á rede" + +#: backends/platform/wii/options.cpp:178 +msgid "Initializing network" +msgstr "Conectando á rede" + +#: backends/platform/wii/options.cpp:182 +msgid "Timeout while initializing network" +msgstr "Tempo de espera esgotado" + +#: backends/platform/wii/options.cpp:186 +#, c-format +msgid "Network not initialized (%d)" +msgstr "Erro de conexión á rede (%d)" + +#: backends/platform/wince/CEActionsPocket.cpp:46 +msgid "Hide Toolbar" +msgstr "Ocultar barra de ferramentas" + +#: backends/platform/wince/CEActionsPocket.cpp:47 +msgid "Show Keyboard" +msgstr "Mostrar teclado" + +#: backends/platform/wince/CEActionsPocket.cpp:48 +msgid "Sound on/off" +msgstr "Son si/non" + +#: backends/platform/wince/CEActionsPocket.cpp:49 +msgid "Right click" +msgstr "Botón secundario" + +#: backends/platform/wince/CEActionsPocket.cpp:50 +msgid "Show/Hide Cursor" +msgstr "Mostrar/ocultar cursor" + +#: backends/platform/wince/CEActionsPocket.cpp:51 +msgid "Free look" +msgstr "Vista libre" + +#: backends/platform/wince/CEActionsPocket.cpp:52 +msgid "Zoom up" +msgstr "Ampliar" + +#: backends/platform/wince/CEActionsPocket.cpp:53 +msgid "Zoom down" +msgstr "Reducir" + +#: backends/platform/wince/CEActionsPocket.cpp:55 +#: backends/platform/wince/CEActionsSmartphone.cpp:49 +msgid "Bind Keys" +msgstr "Vincular teclas" + +#: backends/platform/wince/CEActionsPocket.cpp:56 +msgid "Cursor Up" +msgstr "Arriba" + +#: backends/platform/wince/CEActionsPocket.cpp:57 +msgid "Cursor Down" +msgstr "Abaixo" + +#: backends/platform/wince/CEActionsPocket.cpp:58 +msgid "Cursor Left" +msgstr "Esquerda" + +#: backends/platform/wince/CEActionsPocket.cpp:59 +msgid "Cursor Right" +msgstr "Dereita" + +#: backends/platform/wince/CEActionsPocket.cpp:267 +#: backends/platform/wince/CEActionsSmartphone.cpp:231 +msgid "Do you want to load or save the game?" +msgstr "Queres cargar ou gardar a partida?" + +#: backends/platform/wince/CEActionsPocket.cpp:326 +#: backends/platform/wince/CEActionsSmartphone.cpp:287 +msgid " Are you sure you want to quit ? " +msgstr " Seguro que queres saír?" + +#: backends/platform/wince/CEActionsSmartphone.cpp:50 +msgid "Keyboard" +msgstr "Teclado" + +#: backends/platform/wince/CEActionsSmartphone.cpp:51 +msgid "Rotate" +msgstr "Rotar" + +#: backends/platform/wince/CELauncherDialog.cpp:56 +msgid "Using SDL driver " +msgstr "Empregando driver de SDL" + +#: backends/platform/wince/CELauncherDialog.cpp:60 +msgid "Display " +msgstr "Pantalla" + +#: backends/platform/wince/CELauncherDialog.cpp:83 +msgid "Do you want to perform an automatic scan ?" +msgstr "Queres realizar unha análise automática?" + +#: backends/platform/wince/wince-sdl.cpp:515 +msgid "Map right click action" +msgstr "Asignar acción de botón secundario" + +#: backends/platform/wince/wince-sdl.cpp:519 +msgid "You must map a key to the 'Right Click' action to play this game" +msgstr "" +"Debes asignar unha tecla á acción do botón secundario do rato para xogar" + +#: backends/platform/wince/wince-sdl.cpp:528 +msgid "Map hide toolbar action" +msgstr "Asignar acción Ocultar barra de ferramentas" + +#: backends/platform/wince/wince-sdl.cpp:532 +msgid "You must map a key to the 'Hide toolbar' action to play this game" +msgstr "" +"Debes asignar unha tecla á acción Ocultar barra de ferramentas para xogar" + +#: backends/platform/wince/wince-sdl.cpp:541 +msgid "Map Zoom Up action (optional)" +msgstr "Asignar acción de Ampliar (opcional)" + +#: backends/platform/wince/wince-sdl.cpp:544 +msgid "Map Zoom Down action (optional)" +msgstr "Asignar acción de Reducir (opcional)" + +#: backends/platform/wince/wince-sdl.cpp:552 +msgid "" +"Don't forget to map a key to 'Hide Toolbar' action to see the whole inventory" +msgstr "" +"Non esquezas asignar unha tecla á acción Ocultar barra de ferramentas para " +"ver o inventario completo" + +#: backends/events/default/default-events.cpp:191 +msgid "Do you really want to return to the Launcher?" +msgstr "Seguro que queres volver ao Iniciador?" + +#: backends/events/default/default-events.cpp:191 +msgid "Launcher" +msgstr "Iniciador" + +#: backends/events/default/default-events.cpp:213 +msgid "Do you really want to quit?" +msgstr "Seguro que queres saír?" + +#: backends/events/gph/gph-events.cpp:386 +#: backends/events/gph/gph-events.cpp:429 +#: backends/events/openpandora/op-events.cpp:139 +msgid "Touchscreen 'Tap Mode' - Left Click" +msgstr "Modo pantalla táctil: premer botón primario" + +#: backends/events/gph/gph-events.cpp:388 +#: backends/events/gph/gph-events.cpp:431 +#: backends/events/openpandora/op-events.cpp:141 +msgid "Touchscreen 'Tap Mode' - Right Click" +msgstr "Modo pantalla táctil: premer botón secundario" + +#: backends/events/gph/gph-events.cpp:390 +#: backends/events/gph/gph-events.cpp:433 +#: backends/events/openpandora/op-events.cpp:143 +msgid "Touchscreen 'Tap Mode' - Hover (No Click)" +msgstr "Modo pantalla táctil: apuntar co rato" + +#: backends/events/gph/gph-events.cpp:410 +msgid "Maximum Volume" +msgstr "Volume máximo" + +#: backends/events/gph/gph-events.cpp:412 +msgid "Increasing Volume" +msgstr "Subindo volume" + +#: backends/events/gph/gph-events.cpp:418 +msgid "Minimal Volume" +msgstr "Volume mínimo" + +#: backends/events/gph/gph-events.cpp:420 +msgid "Decreasing Volume" +msgstr "Baixando volume" + +#: backends/updates/macosx/macosx-updates.mm:65 +msgid "Check for Updates..." +msgstr "Buscar actualizacións..." + +#: backends/platform/bada/form.cpp:269 +msgid "Right Click Once" +msgstr "Botón secundario unha vez" + +#: backends/platform/bada/form.cpp:277 +msgid "Move Only" +msgstr "Mover unicamente" + +#: backends/platform/bada/form.cpp:291 +msgid "Escape Key" +msgstr "ESC" + +#: backends/platform/bada/form.cpp:296 +msgid "Game Menu" +msgstr "Menú do xogo" + +#: backends/platform/bada/form.cpp:301 +msgid "Show Keypad" +msgstr "Mostrar teclado numérico" + +#: backends/platform/bada/form.cpp:309 +msgid "Control Mouse" +msgstr "Rato" + +#: backends/events/maemosdl/maemosdl-events.cpp:192 +msgid "Clicking Enabled" +msgstr "Premer activado" + +#: backends/events/maemosdl/maemosdl-events.cpp:192 +msgid "Clicking Disabled" +msgstr "Premer desactivado" diff --git a/po/hu_HU.po b/po/hu_HU.po index a34138c1bf..b263d2c539 100644 --- a/po/hu_HU.po +++ b/po/hu_HU.po @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: ScummVM 1.3.0svn\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" "POT-Creation-Date: 2012-08-12 14:57+0200\n" -"PO-Revision-Date: 2012-07-09 05:58+0100\n" +"PO-Revision-Date: 2012-08-14 07:29+0100\n" "Last-Translator: George Kormendi <grubycza@hotmail.com>\n" "Language-Team: Hungarian\n" "Language: Magyar\n" @@ -921,11 +921,11 @@ msgstr "" #: gui/saveload-dialog.cpp:158 msgid "List view" -msgstr "" +msgstr "Lista nézet" #: gui/saveload-dialog.cpp:159 msgid "Grid view" -msgstr "" +msgstr "Rács nézet" #: gui/saveload-dialog.cpp:202 gui/saveload-dialog.cpp:350 msgid "No date saved" @@ -965,31 +965,28 @@ msgstr "Névtelen játékállás" #: gui/saveload-dialog.cpp:517 msgid "Next" -msgstr "" +msgstr "Következõ" #: gui/saveload-dialog.cpp:520 msgid "Prev" -msgstr "" +msgstr "Elõzõ" #: gui/saveload-dialog.cpp:684 -#, fuzzy msgid "New Save" -msgstr "Mentés" +msgstr "Új Mentés" #: gui/saveload-dialog.cpp:684 -#, fuzzy msgid "Create a new save game" -msgstr "Játék mentés nem sikerült" +msgstr "Új játékmentés készítése" #: gui/saveload-dialog.cpp:789 -#, fuzzy msgid "Name: " msgstr "Név:" #: gui/saveload-dialog.cpp:861 #, c-format msgid "Enter a description for slot %d:" -msgstr "" +msgstr "Adj meg egy leírást a %d slothoz:" #: gui/themebrowser.cpp:44 msgid "Select a Theme" @@ -2230,12 +2227,11 @@ msgstr "" #: engines/queen/queen.cpp:59 msgid "Alternative intro" -msgstr "" +msgstr "Alternatív intro" #: engines/queen/queen.cpp:60 -#, fuzzy msgid "Use an alternative game intro (CD version only)" -msgstr "A floppy verzió intro használata (csak CD verziónál)" +msgstr "Alternatív játékintro használata (csak CD verziónál)" #: engines/sky/compact.cpp:130 msgid "" @@ -2336,13 +2332,15 @@ msgstr "Tárgycimke látható ha az egér felette van" #: engines/teenagent/resources.cpp:68 msgid "" "You're missing the 'teenagent.dat' file. Get it from the ScummVM website" -msgstr "" +msgstr "Hiányzik a 'teenagent.dat' fájl. Szerezd be a ScummVM website-ról" #: engines/teenagent/resources.cpp:89 msgid "" "The teenagent.dat file is compressed and zlib hasn't been included in this " "executable. Please decompress it" msgstr "" +"A teenagent.dat fájl tömörített és a zlib nem része ennek a futtatható " +"állománynak. Kérlek tömörítsd ki" #: engines/parallaction/saveload.cpp:133 #, c-format diff --git a/po/pl_PL.po b/po/pl_PL.po index c2c5c09e19..1bf44d1a66 100644 --- a/po/pl_PL.po +++ b/po/pl_PL.po @@ -1,14 +1,14 @@ # Polish translation for ScummVM. # Copyright (C) 2010-2012 ScummVM Team # This file is distributed under the same license as the ScummVM package. -# Grajpopolsku.pl <grajpopolsku@gmail.com>, 2011. +# Grajpopolsku.pl <grajpopolsku@gmail.com>, 2011-2012. # msgid "" msgstr "" "Project-Id-Version: ScummVM 1.3.0\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" "POT-Creation-Date: 2012-08-12 14:57+0200\n" -"PO-Revision-Date: 2011-10-24 21:14+0100\n" +"PO-Revision-Date: 2012-07-29 15:49+0100\n" "Last-Translator: Micha³ Zi±bkowski <mziab@o2.pl>\n" "Language-Team: Grajpopolsku.pl <grajpopolsku@gmail.com>\n" "Language: Polski\n" @@ -82,7 +82,6 @@ msgid "Remap keys" msgstr "Dostosuj klawisze" #: gui/gui-manager.cpp:129 base/main.cpp:307 -#, fuzzy msgid "Toggle FullScreen" msgstr "W³±cz/wy³±cz pe³ny ekran" @@ -196,9 +195,8 @@ msgid "Platform:" msgstr "Platforma:" #: gui/launcher.cpp:231 -#, fuzzy msgid "Engine" -msgstr "Zbadaj" +msgstr "Silnik" #: gui/launcher.cpp:239 gui/options.cpp:1062 gui/options.cpp:1079 msgid "Graphics" @@ -1197,19 +1195,18 @@ msgstr "" "sprawd¼ plik README." #: engines/dialogs.cpp:228 -#, fuzzy, c-format +#, c-format msgid "" "Gamestate save failed (%s)! Please consult the README for basic information, " "and for instructions on how to obtain further assistance." msgstr "" -"Przepraszamy, ten silnik obecnie nie oferuje pomocy wewn±trz gry. Aby " -"uzyskaæ podstawowe informacje oraz dowiedzieæ jak szukaæ dalszej pomocy, " -"sprawd¼ plik README." +"Zapis stanu gry nie powiód³ siê (%s)! Aby uzyskaæ podstawowe informacje oraz " +"dowiedzieæ jak szukaæ dalszej pomocy, sprawd¼ plik README." #: engines/dialogs.cpp:301 engines/mohawk/dialogs.cpp:109 #: engines/mohawk/dialogs.cpp:174 msgid "~O~K" -msgstr "~O~K" +msgstr "" #: engines/dialogs.cpp:302 engines/mohawk/dialogs.cpp:110 #: engines/mohawk/dialogs.cpp:175 @@ -1261,14 +1258,13 @@ msgstr "" "Dalsze informacje s± dostêpne w pliku README." #: engines/engine.cpp:426 -#, fuzzy, c-format +#, c-format msgid "" "Gamestate load failed (%s)! Please consult the README for basic information, " "and for instructions on how to obtain further assistance." msgstr "" -"Przepraszamy, ten silnik obecnie nie oferuje pomocy wewn±trz gry. Aby " -"uzyskaæ podstawowe informacje oraz dowiedzieæ jak szukaæ dalszej pomocy, " -"sprawd¼ plik README." +"Odczyt stanu gry nie powiód³ siê (%s)! Aby uzyskaæ podstawowe informacje " +"oraz dowiedzieæ jak szukaæ dalszej pomocy, sprawd¼ plik README." #: engines/engine.cpp:439 msgid "" @@ -1287,12 +1283,12 @@ msgstr "W³±cz mimo tego" #: engines/agi/detection.cpp:145 engines/dreamweb/detection.cpp:47 #: engines/sci/detection.cpp:390 msgid "Use original save/load screens" -msgstr "" +msgstr "U¿yj oryginalnych ekranów odczytu/zapisu" #: engines/agi/detection.cpp:146 engines/dreamweb/detection.cpp:48 #: engines/sci/detection.cpp:391 msgid "Use the original save/load screens, instead of the ScummVM ones" -msgstr "" +msgstr "U¿yj oryginalnych ekranów odczytu/zapisu zamiast tych ze ScummVM" #: engines/agi/saveload.cpp:816 engines/sci/engine/kfile.cpp:838 msgid "Restore game:" @@ -1303,68 +1299,68 @@ msgid "Restore" msgstr "Wznów" #: engines/dreamweb/detection.cpp:57 -#, fuzzy msgid "Use bright palette mode" -msgstr "Przedmiot u góry, z prawej" +msgstr "U¿yj trybu jasnej palety" #: engines/dreamweb/detection.cpp:58 msgid "Display graphics using the game's bright palette" -msgstr "" +msgstr "Wy¶wietlaj grafikê za pomoc± jasnej palety gry" #: engines/sci/detection.cpp:370 msgid "EGA undithering" msgstr "Anty-dithering EGA" #: engines/sci/detection.cpp:371 -#, fuzzy msgid "Enable undithering in EGA games" msgstr "W³±cz anty-dithering we wspieranych grach EGA" #: engines/sci/detection.cpp:380 -#, fuzzy msgid "Prefer digital sound effects" -msgstr "G³o¶no¶æ efektów d¼w." +msgstr "Preferuj cyfrowe efekty d¼wiêkowe" #: engines/sci/detection.cpp:381 msgid "Prefer digital sound effects instead of synthesized ones" -msgstr "" +msgstr "Preferuj cyfrowe efekty d¼wiêkowe zamiast syntezowanych" #: engines/sci/detection.cpp:400 msgid "Use IMF/Yamaha FB-01 for MIDI output" -msgstr "" +msgstr "U¿yj IMF/Yamaha FB-01 dla wyj¶cia MIDI" #: engines/sci/detection.cpp:401 msgid "" "Use an IBM Music Feature card or a Yamaha FB-01 FM synth module for MIDI " "output" msgstr "" +"U¿yj karty IBM Music Feature lub modu³u syntezy FM Yamaha FB-01 dla wyj¶cia " +"MIDI" #: engines/sci/detection.cpp:411 msgid "Use CD audio" -msgstr "" +msgstr "U¿yj CD audio" #: engines/sci/detection.cpp:412 msgid "Use CD audio instead of in-game audio, if available" -msgstr "" +msgstr "U¿yj CD audio zamiast muzyki w grze, je¶li jest dostêpne" #: engines/sci/detection.cpp:422 msgid "Use Windows cursors" -msgstr "" +msgstr "U¿yj windowsowych kursorów" #: engines/sci/detection.cpp:423 msgid "" "Use the Windows cursors (smaller and monochrome) instead of the DOS ones" msgstr "" +"U¿yj windowsowych kursorów (mniejsze i monochromatyczne) zamiast DOS-owych" #: engines/sci/detection.cpp:433 -#, fuzzy msgid "Use silver cursors" -msgstr "Zwyk³y kursor" +msgstr "U¿yj srebrnych kursorów" #: engines/sci/detection.cpp:434 msgid "" "Use the alternate set of silver cursors, instead of the normal golden ones" msgstr "" +"U¿yj alternatywnego zestawu srebrnych kursorów zamiast zwyk³ych z³otych" #: engines/scumm/dialogs.cpp:175 #, c-format @@ -1482,24 +1478,23 @@ msgstr "Mowa i napisy" #: engines/scumm/dialogs.cpp:653 msgid "Select a Proficiency Level." -msgstr "" +msgstr "Wybierz poziom umiejêtno¶ci." #: engines/scumm/dialogs.cpp:655 msgid "Refer to your Loom(TM) manual for help." -msgstr "" +msgstr "Pomocy szukaj w instrukcji do³±czonej do Loom(TM)." #: engines/scumm/dialogs.cpp:658 -#, fuzzy msgid "Standard" -msgstr "Standardowy (16bpp)" +msgstr "Standardowy" #: engines/scumm/dialogs.cpp:659 msgid "Practice" -msgstr "" +msgstr "Trening" #: engines/scumm/dialogs.cpp:660 msgid "Expert" -msgstr "" +msgstr "Ekspert" #: engines/scumm/help.cpp:73 msgid "Common keyboard commands:" @@ -2118,118 +2113,109 @@ msgstr "Nie uda³o siê zapisaæ stanu gry" #. Malcolm makes a joke. #: engines/kyra/detection.cpp:62 msgid "Studio audience" -msgstr "" +msgstr "Publiczno¶æ studyjna" #: engines/kyra/detection.cpp:63 msgid "Enable studio audience" -msgstr "" +msgstr "W³±cz publiczno¶æ studyjn±" #. I18N: This option allows the user to skip text and cutscenes. #: engines/kyra/detection.cpp:73 msgid "Skip support" -msgstr "" +msgstr "Obs³uga pomijania" #: engines/kyra/detection.cpp:74 msgid "Allow text and cutscenes to be skipped" -msgstr "" +msgstr "Pozwól pomijaæ tekst i przerywniki" #. I18N: Helium mode makes people sound like they've inhaled Helium. #: engines/kyra/detection.cpp:84 msgid "Helium mode" -msgstr "" +msgstr "Tryb helowy" #: engines/kyra/detection.cpp:85 -#, fuzzy msgid "Enable helium mode" -msgstr "W³±cz tryb Roland GS" +msgstr "W³±cz tryb helowy" #. I18N: When enabled, this option makes scrolling smoother when #. changing from one screen to another. #: engines/kyra/detection.cpp:99 msgid "Smooth scrolling" -msgstr "" +msgstr "P³ynne przewijanie" #: engines/kyra/detection.cpp:100 msgid "Enable smooth scrolling when walking" -msgstr "" +msgstr "W³±cz p³ynne przewijanie przy chodzeniu" #. I18N: When enabled, this option changes the cursor when it floats to the #. edge of the screen to a directional arrow. The player can then click to #. walk towards that direction. #: engines/kyra/detection.cpp:112 -#, fuzzy msgid "Floating cursors" -msgstr "Zwyk³y kursor" +msgstr "P³ywaj±ce kursory" #: engines/kyra/detection.cpp:113 msgid "Enable floating cursors" -msgstr "" +msgstr "W³±cz p³ywaj±ce kursory" #. I18N: HP stands for Hit Points #: engines/kyra/detection.cpp:127 msgid "HP bar graphs" -msgstr "" +msgstr "Histogramy HP" #: engines/kyra/detection.cpp:128 msgid "Enable hit point bar graphs" -msgstr "" +msgstr "W³±cz histogramy punktów ¿ycia" #: engines/kyra/lol.cpp:478 msgid "Attack 1" -msgstr "" +msgstr "Atak 1" #: engines/kyra/lol.cpp:479 msgid "Attack 2" -msgstr "" +msgstr "Atak 2" #: engines/kyra/lol.cpp:480 msgid "Attack 3" -msgstr "" +msgstr "Atak 3" #: engines/kyra/lol.cpp:481 msgid "Move Forward" -msgstr "" +msgstr "Ruch naprzód" #: engines/kyra/lol.cpp:482 msgid "Move Back" -msgstr "" +msgstr "Ruch wstecz" #: engines/kyra/lol.cpp:483 msgid "Slide Left" -msgstr "" +msgstr "¦lizg w lewo" #: engines/kyra/lol.cpp:484 -#, fuzzy msgid "Slide Right" -msgstr "W prawo" +msgstr "¦lizg w prawo" #: engines/kyra/lol.cpp:485 -#, fuzzy msgid "Turn Left" -msgstr "Wy³±cz" +msgstr "Obrót w lewo" #: engines/kyra/lol.cpp:486 -#, fuzzy msgid "Turn Right" -msgstr "Kursor w prawo" +msgstr "Obrót w prawo" #: engines/kyra/lol.cpp:487 -#, fuzzy msgid "Rest" -msgstr "Wznów" +msgstr "Odpoczynek" #: engines/kyra/lol.cpp:488 -#, fuzzy msgid "Options" -msgstr "~O~pcje" +msgstr "Opcje" #: engines/kyra/lol.cpp:489 -#, fuzzy msgid "Choose Spell" -msgstr "Wybierz" +msgstr "Wybierz zaklêcie" #: engines/kyra/sound_midi.cpp:475 -#, fuzzy msgid "" "You appear to be using a General MIDI device,\n" "but your game only supports Roland MT32 MIDI.\n" @@ -2247,8 +2233,9 @@ msgid "Alternative intro" msgstr "" #: engines/queen/queen.cpp:60 +#, fuzzy msgid "Use an alternative game intro (CD version only)" -msgstr "" +msgstr "U¿yj intra z wersji dyskietkowej (tylko dla wersji CD)" #: engines/sky/compact.cpp:130 msgid "" @@ -2268,16 +2255,18 @@ msgstr "" #: engines/sky/detection.cpp:44 msgid "Floppy intro" -msgstr "" +msgstr "Intro z wersji dyskietkowej" #: engines/sky/detection.cpp:45 msgid "Use the floppy version's intro (CD version only)" -msgstr "" +msgstr "U¿yj intra z wersji dyskietkowej (tylko dla wersji CD)" #: engines/sword1/animation.cpp:539 #, c-format msgid "PSX stream cutscene '%s' cannot be played in paletted mode" msgstr "" +"Przerywnik w formacie strumieniowym PSX '%s' nie mo¿e zostaæ odtworzony w " +"trybie indeksowanym" #: engines/sword1/animation.cpp:560 engines/sword2/animation.cpp:455 msgid "DXA cutscenes found but ScummVM has been built without zlib support" @@ -2334,20 +2323,19 @@ msgid "This is the end of the Broken Sword 1 Demo" msgstr "To koniec dema Broken Sword 1" #: engines/sword2/animation.cpp:435 -#, fuzzy msgid "" "PSX cutscenes found but ScummVM has been built without RGB color support" msgstr "" -"Znaleziono przerywniki w formacie DXA, ale ScummVM jest skompilowany bez " -"obs³ugi zlib" +"Znaleziono przerywniki PSX, ale ScummVM jest skompilowany bez obs³ugi trybu " +"RGB" #: engines/sword2/sword2.cpp:79 msgid "Show object labels" -msgstr "" +msgstr "Poka¿ etykiety obiektów" #: engines/sword2/sword2.cpp:80 msgid "Show labels for objects on mouse hover" -msgstr "" +msgstr "Poka¿ etykiety obiektów przy najechaniu myszk±" #: engines/teenagent/resources.cpp:68 msgid "" @@ -2499,9 +2487,8 @@ msgid "Keymap:" msgstr "Klawisze:" #: backends/keymapper/remap-dialog.cpp:66 -#, fuzzy msgid " (Effective)" -msgstr " (Aktywny)" +msgstr " (Dzia³a)" #: backends/keymapper/remap-dialog.cpp:106 msgid " (Active)" @@ -2509,7 +2496,7 @@ msgstr " (Aktywny)" #: backends/keymapper/remap-dialog.cpp:106 msgid " (Blocked)" -msgstr "" +msgstr " (Zablokowany)" #: backends/keymapper/remap-dialog.cpp:119 msgid " (Global)" @@ -2613,7 +2600,7 @@ msgstr "Tryb touchpada wy³±czony." #: backends/platform/maemo/maemo.cpp:209 msgid "Click Mode" -msgstr "" +msgstr "Tryb klikania" #: backends/platform/maemo/maemo.cpp:215 #: backends/platform/symbian/src/SymbianActions.cpp:42 @@ -2624,9 +2611,8 @@ msgid "Left Click" msgstr "Klikniêcie LPM" #: backends/platform/maemo/maemo.cpp:218 -#, fuzzy msgid "Middle Click" -msgstr "Przedmiot na ¶rodku, z lewej" +msgstr "¦rodkowy przycisk" #: backends/platform/maemo/maemo.cpp:221 #: backends/platform/symbian/src/SymbianActions.cpp:43 @@ -96,6 +96,12 @@ ifdef USE_FLAC OSX_STATIC_LIBS += $(STATICLIBPATH)/lib/libFLAC.a endif +ifdef USE_FLUIDSYNTH +OSX_STATIC_LIBS += \ + -framework CoreAudio \ + $(STATICLIBPATH)/lib/libfluidsynth.a +endif + ifdef USE_MAD OSX_STATIC_LIBS += $(STATICLIBPATH)/lib/libmad.a endif diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index 2ea7e8d90e..0d51f5b130 100644 --- a/video/avi_decoder.cpp +++ b/video/avi_decoder.cpp @@ -42,106 +42,128 @@ namespace Video { -/* +#define UNKNOWN_HEADER(a) error("Unknown header found -- \'%s\'", tag2str(a)) + +// IDs used throughout the AVI files +// that will be handled by this player +#define ID_RIFF MKTAG('R','I','F','F') +#define ID_AVI MKTAG('A','V','I',' ') +#define ID_LIST MKTAG('L','I','S','T') +#define ID_HDRL MKTAG('h','d','r','l') +#define ID_AVIH MKTAG('a','v','i','h') +#define ID_STRL MKTAG('s','t','r','l') +#define ID_STRH MKTAG('s','t','r','h') +#define ID_VIDS MKTAG('v','i','d','s') +#define ID_AUDS MKTAG('a','u','d','s') +#define ID_MIDS MKTAG('m','i','d','s') +#define ID_TXTS MKTAG('t','x','t','s') +#define ID_JUNK MKTAG('J','U','N','K') +#define ID_STRF MKTAG('s','t','r','f') +#define ID_MOVI MKTAG('m','o','v','i') +#define ID_REC MKTAG('r','e','c',' ') +#define ID_VEDT MKTAG('v','e','d','t') +#define ID_IDX1 MKTAG('i','d','x','1') +#define ID_STRD MKTAG('s','t','r','d') +#define ID_00AM MKTAG('0','0','A','M') +//#define ID_INFO MKTAG('I','N','F','O') + +// Codec tags +#define ID_RLE MKTAG('R','L','E',' ') +#define ID_CRAM MKTAG('C','R','A','M') +#define ID_MSVC MKTAG('m','s','v','c') +#define ID_WHAM MKTAG('W','H','A','M') +#define ID_CVID MKTAG('c','v','i','d') +#define ID_IV32 MKTAG('i','v','3','2') +#define ID_DUCK MKTAG('D','U','C','K') + static byte char2num(char c) { - return (c >= 48 && c <= 57) ? c - 48 : 0; + c = tolower((byte)c); + return (c >= 'a' && c <= 'f') ? c - 'a' + 10 : c - '0'; } -static byte getStreamNum(uint32 tag) { - return char2num((char)(tag >> 24)) * 16 + char2num((char)(tag >> 16)); +static byte getStreamIndex(uint32 tag) { + return char2num((tag >> 24) & 0xFF) << 4 | char2num((tag >> 16) & 0xFF); } -*/ static uint16 getStreamType(uint32 tag) { return tag & 0xffff; } -AviDecoder::AviDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : _mixer(mixer) { - _soundType = soundType; - - _videoCodec = NULL; +AVIDecoder::AVIDecoder(Audio::Mixer::SoundType soundType) : _soundType(soundType) { _decodedHeader = false; - _audStream = NULL; - _fileStream = NULL; - _audHandle = new Audio::SoundHandle(); - _dirtyPalette = false; - memset(_palette, 0, sizeof(_palette)); - memset(&_wvInfo, 0, sizeof(PCMWAVEFORMAT)); - memset(&_bmInfo, 0, sizeof(BITMAPINFOHEADER)); - memset(&_vidsHeader, 0, sizeof(AVIStreamHeader)); - memset(&_audsHeader, 0, sizeof(AVIStreamHeader)); - memset(&_ixInfo, 0, sizeof(AVIOLDINDEX)); + _fileStream = 0; + memset(&_ixInfo, 0, sizeof(_ixInfo)); + memset(&_header, 0, sizeof(_header)); } -AviDecoder::~AviDecoder() { +AVIDecoder::~AVIDecoder() { close(); - delete _audHandle; } -void AviDecoder::runHandle(uint32 tag) { - assert (_fileStream); +void AVIDecoder::runHandle(uint32 tag) { + assert(_fileStream); if (_fileStream->eos()) return; - debug (3, "Decoding tag %s", tag2str(tag)); + debug(3, "Decoding tag %s", tag2str(tag)); switch (tag) { - case ID_RIFF: - /*_filesize = */_fileStream->readUint32LE(); - if (_fileStream->readUint32BE() != ID_AVI) - error("RIFF file is not an AVI video"); - break; - case ID_LIST: - handleList(); - break; - case ID_AVIH: - _header.size = _fileStream->readUint32LE(); - _header.microSecondsPerFrame = _fileStream->readUint32LE(); - _header.maxBytesPerSecond = _fileStream->readUint32LE(); - _header.padding = _fileStream->readUint32LE(); - _header.flags = _fileStream->readUint32LE(); - _header.totalFrames = _fileStream->readUint32LE(); - _header.initialFrames = _fileStream->readUint32LE(); - _header.streams = _fileStream->readUint32LE(); - _header.bufferSize = _fileStream->readUint32LE(); - _header.width = _fileStream->readUint32LE(); - _header.height = _fileStream->readUint32LE(); - //Ignore 16 bytes of reserved data - _fileStream->skip(16); - break; - case ID_STRH: - handleStreamHeader(); - break; - case ID_STRD: // Extra stream info, safe to ignore - case ID_VEDT: // Unknown, safe to ignore - case ID_JUNK: // Alignment bytes, should be ignored - { - uint32 junkSize = _fileStream->readUint32LE(); - _fileStream->skip(junkSize + (junkSize & 1)); // Alignment - } break; - case ID_IDX1: - _ixInfo.size = _fileStream->readUint32LE(); - _ixInfo.indices = new AVIOLDINDEX::Index[_ixInfo.size / 16]; - debug (0, "%d Indices", (_ixInfo.size / 16)); - for (uint32 i = 0; i < (_ixInfo.size / 16); i++) { - _ixInfo.indices[i].id = _fileStream->readUint32BE(); - _ixInfo.indices[i].flags = _fileStream->readUint32LE(); - _ixInfo.indices[i].offset = _fileStream->readUint32LE(); - _ixInfo.indices[i].size = _fileStream->readUint32LE(); - debug (0, "Index %d == Tag \'%s\', Offset = %d, Size = %d", i, tag2str(_ixInfo.indices[i].id), _ixInfo.indices[i].offset, _ixInfo.indices[i].size); - } - break; - default: - error ("Unknown tag \'%s\' found", tag2str(tag)); + case ID_RIFF: + /*_filesize = */_fileStream->readUint32LE(); + if (_fileStream->readUint32BE() != ID_AVI) + error("RIFF file is not an AVI video"); + break; + case ID_LIST: + handleList(); + break; + case ID_AVIH: + _header.size = _fileStream->readUint32LE(); + _header.microSecondsPerFrame = _fileStream->readUint32LE(); + _header.maxBytesPerSecond = _fileStream->readUint32LE(); + _header.padding = _fileStream->readUint32LE(); + _header.flags = _fileStream->readUint32LE(); + _header.totalFrames = _fileStream->readUint32LE(); + _header.initialFrames = _fileStream->readUint32LE(); + _header.streams = _fileStream->readUint32LE(); + _header.bufferSize = _fileStream->readUint32LE(); + _header.width = _fileStream->readUint32LE(); + _header.height = _fileStream->readUint32LE(); + // Ignore 16 bytes of reserved data + _fileStream->skip(16); + break; + case ID_STRH: + handleStreamHeader(); + break; + case ID_STRD: // Extra stream info, safe to ignore + case ID_VEDT: // Unknown, safe to ignore + case ID_JUNK: // Alignment bytes, should be ignored + { + uint32 junkSize = _fileStream->readUint32LE(); + _fileStream->skip(junkSize + (junkSize & 1)); // Alignment + } break; + case ID_IDX1: + _ixInfo.size = _fileStream->readUint32LE(); + _ixInfo.indices = new OldIndex::Index[_ixInfo.size / 16]; + debug(0, "%d Indices", (_ixInfo.size / 16)); + for (uint32 i = 0; i < (_ixInfo.size / 16); i++) { + _ixInfo.indices[i].id = _fileStream->readUint32BE(); + _ixInfo.indices[i].flags = _fileStream->readUint32LE(); + _ixInfo.indices[i].offset = _fileStream->readUint32LE(); + _ixInfo.indices[i].size = _fileStream->readUint32LE(); + debug(0, "Index %d == Tag \'%s\', Offset = %d, Size = %d", i, tag2str(_ixInfo.indices[i].id), _ixInfo.indices[i].offset, _ixInfo.indices[i].size); + } + break; + default: + error("Unknown tag \'%s\' found", tag2str(tag)); } } -void AviDecoder::handleList() { +void AVIDecoder::handleList() { uint32 listSize = _fileStream->readUint32LE() - 4; // Subtract away listType's 4 bytes uint32 listType = _fileStream->readUint32BE(); uint32 curPos = _fileStream->pos(); - debug (0, "Found LIST of type %s", tag2str(listType)); + debug(0, "Found LIST of type %s", tag2str(listType)); while ((_fileStream->pos() - curPos) < listSize) runHandle(_fileStream->readUint32BE()); @@ -151,12 +173,14 @@ void AviDecoder::handleList() { _decodedHeader = true; } -void AviDecoder::handleStreamHeader() { +void AVIDecoder::handleStreamHeader() { AVIStreamHeader sHeader; sHeader.size = _fileStream->readUint32LE(); sHeader.streamType = _fileStream->readUint32BE(); + if (sHeader.streamType == ID_MIDS || sHeader.streamType == ID_TXTS) - error ("Unhandled MIDI/Text stream"); + error("Unhandled MIDI/Text stream"); + sHeader.streamHandler = _fileStream->readUint32BE(); sHeader.flags = _fileStream->readUint32LE(); sHeader.priority = _fileStream->readUint16LE(); @@ -174,63 +198,67 @@ void AviDecoder::handleStreamHeader() { if (_fileStream->readUint32BE() != ID_STRF) error("Could not find STRF tag"); + uint32 strfSize = _fileStream->readUint32LE(); uint32 startPos = _fileStream->pos(); if (sHeader.streamType == ID_VIDS) { - _vidsHeader = sHeader; - - _bmInfo.size = _fileStream->readUint32LE(); - _bmInfo.width = _fileStream->readUint32LE(); - assert (_header.width == _bmInfo.width); - _bmInfo.height = _fileStream->readUint32LE(); - assert (_header.height == _bmInfo.height); - _bmInfo.planes = _fileStream->readUint16LE(); - _bmInfo.bitCount = _fileStream->readUint16LE(); - _bmInfo.compression = _fileStream->readUint32BE(); - _bmInfo.sizeImage = _fileStream->readUint32LE(); - _bmInfo.xPelsPerMeter = _fileStream->readUint32LE(); - _bmInfo.yPelsPerMeter = _fileStream->readUint32LE(); - _bmInfo.clrUsed = _fileStream->readUint32LE(); - _bmInfo.clrImportant = _fileStream->readUint32LE(); - - if (_bmInfo.bitCount == 8) { - if (_bmInfo.clrUsed == 0) - _bmInfo.clrUsed = 256; - - for (uint32 i = 0; i < _bmInfo.clrUsed; i++) { - _palette[i * 3 + 2] = _fileStream->readByte(); - _palette[i * 3 + 1] = _fileStream->readByte(); - _palette[i * 3] = _fileStream->readByte(); + BitmapInfoHeader bmInfo; + bmInfo.size = _fileStream->readUint32LE(); + bmInfo.width = _fileStream->readUint32LE(); + bmInfo.height = _fileStream->readUint32LE(); + bmInfo.planes = _fileStream->readUint16LE(); + bmInfo.bitCount = _fileStream->readUint16LE(); + bmInfo.compression = _fileStream->readUint32BE(); + bmInfo.sizeImage = _fileStream->readUint32LE(); + bmInfo.xPelsPerMeter = _fileStream->readUint32LE(); + bmInfo.yPelsPerMeter = _fileStream->readUint32LE(); + bmInfo.clrUsed = _fileStream->readUint32LE(); + bmInfo.clrImportant = _fileStream->readUint32LE(); + + if (bmInfo.clrUsed == 0) + bmInfo.clrUsed = 256; + + if (sHeader.streamHandler == 0) + sHeader.streamHandler = bmInfo.compression; + + AVIVideoTrack *track = new AVIVideoTrack(_header.totalFrames, sHeader, bmInfo); + + if (bmInfo.bitCount == 8) { + byte *palette = const_cast<byte *>(track->getPalette()); + for (uint32 i = 0; i < bmInfo.clrUsed; i++) { + palette[i * 3 + 2] = _fileStream->readByte(); + palette[i * 3 + 1] = _fileStream->readByte(); + palette[i * 3] = _fileStream->readByte(); _fileStream->readByte(); } - _dirtyPalette = true; + track->markPaletteDirty(); } - if (!_vidsHeader.streamHandler) - _vidsHeader.streamHandler = _bmInfo.compression; + addTrack(track); } else if (sHeader.streamType == ID_AUDS) { - _audsHeader = sHeader; - - _wvInfo.tag = _fileStream->readUint16LE(); - _wvInfo.channels = _fileStream->readUint16LE(); - _wvInfo.samplesPerSec = _fileStream->readUint32LE(); - _wvInfo.avgBytesPerSec = _fileStream->readUint32LE(); - _wvInfo.blockAlign = _fileStream->readUint16LE(); - _wvInfo.size = _fileStream->readUint16LE(); + PCMWaveFormat wvInfo; + wvInfo.tag = _fileStream->readUint16LE(); + wvInfo.channels = _fileStream->readUint16LE(); + wvInfo.samplesPerSec = _fileStream->readUint32LE(); + wvInfo.avgBytesPerSec = _fileStream->readUint32LE(); + wvInfo.blockAlign = _fileStream->readUint16LE(); + wvInfo.size = _fileStream->readUint16LE(); // AVI seems to treat the sampleSize as including the second // channel as well, so divide for our sake. - if (_wvInfo.channels == 2) - _audsHeader.sampleSize /= 2; + if (wvInfo.channels == 2) + sHeader.sampleSize /= 2; + + addTrack(new AVIAudioTrack(sHeader, wvInfo, _soundType)); } // Ensure that we're at the end of the chunk _fileStream->seek(startPos + strfSize); } -bool AviDecoder::loadStream(Common::SeekableReadStream *stream) { +bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) { close(); _fileStream = stream; @@ -252,74 +280,31 @@ bool AviDecoder::loadStream(Common::SeekableReadStream *stream) { if (nextTag == ID_LIST) { _fileStream->readUint32BE(); // Skip size if (_fileStream->readUint32BE() != ID_MOVI) - error ("Expected 'movi' LIST"); - } else - error ("Expected 'movi' LIST"); - - // Now, create the codec - _videoCodec = createCodec(); - - // Initialize the video stuff too - _audStream = createAudioStream(); - if (_audStream) - _mixer->playStream(_soundType, _audHandle, _audStream, -1, getVolume(), getBalance()); - - debug (0, "Frames = %d, Dimensions = %d x %d", _header.totalFrames, _header.width, _header.height); - debug (0, "Frame Rate = %d", _vidsHeader.rate / _vidsHeader.scale); - if (_wvInfo.samplesPerSec != 0) - debug (0, "Sound Rate = %d", _wvInfo.samplesPerSec); - debug (0, "Video Codec = \'%s\'", tag2str(_vidsHeader.streamHandler)); - - if (!_videoCodec) - return false; + error("Expected 'movi' LIST"); + } else { + error("Expected 'movi' LIST"); + } return true; } -void AviDecoder::close() { - if (!_fileStream) - return; +void AVIDecoder::close() { + VideoDecoder::close(); delete _fileStream; _fileStream = 0; - - // Deinitialize sound - _mixer->stopHandle(*_audHandle); - _audStream = 0; - _decodedHeader = false; - delete _videoCodec; - _videoCodec = 0; - delete[] _ixInfo.indices; - _ixInfo.indices = 0; - - memset(_palette, 0, sizeof(_palette)); - memset(&_wvInfo, 0, sizeof(PCMWAVEFORMAT)); - memset(&_bmInfo, 0, sizeof(BITMAPINFOHEADER)); - memset(&_vidsHeader, 0, sizeof(AVIStreamHeader)); - memset(&_audsHeader, 0, sizeof(AVIStreamHeader)); - memset(&_ixInfo, 0, sizeof(AVIOLDINDEX)); - - reset(); + memset(&_ixInfo, 0, sizeof(_ixInfo)); + memset(&_header, 0, sizeof(_header)); } -uint32 AviDecoder::getTime() const { - if (_audStream) - return _mixer->getSoundElapsedTime(*_audHandle); - - return FixedRateVideoDecoder::getTime(); -} - -const Graphics::Surface *AviDecoder::decodeNextFrame() { +void AVIDecoder::readNextPacket() { uint32 nextTag = _fileStream->readUint32BE(); if (_fileStream->eos()) - return NULL; - - if (_curFrame == -1) - _startTime = g_system->getMillis(); + return; if (nextTag == ID_LIST) { // A list of audio/video chunks @@ -327,138 +312,170 @@ const Graphics::Surface *AviDecoder::decodeNextFrame() { int32 startPos = _fileStream->pos(); if (_fileStream->readUint32BE() != ID_REC) - error ("Expected 'rec ' LIST"); - - // Decode chunks in the list and see if we get a frame - const Graphics::Surface *frame = NULL; - while (_fileStream->pos() < startPos + (int32)listSize) { - const Graphics::Surface *temp = decodeNextFrame(); - if (temp) - frame = temp; - } + error("Expected 'rec ' LIST"); - return frame; - } else if (getStreamType(nextTag) == 'wb') { - // Audio Chunk - uint32 chunkSize = _fileStream->readUint32LE(); - queueAudioBuffer(chunkSize); - _fileStream->skip(chunkSize & 1); // Alignment - } else if (getStreamType(nextTag) == 'dc' || getStreamType(nextTag) == 'id' || - getStreamType(nextTag) == 'AM' || getStreamType(nextTag) == '32' || - getStreamType(nextTag) == 'iv') { - // Compressed Frame - _curFrame++; - uint32 chunkSize = _fileStream->readUint32LE(); - - if (chunkSize == 0) // Keep last frame on screen - return NULL; - - Common::SeekableReadStream *frameData = _fileStream->readStream(chunkSize); - const Graphics::Surface *surface = _videoCodec->decodeImage(frameData); - delete frameData; - _fileStream->skip(chunkSize & 1); // Alignment - return surface; - } else if (getStreamType(nextTag) == 'pc') { - // Palette Change - _fileStream->readUint32LE(); // Chunk size, not needed here - byte firstEntry = _fileStream->readByte(); - uint16 numEntries = _fileStream->readByte(); - _fileStream->readUint16LE(); // Reserved - - // 0 entries means all colors are going to be changed - if (numEntries == 0) - numEntries = 256; - - for (uint16 i = firstEntry; i < numEntries + firstEntry; i++) { - _palette[i * 3] = _fileStream->readByte(); - _palette[i * 3 + 1] = _fileStream->readByte(); - _palette[i * 3 + 2] = _fileStream->readByte(); - _fileStream->readByte(); // Flags that don't serve us any purpose - } + // Decode chunks in the list + while (_fileStream->pos() < startPos + (int32)listSize) + readNextPacket(); - _dirtyPalette = true; + return; + } else if (nextTag == ID_JUNK || nextTag == ID_IDX1) { + runHandle(nextTag); + return; + } - // No alignment necessary. It's always even. - } else if (nextTag == ID_JUNK) { - runHandle(ID_JUNK); - } else if (nextTag == ID_IDX1) { - runHandle(ID_IDX1); - } else - error("Tag = \'%s\', %d", tag2str(nextTag), _fileStream->pos()); + Track *track = getTrack(getStreamIndex(nextTag)); - return NULL; -} + if (!track) + error("Cannot get track from tag '%s'", tag2str(nextTag)); -Codec *AviDecoder::createCodec() { - switch (_vidsHeader.streamHandler) { - case ID_CRAM: - case ID_MSVC: - case ID_WHAM: - return new MSVideo1Decoder(_bmInfo.width, _bmInfo.height, _bmInfo.bitCount); - case ID_RLE: - return new MSRLEDecoder(_bmInfo.width, _bmInfo.height, _bmInfo.bitCount); - case ID_CVID: - return new CinepakDecoder(_bmInfo.bitCount); - case ID_IV32: - return new Indeo3Decoder(_bmInfo.width, _bmInfo.height); -#ifdef VIDEO_CODECS_TRUEMOTION1_H - case ID_DUCK: - return new TrueMotion1Decoder(_bmInfo.width, _bmInfo.height); -#endif - default: - warning ("Unknown/Unhandled compression format \'%s\'", tag2str(_vidsHeader.streamHandler)); + uint32 chunkSize = _fileStream->readUint32LE(); + Common::SeekableReadStream *chunk = 0; + + if (chunkSize != 0) { + chunk = _fileStream->readStream(chunkSize); + _fileStream->skip(chunkSize & 1); } - return NULL; + if (track->getTrackType() == Track::kTrackTypeAudio) { + if (getStreamType(nextTag) != MKTAG16('w', 'b')) + error("Invalid audio track tag '%s'", tag2str(nextTag)); + + assert(chunk); + ((AVIAudioTrack *)track)->queueSound(chunk); + } else { + AVIVideoTrack *videoTrack = (AVIVideoTrack *)track; + + if (getStreamType(nextTag) == MKTAG16('p', 'c')) { + // Palette Change + assert(chunk); + byte firstEntry = chunk->readByte(); + uint16 numEntries = chunk->readByte(); + chunk->readUint16LE(); // Reserved + + // 0 entries means all colors are going to be changed + if (numEntries == 0) + numEntries = 256; + + byte *palette = const_cast<byte *>(videoTrack->getPalette()); + + for (uint16 i = firstEntry; i < numEntries + firstEntry; i++) { + palette[i * 3] = chunk->readByte(); + palette[i * 3 + 1] = chunk->readByte(); + palette[i * 3 + 2] = chunk->readByte(); + chunk->readByte(); // Flags that don't serve us any purpose + } + + delete chunk; + videoTrack->markPaletteDirty(); + } else if (getStreamType(nextTag) == MKTAG16('d', 'b')) { + // TODO: Check if this really is uncompressed. Many videos + // falsely put compressed data in here. + error("Uncompressed AVI frame found"); + } else { + // Otherwise, assume it's a compressed frame + videoTrack->decodeFrame(chunk); + } + } } -Graphics::PixelFormat AviDecoder::getPixelFormat() const { - assert(_videoCodec); - return _videoCodec->getPixelFormat(); +AVIDecoder::AVIVideoTrack::AVIVideoTrack(int frameCount, const AVIStreamHeader &streamHeader, const BitmapInfoHeader &bitmapInfoHeader) + : _frameCount(frameCount), _vidsHeader(streamHeader), _bmInfo(bitmapInfoHeader) { + memset(_palette, 0, sizeof(_palette)); + _videoCodec = createCodec(); + _dirtyPalette = false; + _lastFrame = 0; + _curFrame = -1; } -Audio::QueuingAudioStream *AviDecoder::createAudioStream() { - if (_wvInfo.tag == kWaveFormatPCM || _wvInfo.tag == kWaveFormatDK3) - return Audio::makeQueuingAudioStream(_wvInfo.samplesPerSec, _wvInfo.channels == 2); - else if (_wvInfo.tag != kWaveFormatNone) // No sound - warning("Unsupported AVI audio format %d", _wvInfo.tag); +AVIDecoder::AVIVideoTrack::~AVIVideoTrack() { + delete _videoCodec; +} - return NULL; +void AVIDecoder::AVIVideoTrack::decodeFrame(Common::SeekableReadStream *stream) { + if (stream) { + if (_videoCodec) + _lastFrame = _videoCodec->decodeImage(stream); + } else { + // Empty frame + _lastFrame = 0; + } + + delete stream; + _curFrame++; } -void AviDecoder::queueAudioBuffer(uint32 chunkSize) { - // Return if we haven't created the queue (unsupported audio format) - if (!_audStream) { - _fileStream->skip(chunkSize); - return; +Graphics::PixelFormat AVIDecoder::AVIVideoTrack::getPixelFormat() const { + if (_videoCodec) + return _videoCodec->getPixelFormat(); + + return Graphics::PixelFormat(); +} + +Codec *AVIDecoder::AVIVideoTrack::createCodec() { + switch (_vidsHeader.streamHandler) { + case ID_CRAM: + case ID_MSVC: + case ID_WHAM: + return new MSVideo1Decoder(_bmInfo.width, _bmInfo.height, _bmInfo.bitCount); + case ID_RLE: + return new MSRLEDecoder(_bmInfo.width, _bmInfo.height, _bmInfo.bitCount); + case ID_CVID: + return new CinepakDecoder(_bmInfo.bitCount); + case ID_IV32: + return new Indeo3Decoder(_bmInfo.width, _bmInfo.height); +#ifdef VIDEO_CODECS_TRUEMOTION1_H + case ID_DUCK: + return new TrueMotion1Decoder(_bmInfo.width, _bmInfo.height); +#endif + default: + warning("Unknown/Unhandled compression format \'%s\'", tag2str(_vidsHeader.streamHandler)); } - Common::SeekableReadStream *stream = _fileStream->readStream(chunkSize); + return 0; +} - if (_wvInfo.tag == kWaveFormatPCM) { - byte flags = 0; - if (_audsHeader.sampleSize == 2) - flags |= Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN; - else - flags |= Audio::FLAG_UNSIGNED; +AVIDecoder::AVIAudioTrack::AVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType) + : _audsHeader(streamHeader), _wvInfo(waveFormat), _soundType(soundType) { + _audStream = createAudioStream(); +} - if (_wvInfo.channels == 2) - flags |= Audio::FLAG_STEREO; +AVIDecoder::AVIAudioTrack::~AVIAudioTrack() { + delete _audStream; +} - _audStream->queueAudioStream(Audio::makeRawStream(stream, _wvInfo.samplesPerSec, flags, DisposeAfterUse::YES), DisposeAfterUse::YES); - } else if (_wvInfo.tag == kWaveFormatDK3) { - _audStream->queueAudioStream(Audio::makeADPCMStream(stream, DisposeAfterUse::YES, chunkSize, Audio::kADPCMDK3, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign), DisposeAfterUse::YES); +void AVIDecoder::AVIAudioTrack::queueSound(Common::SeekableReadStream *stream) { + if (_audStream) { + if (_wvInfo.tag == kWaveFormatPCM) { + byte flags = 0; + if (_audsHeader.sampleSize == 2) + flags |= Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN; + else + flags |= Audio::FLAG_UNSIGNED; + + if (_wvInfo.channels == 2) + flags |= Audio::FLAG_STEREO; + + _audStream->queueAudioStream(Audio::makeRawStream(stream, _wvInfo.samplesPerSec, flags, DisposeAfterUse::YES), DisposeAfterUse::YES); + } else if (_wvInfo.tag == kWaveFormatDK3) { + _audStream->queueAudioStream(Audio::makeADPCMStream(stream, DisposeAfterUse::YES, stream->size(), Audio::kADPCMDK3, _wvInfo.samplesPerSec, _wvInfo.channels, _wvInfo.blockAlign), DisposeAfterUse::YES); + } + } else { + delete stream; } } -void AviDecoder::updateVolume() { - if (g_system->getMixer()->isSoundHandleActive(*_audHandle)) - g_system->getMixer()->setChannelVolume(*_audHandle, getVolume()); +Audio::AudioStream *AVIDecoder::AVIAudioTrack::getAudioStream() const { + return _audStream; } -void AviDecoder::updateBalance() { - if (g_system->getMixer()->isSoundHandleActive(*_audHandle)) - g_system->getMixer()->setChannelBalance(*_audHandle, getBalance()); +Audio::QueuingAudioStream *AVIDecoder::AVIAudioTrack::createAudioStream() { + if (_wvInfo.tag == kWaveFormatPCM || _wvInfo.tag == kWaveFormatDK3) + return Audio::makeQueuingAudioStream(_wvInfo.samplesPerSec, _wvInfo.channels == 2); + else if (_wvInfo.tag != kWaveFormatNone) // No sound + warning("Unsupported AVI audio format %d", _wvInfo.tag); + + return 0; } } // End of namespace Video diff --git a/video/avi_decoder.h b/video/avi_decoder.h index fb4dae6711..a3a262db36 100644 --- a/video/avi_decoder.h +++ b/video/avi_decoder.h @@ -47,196 +47,183 @@ namespace Video { class Codec; -#define UNKNOWN_HEADER(a) error("Unknown header found -- \'%s\'", tag2str(a)) - -// IDs used throughout the AVI files -// that will be handled by this player -#define ID_RIFF MKTAG('R','I','F','F') -#define ID_AVI MKTAG('A','V','I',' ') -#define ID_LIST MKTAG('L','I','S','T') -#define ID_HDRL MKTAG('h','d','r','l') -#define ID_AVIH MKTAG('a','v','i','h') -#define ID_STRL MKTAG('s','t','r','l') -#define ID_STRH MKTAG('s','t','r','h') -#define ID_VIDS MKTAG('v','i','d','s') -#define ID_AUDS MKTAG('a','u','d','s') -#define ID_MIDS MKTAG('m','i','d','s') -#define ID_TXTS MKTAG('t','x','t','s') -#define ID_JUNK MKTAG('J','U','N','K') -#define ID_STRF MKTAG('s','t','r','f') -#define ID_MOVI MKTAG('m','o','v','i') -#define ID_REC MKTAG('r','e','c',' ') -#define ID_VEDT MKTAG('v','e','d','t') -#define ID_IDX1 MKTAG('i','d','x','1') -#define ID_STRD MKTAG('s','t','r','d') -#define ID_00AM MKTAG('0','0','A','M') -//#define ID_INFO MKTAG('I','N','F','O') - -// Codec tags -#define ID_RLE MKTAG('R','L','E',' ') -#define ID_CRAM MKTAG('C','R','A','M') -#define ID_MSVC MKTAG('m','s','v','c') -#define ID_WHAM MKTAG('W','H','A','M') -#define ID_CVID MKTAG('c','v','i','d') -#define ID_IV32 MKTAG('i','v','3','2') -#define ID_DUCK MKTAG('D','U','C','K') - -struct BITMAPINFOHEADER { - uint32 size; - uint32 width; - uint32 height; - uint16 planes; - uint16 bitCount; - uint32 compression; - uint32 sizeImage; - uint32 xPelsPerMeter; - uint32 yPelsPerMeter; - uint32 clrUsed; - uint32 clrImportant; -}; - -struct WAVEFORMAT { - uint16 tag; - uint16 channels; - uint32 samplesPerSec; - uint32 avgBytesPerSec; - uint16 blockAlign; -}; - -struct PCMWAVEFORMAT : public WAVEFORMAT { - uint16 size; -}; - -struct WAVEFORMATEX : public WAVEFORMAT { - uint16 bitsPerSample; - uint16 size; -}; - -struct AVIOLDINDEX { - uint32 size; - struct Index { - uint32 id; - uint32 flags; - uint32 offset; - uint32 size; - } *indices; -}; - -// Index Flags -enum IndexFlags { - AVIIF_INDEX = 0x10 -}; - -// Audio Codecs -enum { - kWaveFormatNone = 0, - kWaveFormatPCM = 1, - kWaveFormatDK3 = 98 -}; - -struct AVIHeader { - uint32 size; - uint32 microSecondsPerFrame; - uint32 maxBytesPerSecond; - uint32 padding; - uint32 flags; - uint32 totalFrames; - uint32 initialFrames; - uint32 streams; - uint32 bufferSize; - uint32 width; - uint32 height; -}; - -// Flags from the AVIHeader -enum AviFlags { - AVIF_HASINDEX = 0x00000010, - AVIF_MUSTUSEINDEX = 0x00000020, - AVIF_ISINTERLEAVED = 0x00000100, - AVIF_TRUSTCKTYPE = 0x00000800, - AVIF_WASCAPTUREFILE = 0x00010000, - AVIF_WASCOPYRIGHTED = 0x00020000 -}; - -struct AVIStreamHeader { - uint32 size; - uint32 streamType; - uint32 streamHandler; - uint32 flags; - uint16 priority; - uint16 language; - uint32 initialFrames; - uint32 scale; - uint32 rate; - uint32 start; - uint32 length; - uint32 bufferSize; - uint32 quality; - uint32 sampleSize; - Common::Rect frame; -}; - /** * Decoder for AVI videos. * * Video decoder used in engines: * - sci */ -class AviDecoder : public FixedRateVideoDecoder { +class AVIDecoder : public VideoDecoder { public: - AviDecoder(Audio::Mixer *mixer, - Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); - virtual ~AviDecoder(); + AVIDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); + virtual ~AVIDecoder(); bool loadStream(Common::SeekableReadStream *stream); void close(); - - bool isVideoLoaded() const { return _fileStream != 0; } uint16 getWidth() const { return _header.width; } uint16 getHeight() const { return _header.height; } - uint32 getFrameCount() const { return _header.totalFrames; } - uint32 getTime() const; - const Graphics::Surface *decodeNextFrame(); - Graphics::PixelFormat getPixelFormat() const; - const byte *getPalette() { _dirtyPalette = false; return _palette; } - bool hasDirtyPalette() const { return _dirtyPalette; } protected: - // VideoDecoder API - void updateVolume(); - void updateBalance(); - - // FixedRateVideoDecoder API - Common::Rational getFrameRate() const { return Common::Rational(_vidsHeader.rate, _vidsHeader.scale); } + void readNextPacket(); private: - Audio::Mixer *_mixer; - BITMAPINFOHEADER _bmInfo; - PCMWAVEFORMAT _wvInfo; - AVIOLDINDEX _ixInfo; - AVIHeader _header; - AVIStreamHeader _vidsHeader; - AVIStreamHeader _audsHeader; - byte _palette[3 * 256]; - bool _dirtyPalette; + struct BitmapInfoHeader { + uint32 size; + uint32 width; + uint32 height; + uint16 planes; + uint16 bitCount; + uint32 compression; + uint32 sizeImage; + uint32 xPelsPerMeter; + uint32 yPelsPerMeter; + uint32 clrUsed; + uint32 clrImportant; + }; + + struct WaveFormat { + uint16 tag; + uint16 channels; + uint32 samplesPerSec; + uint32 avgBytesPerSec; + uint16 blockAlign; + }; + + struct PCMWaveFormat : public WaveFormat { + uint16 size; + }; + + struct WaveFormatEX : public WaveFormat { + uint16 bitsPerSample; + uint16 size; + }; + + struct OldIndex { + uint32 size; + struct Index { + uint32 id; + uint32 flags; + uint32 offset; + uint32 size; + } *indices; + }; + + // Index Flags + enum IndexFlags { + AVIIF_INDEX = 0x10 + }; + + struct AVIHeader { + uint32 size; + uint32 microSecondsPerFrame; + uint32 maxBytesPerSecond; + uint32 padding; + uint32 flags; + uint32 totalFrames; + uint32 initialFrames; + uint32 streams; + uint32 bufferSize; + uint32 width; + uint32 height; + }; + + // Flags from the AVIHeader + enum AVIFlags { + AVIF_HASINDEX = 0x00000010, + AVIF_MUSTUSEINDEX = 0x00000020, + AVIF_ISINTERLEAVED = 0x00000100, + AVIF_TRUSTCKTYPE = 0x00000800, + AVIF_WASCAPTUREFILE = 0x00010000, + AVIF_WASCOPYRIGHTED = 0x00020000 + }; + + struct AVIStreamHeader { + uint32 size; + uint32 streamType; + uint32 streamHandler; + uint32 flags; + uint16 priority; + uint16 language; + uint32 initialFrames; + uint32 scale; + uint32 rate; + uint32 start; + uint32 length; + uint32 bufferSize; + uint32 quality; + uint32 sampleSize; + Common::Rect frame; + }; + + class AVIVideoTrack : public FixedRateVideoTrack { + public: + AVIVideoTrack(int frameCount, const AVIStreamHeader &streamHeader, const BitmapInfoHeader &bitmapInfoHeader); + ~AVIVideoTrack(); + + void decodeFrame(Common::SeekableReadStream *stream); + + uint16 getWidth() const { return _bmInfo.width; } + uint16 getHeight() const { return _bmInfo.height; } + Graphics::PixelFormat getPixelFormat() const; + int getCurFrame() const { return _curFrame; } + int getFrameCount() const { return _frameCount; } + const Graphics::Surface *decodeNextFrame() { return _lastFrame; } + const byte *getPalette() const { _dirtyPalette = false; return _palette; } + bool hasDirtyPalette() const { return _dirtyPalette; } + void markPaletteDirty() { _dirtyPalette = true; } + + protected: + Common::Rational getFrameRate() const { return Common::Rational(_vidsHeader.rate, _vidsHeader.scale); } + + private: + AVIStreamHeader _vidsHeader; + BitmapInfoHeader _bmInfo; + byte _palette[3 * 256]; + mutable bool _dirtyPalette; + int _frameCount, _curFrame; + + Codec *_videoCodec; + const Graphics::Surface *_lastFrame; + Codec *createCodec(); + }; + + class AVIAudioTrack : public AudioTrack { + public: + AVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType); + ~AVIAudioTrack(); + + void queueSound(Common::SeekableReadStream *stream); + Audio::Mixer::SoundType getSoundType() const { return _soundType; } + + protected: + Audio::AudioStream *getAudioStream() const; + + private: + // Audio Codecs + enum { + kWaveFormatNone = 0, + kWaveFormatPCM = 1, + kWaveFormatDK3 = 98 + }; + + AVIStreamHeader _audsHeader; + PCMWaveFormat _wvInfo; + Audio::Mixer::SoundType _soundType; + Audio::QueuingAudioStream *_audStream; + Audio::QueuingAudioStream *createAudioStream(); + }; + + OldIndex _ixInfo; + AVIHeader _header; Common::SeekableReadStream *_fileStream; bool _decodedHeader; - Codec *_videoCodec; - Codec *createCodec(); - Audio::Mixer::SoundType _soundType; void runHandle(uint32 tag); void handleList(); void handleStreamHeader(); - void handlePalChange(); - - Audio::SoundHandle *_audHandle; - Audio::QueuingAudioStream *_audStream; - Audio::QueuingAudioStream *createAudioStream(); - void queueAudioBuffer(uint32 chunkSize); }; } // End of namespace Video diff --git a/video/bink_decoder.cpp b/video/bink_decoder.cpp index 538487f067..620316806f 100644 --- a/video/bink_decoder.cpp +++ b/video/bink_decoder.cpp @@ -24,6 +24,7 @@ // based quite heavily on the Bink decoder found in FFmpeg. // Many thanks to Kostya Shishkov for doing the hard work. +#include "audio/audiostream.h" #include "audio/decoders/raw.h" #include "common/util.h" @@ -60,139 +61,108 @@ static const uint32 kDCStartBits = 11; namespace Video { -BinkDecoder::VideoFrame::VideoFrame() : bits(0) { -} - -BinkDecoder::VideoFrame::~VideoFrame() { - delete bits; +BinkDecoder::BinkDecoder() { + _bink = 0; } - -BinkDecoder::AudioTrack::AudioTrack() : bits(0), bands(0), rdft(0), dct(0) { +BinkDecoder::~BinkDecoder() { + close(); } -BinkDecoder::AudioTrack::~AudioTrack() { - delete bits; - - delete[] bands; - - delete rdft; - delete dct; -} +bool BinkDecoder::loadStream(Common::SeekableReadStream *stream) { + close(); + uint32 id = stream->readUint32BE(); + if ((id != kBIKfID) && (id != kBIKgID) && (id != kBIKhID) && (id != kBIKiID)) + return false; -BinkDecoder::BinkDecoder() { - _bink = 0; - _audioTrack = 0; + uint32 fileSize = stream->readUint32LE() + 8; + uint32 frameCount = stream->readUint32LE(); + uint32 largestFrameSize = stream->readUint32LE(); - for (int i = 0; i < 16; i++) - _huffman[i] = 0; + if (largestFrameSize > fileSize) { + warning("Largest frame size greater than file size"); + return false; + } - for (int i = 0; i < kSourceMAX; i++) { - _bundles[i].countLength = 0; + stream->skip(4); - _bundles[i].huffman.index = 0; - for (int j = 0; j < 16; j++) - _bundles[i].huffman.symbols[j] = j; + uint32 width = stream->readUint32LE(); + uint32 height = stream->readUint32LE(); - _bundles[i].data = 0; - _bundles[i].dataEnd = 0; - _bundles[i].curDec = 0; - _bundles[i].curPtr = 0; + uint32 frameRateNum = stream->readUint32LE(); + uint32 frameRateDen = stream->readUint32LE(); + if (frameRateNum == 0 || frameRateDen == 0) { + warning("Invalid frame rate (%d/%d)", frameRateNum, frameRateDen); + return false; } - for (int i = 0; i < 16; i++) { - _colHighHuffman[i].index = 0; - for (int j = 0; j < 16; j++) - _colHighHuffman[i].symbols[j] = j; - } + _bink = stream; - for (int i = 0; i < 4; i++) { - _curPlanes[i] = 0; - _oldPlanes[i] = 0; - } + uint32 videoFlags = _bink->readUint32LE(); - _audioStream = 0; -} + // BIKh and BIKi swap the chroma planes + addTrack(new BinkVideoTrack(width, height, getDefaultHighColorFormat(), frameCount, + Common::Rational(frameRateNum, frameRateDen), (id == kBIKhID || id == kBIKiID), videoFlags & kVideoFlagAlpha, id)); -void BinkDecoder::startAudio() { - if (_audioTrack < _audioTracks.size()) { - const AudioTrack &audio = _audioTracks[_audioTrack]; + uint32 audioTrackCount = _bink->readUint32LE(); - _audioStream = Audio::makeQueuingAudioStream(audio.outSampleRate, audio.outChannels == 2); - g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_audioHandle, _audioStream, -1, getVolume(), getBalance()); - } // else no audio -} + if (audioTrackCount > 0) { + _audioTracks.reserve(audioTrackCount); -void BinkDecoder::stopAudio() { - if (_audioStream) { - g_system->getMixer()->stopHandle(_audioHandle); - _audioStream = 0; - } -} + _bink->skip(4 * audioTrackCount); -BinkDecoder::~BinkDecoder() { - close(); -} + // Reading audio track properties + for (uint32 i = 0; i < audioTrackCount; i++) { + AudioInfo track; -void BinkDecoder::close() { - reset(); + track.sampleRate = _bink->readUint16LE(); + track.flags = _bink->readUint16LE(); - // Stop audio - stopAudio(); + _audioTracks.push_back(track); - for (int i = 0; i < 4; i++) { - delete[] _curPlanes[i]; _curPlanes[i] = 0; - delete[] _oldPlanes[i]; _oldPlanes[i] = 0; + initAudioTrack(_audioTracks[i]); + } + + _bink->skip(4 * audioTrackCount); } - deinitBundles(); + // Reading video frame properties + _frames.resize(frameCount); + for (uint32 i = 0; i < frameCount; i++) { + _frames[i].offset = _bink->readUint32LE(); + _frames[i].keyFrame = _frames[i].offset & 1; - for (int i = 0; i < 16; i++) { - delete _huffman[i]; - _huffman[i] = 0; - } + _frames[i].offset &= ~1; - delete _bink; _bink = 0; - _surface.free(); + if (i != 0) + _frames[i - 1].size = _frames[i].offset - _frames[i - 1].offset; - _audioTrack = 0; + _frames[i].bits = 0; + } - for (int i = 0; i < kSourceMAX; i++) { - _bundles[i].countLength = 0; + _frames[frameCount - 1].size = _bink->size() - _frames[frameCount - 1].offset; - _bundles[i].huffman.index = 0; - for (int j = 0; j < 16; j++) - _bundles[i].huffman.symbols[j] = j; + return true; +} - _bundles[i].data = 0; - _bundles[i].dataEnd = 0; - _bundles[i].curDec = 0; - _bundles[i].curPtr = 0; - } +void BinkDecoder::close() { + VideoDecoder::close(); - for (int i = 0; i < 16; i++) { - _colHighHuffman[i].index = 0; - for (int j = 0; j < 16; j++) - _colHighHuffman[i].symbols[j] = j; - } + delete _bink; + _bink = 0; _audioTracks.clear(); _frames.clear(); } -uint32 BinkDecoder::getTime() const { - if (_audioStream && g_system->getMixer()->isSoundHandleActive(_audioHandle)) - return g_system->getMixer()->getSoundElapsedTime(_audioHandle) + _audioStartOffset; +void BinkDecoder::readNextPacket() { + BinkVideoTrack *videoTrack = (BinkVideoTrack *)getTrack(0); - return g_system->getMillis() - _startTime; -} - -const Graphics::Surface *BinkDecoder::decodeNextFrame() { - if (endOfVideo()) - return 0; + if (videoTrack->endOfTrack()) + return; - VideoFrame &frame = _frames[_curFrame + 1]; + VideoFrame &frame = _frames[videoTrack->getCurFrame() + 1]; if (!_bink->seek(frame.offset)) error("Bad bink seek"); @@ -200,7 +170,7 @@ const Graphics::Surface *BinkDecoder::decodeNextFrame() { uint32 frameSize = frame.size; for (uint32 i = 0; i < _audioTracks.size(); i++) { - AudioTrack &audio = _audioTracks[i]; + AudioInfo &audio = _audioTracks[i]; uint32 audioPacketLength = _bink->readUint32LE(); @@ -210,24 +180,21 @@ const Graphics::Surface *BinkDecoder::decodeNextFrame() { error("Audio packet too big for the frame"); if (audioPacketLength >= 4) { + // Get our track - audio index plus one as the first track is video + BinkAudioTrack *audioTrack = (BinkAudioTrack *)getTrack(i + 1); uint32 audioPacketStart = _bink->pos(); uint32 audioPacketEnd = _bink->pos() + audioPacketLength; - if (i == _audioTrack) { - // Only play one audio track - - // Number of samples in bytes - audio.sampleCount = _bink->readUint32LE() / (2 * audio.channels); + // Number of samples in bytes + audio.sampleCount = _bink->readUint32LE() / (2 * audio.channels); - audio.bits = - new Common::BitStream32LELSB(new Common::SeekableSubReadStream(_bink, - audioPacketStart + 4, audioPacketEnd), true); + audio.bits = new Common::BitStream32LELSB(new Common::SeekableSubReadStream(_bink, + audioPacketStart + 4, audioPacketEnd), true); - audioPacket(audio); + audioTrack->decodePacket(); - delete audio.bits; - audio.bits = 0; - } + delete audio.bits; + audio.bits = 0; _bink->seek(audioPacketEnd); @@ -238,67 +205,125 @@ const Graphics::Surface *BinkDecoder::decodeNextFrame() { uint32 videoPacketStart = _bink->pos(); uint32 videoPacketEnd = _bink->pos() + frameSize; - frame.bits = - new Common::BitStream32LELSB(new Common::SeekableSubReadStream(_bink, - videoPacketStart, videoPacketEnd), true); + frame.bits = new Common::BitStream32LELSB(new Common::SeekableSubReadStream(_bink, + videoPacketStart, videoPacketEnd), true); - videoPacket(frame); + videoTrack->decodePacket(frame); delete frame.bits; frame.bits = 0; +} - _curFrame++; - if (_curFrame == 0) - _startTime = g_system->getMillis(); +BinkDecoder::VideoFrame::VideoFrame() : bits(0) { +} - return &_surface; +BinkDecoder::VideoFrame::~VideoFrame() { + delete bits; } -void BinkDecoder::audioPacket(AudioTrack &audio) { - if (!_audioStream) - return; - int outSize = audio.frameLen * audio.channels; - while (audio.bits->pos() < audio.bits->size()) { - int16 *out = (int16 *)malloc(outSize * 2); - memset(out, 0, outSize * 2); +BinkDecoder::AudioInfo::AudioInfo() : bits(0), bands(0), rdft(0), dct(0) { +} - audioBlock(audio, out); +BinkDecoder::AudioInfo::~AudioInfo() { + delete bits; - byte flags = Audio::FLAG_16BITS; - if (audio.outChannels == 2) - flags |= Audio::FLAG_STEREO; + delete[] bands; -#ifdef SCUMM_LITTLE_ENDIAN - flags |= Audio::FLAG_LITTLE_ENDIAN; -#endif + delete rdft; + delete dct; +} + +BinkDecoder::BinkVideoTrack::BinkVideoTrack(uint32 width, uint32 height, const Graphics::PixelFormat &format, uint32 frameCount, const Common::Rational &frameRate, bool swapPlanes, bool hasAlpha, uint32 id) : + _frameCount(frameCount), _frameRate(frameRate), _swapPlanes(swapPlanes), _hasAlpha(hasAlpha), _id(id) { + _curFrame = -1; + + for (int i = 0; i < 16; i++) + _huffman[i] = 0; + + for (int i = 0; i < kSourceMAX; i++) { + _bundles[i].countLength = 0; + + _bundles[i].huffman.index = 0; + for (int j = 0; j < 16; j++) + _bundles[i].huffman.symbols[j] = j; + + _bundles[i].data = 0; + _bundles[i].dataEnd = 0; + _bundles[i].curDec = 0; + _bundles[i].curPtr = 0; + } + + for (int i = 0; i < 16; i++) { + _colHighHuffman[i].index = 0; + for (int j = 0; j < 16; j++) + _colHighHuffman[i].symbols[j] = j; + } + + _surface.create(width, height, format); + + // Give the planes a bit extra space + width = _surface.w + 32; + height = _surface.h + 32; + + _curPlanes[0] = new byte[ width * height ]; // Y + _curPlanes[1] = new byte[(width >> 1) * (height >> 1)]; // U, 1/4 resolution + _curPlanes[2] = new byte[(width >> 1) * (height >> 1)]; // V, 1/4 resolution + _curPlanes[3] = new byte[ width * height ]; // A + _oldPlanes[0] = new byte[ width * height ]; // Y + _oldPlanes[1] = new byte[(width >> 1) * (height >> 1)]; // U, 1/4 resolution + _oldPlanes[2] = new byte[(width >> 1) * (height >> 1)]; // V, 1/4 resolution + _oldPlanes[3] = new byte[ width * height ]; // A + + // Initialize the video with solid black + memset(_curPlanes[0], 0, width * height ); + memset(_curPlanes[1], 0, (width >> 1) * (height >> 1)); + memset(_curPlanes[2], 0, (width >> 1) * (height >> 1)); + memset(_curPlanes[3], 255, width * height ); + memset(_oldPlanes[0], 0, width * height ); + memset(_oldPlanes[1], 0, (width >> 1) * (height >> 1)); + memset(_oldPlanes[2], 0, (width >> 1) * (height >> 1)); + memset(_oldPlanes[3], 255, width * height ); - _audioStream->queueBuffer((byte *)out, audio.blockSize * 2, DisposeAfterUse::YES, flags); + initBundles(); + initHuffman(); +} - if (audio.bits->pos() & 0x1F) // next data block starts at a 32-byte boundary - audio.bits->skip(32 - (audio.bits->pos() & 0x1F)); +BinkDecoder::BinkVideoTrack::~BinkVideoTrack() { + for (int i = 0; i < 4; i++) { + delete[] _curPlanes[i]; _curPlanes[i] = 0; + delete[] _oldPlanes[i]; _oldPlanes[i] = 0; } + + deinitBundles(); + + for (int i = 0; i < 16; i++) { + delete _huffman[i]; + _huffman[i] = 0; + } + + _surface.free(); } -void BinkDecoder::videoPacket(VideoFrame &video) { - assert(video.bits); +void BinkDecoder::BinkVideoTrack::decodePacket(VideoFrame &frame) { + assert(frame.bits); if (_hasAlpha) { if (_id == kBIKiID) - video.bits->skip(32); + frame.bits->skip(32); - decodePlane(video, 3, false); + decodePlane(frame, 3, false); } if (_id == kBIKiID) - video.bits->skip(32); + frame.bits->skip(32); for (int i = 0; i < 3; i++) { int planeIdx = ((i == 0) || !_swapPlanes) ? i : (i ^ 3); - decodePlane(video, planeIdx, i != 0); + decodePlane(frame, planeIdx, i != 0); - if (video.bits->pos() >= video.bits->size()) + if (frame.bits->pos() >= frame.bits->size()) break; } @@ -311,10 +336,11 @@ void BinkDecoder::videoPacket(VideoFrame &video) { // And swap the planes with the reference planes for (int i = 0; i < 4; i++) SWAP(_curPlanes[i], _oldPlanes[i]); -} -void BinkDecoder::decodePlane(VideoFrame &video, int planeIdx, bool isChroma) { + _curFrame++; +} +void BinkDecoder::BinkVideoTrack::decodePlane(VideoFrame &video, int planeIdx, bool isChroma) { uint32 blockWidth = isChroma ? ((_surface.w + 15) >> 4) : ((_surface.w + 7) >> 3); uint32 blockHeight = isChroma ? ((_surface.h + 15) >> 4) : ((_surface.h + 7) >> 3); uint32 width = isChroma ? (_surface.w >> 1) : _surface.w; @@ -371,48 +397,38 @@ void BinkDecoder::decodePlane(VideoFrame &video, int planeIdx, bool isChroma) { } switch (blockType) { - case kBlockSkip: - blockSkip(ctx); - break; - - case kBlockScaled: - blockScaled(ctx); - break; - - case kBlockMotion: - blockMotion(ctx); - break; - - case kBlockRun: - blockRun(ctx); - break; - - case kBlockResidue: - blockResidue(ctx); - break; - - case kBlockIntra: - blockIntra(ctx); - break; - - case kBlockFill: - blockFill(ctx); - break; - - case kBlockInter: - blockInter(ctx); - break; - - case kBlockPattern: - blockPattern(ctx); - break; - - case kBlockRaw: - blockRaw(ctx); - break; - - default: - error("Unknown block type: %d", blockType); + case kBlockSkip: + blockSkip(ctx); + break; + case kBlockScaled: + blockScaled(ctx); + break; + case kBlockMotion: + blockMotion(ctx); + break; + case kBlockRun: + blockRun(ctx); + break; + case kBlockResidue: + blockResidue(ctx); + break; + case kBlockIntra: + blockIntra(ctx); + break; + case kBlockFill: + blockFill(ctx); + break; + case kBlockInter: + blockInter(ctx); + break; + case kBlockPattern: + blockPattern(ctx); + break; + case kBlockRaw: + blockRaw(ctx); + break; + default: + error("Unknown block type: %d", blockType); } } @@ -424,7 +440,7 @@ void BinkDecoder::decodePlane(VideoFrame &video, int planeIdx, bool isChroma) { } -void BinkDecoder::readBundle(VideoFrame &video, Source source) { +void BinkDecoder::BinkVideoTrack::readBundle(VideoFrame &video, Source source) { if (source == kSourceColors) { for (int i = 0; i < 16; i++) readHuffman(video, _colHighHuffman[i]); @@ -439,12 +455,11 @@ void BinkDecoder::readBundle(VideoFrame &video, Source source) { _bundles[source].curPtr = _bundles[source].data; } -void BinkDecoder::readHuffman(VideoFrame &video, Huffman &huffman) { +void BinkDecoder::BinkVideoTrack::readHuffman(VideoFrame &video, Huffman &huffman) { huffman.index = video.bits->getBits(4); if (huffman.index == 0) { // The first tree always gives raw nibbles - for (int i = 0; i < 16; i++) huffman.symbols[i] = i; @@ -455,7 +470,6 @@ void BinkDecoder::readHuffman(VideoFrame &video, Huffman &huffman) { if (video.bits->getBit()) { // Symbol selection - memset(hasSymbol, 0, 16); uint8 length = video.bits->getBits(3); @@ -493,9 +507,9 @@ void BinkDecoder::readHuffman(VideoFrame &video, Huffman &huffman) { memcpy(huffman.symbols, in, 16); } -void BinkDecoder::mergeHuffmanSymbols(VideoFrame &video, byte *dst, const byte *src, int size) { +void BinkDecoder::BinkVideoTrack::mergeHuffmanSymbols(VideoFrame &video, byte *dst, const byte *src, int size) { const byte *src2 = src + size; - int size2 = size; + int size2 = size; do { if (!video.bits->getBit()) { @@ -510,197 +524,12 @@ void BinkDecoder::mergeHuffmanSymbols(VideoFrame &video, byte *dst, const byte * while (size--) *dst++ = *src++; + while (size2--) *dst++ = *src2++; } -bool BinkDecoder::loadStream(Common::SeekableReadStream *stream) { - Graphics::PixelFormat format = g_system->getScreenFormat(); - return loadStream(stream, format); -} - -bool BinkDecoder::loadStream(Common::SeekableReadStream *stream, const Graphics::PixelFormat &format) { - close(); - - _id = stream->readUint32BE(); - if ((_id != kBIKfID) && (_id != kBIKgID) && (_id != kBIKhID) && (_id != kBIKiID)) - return false; - - uint32 fileSize = stream->readUint32LE() + 8; - uint32 frameCount = stream->readUint32LE(); - uint32 largestFrameSize = stream->readUint32LE(); - - if (largestFrameSize > fileSize) { - warning("Largest frame size greater than file size"); - return false; - } - - stream->skip(4); - - uint32 width = stream->readUint32LE(); - uint32 height = stream->readUint32LE(); - - uint32 frameRateNum = stream->readUint32LE(); - uint32 frameRateDen = stream->readUint32LE(); - if (frameRateNum == 0 || frameRateDen == 0) { - warning("Invalid frame rate (%d/%d)", frameRateNum, frameRateDen); - return false; - } - - _frameRate = Common::Rational(frameRateNum, frameRateDen); - _bink = stream; - - _videoFlags = _bink->readUint32LE(); - - uint32 audioTrackCount = _bink->readUint32LE(); - - if (audioTrackCount > 1) { - warning("More than one audio track found. Using the first one"); - - _audioTrack = 0; - } - - if (audioTrackCount > 0) { - _audioTracks.reserve(audioTrackCount); - - _bink->skip(4 * audioTrackCount); - - // Reading audio track properties - for (uint32 i = 0; i < audioTrackCount; i++) { - AudioTrack track; - - track.sampleRate = _bink->readUint16LE(); - track.flags = _bink->readUint16LE(); - - _audioTracks.push_back(track); - - initAudioTrack(_audioTracks[i]); - } - - _bink->skip(4 * audioTrackCount); - } - - // Reading video frame properties - _frames.resize(frameCount); - for (uint32 i = 0; i < frameCount; i++) { - _frames[i].offset = _bink->readUint32LE(); - _frames[i].keyFrame = _frames[i].offset & 1; - - _frames[i].offset &= ~1; - - if (i != 0) - _frames[i - 1].size = _frames[i].offset - _frames[i - 1].offset; - - _frames[i].bits = 0; - } - - _frames[frameCount - 1].size = _bink->size() - _frames[frameCount - 1].offset; - - _hasAlpha = _videoFlags & kVideoFlagAlpha; - _swapPlanes = (_id == kBIKhID) || (_id == kBIKiID); // BIKh and BIKi swap the chroma planes - - _surface.create(width, height, format); - - // Give the planes a bit extra space - width = _surface.w + 32; - height = _surface.h + 32; - - _curPlanes[0] = new byte[ width * height ]; // Y - _curPlanes[1] = new byte[(width >> 1) * (height >> 1)]; // U, 1/4 resolution - _curPlanes[2] = new byte[(width >> 1) * (height >> 1)]; // V, 1/4 resolution - _curPlanes[3] = new byte[ width * height ]; // A - _oldPlanes[0] = new byte[ width * height ]; // Y - _oldPlanes[1] = new byte[(width >> 1) * (height >> 1)]; // U, 1/4 resolution - _oldPlanes[2] = new byte[(width >> 1) * (height >> 1)]; // V, 1/4 resolution - _oldPlanes[3] = new byte[ width * height ]; // A - - // Initialize the video with solid black - memset(_curPlanes[0], 0, width * height ); - memset(_curPlanes[1], 0, (width >> 1) * (height >> 1)); - memset(_curPlanes[2], 0, (width >> 1) * (height >> 1)); - memset(_curPlanes[3], 255, width * height ); - memset(_oldPlanes[0], 0, width * height ); - memset(_oldPlanes[1], 0, (width >> 1) * (height >> 1)); - memset(_oldPlanes[2], 0, (width >> 1) * (height >> 1)); - memset(_oldPlanes[3], 255, width * height ); - - initBundles(); - initHuffman(); - - startAudio(); - _audioStartOffset = 0; - - return true; -} - -void BinkDecoder::initAudioTrack(AudioTrack &audio) { - audio.sampleCount = 0; - audio.bits = 0; - - audio.channels = ((audio.flags & kAudioFlagStereo) != 0) ? 2 : 1; - audio.codec = ((audio.flags & kAudioFlagDCT ) != 0) ? kAudioCodecDCT : kAudioCodecRDFT; - - if (audio.channels > kAudioChannelsMax) - error("Too many audio channels: %d", audio.channels); - - uint32 frameLenBits; - // Calculate frame length - if (audio.sampleRate < 22050) - frameLenBits = 9; - else if(audio.sampleRate < 44100) - frameLenBits = 10; - else - frameLenBits = 11; - - audio.frameLen = 1 << frameLenBits; - - audio.outSampleRate = audio.sampleRate; - audio.outChannels = audio.channels; - - if (audio.codec == kAudioCodecRDFT) { - // RDFT audio already interleaves the samples correctly - - if (audio.channels == 2) - frameLenBits++; - - audio.sampleRate *= audio.channels; - audio.frameLen *= audio.channels; - audio.channels = 1; - } - - audio.overlapLen = audio.frameLen / 16; - audio.blockSize = (audio.frameLen - audio.overlapLen) * audio.channels; - audio.root = 2.0 / sqrt((double)audio.frameLen); - - uint32 sampleRateHalf = (audio.sampleRate + 1) / 2; - - // Calculate number of bands - for (audio.bandCount = 1; audio.bandCount < 25; audio.bandCount++) - if (sampleRateHalf <= binkCriticalFreqs[audio.bandCount - 1]) - break; - - audio.bands = new uint32[audio.bandCount + 1]; - - // Populate bands - audio.bands[0] = 1; - for (uint32 i = 1; i < audio.bandCount; i++) - audio.bands[i] = binkCriticalFreqs[i - 1] * (audio.frameLen / 2) / sampleRateHalf; - audio.bands[audio.bandCount] = audio.frameLen / 2; - - audio.first = true; - - for (uint8 i = 0; i < audio.channels; i++) - audio.coeffsPtr[i] = audio.coeffs + i * audio.frameLen; - - audio.codec = ((audio.flags & kAudioFlagDCT) != 0) ? kAudioCodecDCT : kAudioCodecRDFT; - - if (audio.codec == kAudioCodecRDFT) - audio.rdft = new Common::RDFT(frameLenBits, Common::RDFT::DFT_C2R); - else if (audio.codec == kAudioCodecDCT) - audio.dct = new Common::DCT(frameLenBits, Common::DCT::DCT_III); -} - -void BinkDecoder::initBundles() { +void BinkDecoder::BinkVideoTrack::initBundles() { uint32 bw = (_surface.w + 7) >> 3; uint32 bh = (_surface.h + 7) >> 3; uint32 blocks = bw * bh; @@ -729,21 +558,21 @@ void BinkDecoder::initBundles() { } } -void BinkDecoder::deinitBundles() { +void BinkDecoder::BinkVideoTrack::deinitBundles() { for (int i = 0; i < kSourceMAX; i++) delete[] _bundles[i].data; } -void BinkDecoder::initHuffman() { +void BinkDecoder::BinkVideoTrack::initHuffman() { for (int i = 0; i < 16; i++) _huffman[i] = new Common::Huffman(binkHuffmanLengths[i][15], 16, binkHuffmanCodes[i], binkHuffmanLengths[i]); } -byte BinkDecoder::getHuffmanSymbol(VideoFrame &video, Huffman &huffman) { +byte BinkDecoder::BinkVideoTrack::getHuffmanSymbol(VideoFrame &video, Huffman &huffman) { return huffman.symbols[_huffman[huffman.index]->getSymbol(*video.bits)]; } -int32 BinkDecoder::getBundleValue(Source source) { +int32 BinkDecoder::BinkVideoTrack::getBundleValue(Source source) { if ((source < kSourceXOff) || (source == kSourceRun)) return *_bundles[source].curPtr++; @@ -757,7 +586,7 @@ int32 BinkDecoder::getBundleValue(Source source) { return ret; } -uint32 BinkDecoder::readBundleCount(VideoFrame &video, Bundle &bundle) { +uint32 BinkDecoder::BinkVideoTrack::readBundleCount(VideoFrame &video, Bundle &bundle) { if (!bundle.curDec || (bundle.curDec > bundle.curPtr)) return 0; @@ -768,7 +597,7 @@ uint32 BinkDecoder::readBundleCount(VideoFrame &video, Bundle &bundle) { return n; } -void BinkDecoder::blockSkip(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockSkip(DecodeContext &ctx) { byte *dest = ctx.dest; byte *prev = ctx.prev; @@ -776,7 +605,7 @@ void BinkDecoder::blockSkip(DecodeContext &ctx) { memcpy(dest, prev, 8); } -void BinkDecoder::blockScaledSkip(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockScaledSkip(DecodeContext &ctx) { byte *dest = ctx.dest; byte *prev = ctx.prev; @@ -784,7 +613,7 @@ void BinkDecoder::blockScaledSkip(DecodeContext &ctx) { memcpy(dest, prev, 16); } -void BinkDecoder::blockScaledRun(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockScaledRun(DecodeContext &ctx) { const uint8 *scan = binkPatterns[ctx.video->bits->getBits(4)]; int i = 0; @@ -820,7 +649,7 @@ void BinkDecoder::blockScaledRun(DecodeContext &ctx) { ctx.dest[ctx.coordScaledMap4[*scan]] = getBundleValue(kSourceColors); } -void BinkDecoder::blockScaledIntra(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockScaledIntra(DecodeContext &ctx) { int16 block[64]; memset(block, 0, 64 * sizeof(int16)); @@ -841,7 +670,7 @@ void BinkDecoder::blockScaledIntra(DecodeContext &ctx) { } } -void BinkDecoder::blockScaledFill(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockScaledFill(DecodeContext &ctx) { byte v = getBundleValue(kSourceColors); byte *dest = ctx.dest; @@ -849,7 +678,7 @@ void BinkDecoder::blockScaledFill(DecodeContext &ctx) { memset(dest, v, 16); } -void BinkDecoder::blockScaledPattern(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockScaledPattern(DecodeContext &ctx) { byte col[2]; for (int i = 0; i < 2; i++) @@ -865,7 +694,7 @@ void BinkDecoder::blockScaledPattern(DecodeContext &ctx) { } } -void BinkDecoder::blockScaledRaw(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockScaledRaw(DecodeContext &ctx) { byte row[8]; byte *dest1 = ctx.dest; @@ -880,32 +709,27 @@ void BinkDecoder::blockScaledRaw(DecodeContext &ctx) { } } -void BinkDecoder::blockScaled(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockScaled(DecodeContext &ctx) { BlockType blockType = (BlockType) getBundleValue(kSourceSubBlockTypes); switch (blockType) { - case kBlockRun: - blockScaledRun(ctx); - break; - - case kBlockIntra: - blockScaledIntra(ctx); - break; - - case kBlockFill: - blockScaledFill(ctx); - break; - - case kBlockPattern: - blockScaledPattern(ctx); - break; - - case kBlockRaw: - blockScaledRaw(ctx); - break; - - default: - error("Invalid 16x16 block type: %d", blockType); + case kBlockRun: + blockScaledRun(ctx); + break; + case kBlockIntra: + blockScaledIntra(ctx); + break; + case kBlockFill: + blockScaledFill(ctx); + break; + case kBlockPattern: + blockScaledPattern(ctx); + break; + case kBlockRaw: + blockScaledRaw(ctx); + break; + default: + error("Invalid 16x16 block type: %d", blockType); } ctx.blockX += 1; @@ -913,7 +737,7 @@ void BinkDecoder::blockScaled(DecodeContext &ctx) { ctx.prev += 8; } -void BinkDecoder::blockMotion(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockMotion(DecodeContext &ctx) { int8 xOff = getBundleValue(kSourceXOff); int8 yOff = getBundleValue(kSourceYOff); @@ -926,7 +750,7 @@ void BinkDecoder::blockMotion(DecodeContext &ctx) { memcpy(dest, prev, 8); } -void BinkDecoder::blockRun(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockRun(DecodeContext &ctx) { const uint8 *scan = binkPatterns[ctx.video->bits->getBits(4)]; int i = 0; @@ -953,7 +777,7 @@ void BinkDecoder::blockRun(DecodeContext &ctx) { ctx.dest[ctx.coordMap[*scan++]] = getBundleValue(kSourceColors); } -void BinkDecoder::blockResidue(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockResidue(DecodeContext &ctx) { blockMotion(ctx); byte v = ctx.video->bits->getBits(7); @@ -970,7 +794,7 @@ void BinkDecoder::blockResidue(DecodeContext &ctx) { dst[j] += src[j]; } -void BinkDecoder::blockIntra(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockIntra(DecodeContext &ctx) { int16 block[64]; memset(block, 0, 64 * sizeof(int16)); @@ -981,7 +805,7 @@ void BinkDecoder::blockIntra(DecodeContext &ctx) { IDCTPut(ctx, block); } -void BinkDecoder::blockFill(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockFill(DecodeContext &ctx) { byte v = getBundleValue(kSourceColors); byte *dest = ctx.dest; @@ -989,7 +813,7 @@ void BinkDecoder::blockFill(DecodeContext &ctx) { memset(dest, v, 8); } -void BinkDecoder::blockInter(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockInter(DecodeContext &ctx) { blockMotion(ctx); int16 block[64]; @@ -1002,7 +826,7 @@ void BinkDecoder::blockInter(DecodeContext &ctx) { IDCTAdd(ctx, block); } -void BinkDecoder::blockPattern(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockPattern(DecodeContext &ctx) { byte col[2]; for (int i = 0; i < 2; i++) @@ -1017,7 +841,7 @@ void BinkDecoder::blockPattern(DecodeContext &ctx) { } } -void BinkDecoder::blockRaw(DecodeContext &ctx) { +void BinkDecoder::BinkVideoTrack::blockRaw(DecodeContext &ctx) { byte *dest = ctx.dest; byte *data = _bundles[kSourceColors].curPtr; for (int i = 0; i < 8; i++, dest += ctx.pitch, data += 8) @@ -1026,7 +850,7 @@ void BinkDecoder::blockRaw(DecodeContext &ctx) { _bundles[kSourceColors].curPtr += 64; } -void BinkDecoder::readRuns(VideoFrame &video, Bundle &bundle) { +void BinkDecoder::BinkVideoTrack::readRuns(VideoFrame &video, Bundle &bundle) { uint32 n = readBundleCount(video, bundle); if (n == 0) return; @@ -1046,7 +870,7 @@ void BinkDecoder::readRuns(VideoFrame &video, Bundle &bundle) { *bundle.curDec++ = getHuffmanSymbol(video, bundle.huffman); } -void BinkDecoder::readMotionValues(VideoFrame &video, Bundle &bundle) { +void BinkDecoder::BinkVideoTrack::readMotionValues(VideoFrame &video, Bundle &bundle) { uint32 n = readBundleCount(video, bundle); if (n == 0) return; @@ -1083,7 +907,7 @@ void BinkDecoder::readMotionValues(VideoFrame &video, Bundle &bundle) { } const uint8 rleLens[4] = { 4, 8, 12, 32 }; -void BinkDecoder::readBlockTypes(VideoFrame &video, Bundle &bundle) { +void BinkDecoder::BinkVideoTrack::readBlockTypes(VideoFrame &video, Bundle &bundle) { uint32 n = readBundleCount(video, bundle); if (n == 0) return; @@ -1120,7 +944,7 @@ void BinkDecoder::readBlockTypes(VideoFrame &video, Bundle &bundle) { } while (bundle.curDec < decEnd); } -void BinkDecoder::readPatterns(VideoFrame &video, Bundle &bundle) { +void BinkDecoder::BinkVideoTrack::readPatterns(VideoFrame &video, Bundle &bundle) { uint32 n = readBundleCount(video, bundle); if (n == 0) return; @@ -1138,7 +962,7 @@ void BinkDecoder::readPatterns(VideoFrame &video, Bundle &bundle) { } -void BinkDecoder::readColors(VideoFrame &video, Bundle &bundle) { +void BinkDecoder::BinkVideoTrack::readColors(VideoFrame &video, Bundle &bundle) { uint32 n = readBundleCount(video, bundle); if (n == 0) return; @@ -1182,7 +1006,7 @@ void BinkDecoder::readColors(VideoFrame &video, Bundle &bundle) { } } -void BinkDecoder::readDCS(VideoFrame &video, Bundle &bundle, int startBits, bool hasSign) { +void BinkDecoder::BinkVideoTrack::readDCS(VideoFrame &video, Bundle &bundle, int startBits, bool hasSign) { uint32 length = readBundleCount(video, bundle); if (length == 0) return; @@ -1228,7 +1052,7 @@ void BinkDecoder::readDCS(VideoFrame &video, Bundle &bundle, int startBits, bool } /** Reads 8x8 block of DCT coefficients. */ -void BinkDecoder::readDCTCoeffs(VideoFrame &video, int16 *block, bool isIntra) { +void BinkDecoder::BinkVideoTrack::readDCTCoeffs(VideoFrame &video, int16 *block, bool isIntra) { int coefCount = 0; int coefIdx[64]; @@ -1326,7 +1150,7 @@ void BinkDecoder::readDCTCoeffs(VideoFrame &video, int16 *block, bool isIntra) { } /** Reads 8x8 block with residue after motion compensation. */ -void BinkDecoder::readResidue(VideoFrame &video, int16 *block, int masksCount) { +void BinkDecoder::BinkVideoTrack::readResidue(VideoFrame &video, int16 *block, int masksCount) { int nzCoeff[64]; int nzCoeffCount = 0; @@ -1417,63 +1241,170 @@ void BinkDecoder::readResidue(VideoFrame &video, int16 *block, int masksCount) { } } -float BinkDecoder::getFloat(AudioTrack &audio) { - int power = audio.bits->getBits(5); +#define A1 2896 /* (1/sqrt(2))<<12 */ +#define A2 2217 +#define A3 3784 +#define A4 -5352 - float f = ldexp((float)audio.bits->getBits(23), power - 23); +#define IDCT_TRANSFORM(dest,s0,s1,s2,s3,s4,s5,s6,s7,d0,d1,d2,d3,d4,d5,d6,d7,munge,src) {\ + const int a0 = (src)[s0] + (src)[s4]; \ + const int a1 = (src)[s0] - (src)[s4]; \ + const int a2 = (src)[s2] + (src)[s6]; \ + const int a3 = (A1*((src)[s2] - (src)[s6])) >> 11; \ + const int a4 = (src)[s5] + (src)[s3]; \ + const int a5 = (src)[s5] - (src)[s3]; \ + const int a6 = (src)[s1] + (src)[s7]; \ + const int a7 = (src)[s1] - (src)[s7]; \ + const int b0 = a4 + a6; \ + const int b1 = (A3*(a5 + a7)) >> 11; \ + const int b2 = ((A4*a5) >> 11) - b0 + b1; \ + const int b3 = (A1*(a6 - a4) >> 11) - b2; \ + const int b4 = ((A2*a7) >> 11) + b3 - b1; \ + (dest)[d0] = munge(a0+a2 +b0); \ + (dest)[d1] = munge(a1+a3-a2+b2); \ + (dest)[d2] = munge(a1-a3+a2+b3); \ + (dest)[d3] = munge(a0-a2 -b4); \ + (dest)[d4] = munge(a0-a2 +b4); \ + (dest)[d5] = munge(a1-a3+a2-b3); \ + (dest)[d6] = munge(a1+a3-a2-b2); \ + (dest)[d7] = munge(a0+a2 -b0); \ +} +/* end IDCT_TRANSFORM macro */ - if (audio.bits->getBit()) - f = -f; +#define MUNGE_NONE(x) (x) +#define IDCT_COL(dest,src) IDCT_TRANSFORM(dest,0,8,16,24,32,40,48,56,0,8,16,24,32,40,48,56,MUNGE_NONE,src) - return f; +#define MUNGE_ROW(x) (((x) + 0x7F)>>8) +#define IDCT_ROW(dest,src) IDCT_TRANSFORM(dest,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,MUNGE_ROW,src) + +static inline void IDCTCol(int16 *dest, const int16 *src) { + if ((src[8] | src[16] | src[24] | src[32] | src[40] | src[48] | src[56]) == 0) { + dest[ 0] = + dest[ 8] = + dest[16] = + dest[24] = + dest[32] = + dest[40] = + dest[48] = + dest[56] = src[0]; + } else { + IDCT_COL(dest, src); + } +} + +void BinkDecoder::BinkVideoTrack::IDCT(int16 *block) { + int i; + int16 temp[64]; + + for (i = 0; i < 8; i++) + IDCTCol(&temp[i], &block[i]); + for (i = 0; i < 8; i++) { + IDCT_ROW( (&block[8*i]), (&temp[8*i]) ); + } +} + +void BinkDecoder::BinkVideoTrack::IDCTAdd(DecodeContext &ctx, int16 *block) { + int i, j; + + IDCT(block); + byte *dest = ctx.dest; + for (i = 0; i < 8; i++, dest += ctx.pitch, block += 8) + for (j = 0; j < 8; j++) + dest[j] += block[j]; +} + +void BinkDecoder::BinkVideoTrack::IDCTPut(DecodeContext &ctx, int16 *block) { + int i; + int16 temp[64]; + for (i = 0; i < 8; i++) + IDCTCol(&temp[i], &block[i]); + for (i = 0; i < 8; i++) { + IDCT_ROW( (&ctx.dest[i*ctx.pitch]), (&temp[8*i]) ); + } +} + +BinkDecoder::BinkAudioTrack::BinkAudioTrack(BinkDecoder::AudioInfo &audio) : _audioInfo(&audio) { + _audioStream = Audio::makeQueuingAudioStream(_audioInfo->outSampleRate, _audioInfo->outChannels == 2); +} + +BinkDecoder::BinkAudioTrack::~BinkAudioTrack() { + delete _audioStream; +} + +Audio::AudioStream *BinkDecoder::BinkAudioTrack::getAudioStream() const { + return _audioStream; +} + +void BinkDecoder::BinkAudioTrack::decodePacket() { + int outSize = _audioInfo->frameLen * _audioInfo->channels; + + while (_audioInfo->bits->pos() < _audioInfo->bits->size()) { + int16 *out = (int16 *)malloc(outSize * 2); + memset(out, 0, outSize * 2); + + audioBlock(out); + + byte flags = Audio::FLAG_16BITS; + if (_audioInfo->outChannels == 2) + flags |= Audio::FLAG_STEREO; + +#ifdef SCUMM_LITTLE_ENDIAN + flags |= Audio::FLAG_LITTLE_ENDIAN; +#endif + + _audioStream->queueBuffer((byte *)out, _audioInfo->blockSize * 2, DisposeAfterUse::YES, flags); + + if (_audioInfo->bits->pos() & 0x1F) // next data block starts at a 32-byte boundary + _audioInfo->bits->skip(32 - (_audioInfo->bits->pos() & 0x1F)); + } } -void BinkDecoder::audioBlock(AudioTrack &audio, int16 *out) { - if (audio.codec == kAudioCodecDCT) - audioBlockDCT (audio); - else if (audio.codec == kAudioCodecRDFT) - audioBlockRDFT(audio); +void BinkDecoder::BinkAudioTrack::audioBlock(int16 *out) { + if (_audioInfo->codec == kAudioCodecDCT) + audioBlockDCT (); + else if (_audioInfo->codec == kAudioCodecRDFT) + audioBlockRDFT(); - floatToInt16Interleave(out, const_cast<const float **>(audio.coeffsPtr), audio.frameLen, audio.channels); + floatToInt16Interleave(out, const_cast<const float **>(_audioInfo->coeffsPtr), _audioInfo->frameLen, _audioInfo->channels); - if (!audio.first) { - int count = audio.overlapLen * audio.channels; + if (!_audioInfo->first) { + int count = _audioInfo->overlapLen * _audioInfo->channels; int shift = Common::intLog2(count); for (int i = 0; i < count; i++) { - out[i] = (audio.prevCoeffs[i] * (count - i) + out[i] * i) >> shift; + out[i] = (_audioInfo->prevCoeffs[i] * (count - i) + out[i] * i) >> shift; } } - memcpy(audio.prevCoeffs, out + audio.blockSize, audio.overlapLen * audio.channels * sizeof(*out)); + memcpy(_audioInfo->prevCoeffs, out + _audioInfo->blockSize, _audioInfo->overlapLen * _audioInfo->channels * sizeof(*out)); - audio.first = false; + _audioInfo->first = false; } -void BinkDecoder::audioBlockDCT(AudioTrack &audio) { - audio.bits->skip(2); +void BinkDecoder::BinkAudioTrack::audioBlockDCT() { + _audioInfo->bits->skip(2); - for (uint8 i = 0; i < audio.channels; i++) { - float *coeffs = audio.coeffsPtr[i]; + for (uint8 i = 0; i < _audioInfo->channels; i++) { + float *coeffs = _audioInfo->coeffsPtr[i]; - readAudioCoeffs(audio, coeffs); + readAudioCoeffs(coeffs); coeffs[0] /= 0.5; - audio.dct->calc(coeffs); + _audioInfo->dct->calc(coeffs); - for (uint32 j = 0; j < audio.frameLen; j++) - coeffs[j] *= (audio.frameLen / 2.0); + for (uint32 j = 0; j < _audioInfo->frameLen; j++) + coeffs[j] *= (_audioInfo->frameLen / 2.0); } } -void BinkDecoder::audioBlockRDFT(AudioTrack &audio) { - for (uint8 i = 0; i < audio.channels; i++) { - float *coeffs = audio.coeffsPtr[i]; +void BinkDecoder::BinkAudioTrack::audioBlockRDFT() { + for (uint8 i = 0; i < _audioInfo->channels; i++) { + float *coeffs = _audioInfo->coeffsPtr[i]; - readAudioCoeffs(audio, coeffs); + readAudioCoeffs(coeffs); - audio.rdft->calc(coeffs); + _audioInfo->rdft->calc(coeffs); } } @@ -1481,56 +1412,56 @@ static const uint8 rleLengthTab[16] = { 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 32, 64 }; -void BinkDecoder::readAudioCoeffs(AudioTrack &audio, float *coeffs) { - coeffs[0] = getFloat(audio) * audio.root; - coeffs[1] = getFloat(audio) * audio.root; +void BinkDecoder::BinkAudioTrack::readAudioCoeffs(float *coeffs) { + coeffs[0] = getFloat() * _audioInfo->root; + coeffs[1] = getFloat() * _audioInfo->root; float quant[25]; - for (uint32 i = 0; i < audio.bandCount; i++) { - int value = audio.bits->getBits(8); + for (uint32 i = 0; i < _audioInfo->bandCount; i++) { + int value = _audioInfo->bits->getBits(8); // 0.066399999 / log10(M_E) - quant[i] = exp(MIN(value, 95) * 0.15289164787221953823f) * audio.root; + quant[i] = exp(MIN(value, 95) * 0.15289164787221953823f) * _audioInfo->root; } float q = 0.0; // Find band (k) int k; - for (k = 0; audio.bands[k] < 1; k++) + for (k = 0; _audioInfo->bands[k] < 1; k++) q = quant[k]; // Parse coefficients uint32 i = 2; - while (i < audio.frameLen) { + while (i < _audioInfo->frameLen) { uint32 j = 0; - if (audio.bits->getBit()) - j = i + rleLengthTab[audio.bits->getBits(4)] * 8; + if (_audioInfo->bits->getBit()) + j = i + rleLengthTab[_audioInfo->bits->getBits(4)] * 8; else j = i + 8; - j = MIN(j, audio.frameLen); + j = MIN(j, _audioInfo->frameLen); - int width = audio.bits->getBits(4); + int width = _audioInfo->bits->getBits(4); if (width == 0) { memset(coeffs + i, 0, (j - i) * sizeof(*coeffs)); i = j; - while (audio.bands[k] * 2 < i) + while (_audioInfo->bands[k] * 2 < i) q = quant[k++]; } else { while (i < j) { - if (audio.bands[k] * 2 == i) + if (_audioInfo->bands[k] * 2 == i) q = quant[k++]; - int coeff = audio.bits->getBits(width); + int coeff = _audioInfo->bits->getBits(width); if (coeff) { - if (audio.bits->getBit()) + if (_audioInfo->bits->getBit()) coeffs[i] = -q * coeff; else coeffs[i] = q * coeff; @@ -1548,10 +1479,10 @@ void BinkDecoder::readAudioCoeffs(AudioTrack &audio, float *coeffs) { } static inline int floatToInt16One(float src) { - return (int16) CLIP<int>((int) floor(src + 0.5), -32768, 32767); + return (int16)CLIP<int>((int)floor(src + 0.5), -32768, 32767); } -void BinkDecoder::floatToInt16Interleave(int16 *dst, const float **src, uint32 length, uint8 channels) { +void BinkDecoder::BinkAudioTrack::floatToInt16Interleave(int16 *dst, const float **src, uint32 length, uint8 channels) { if (channels == 2) { for (uint32 i = 0; i < length; i++) { dst[2 * i ] = floatToInt16One(src[0][i]); @@ -1564,97 +1495,84 @@ void BinkDecoder::floatToInt16Interleave(int16 *dst, const float **src, uint32 l } } -#define A1 2896 /* (1/sqrt(2))<<12 */ -#define A2 2217 -#define A3 3784 -#define A4 -5352 +float BinkDecoder::BinkAudioTrack::getFloat() { + int power = _audioInfo->bits->getBits(5); -#define IDCT_TRANSFORM(dest,s0,s1,s2,s3,s4,s5,s6,s7,d0,d1,d2,d3,d4,d5,d6,d7,munge,src) {\ - const int a0 = (src)[s0] + (src)[s4]; \ - const int a1 = (src)[s0] - (src)[s4]; \ - const int a2 = (src)[s2] + (src)[s6]; \ - const int a3 = (A1*((src)[s2] - (src)[s6])) >> 11; \ - const int a4 = (src)[s5] + (src)[s3]; \ - const int a5 = (src)[s5] - (src)[s3]; \ - const int a6 = (src)[s1] + (src)[s7]; \ - const int a7 = (src)[s1] - (src)[s7]; \ - const int b0 = a4 + a6; \ - const int b1 = (A3*(a5 + a7)) >> 11; \ - const int b2 = ((A4*a5) >> 11) - b0 + b1; \ - const int b3 = (A1*(a6 - a4) >> 11) - b2; \ - const int b4 = ((A2*a7) >> 11) + b3 - b1; \ - (dest)[d0] = munge(a0+a2 +b0); \ - (dest)[d1] = munge(a1+a3-a2+b2); \ - (dest)[d2] = munge(a1-a3+a2+b3); \ - (dest)[d3] = munge(a0-a2 -b4); \ - (dest)[d4] = munge(a0-a2 +b4); \ - (dest)[d5] = munge(a1-a3+a2-b3); \ - (dest)[d6] = munge(a1+a3-a2-b2); \ - (dest)[d7] = munge(a0+a2 -b0); \ + float f = ldexp((float)_audioInfo->bits->getBits(23), power - 23); + + if (_audioInfo->bits->getBit()) + f = -f; + + return f; } -/* end IDCT_TRANSFORM macro */ -#define MUNGE_NONE(x) (x) -#define IDCT_COL(dest,src) IDCT_TRANSFORM(dest,0,8,16,24,32,40,48,56,0,8,16,24,32,40,48,56,MUNGE_NONE,src) +void BinkDecoder::initAudioTrack(AudioInfo &audio) { + audio.sampleCount = 0; + audio.bits = 0; -#define MUNGE_ROW(x) (((x) + 0x7F)>>8) -#define IDCT_ROW(dest,src) IDCT_TRANSFORM(dest,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,MUNGE_ROW,src) + audio.channels = ((audio.flags & kAudioFlagStereo) != 0) ? 2 : 1; + audio.codec = ((audio.flags & kAudioFlagDCT ) != 0) ? kAudioCodecDCT : kAudioCodecRDFT; -static inline void IDCTCol(int16 *dest, const int16 *src) -{ - if ((src[8] | src[16] | src[24] | src[32] | src[40] | src[48] | src[56]) == 0) { - dest[ 0] = - dest[ 8] = - dest[16] = - dest[24] = - dest[32] = - dest[40] = - dest[48] = - dest[56] = src[0]; - } else { - IDCT_COL(dest, src); - } -} + if (audio.channels > kAudioChannelsMax) + error("Too many audio channels: %d", audio.channels); -void BinkDecoder::IDCT(int16 *block) { - int i; - int16 temp[64]; + uint32 frameLenBits; + // Calculate frame length + if (audio.sampleRate < 22050) + frameLenBits = 9; + else if(audio.sampleRate < 44100) + frameLenBits = 10; + else + frameLenBits = 11; - for (i = 0; i < 8; i++) - IDCTCol(&temp[i], &block[i]); - for (i = 0; i < 8; i++) { - IDCT_ROW( (&block[8*i]), (&temp[8*i]) ); - } -} + audio.frameLen = 1 << frameLenBits; -void BinkDecoder::IDCTAdd(DecodeContext &ctx, int16 *block) { - int i, j; + audio.outSampleRate = audio.sampleRate; + audio.outChannels = audio.channels; - IDCT(block); - byte *dest = ctx.dest; - for (i = 0; i < 8; i++, dest += ctx.pitch, block += 8) - for (j = 0; j < 8; j++) - dest[j] += block[j]; -} + if (audio.codec == kAudioCodecRDFT) { + // RDFT audio already interleaves the samples correctly -void BinkDecoder::IDCTPut(DecodeContext &ctx, int16 *block) { - int i; - int16 temp[64]; - for (i = 0; i < 8; i++) - IDCTCol(&temp[i], &block[i]); - for (i = 0; i < 8; i++) { - IDCT_ROW( (&ctx.dest[i*ctx.pitch]), (&temp[8*i]) ); + if (audio.channels == 2) + frameLenBits++; + + audio.sampleRate *= audio.channels; + audio.frameLen *= audio.channels; + audio.channels = 1; } -} -void BinkDecoder::updateVolume() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) - g_system->getMixer()->setChannelVolume(_audioHandle, getVolume()); -} + audio.overlapLen = audio.frameLen / 16; + audio.blockSize = (audio.frameLen - audio.overlapLen) * audio.channels; + audio.root = 2.0 / sqrt((double)audio.frameLen); + + uint32 sampleRateHalf = (audio.sampleRate + 1) / 2; + + // Calculate number of bands + for (audio.bandCount = 1; audio.bandCount < 25; audio.bandCount++) + if (sampleRateHalf <= binkCriticalFreqs[audio.bandCount - 1]) + break; + + audio.bands = new uint32[audio.bandCount + 1]; + + // Populate bands + audio.bands[0] = 1; + for (uint32 i = 1; i < audio.bandCount; i++) + audio.bands[i] = binkCriticalFreqs[i - 1] * (audio.frameLen / 2) / sampleRateHalf; + audio.bands[audio.bandCount] = audio.frameLen / 2; + + audio.first = true; + + for (uint8 i = 0; i < audio.channels; i++) + audio.coeffsPtr[i] = audio.coeffs + i * audio.frameLen; + + audio.codec = ((audio.flags & kAudioFlagDCT) != 0) ? kAudioCodecDCT : kAudioCodecRDFT; + + if (audio.codec == kAudioCodecRDFT) + audio.rdft = new Common::RDFT(frameLenBits, Common::RDFT::DFT_C2R); + else if (audio.codec == kAudioCodecDCT) + audio.dct = new Common::DCT(frameLenBits, Common::DCT::DCT_III); -void BinkDecoder::updateBalance() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) - g_system->getMixer()->setChannelBalance(_audioHandle, getBalance()); + addTrack(new BinkAudioTrack(audio)); } } // End of namespace Video diff --git a/video/bink_decoder.h b/video/bink_decoder.h index a5e1b10270..150e91aab7 100644 --- a/video/bink_decoder.h +++ b/video/bink_decoder.h @@ -31,22 +31,27 @@ #ifndef VIDEO_BINK_DECODER_H #define VIDEO_BINK_DECODER_H -#include "audio/audiostream.h" -#include "audio/mixer.h" #include "common/array.h" #include "common/rational.h" -#include "graphics/surface.h" - #include "video/video_decoder.h" +namespace Audio { +class AudioStream; +class QueuingAudioStream; +} + namespace Common { - class SeekableReadStream; - class BitStream; - class Huffman; +class SeekableReadStream; +class BitStream; +class Huffman; - class RDFT; - class DCT; +class RDFT; +class DCT; +} + +namespace Graphics { +struct Surface; } namespace Video { @@ -57,92 +62,28 @@ namespace Video { * Video decoder used in engines: * - scumm (he) */ -class BinkDecoder : public FixedRateVideoDecoder { +class BinkDecoder : public VideoDecoder { public: BinkDecoder(); ~BinkDecoder(); - // VideoDecoder API bool loadStream(Common::SeekableReadStream *stream); void close(); - bool isVideoLoaded() const { return _bink != 0; } - uint16 getWidth() const { return _surface.w; } - uint16 getHeight() const { return _surface.h; } - Graphics::PixelFormat getPixelFormat() const { return _surface.format; } - uint32 getFrameCount() const { return _frames.size(); } - uint32 getTime() const; - const Graphics::Surface *decodeNextFrame(); - - // FixedRateVideoDecoder - Common::Rational getFrameRate() const { return _frameRate; } - - // Bink specific - bool loadStream(Common::SeekableReadStream *stream, const Graphics::PixelFormat &format); protected: - // VideoDecoder API - void updateVolume(); - void updateBalance(); + void readNextPacket(); +private: static const int kAudioChannelsMax = 2; static const int kAudioBlockSizeMax = (kAudioChannelsMax << 11); - /** IDs for different data types used in Bink video codec. */ - enum Source { - kSourceBlockTypes = 0, ///< 8x8 block types. - kSourceSubBlockTypes , ///< 16x16 block types (a subset of 8x8 block types). - kSourceColors , ///< Pixel values used for different block types. - kSourcePattern , ///< 8-bit values for 2-color pattern fill. - kSourceXOff , ///< X components of motion value. - kSourceYOff , ///< Y components of motion value. - kSourceIntraDC , ///< DC values for intrablocks with DCT. - kSourceInterDC , ///< DC values for interblocks with DCT. - kSourceRun , ///< Run lengths for special fill block. - - kSourceMAX - }; - - /** Bink video block types. */ - enum BlockType { - kBlockSkip = 0, ///< Skipped block. - kBlockScaled , ///< Block has size 16x16. - kBlockMotion , ///< Block is copied from previous frame with some offset. - kBlockRun , ///< Block is composed from runs of colors with custom scan order. - kBlockResidue , ///< Motion block with some difference added. - kBlockIntra , ///< Intra DCT block. - kBlockFill , ///< Block is filled with single color. - kBlockInter , ///< Motion block with DCT applied to the difference. - kBlockPattern , ///< Block is filled with two colors following custom pattern. - kBlockRaw ///< Uncoded 8x8 block. - }; - - /** Data structure for decoding and tranlating Huffman'd data. */ - struct Huffman { - int index; ///< Index of the Huffman codebook to use. - byte symbols[16]; ///< Huffman symbol => Bink symbol tranlation list. - }; - - /** Data structure used for decoding a single Bink data type. */ - struct Bundle { - int countLengths[2]; ///< Lengths of number of entries to decode (in bits). - int countLength; ///< Length of number of entries to decode (in bits) for the current plane. - - Huffman huffman; ///< Huffman codebook. - - byte *data; ///< Buffer for decoded symbols. - byte *dataEnd; ///< Buffer end. - - byte *curDec; ///< Pointer to the data that wasn't yet decoded. - byte *curPtr; ///< Pointer to the data that wasn't yet read. - }; - enum AudioCodec { kAudioCodecDCT, kAudioCodecRDFT }; /** An audio track. */ - struct AudioTrack { + struct AudioInfo { uint16 flags; uint32 sampleRate; @@ -177,8 +118,8 @@ protected: Common::RDFT *rdft; Common::DCT *dct; - AudioTrack(); - ~AudioTrack(); + AudioInfo(); + ~AudioInfo(); }; /** A video frame. */ @@ -194,149 +135,218 @@ protected: ~VideoFrame(); }; - /** A decoder state. */ - struct DecodeContext { - VideoFrame *video; + class BinkVideoTrack : public FixedRateVideoTrack { + public: + BinkVideoTrack(uint32 width, uint32 height, const Graphics::PixelFormat &format, uint32 frameCount, const Common::Rational &frameRate, bool swapPlanes, bool hasAlpha, uint32 id); + ~BinkVideoTrack(); + + uint16 getWidth() const { return _surface.w; } + uint16 getHeight() const { return _surface.h; } + Graphics::PixelFormat getPixelFormat() const { return _surface.format; } + int getCurFrame() const { return _curFrame; } + int getFrameCount() const { return _frameCount; } + const Graphics::Surface *decodeNextFrame() { return &_surface; } + + /** Decode a video packet. */ + void decodePacket(VideoFrame &frame); + + protected: + Common::Rational getFrameRate() const { return _frameRate; } - uint32 planeIdx; + private: + /** A decoder state. */ + struct DecodeContext { + VideoFrame *video; + + uint32 planeIdx; - uint32 blockX; - uint32 blockY; + uint32 blockX; + uint32 blockY; - byte *dest; - byte *prev; + byte *dest; + byte *prev; - byte *destStart, *destEnd; - byte *prevStart, *prevEnd; + byte *destStart, *destEnd; + byte *prevStart, *prevEnd; - uint32 pitch; + uint32 pitch; - int coordMap[64]; - int coordScaledMap1[64]; - int coordScaledMap2[64]; - int coordScaledMap3[64]; - int coordScaledMap4[64]; + int coordMap[64]; + int coordScaledMap1[64]; + int coordScaledMap2[64]; + int coordScaledMap3[64]; + int coordScaledMap4[64]; + }; + + /** IDs for different data types used in Bink video codec. */ + enum Source { + kSourceBlockTypes = 0, ///< 8x8 block types. + kSourceSubBlockTypes , ///< 16x16 block types (a subset of 8x8 block types). + kSourceColors , ///< Pixel values used for different block types. + kSourcePattern , ///< 8-bit values for 2-color pattern fill. + kSourceXOff , ///< X components of motion value. + kSourceYOff , ///< Y components of motion value. + kSourceIntraDC , ///< DC values for intrablocks with DCT. + kSourceInterDC , ///< DC values for interblocks with DCT. + kSourceRun , ///< Run lengths for special fill block. + + kSourceMAX + }; + + /** Bink video block types. */ + enum BlockType { + kBlockSkip = 0, ///< Skipped block. + kBlockScaled , ///< Block has size 16x16. + kBlockMotion , ///< Block is copied from previous frame with some offset. + kBlockRun , ///< Block is composed from runs of colors with custom scan order. + kBlockResidue , ///< Motion block with some difference added. + kBlockIntra , ///< Intra DCT block. + kBlockFill , ///< Block is filled with single color. + kBlockInter , ///< Motion block with DCT applied to the difference. + kBlockPattern , ///< Block is filled with two colors following custom pattern. + kBlockRaw ///< Uncoded 8x8 block. + }; + + /** Data structure for decoding and tranlating Huffman'd data. */ + struct Huffman { + int index; ///< Index of the Huffman codebook to use. + byte symbols[16]; ///< Huffman symbol => Bink symbol tranlation list. + }; + + /** Data structure used for decoding a single Bink data type. */ + struct Bundle { + int countLengths[2]; ///< Lengths of number of entries to decode (in bits). + int countLength; ///< Length of number of entries to decode (in bits) for the current plane. + + Huffman huffman; ///< Huffman codebook. + + byte *data; ///< Buffer for decoded symbols. + byte *dataEnd; ///< Buffer end. + + byte *curDec; ///< Pointer to the data that wasn't yet decoded. + byte *curPtr; ///< Pointer to the data that wasn't yet read. + }; + + int _curFrame; + int _frameCount; + + Graphics::Surface _surface; + + uint32 _id; ///< The BIK FourCC. + + bool _hasAlpha; ///< Do video frames have alpha? + bool _swapPlanes; ///< Are the planes ordered (A)YVU instead of (A)YUV? + + Common::Rational _frameRate; + + Bundle _bundles[kSourceMAX]; ///< Bundles for decoding all data types. + + Common::Huffman *_huffman[16]; ///< The 16 Huffman codebooks used in Bink decoding. + + /** Huffman codebooks to use for decoding high nibbles in color data types. */ + Huffman _colHighHuffman[16]; + /** Value of the last decoded high nibble in color data types. */ + int _colLastVal; + + byte *_curPlanes[4]; ///< The 4 color planes, YUVA, current frame. + byte *_oldPlanes[4]; ///< The 4 color planes, YUVA, last frame. + + /** Initialize the bundles. */ + void initBundles(); + /** Deinitialize the bundles. */ + void deinitBundles(); + + /** Initialize the Huffman decoders. */ + void initHuffman(); + + /** Decode a plane. */ + void decodePlane(VideoFrame &video, int planeIdx, bool isChroma); + + /** Read/Initialize a bundle for decoding a plane. */ + void readBundle(VideoFrame &video, Source source); + + /** Read the symbols for a Huffman code. */ + void readHuffman(VideoFrame &video, Huffman &huffman); + /** Merge two Huffman symbol lists. */ + void mergeHuffmanSymbols(VideoFrame &video, byte *dst, const byte *src, int size); + + /** Read and translate a symbol out of a Huffman code. */ + byte getHuffmanSymbol(VideoFrame &video, Huffman &huffman); + + /** Get a direct value out of a bundle. */ + int32 getBundleValue(Source source); + /** Read a count value out of a bundle. */ + uint32 readBundleCount(VideoFrame &video, Bundle &bundle); + + // Handle the block types + void blockSkip (DecodeContext &ctx); + void blockScaledSkip (DecodeContext &ctx); + void blockScaledRun (DecodeContext &ctx); + void blockScaledIntra (DecodeContext &ctx); + void blockScaledFill (DecodeContext &ctx); + void blockScaledPattern(DecodeContext &ctx); + void blockScaledRaw (DecodeContext &ctx); + void blockScaled (DecodeContext &ctx); + void blockMotion (DecodeContext &ctx); + void blockRun (DecodeContext &ctx); + void blockResidue (DecodeContext &ctx); + void blockIntra (DecodeContext &ctx); + void blockFill (DecodeContext &ctx); + void blockInter (DecodeContext &ctx); + void blockPattern (DecodeContext &ctx); + void blockRaw (DecodeContext &ctx); + + // Read the bundles + void readRuns (VideoFrame &video, Bundle &bundle); + void readMotionValues(VideoFrame &video, Bundle &bundle); + void readBlockTypes (VideoFrame &video, Bundle &bundle); + void readPatterns (VideoFrame &video, Bundle &bundle); + void readColors (VideoFrame &video, Bundle &bundle); + void readDCS (VideoFrame &video, Bundle &bundle, int startBits, bool hasSign); + void readDCTCoeffs (VideoFrame &video, int16 *block, bool isIntra); + void readResidue (VideoFrame &video, int16 *block, int masksCount); + + // Bink video IDCT + void IDCT(int16 *block); + void IDCTPut(DecodeContext &ctx, int16 *block); + void IDCTAdd(DecodeContext &ctx, int16 *block); }; - Common::SeekableReadStream *_bink; + class BinkAudioTrack : public AudioTrack { + public: + BinkAudioTrack(AudioInfo &audio); + ~BinkAudioTrack(); + + /** Decode an audio packet. */ + void decodePacket(); - uint32 _id; ///< The BIK FourCC. + protected: + Audio::AudioStream *getAudioStream() const; - Common::Rational _frameRate; + private: + AudioInfo *_audioInfo; + Audio::QueuingAudioStream *_audioStream; - Graphics::Surface _surface; + float getFloat(); - Audio::SoundHandle _audioHandle; - Audio::QueuingAudioStream *_audioStream; - int32 _audioStartOffset; + /** Decode an audio block. */ + void audioBlock(int16 *out); + /** Decode a DCT'd audio block. */ + void audioBlockDCT(); + /** Decode a RDFT'd audio block. */ + void audioBlockRDFT(); - uint32 _videoFlags; ///< Video frame features. + void readAudioCoeffs(float *coeffs); - bool _hasAlpha; ///< Do video frames have alpha? - bool _swapPlanes; ///< Are the planes ordered (A)YVU instead of (A)YUV? + static void floatToInt16Interleave(int16 *dst, const float **src, uint32 length, uint8 channels); + }; + + Common::SeekableReadStream *_bink; - Common::Array<AudioTrack> _audioTracks; ///< All audio tracks. + Common::Array<AudioInfo> _audioTracks; ///< All audio tracks. Common::Array<VideoFrame> _frames; ///< All video frames. - uint32 _audioTrack; ///< Audio track to use. - - Common::Huffman *_huffman[16]; ///< The 16 Huffman codebooks used in Bink decoding. - - Bundle _bundles[kSourceMAX]; ///< Bundles for decoding all data types. - - /** Huffman codebooks to use for decoding high nibbles in color data types. */ - Huffman _colHighHuffman[16]; - /** Value of the last decoded high nibble in color data types. */ - int _colLastVal; - - byte *_curPlanes[4]; ///< The 4 color planes, YUVA, current frame. - byte *_oldPlanes[4]; ///< The 4 color planes, YUVA, last frame. - - - /** Initialize the bundles. */ - void initBundles(); - /** Deinitialize the bundles. */ - void deinitBundles(); - - /** Initialize the Huffman decoders. */ - void initHuffman(); - - /** Decode an audio packet. */ - void audioPacket(AudioTrack &audio); - /** Decode a video packet. */ - virtual void videoPacket(VideoFrame &video); - - /** Decode a plane. */ - void decodePlane(VideoFrame &video, int planeIdx, bool isChroma); - - /** Read/Initialize a bundle for decoding a plane. */ - void readBundle(VideoFrame &video, Source source); - - /** Read the symbols for a Huffman code. */ - void readHuffman(VideoFrame &video, Huffman &huffman); - /** Merge two Huffman symbol lists. */ - void mergeHuffmanSymbols(VideoFrame &video, byte *dst, const byte *src, int size); - - /** Read and translate a symbol out of a Huffman code. */ - byte getHuffmanSymbol(VideoFrame &video, Huffman &huffman); - - /** Get a direct value out of a bundle. */ - int32 getBundleValue(Source source); - /** Read a count value out of a bundle. */ - uint32 readBundleCount(VideoFrame &video, Bundle &bundle); - - // Handle the block types - void blockSkip (DecodeContext &ctx); - void blockScaledSkip (DecodeContext &ctx); - void blockScaledRun (DecodeContext &ctx); - void blockScaledIntra (DecodeContext &ctx); - void blockScaledFill (DecodeContext &ctx); - void blockScaledPattern(DecodeContext &ctx); - void blockScaledRaw (DecodeContext &ctx); - void blockScaled (DecodeContext &ctx); - void blockMotion (DecodeContext &ctx); - void blockRun (DecodeContext &ctx); - void blockResidue (DecodeContext &ctx); - void blockIntra (DecodeContext &ctx); - void blockFill (DecodeContext &ctx); - void blockInter (DecodeContext &ctx); - void blockPattern (DecodeContext &ctx); - void blockRaw (DecodeContext &ctx); - - // Read the bundles - void readRuns (VideoFrame &video, Bundle &bundle); - void readMotionValues(VideoFrame &video, Bundle &bundle); - void readBlockTypes (VideoFrame &video, Bundle &bundle); - void readPatterns (VideoFrame &video, Bundle &bundle); - void readColors (VideoFrame &video, Bundle &bundle); - void readDCS (VideoFrame &video, Bundle &bundle, int startBits, bool hasSign); - void readDCTCoeffs (VideoFrame &video, int16 *block, bool isIntra); - void readResidue (VideoFrame &video, int16 *block, int masksCount); - - void initAudioTrack(AudioTrack &audio); - - float getFloat(AudioTrack &audio); - - /** Decode an audio block. */ - void audioBlock (AudioTrack &audio, int16 *out); - /** Decode a DCT'd audio block. */ - void audioBlockDCT (AudioTrack &audio); - /** Decode a RDFT'd audio block. */ - void audioBlockRDFT(AudioTrack &audio); - - void readAudioCoeffs(AudioTrack &audio, float *coeffs); - - void floatToInt16Interleave(int16 *dst, const float **src, uint32 length, uint8 channels); - - // Bink video IDCT - void IDCT(int16 *block); - void IDCTPut(DecodeContext &ctx, int16 *block); - void IDCTAdd(DecodeContext &ctx, int16 *block); - - /** Start playing the audio track */ - void startAudio(); - /** Stop playing the audio track */ - void stopAudio(); + void initAudioTrack(AudioInfo &audio); }; } // End of namespace Video diff --git a/video/codecs/svq1.cpp b/video/codecs/svq1.cpp index eba0c90305..14452ab15b 100644 --- a/video/codecs/svq1.cpp +++ b/video/codecs/svq1.cpp @@ -317,7 +317,7 @@ bool SVQ1Decoder::svq1DecodeBlockIntra(Common::BitStream *s, byte *pixels, int p for (uint y = 0; y < height; y++) memset(&dst[y * (pitch / 4)], mean, width); } else { - const uint32 *codebook = s_svq1IntraCodebooks[level]; + const uint32 *codebook = (const uint32 *)s_svq1IntraCodebooks[level]; uint32 bitCache = s->getBits(stages * 4); // calculate codebook entries for this vector @@ -336,7 +336,7 @@ bool SVQ1Decoder::svq1DecodeBlockIntra(Common::BitStream *s, byte *pixels, int p // add codebook entries to vector for (int j = 0; j < stages; j++) { - n3 = codebook[entries[j]] ^ 0x80808080; + n3 = READ_UINT32(&codebook[entries[j]]) ^ 0x80808080; n1 += (n3 & 0xFF00FF00) >> 8; n2 += n3 & 0x00FF00FF; } @@ -409,7 +409,7 @@ bool SVQ1Decoder::svq1DecodeBlockNonIntra(Common::BitStream *s, byte *pixels, in } int mean = _interMean->getSymbol(*s) - 256; - const uint32 *codebook = s_svq1InterCodebooks[level]; + const uint32 *codebook = (const uint32 *)s_svq1InterCodebooks[level]; uint32 bitCache = s->getBits(stages * 4); // calculate codebook entries for this vector @@ -430,7 +430,7 @@ bool SVQ1Decoder::svq1DecodeBlockNonIntra(Common::BitStream *s, byte *pixels, in // add codebook entries to vector for (int j = 0; j < stages; j++) { - n3 = codebook[entries[j]] ^ 0x80808080; + n3 = READ_UINT32(&codebook[entries[j]]) ^ 0x80808080; n1 += (n3 & 0xFF00FF00) >> 8; n2 += n3 & 0x00FF00FF; } diff --git a/video/codecs/svq1_cb.h b/video/codecs/svq1_cb.h index f9a8c54e40..8281b3fc28 100644 --- a/video/codecs/svq1_cb.h +++ b/video/codecs/svq1_cb.h @@ -30,1477 +30,1477 @@ namespace Video { -static const uint32 s_svq1InterCodebook4x2[192] = { - 0xf9fa0207, 0xfcfd0307, 0x0807fef9, 0x0403fcf8, - 0x03091113, 0xf8f4f0f2, 0xfdf8f0ee, 0x080c0e0b, - 0x14f6f007, 0x14f6ef07, 0xeb0812fa, 0xec0912f9, - 0xf2ec0319, 0xf3ee071d, 0x0e15fce3, 0x0e14fae1, - 0xe8e4e6ed, 0x0a16201f, 0x1c1f180f, 0xf3eae0e0, - 0xe6e9f802, 0x231b03f7, 0x15150b03, 0xdee5fc08, - 0x2f0ce1e2, 0x2f0de2e3, 0xd2ef1e26, 0xd2ed1a22, - 0xd5cdced6, 0x30373022, 0x2a333630, 0xd1cbccd4, - 0xfa000504, 0x0100fefe, 0xfefffaf5, 0x01090801, - 0x05fa0100, 0x02f40108, 0x08f9f207, 0x0800f805, - 0x080b0401, 0xfb00f8f4, 0x040001ff, 0x1003f8f1, - 0xfafc0811, 0xf8f3fc09, 0xee010602, 0xf40b0bff, - 0x00020006, 0xebf9060e, 0xecf3ff01, 0x150a0101, - 0x0d07fbea, 0x0c04fff5, 0x130e00f9, 0xedfb03fc, - 0x0f0af2e6, 0xfefa0412, 0xeefb1319, 0x0204f9ec, - 0xfcfffaf3, 0xddfe2519, 0x01010405, 0x2b02dceb, - 0x03fffe02, 0xfffafe08, 0x0c02fdfe, 0xfffefefb, - 0xfbfffffd, 0xfe0807ff, 0xfd050702, 0xf8fd0101, - 0xfefdfffd, 0x0d02fdfe, 0xfaf5000f, 0x00000003, - 0xfcfbf7fa, 0x03010412, 0x0400030c, 0xfd03fdf0, - 0x021203ef, 0xfffffdff, 0x00f810fa, 0x00f90ef7, - 0xfb0ef303, 0xfc0ef303, 0xe90e14f9, 0x04f8f908, - 0x10edf108, 0xfd0b0df6, 0x1a01ff09, 0x02e5f105, - 0xfc1007ec, 0x011f09d8, 0xf9e2f41a, 0x04edfe28, - 0x00000006, 0x0201fefa, 0xfa00ff00, 0xfffe0009, - 0xfd0208f9, 0x02fd02ff, 0x04fefc07, 0xfa000002, - 0x0209fefd, 0xfc00fffe, 0xfd00fdfd, 0x040a02fa, - 0x08f60003, 0x04fc0000, 0x020401ff, 0x07f7f903, - 0xfcf70102, 0x00000cff, 0xfc07ff03, 0x0204f203, - 0x0b01f7f4, 0x00010502, 0x02000103, 0xed060800, - 0xfcf9f6fa, 0x07050709, 0xfd031506, 0xfefbf7f5, - 0xfff0f7fc, 0x2401fbfe, 0x00130b08, 0xd7fc0502, - 0xfffeffff, 0x0601fefe, 0xf8010400, 0x00010101, - 0x0004fdfe, 0xfd03ff02, 0x01fc0301, 0xfb0003ff, - 0x03020403, 0xfffafdfe, 0x02fefdfe, 0x000108fc, - 0x060204f9, 0x0001fff9, 0x01fc02fe, 0xff02fa08, - 0x020002fa, 0xfff80405, 0x0900f5ff, 0x0202fe00, - 0xfffcfb11, 0xfefefcff, 0xfd09f300, 0x02f90cff, - 0x02fbfe00, 0xfd14fbf9, 0xe2ff0707, 0x01080503, - 0xfcff03fa, 0x12f5fe02, 0x0e03f900, 0xf7eefd14, - 0xff00fe07, 0xff0000fe, 0x0001fffc, 0x040002fe, - 0x0102fd01, 0x01fb0103, 0xfeff00fd, 0xfd000107, - 0xfe000502, 0x01fffb02, 0xff04feff, 0x0005fd00, - 0xfeff0300, 0xff0501fc, 0x09ff00ff, 0xfffffeff, - 0xff0505fe, 0xfefd02fe, 0x01f50201, 0x02030102, - 0xfefff602, 0x01040204, 0x01fb0504, 0x01f50600, - 0x06060001, 0xf1010200, 0x09050307, 0x020202e2, - 0x020901de, 0x02080805, 0x06060207, 0x0401e502 +static const int8 s_svq1InterCodebook4x2[768] = { + 7, 2, -6, -7, 7, 3, -3, -4, -7, -2, 7, 8, -8, -4, 3, 4, + 19, 17, 9, 3,-14,-16,-12, -8,-18,-16, -8, -3, 11, 14, 12, 8, + 7,-16,-10, 20, 7,-17,-10, 20, -6, 18, 8,-21, -7, 18, 9,-20, + 25, 3,-20,-14, 29, 7,-18,-13,-29, -4, 21, 14,-31, -6, 20, 14, + -19,-26,-28,-24, 31, 32, 22, 10, 15, 24, 31, 28,-32,-32,-22,-13, + 2, -8,-23,-26, -9, 3, 27, 35, 3, 11, 21, 21, 8, -4,-27,-34, + -30,-31, 12, 47,-29,-30, 13, 47, 38, 30,-17,-46, 34, 26,-19,-46, + -42,-50,-51,-43, 34, 48, 55, 48, 48, 54, 51, 42,-44,-52,-53,-47, + 4, 5, 0, -6, -2, -2, 0, 1,-11, -6, -1, -2, 1, 8, 9, 1, + 0, 1, -6, 5, 8, 1,-12, 2, 7,-14, -7, 8, 5, -8, 0, 8, + 1, 4, 11, 8,-12, -8, 0, -5, -1, 1, 0, 4,-15, -8, 3, 16, + 17, 8, -4, -6, 9, -4,-13, -8, 2, 6, 1,-18, -1, 11, 11,-12, + 6, 0, 2, 0, 14, 6, -7,-21, 1, -1,-13,-20, 1, 1, 10, 21, + -22, -5, 7, 13,-11, -1, 4, 12, -7, 0, 14, 19, -4, 3, -5,-19, + -26,-14, 10, 15, 18, 4, -6, -2, 25, 19, -5,-18,-20, -7, 4, 2, + -13, -6, -1, -4, 25, 37, -2,-35, 5, 4, 1, 1,-21,-36, 2, 43, + 2, -2, -1, 3, 8, -2, -6, -1, -2, -3, 2, 12, -5, -2, -2, -1, + -3, -1, -1, -5, -1, 7, 8, -2, 2, 7, 5, -3, 1, 1, -3, -8, + -3, -1, -3, -2, -2, -3, 2, 13, 15, 0,-11, -6, 3, 0, 0, 0, + -6, -9, -5, -4, 18, 4, 1, 3, 12, 3, 0, 4,-16, -3, 3, -3, + -17, 3, 18, 2, -1, -3, -1, -1, -6, 16, -8, 0, -9, 14, -7, 0, + 3,-13, 14, -5, 3,-13, 14, -4, -7, 20, 14,-23, 8, -7, -8, 4, + 8,-15,-19, 16,-10, 13, 11, -3, 9, -1, 1, 26, 5,-15,-27, 2, + -20, 7, 16, -4,-40, 9, 31, 1, 26,-12,-30, -7, 40, -2,-19, 4, + 6, 0, 0, 0, -6, -2, 1, 2, 0, -1, 0, -6, 9, 0, -2, -1, + -7, 8, 2, -3, -1, 2, -3, 2, 7, -4, -2, 4, 2, 0, 0, -6, + -3, -2, 9, 2, -2, -1, 0, -4, -3, -3, 0, -3, -6, 2, 10, 4, + 3, 0,-10, 8, 0, 0, -4, 4, -1, 1, 4, 2, 3, -7, -9, 7, + 2, 1, -9, -4, -1, 12, 0, 0, 3, -1, 7, -4, 3,-14, 4, 2, + -12, -9, 1, 11, 2, 5, 1, 0, 3, 1, 0, 2, 0, 8, 6,-19, + -6,-10, -7, -4, 9, 7, 5, 7, 6, 21, 3, -3,-11, -9, -5, -2, + -4, -9,-16, -1, -2, -5, 1, 36, 8, 11, 19, 0, 2, 5, -4,-41, + -1, -1, -2, -1, -2, -2, 1, 6, 0, 4, 1, -8, 1, 1, 1, 0, + -2, -3, 4, 0, 2, -1, 3, -3, 1, 3, -4, 1, -1, 3, 0, -5, + 3, 4, 2, 3, -2, -3, -6, -1, -2, -3, -2, 2, -4, 8, 1, 0, + -7, 4, 2, 6, -7, -1, 1, 0, -2, 2, -4, 1, 8, -6, 2, -1, + -6, 2, 0, 2, 5, 4, -8, -1, -1,-11, 0, 9, 0, -2, 2, 2, + 17, -5, -4, -1, -1, -4, -2, -2, 0,-13, 9, -3, -1, 12, -7, 2, + 0, -2, -5, 2, -7, -5, 20, -3, 7, 7, -1,-30, 3, 5, 8, 1, + -6, 3, -1, -4, 2, -2,-11, 18, 0, -7, 3, 14, 20, -3,-18, -9, + 7, -2, 0, -1, -2, 0, 0, -1, -4, -1, 1, 0, -2, 2, 0, 4, + 1, -3, 2, 1, 3, 1, -5, 1, -3, 0, -1, -2, 7, 1, 0, -3, + 2, 5, 0, -2, 2, -5, -1, 1, -1, -2, 4, -1, 0, -3, 5, 0, + 0, 3, -1, -2, -4, 1, 5, -1, -1, 0, -1, 9, -1, -2, -1, -1, + -2, 5, 5, -1, -2, 2, -3, -2, 1, 2,-11, 1, 2, 1, 3, 2, + 2,-10, -1, -2, 4, 2, 4, 1, 4, 5, -5, 1, 0, 6,-11, 1, + 1, 0, 6, 6, 0, 2, 1,-15, 7, 3, 5, 9,-30, 2, 2, 2, + -34, 1, 9, 2, 5, 8, 8, 2, 7, 2, 6, 6, 2,-27, 1, 4 }; -static const uint32 s_svq1InterCodebook4x4[384] = { - 0xf9fa0004, 0xf7f3f8fc, 0x06fff8f8, 0x1b1605fe, - 0x0a0bf9f0, 0x0a0df9ee, 0x080cfcf1, 0x0509fff7, - 0xf00f02fe, 0xed1302fd, 0xed1302fd, 0xf20f03fe, - 0x10161611, 0xfefbf9fa, 0xf4f0f0f4, 0xfdff0101, - 0x0800ef0b, 0x09ffeb0e, 0x08feeb0e, 0x06fef00b, - 0x0bf0fe07, 0x0eebfe09, 0x0eeaff0a, 0x0aeeff08, - 0xf70310f6, 0xf50414f3, 0xf60415f2, 0xf80310f5, - 0xf7f7040b, 0xf2f4060f, 0xf2f40811, 0xf5f90a10, - 0x0d0e0a04, 0x100f07ff, 0x0803f9f4, 0xf6eee9ec, - 0xe7e6eef6, 0xf5fa0104, 0x030b0f0d, 0x080d0f0c, - 0xf5f0edf0, 0x0b0f0c07, 0x0b10100b, 0xf6f5f7fa, - 0x050c1312, 0xfc051012, 0xf1f60006, 0xeae9eff7, - 0x15fff2f6, 0x1d00eff5, 0x1e01f0f5, 0x1700f2f6, - 0xfaf4eff0, 0xf9f2eded, 0x0201fffd, 0x131d231b, - 0x1717f8db, 0x1d1cf7d6, 0x1c1af6d5, 0x1613f5da, - 0xdff01020, 0xdbee1427, 0xdaed1326, 0xdeef0f20, - 0xfcfa0918, 0x03faf6ff, 0x03fff7f8, 0xfa020703, - 0x00fffdff, 0xf90204ff, 0xf0030bfd, 0xee091401, - 0x0c06f8fd, 0x0d07f6fb, 0x0705f7fa, 0xff02fbfb, - 0xfffd0cf8, 0x01fd0ff6, 0x01fc0df5, 0x02fd08f5, - 0xf4fb0609, 0xf3f80003, 0xfffffcfc, 0x120f01fc, - 0x0c0e0d09, 0xfeff0304, 0xfbf8fbfe, 0xfcf7f5f9, - 0xfcf9fb07, 0xfcf9fe0e, 0xfbf80011, 0xfbf9010f, - 0x0406fff6, 0x0402f7f1, 0x00fdff02, 0xf6f80d19, - 0xf0fd0b07, 0xf1fd0b07, 0xf7fe0706, 0xfbfd0204, - 0x00fffff9, 0x0602fef7, 0x0e06fcf4, 0x1308faf3, - 0xfbf5eeee, 0x040300fd, 0x06060806, 0x06060606, - 0xf60d03fb, 0xf70f01fa, 0xfa0ffdfa, 0xfd0afafa, - 0xf7f70109, 0x0506090b, 0x07080300, 0xfbfaf2f1, - 0x130bfaf5, 0xf8f7fbfe, 0xf6f70206, 0x05040506, - 0x0f08fdf9, 0x0f0a03ff, 0xfeff0505, 0xe7ebfe04, - 0x05fafa06, 0x09f9f708, 0x0df9f408, 0x0ef9f204, - 0x0101fdfc, 0xfdfefbfd, 0xfcfe0007, 0xfcfc0714, - 0x0afaecfd, 0x01000006, 0xff050805, 0xfe0000fd, - 0x02ff060d, 0x03020305, 0x000300fd, 0xfbfef8f0, - 0x00faf9fe, 0x01fdfafd, 0xff02fffb, 0x05100cff, - 0x080901f9, 0x0305fef6, 0x030702fa, 0xf9ff00fc, - 0xe8f70403, 0x03060200, 0x0704ffff, 0xfeff0305, - 0x02f70603, 0x01f30601, 0x02f60801, 0x01f90801, - 0x1602fdfd, 0x0cfbfdfe, 0x02f6fdfe, 0x02fcfffd, - 0x02080c0b, 0xf8fbfbfb, 0xfd00fcfa, 0x0303fffe, - 0xfffefa0c, 0xfefef80c, 0xfd00f909, 0xfe02fa04, - 0xfd0c01ed, 0xfc0504fc, 0xfffe0106, 0x07fefc04, - 0xf8f9fcfd, 0x00fefcfc, 0x100e02ff, 0x0404fefc, - 0xfb0207ff, 0x01ff00fe, 0x0dfffd04, 0x08f2f406, - 0xfb0405ff, 0xf70305fe, 0xf40407fe, 0xf70407ff, - 0x0101fdfa, 0xfa000b0b, 0xf9fe0406, 0x0a03f6f4, - 0xfefdfdfe, 0x0a0e0b06, 0xf6f6f5f7, 0x02030202, - 0xfff9fbf9, 0x070002ff, 0x090001ff, 0xfffb0403, - 0xfff1ff0a, 0x02fb0104, 0x01ff01fd, 0x040401fd, - 0x0a04ff02, 0x00ff0206, 0xf4f90202, 0xfd0002fc, - 0xf8fffcff, 0xf702ff03, 0xfb050004, 0x03080002, - 0x01010203, 0x0300fe04, 0x0104ff02, 0xe7ff0600, - 0xfcfefeff, 0xfcff00fd, 0x02fcffff, 0x1902fa00, - 0x0005fff5, 0x02fe0007, 0x04fdff0a, 0xfffefbfb, - 0xff030600, 0x01fffffe, 0xfbf4f9ff, 0x04020608, - 0xfaff0602, 0xfcff0a09, 0x00fc0001, 0xfbf7fe03, - 0x000403fc, 0x000303fc, 0x020300f5, 0x020703f5, - 0x0307fc02, 0x0107f801, 0x0104f4ff, 0x0202f703, - 0x09fefe02, 0x0103fdef, 0xfa0107fc, 0x03ff0405, - 0xfc0002ff, 0xff0c08f9, 0xfb0405fe, 0xfef8fb03, - 0xfefb0000, 0x1b03f8fe, 0x06fdfcff, 0xf9fe01fd, - 0xff010404, 0xfdf9f6f9, 0x03050a0a, 0xfdfcfefe, - 0x07050100, 0xecf0fe04, 0x08070400, 0xfffe0002, - 0x110301fe, 0xfffe01fd, 0xfefffeff, 0x00fffbff, - 0x0001fd05, 0x0000fe06, 0xfd00feff, 0xff0801f5, - 0x00000003, 0x01040200, 0x01060002, 0x02fdeefe, - 0x010600f2, 0x01fffefb, 0x010001ff, 0x00040701, - 0xfc0100ff, 0xfc030801, 0x030104fd, 0x01fc01fa, - 0x0303f401, 0xff00f6ff, 0x01020002, 0x04020203, - 0x03000003, 0x01fe0002, 0x00fb0205, 0xfff2ff06, - 0xfdfdfafe, 0x0504ff02, 0x00feff06, 0xfbff0404, - 0x00f501fc, 0x01fc02ff, 0xff03fd02, 0x000ffe01, - 0xfe00ff01, 0x01f9fc01, 0x15fffafe, 0x01ff02fe, - 0x00feff15, 0xfe01fdff, 0xff02fef7, 0xfffc0102, - 0xfa020801, 0x0004fff6, 0x0303fdfc, 0xffff0005, - 0xfe010203, 0x0304fefe, 0xeffc0205, 0x0304fe00, - 0x0300fcf9, 0xff020909, 0xff00faf5, 0x01000105, - 0xf5051100, 0x00fafe03, 0x01fcfe02, 0xff0201fc, - 0xfdfbfffb, 0xfefd05fd, 0xfb021004, 0xffff05fe, - 0x01fc0000, 0x0b0502ff, 0x01feffff, 0xfffdfefc, - 0x000afffb, 0xfd000106, 0x0001fc00, 0xff03fcfe, - 0x00030906, 0x00fe01fe, 0xfefefdfe, 0xfa010001, - 0x01020001, 0x01fe03ff, 0x00f1ff00, 0x060205ff, - 0x02020002, 0x06fcf400, 0xff040100, 0xfc010201, - 0x00f9fe01, 0xff000000, 0x030b02fb, 0xfa000301, - 0xfcf7fd00, 0x00ff0301, 0x00fe0104, 0x06fffd07, - 0x0206fe01, 0xfe03ff00, 0x020004fe, 0x02f202ff, - 0xff000202, 0xf2fd03fe, 0xfd030200, 0x02030105, - 0xf204fd01, 0xff0bfe01, 0x0003ff00, 0x020001ff, - 0x02fd03fe, 0x03fcfffc, 0x030102ff, 0x0702fefa, - 0x000201fe, 0xff0000fe, 0x02ff050c, 0xf901fff8, - 0x02fcfe02, 0xfef5000b, 0xfffd0103, 0xff010300, - 0xfe000300, 0xfdfffa00, 0x00fef90c, 0x0101fe07, - 0x02020201, 0x020002ff, 0x000400e9, 0x03010203, - 0x05fffbfc, 0xff0a05fd, 0xfc030000, 0xfb02ff01 +static const int8 s_svq1InterCodebook4x4[1536] = { + 4, 0, -6, -7, -4, -8,-13, -9, -8, -8, -1, 6, -2, 5, 22, 27, + -16, -7, 11, 10,-18, -7, 13, 10,-15, -4, 12, 8, -9, -1, 9, 5, + -2, 2, 15,-16, -3, 2, 19,-19, -3, 2, 19,-19, -2, 3, 15,-14, + 17, 22, 22, 16, -6, -7, -5, -2,-12,-16,-16,-12, 1, 1, -1, -3, + 11,-17, 0, 8, 14,-21, -1, 9, 14,-21, -2, 8, 11,-16, -2, 6, + 7, -2,-16, 11, 9, -2,-21, 14, 10, -1,-22, 14, 8, -1,-18, 10, + -10, 16, 3, -9,-13, 20, 4,-11,-14, 21, 4,-10,-11, 16, 3, -8, + 11, 4, -9, -9, 15, 6,-12,-14, 17, 8,-12,-14, 16, 10, -7,-11, + 4, 10, 14, 13, -1, 7, 15, 16,-12, -7, 3, 8,-20,-23,-18,-10, + -10,-18,-26,-25, 4, 1, -6,-11, 13, 15, 11, 3, 12, 15, 13, 8, + -16,-19,-16,-11, 7, 12, 15, 11, 11, 16, 16, 11, -6, -9,-11,-10, + 18, 19, 12, 5, 18, 16, 5, -4, 6, 0,-10,-15, -9,-17,-23,-22, + -10,-14, -1, 21,-11,-17, 0, 29,-11,-16, 1, 30,-10,-14, 0, 23, + -16,-17,-12, -6,-19,-19,-14, -7, -3, -1, 1, 2, 27, 35, 29, 19, + -37, -8, 23, 23,-42, -9, 28, 29,-43,-10, 26, 28,-38,-11, 19, 22, + 32, 16,-16,-33, 39, 20,-18,-37, 38, 19,-19,-38, 32, 15,-17,-34, + 24, 9, -6, -4, -1,-10, -6, 3, -8, -9, -1, 3, 3, 7, 2, -6, + -1, -3, -1, 0, -1, 4, 2, -7, -3, 11, 3,-16, 1, 20, 9,-18, + -3, -8, 6, 12, -5,-10, 7, 13, -6, -9, 5, 7, -5, -5, 2, -1, + -8, 12, -3, -1,-10, 15, -3, 1,-11, 13, -4, 1,-11, 8, -3, 2, + 9, 6, -5,-12, 3, 0, -8,-13, -4, -4, -1, -1, -4, 1, 15, 18, + 9, 13, 14, 12, 4, 3, -1, -2, -2, -5, -8, -5, -7,-11, -9, -4, + 7, -5, -7, -4, 14, -2, -7, -4, 17, 0, -8, -5, 15, 1, -7, -5, + -10, -1, 6, 4,-15, -9, 2, 4, 2, -1, -3, 0, 25, 13, -8,-10, + 7, 11, -3,-16, 7, 11, -3,-15, 6, 7, -2, -9, 4, 2, -3, -5, + -7, -1, -1, 0, -9, -2, 2, 6,-12, -4, 6, 14,-13, -6, 8, 19, + -18,-18,-11, -5, -3, 0, 3, 4, 6, 8, 6, 6, 6, 6, 6, 6, + -5, 3, 13,-10, -6, 1, 15, -9, -6, -3, 15, -6, -6, -6, 10, -3, + 9, 1, -9, -9, 11, 9, 6, 5, 0, 3, 8, 7,-15,-14, -6, -5, + -11, -6, 11, 19, -2, -5, -9, -8, 6, 2, -9,-10, 6, 5, 4, 5, + -7, -3, 8, 15, -1, 3, 10, 15, 5, 5, -1, -2, 4, -2,-21,-25, + 6, -6, -6, 5, 8, -9, -7, 9, 8,-12, -7, 13, 4,-14, -7, 14, + -4, -3, 1, 1, -3, -5, -2, -3, 7, 0, -2, -4, 20, 7, -4, -4, + -3,-20, -6, 10, 6, 0, 0, 1, 5, 8, 5, -1, -3, 0, 0, -2, + 13, 6, -1, 2, 5, 3, 2, 3, -3, 0, 3, 0,-16, -8, -2, -5, + -2, -7, -6, 0, -3, -6, -3, 1, -5, -1, 2, -1, -1, 12, 16, 5, + -7, 1, 9, 8,-10, -2, 5, 3, -6, 2, 7, 3, -4, 0, -1, -7, + 3, 4, -9,-24, 0, 2, 6, 3, -1, -1, 4, 7, 5, 3, -1, -2, + 3, 6, -9, 2, 1, 6,-13, 1, 1, 8,-10, 2, 1, 8, -7, 1, + -3, -3, 2, 22, -2, -3, -5, 12, -2, -3,-10, 2, -3, -1, -4, 2, + 11, 12, 8, 2, -5, -5, -5, -8, -6, -4, 0, -3, -2, -1, 3, 3, + 12, -6, -2, -1, 12, -8, -2, -2, 9, -7, 0, -3, 4, -6, 2, -2, + -19, 1, 12, -3, -4, 4, 5, -4, 6, 1, -2, -1, 4, -4, -2, 7, + -3, -4, -7, -8, -4, -4, -2, 0, -1, 2, 14, 16, -4, -2, 4, 4, + -1, 7, 2, -5, -2, 0, -1, 1, 4, -3, -1, 13, 6,-12,-14, 8, + -1, 5, 4, -5, -2, 5, 3, -9, -2, 7, 4,-12, -1, 7, 4, -9, + -6, -3, 1, 1, 11, 11, 0, -6, 6, 4, -2, -7,-12,-10, 3, 10, + -2, -3, -3, -2, 6, 11, 14, 10, -9,-11,-10,-10, 2, 2, 3, 2, + -7, -5, -7, -1, -1, 2, 0, 7, -1, 1, 0, 9, 3, 4, -5, -1, + 10, -1,-15, -1, 4, 1, -5, 2, -3, 1, -1, 1, -3, 1, 4, 4, + 2, -1, 4, 10, 6, 2, -1, 0, 2, 2, -7,-12, -4, 2, 0, -3, + -1, -4, -1, -8, 3, -1, 2, -9, 4, 0, 5, -5, 2, 0, 8, 3, + 3, 2, 1, 1, 4, -2, 0, 3, 2, -1, 4, 1, 0, 6, -1,-25, + -1, -2, -2, -4, -3, 0, -1, -4, -1, -1, -4, 2, 0, -6, 2, 25, + -11, -1, 5, 0, 7, 0, -2, 2, 10, -1, -3, 4, -5, -5, -2, -1, + 0, 6, 3, -1, -2, -1, -1, 1, -1, -7,-12, -5, 8, 6, 2, 4, + 2, 6, -1, -6, 9, 10, -1, -4, 1, 0, -4, 0, 3, -2, -9, -5, + -4, 3, 4, 0, -4, 3, 3, 0,-11, 0, 3, 2,-11, 3, 7, 2, + 2, -4, 7, 3, 1, -8, 7, 1, -1,-12, 4, 1, 3, -9, 2, 2, + 2, -2, -2, 9,-17, -3, 3, 1, -4, 7, 1, -6, 5, 4, -1, 3, + -1, 2, 0, -4, -7, 8, 12, -1, -2, 5, 4, -5, 3, -5, -8, -2, + 0, 0, -5, -2, -2, -8, 3, 27, -1, -4, -3, 6, -3, 1, -2, -7, + 4, 4, 1, -1, -7,-10, -7, -3, 10, 10, 5, 3, -2, -2, -4, -3, + 0, 1, 5, 7, 4, -2,-16,-20, 0, 4, 7, 8, 2, 0, -2, -1, + -2, 1, 3, 17, -3, 1, -2, -1, -1, -2, -1, -2, -1, -5, -1, 0, + 5, -3, 1, 0, 6, -2, 0, 0, -1, -2, 0, -3,-11, 1, 8, -1, + 3, 0, 0, 0, 0, 2, 4, 1, 2, 0, 6, 1, -2,-18, -3, 2, + -14, 0, 6, 1, -5, -2, -1, 1, -1, 1, 0, 1, 1, 7, 4, 0, + -1, 0, 1, -4, 1, 8, 3, -4, -3, 4, 1, 3, -6, 1, -4, 1, + 1,-12, 3, 3, -1,-10, 0, -1, 2, 0, 2, 1, 3, 2, 2, 4, + 3, 0, 0, 3, 2, 0, -2, 1, 5, 2, -5, 0, 6, -1,-14, -1, + -2, -6, -3, -3, 2, -1, 4, 5, 6, -1, -2, 0, 4, 4, -1, -5, + -4, 1,-11, 0, -1, 2, -4, 1, 2, -3, 3, -1, 1, -2, 15, 0, + 1, -1, 0, -2, 1, -4, -7, 1, -2, -6, -1, 21, -2, 2, -1, 1, + 21, -1, -2, 0, -1, -3, 1, -2, -9, -2, 2, -1, 2, 1, -4, -1, + 1, 8, 2, -6,-10, -1, 4, 0, -4, -3, 3, 3, 5, 0, -1, -1, + 3, 2, 1, -2, -2, -2, 4, 3, 5, 2, -4,-17, 0, -2, 4, 3, + -7, -4, 0, 3, 9, 9, 2, -1,-11, -6, 0, -1, 5, 1, 0, 1, + 0, 17, 5,-11, 3, -2, -6, 0, 2, -2, -4, 1, -4, 1, 2, -1, + -5, -1, -5, -3, -3, 5, -3, -2, 4, 16, 2, -5, -2, 5, -1, -1, + 0, 0, -4, 1, -1, 2, 5, 11, -1, -1, -2, 1, -4, -2, -3, -1, + -5, -1, 10, 0, 6, 1, 0, -3, 0, -4, 1, 0, -2, -4, 3, -1, + 6, 9, 3, 0, -2, 1, -2, 0, -2, -3, -2, -2, 1, 0, 1, -6, + 1, 0, 2, 1, -1, 3, -2, 1, 0, -1,-15, 0, -1, 5, 2, 6, + 2, 0, 2, 2, 0,-12, -4, 6, 0, 1, 4, -1, 1, 2, 1, -4, + 1, -2, -7, 0, 0, 0, 0, -1, -5, 2, 11, 3, 1, 3, 0, -6, + 0, -3, -9, -4, 1, 3, -1, 0, 4, 1, -2, 0, 7, -3, -1, 6, + 1, -2, 6, 2, 0, -1, 3, -2, -2, 4, 0, 2, -1, 2,-14, 2, + 2, 2, 0, -1, -2, 3, -3,-14, 0, 2, 3, -3, 5, 1, 3, 2, + 1, -3, 4,-14, 1, -2, 11, -1, 0, -1, 3, 0, -1, 1, 0, 2, + -2, 3, -3, 2, -4, -1, -4, 3, -1, 2, 1, 3, -6, -2, 2, 7, + -2, 1, 2, 0, -2, 0, 0, -1, 12, 5, -1, 2, -8, -1, 1, -7, + 2, -2, -4, 2, 11, 0,-11, -2, 3, 1, -3, -1, 0, 3, 1, -1, + 0, 3, 0, -2, 0, -6, -1, -3, 12, -7, -2, 0, 7, -2, 1, 1, + 1, 2, 2, 2, -1, 2, 0, 2,-23, 0, 4, 0, 3, 2, 1, 3, + -4, -5, -1, 5, -3, 5, 10, -1, 0, 0, 3, -4, 1, -1, 2, -5 }; -static const uint32 s_svq1InterCodebook8x4[768] = { - 0x00040809, 0xfdfcfcfd, 0xff040809, 0xfdfbfbfc, - 0xfe030708, 0xfcfbfbfb, 0xfe010406, 0xfdfcfbfc, - 0xfcf5f2f4, 0x06060501, 0xfbf9f6f8, 0x010101fe, - 0x01030405, 0xffff0000, 0x06090d0d, 0xfeff0003, - 0xfffdfcfc, 0x0b080401, 0xfefcfafb, 0x0c080300, - 0xfcfaf9f9, 0x0a0702fe, 0xfcfbf9f9, 0x080501fe, - 0x01fffefd, 0x06070603, 0x07050302, 0x04060808, - 0x03040504, 0xf9fafe01, 0xf9fe0001, 0xf0eff2f6, - 0x0801fcfb, 0xf9fd0309, 0x0b01faf9, 0xf8fd050c, - 0x0900f9f8, 0xf9fd050b, 0x05fffaf8, 0xfafe0408, - 0xf8f9fbfc, 0xfaf8f7f7, 0xf9fafbfc, 0xfefcfaf9, - 0x03020100, 0x090a0805, 0x06030201, 0x0d0e0c09, - 0x05060605, 0x01020304, 0x07070605, 0x04060606, - 0x010100ff, 0x05050503, 0xefeff0f3, 0xfcfaf6f2, - 0x100d0b09, 0x0a0c0d0f, 0xf9fafbfc, 0xfbfaf9f9, - 0xf9f9fafa, 0xfbfaf9f9, 0x0000fffe, 0xff000000, - 0xf0f1f3f5, 0xf6f4f2f0, 0x05040302, 0x03030304, - 0x08080706, 0x05060708, 0x03030403, 0x03030303, - 0x01040403, 0xeff3f9fe, 0x05070705, 0xedf3fb01, - 0x08090806, 0xf0f7ff05, 0x0a0a0806, 0xf5fc0207, - 0xf6ff0912, 0x00fcf7f3, 0xf4ff0c16, 0x02fcf6f1, - 0xf6000d17, 0x02fdf7f3, 0xfa020c14, 0x02fefaf7, - 0xf9fafafa, 0xfaf9f9f9, 0xf8f8f9fa, 0xf8f7f7f7, - 0xfdfdfdfd, 0xfdfdfdfd, 0x15120f0c, 0x0e111315, - 0x1212100e, 0x0d0f1012, 0x05060605, 0x03040405, - 0xf6f7f9fa, 0xf9f7f6f6, 0xf2f3f5f6, 0xf6f4f3f2, - 0x05fcefe5, 0x070a0a09, 0x07fdede0, 0x080b0c0b, - 0x08fef0e2, 0x070a0c0c, 0x0700f4e9, 0x06090b0a, - 0x0c101110, 0xf4f8ff06, 0x0a0f1211, 0xeef1f801, - 0x040a0e0f, 0xe9ecf2fb, 0xff04080a, 0xeaebf0f7, - 0xf5f4f4f6, 0x140e04fb, 0xf4f1f3f5, 0x1b1307fc, - 0xf5f2f3f5, 0x1c1508fd, 0xf7f4f5f6, 0x191208fe, - 0x01ffffff, 0x05060604, 0x02000000, 0xfe010304, - 0x04020000, 0xf6f9ff04, 0x05030000, 0xf1f5fd03, - 0xfff8f3f2, 0xfcff0303, 0x04fffcfb, 0x00030808, - 0x03020203, 0x01030504, 0xfe000305, 0xfffffffe, - 0xfafa0109, 0xfffefdfb, 0xfafa010c, 0x00fffefc, - 0xfcfc040e, 0xfffffefe, 0xffff060e, 0xffffffff, - 0x0a080604, 0x0507090b, 0x00ffffff, 0xfeffff00, - 0xfbfcfcfe, 0xfcfbfbfb, 0xfcfdfdfe, 0xfffefdfc, - 0x04040302, 0x00000103, 0x050401ff, 0x03040506, - 0x02fefaf8, 0x03040403, 0xfbf7f3f2, 0x0000fffe, - 0xfcfbfcfd, 0x0d0c0700, 0xfbfbfcfd, 0x0a0904fe, - 0xfbfcfdfe, 0x0403fffc, 0xfdfeffff, 0x0100fefd, - 0xf8fe0509, 0xfcf9f6f5, 0x02060a0c, 0x0000ff00, - 0x04030202, 0x01010103, 0x00fcf8f7, 0x00010201, - 0x05080806, 0xf3f5fb01, 0x02020100, 0xf5f8fcff, - 0x0301fefd, 0xfcff0103, 0x0502fffe, 0x01040606, - 0x05050403, 0xfafd0104, 0x02040605, 0xfd000202, - 0xfb000506, 0xfefffefb, 0xf5fd0407, 0xfefdf9f4, - 0xffff0001, 0x000000ff, 0x04040302, 0x03040505, - 0xf6f7f7f9, 0xfaf9f7f6, 0x06050403, 0x05050505, - 0xf9f9f9f9, 0xfcfbfafa, 0xfffdfcfb, 0x0000ffff, - 0x0401fefd, 0x05050505, 0x0603fffe, 0x090a0a09, - 0x030a01f2, 0x010100fe, 0x030d02f0, 0x0001fffd, - 0x030c02f1, 0x0101fefc, 0x020a03f6, 0x0101fffd, - 0x02040100, 0x0bfdf6fb, 0x020401ff, 0x0ffef3fa, - 0x010300ff, 0x0ffff4fa, 0x010201ff, 0x0b00f8fc, - 0xfefe050a, 0xfc010502, 0xfaf80007, 0xfc020501, - 0xf9f4fb02, 0xff040702, 0xfcf6f9ff, 0x02070904, - 0xfafcfbfb, 0xfdfbfbfa, 0xfcfefeff, 0xfcfbfafb, - 0x04070706, 0xfdfdfe00, 0x0a0d0e0d, 0xfeff0105, - 0x02020101, 0x02020202, 0xf7f8fafb, 0xfaf9f8f7, - 0x0b0a0907, 0x0507090b, 0xfdfdfeff, 0xfdfcfcfc, - 0x0000ffff, 0xffff0000, 0xfbfcfdfd, 0xfefdfdfc, - 0xfdff0102, 0x00fffefd, 0x03080c0c, 0x01000001, - 0xfaf8f8fa, 0x080602fe, 0xfeff0101, 0x07050300, - 0xff010303, 0x020000ff, 0xff000100, 0xfffeffff, - 0x00000001, 0x04020000, 0x04030102, 0x02000103, - 0x00000102, 0x0300ffff, 0xf4fa0105, 0x04fff8f3, - 0xfeff00fe, 0x030200ff, 0x00fefdfa, 0x01010101, - 0x0400fbf7, 0x00010305, 0x0703fdf8, 0x00010408, - 0x03020201, 0xfdff0103, 0x06050504, 0x00020506, - 0x00000000, 0xfcfe0001, 0xfdfcfdfd, 0xf8f9fcfd, - 0xff060c0e, 0x0000fdfd, 0xfd010507, 0xfffefcfb, - 0xfefefefe, 0xfffffefe, 0x01fffcfa, 0xff000101, - 0xfd010202, 0xfdfaf9fa, 0xfdff0001, 0x060401fe, - 0x02010000, 0x07080704, 0x00000000, 0xf8f9fcff, - 0xfe010200, 0xfffefdfd, 0xfd0001ff, 0x0200fefb, - 0xfbfefffe, 0x090601fc, 0xfcfdfefd, 0x0d0b05fe, - 0x0602fefc, 0xf2f6fd04, 0x0401fffe, 0xfeff0104, - 0xfeff0000, 0x060400fe, 0xfd000202, 0x090500fd, - 0x01fefcfc, 0xf9030906, 0xfffefefe, 0xf5000804, - 0x00000101, 0xf6ff0602, 0x00010202, 0xf9000402, - 0xfafdfeff, 0xf8f8f8f9, 0x01030302, 0xfcfdfeff, - 0x04050505, 0xff000203, 0x03030303, 0x01010202, - 0xfe020303, 0x0a0700fd, 0xfe020201, 0x0300fcfb, - 0x02040300, 0xfcfafbfd, 0x04040200, 0xf9f9fc01, - 0x05050402, 0x06060505, 0xfbfdfcfc, 0xfefdfdfb, - 0xfbfcfcfd, 0xfefefefc, 0x00000101, 0x04050402, - 0x040300fe, 0x02020304, 0x00fcf9f7, 0x06060603, - 0xfefdfbfb, 0x04030100, 0xfe020505, 0xfdfbfafc, - 0x07fcfa01, 0x01fefe05, 0x06fcfb05, 0x01fcfb04, - 0x06fcfb05, 0x01fdfb04, 0x08fdf901, 0x01fdff07, - 0x00fcf9f8, 0x05050402, 0x02050605, 0xf9f9fbff, - 0x01040605, 0xfbfafbfd, 0xfefbf9f9, 0x0a090601, - 0x01000306, 0xf2f80003, 0x01ff0003, 0xfc000304, - 0x01000001, 0x01010102, 0x0201ffff, 0x00ffff01, - 0x01010101, 0x00fdfe00, 0x00010201, 0xfcf7f8fe, - 0x02030301, 0x01fdfd01, 0x01010100, 0x08040101, - 0x07090502, 0x01ffff02, 0x0001fffc, 0x02fffcfd, - 0x030300fd, 0x0200ff00, 0x0101fffc, 0xfcfbfcfe, - 0xfefeff01, 0x050402ff, 0x00010102, 0x0000ffff, - 0x05040302, 0x00010204, 0xfdfaf7f7, 0xffffffff, - 0x0704fafa, 0xfefffe00, 0x0605feff, 0xff00feff, - 0x0001ff04, 0xfe00fefc, 0xfeff0107, 0x010301fd, - 0x03010204, 0x02010103, 0x00fcfe02, 0x00000103, - 0xfcf8fc01, 0x00010201, 0xfaf7fd02, 0x02030300, - 0xff00ffff, 0x020100ff, 0xf8fc0103, 0x0201fdf9, - 0xfefdff02, 0x000100ff, 0x0b0500ff, 0xfdff0309, - 0xfffefeff, 0x01010101, 0x0300ff00, 0x05050606, - 0xffff0102, 0xfcfafbfe, 0x01020202, 0xfbfbfcff, - 0xf9fafdff, 0x01fffcfa, 0x04030505, 0x05040304, - 0xfefdfeff, 0x0100fefe, 0x00000000, 0x03020100, - 0xfffcfafa, 0x02020202, 0xfefbf9fa, 0x00ffff00, - 0x04020202, 0x04030304, 0xff000102, 0x04020000, - 0xf8fb050c, 0x020200fb, 0xfdfafd02, 0xfeff0000, - 0x03fffdfe, 0xfdfe0104, 0x04030202, 0xffff0103, - 0x00010203, 0x00030401, 0xfb000304, 0x030300fa, - 0xf9010302, 0x0301faf4, 0xff040301, 0x0100fcfa, - 0x0602fcf7, 0x00010407, 0x0604fff9, 0xfdfd0004, - 0x040400fa, 0xfefdfe01, 0x020301fc, 0x00fffe00, - 0xfb020500, 0xfc0103fd, 0xfa0204fe, 0xfd0406fd, - 0xfb0305ff, 0xfc0307ff, 0xfa0002ff, 0xfd0305fd, - 0x0503fdf8, 0xfefe0103, 0xfe040402, 0x0301fdfc, - 0xfbfd0102, 0x030403fd, 0x03fbfafb, 0xfbff080a, - 0xfc020300, 0x0600f9f7, 0x0705fffb, 0xfdfdff04, - 0x03fefbfb, 0xfcff0506, 0xfc000609, 0xff0101fe, - 0x01ffffff, 0x00ff0001, 0x000000ff, 0x00ffff00, - 0xfffe0102, 0x00000101, 0xff02080c, 0xf9f9fcff, - 0x06030102, 0x00020407, 0x00ff0001, 0xf8f9fcff, - 0x00ff0000, 0xfdff0000, 0x00000000, 0xfe000101, - 0x010100ff, 0xfeff0000, 0xfdff0000, 0x01fffdfc, - 0x000000ff, 0x0c0a0401, 0xfefe00ff, 0x01fffdfd, - 0xfcfefffd, 0x07090902, 0xfdff00fd, 0x01ff0200, - 0xfdfe01ff, 0x00fdff00, 0xfefd0000, 0x01ffff00, - 0xfffffeff, 0xfefffffe, 0xfffeff02, 0xfe000100, - 0x02feff03, 0xfdff0305, 0x01fbfb01, 0x00020606, - 0xff000201, 0xfe000100, 0x00fffdfb, 0xfe010201, - 0xfefefbf9, 0x0100fefe, 0x010100ff, 0x0c090300, - 0x01050600, 0x0300fdfe, 0x01050600, 0x03020101, - 0xfdfefefb, 0x00000000, 0xfefdfdfa, 0xfeff0000, - 0x01020404, 0x00ffff00, 0x0100fefe, 0x00010102, - 0xff010202, 0xf6f7fbfd, 0xffff0102, 0x01040401, - 0xfefe0004, 0x00fffefe, 0xfdfc0107, 0x010100fe, - 0xfeff050a, 0x00010100, 0xfcfd0105, 0xfefffffd, - 0xfdff0102, 0xff0101fd, 0x0003fffe, 0x000101ff, - 0x020701fd, 0x00fffefd, 0xff0804fe, 0x0200fbf8, - 0x0201fffc, 0xfefcfd01, 0x01fefdfb, 0x06040404, - 0xfdfcfefd, 0x02010100, 0x01020202, 0xffff0102, - 0xff00fffc, 0xfffffdfd, 0x02040401, 0xfdfeff00, - 0x03050604, 0xfcfe0102, 0x01010100, 0xfafcff01, - 0xff020201, 0x02fffbfa, 0x0101fefd, 0x0502fdfc, - 0x0202fffe, 0x0300fcfd, 0x0602fefe, 0x02010205, - 0x00fdfd02, 0x01030200, 0x0301ff03, 0xfbff0201, - 0xfefcf9fb, 0x01080801, 0x000200ff, 0xfd0100fd, - 0xfefbfbfe, 0xfe00fffd, 0x0400fcff, 0x00040200, - 0x0a080000, 0xff030102, 0x0302fdfc, 0xff01fdfd, - 0x02fcfe01, 0xfffe0307, 0xfffe0406, 0x03ff0002, - 0xfefe0101, 0x04fdfbfe, 0x0101fefa, 0x04fefcff, - 0xfefefffe, 0xfe000100, 0xff0001ff, 0xfdff0000, - 0xfcfe0100, 0x0000fffd, 0x00050806, 0x03020100, - 0x0502fefe, 0x01000002, 0xfffefe02, 0x040201ff, - 0x0100ff02, 0x01000000, 0x01fff9f8, 0x0301ffff, - 0x02060300, 0x000201fe, 0x00fff9f6, 0x0102fffd, - 0x02020000, 0xff010101, 0xfefe0003, 0x00010200, - 0x00000108, 0x00fffdfe, 0x0502fe02, 0x01fffe01, - 0xfffdfafd, 0x02fffdfd, 0x02010002, 0x00000102, - 0xfeffff01, 0x000100ff, 0xff02090f, 0xfdfdfdfe, - 0x00fefd00, 0xffffff00, 0x00010001, 0xffffff00, - 0xfe020200, 0xf8f9fdfd, 0x00020200, 0x01010201, - 0x02020201, 0x03000103, 0xfeff0001, 0x0500feff, - 0x01fffaf5, 0xfd010302, 0xff030401, 0xff0201fe, - 0xff010202, 0xff0100fe, 0xffff0000, 0x02030200, - 0x01020101, 0xfc0001ff, 0xfe000000, 0xfe0402fe, - 0x0000fdfe, 0xfa0102ff, 0x05050200, 0xf9ff0203, - 0x00000204, 0xff010303, 0x03ffff00, 0xff010406, - 0x0200fefe, 0xfefe0002, 0xfbff00ff, 0x01fffbf9, - 0x00feff05, 0xfb020402, 0x02fefb00, 0xfa000201, - 0x01000106, 0x0204fffe, 0x00fdfd02, 0x0000feff, - 0x0200ff01, 0x0b060000, 0x00ffff02, 0x0503fefd, - 0x00fffe00, 0xfd0000ff, 0xffffff01, 0xf9fdfffe, - 0xfefe0101, 0xfe010301, 0xff0002ff, 0x000001ff, - 0xff0302fc, 0x0100fefe, 0x0504fef5, 0xfeff0206, - 0xff01fefa, 0x0901fcfd, 0x030300fd, 0x03fdfd02, - 0x00000101, 0x03feff01, 0xfdfd0002, 0x03ffff00, - 0x01fdff01, 0x06fcfa02, 0xfefbfe00, 0x03fefd00, - 0xfe010202, 0xff0201fe, 0xfe0101ff, 0xff0706ff, - 0xfefc0001, 0x01fdfe01, 0xfefd00fc, 0x00fd0002, - 0x010304fd, 0xff000708, 0xfc0104fd, 0xfdfe0302, - 0xfc0106fd, 0xffff0101, 0xfdfd04fe, 0xffff0003, - 0x02fc0201, 0x02fffd04, 0x05fcff03, 0x02fdfa04 +static const int8 s_svq1InterCodebook8x4[3072] = { + 9, 8, 4, 0, -3, -4, -4, -3, 9, 8, 4, -1, -4, -5, -5, -3, + 8, 7, 3, -2, -5, -5, -5, -4, 6, 4, 1, -2, -4, -5, -4, -3, + -12,-14,-11, -4, 1, 5, 6, 6, -8,-10, -7, -5, -2, 1, 1, 1, + 5, 4, 3, 1, 0, 0, -1, -1, 13, 13, 9, 6, 3, 0, -1, -2, + -4, -4, -3, -1, 1, 4, 8, 11, -5, -6, -4, -2, 0, 3, 8, 12, + -7, -7, -6, -4, -2, 2, 7, 10, -7, -7, -5, -4, -2, 1, 5, 8, + -3, -2, -1, 1, 3, 6, 7, 6, 2, 3, 5, 7, 8, 8, 6, 4, + 4, 5, 4, 3, 1, -2, -6, -7, 1, 0, -2, -7,-10,-14,-17,-16, + -5, -4, 1, 8, 9, 3, -3, -7, -7, -6, 1, 11, 12, 5, -3, -8, + -8, -7, 0, 9, 11, 5, -3, -7, -8, -6, -1, 5, 8, 4, -2, -6, + -4, -5, -7, -8, -9, -9, -8, -6, -4, -5, -6, -7, -7, -6, -4, -2, + 0, 1, 2, 3, 5, 8, 10, 9, 1, 2, 3, 6, 9, 12, 14, 13, + 5, 6, 6, 5, 4, 3, 2, 1, 5, 6, 7, 7, 6, 6, 6, 4, + -1, 0, 1, 1, 3, 5, 5, 5,-13,-16,-17,-17,-14,-10, -6, -4, + 9, 11, 13, 16, 15, 13, 12, 10, -4, -5, -6, -7, -7, -7, -6, -5, + -6, -6, -7, -7, -7, -7, -6, -5, -2, -1, 0, 0, 0, 0, 0, -1, + -11,-13,-15,-16,-16,-14,-12,-10, 2, 3, 4, 5, 4, 3, 3, 3, + 6, 7, 8, 8, 8, 7, 6, 5, 3, 4, 3, 3, 3, 3, 3, 3, + 3, 4, 4, 1, -2, -7,-13,-17, 5, 7, 7, 5, 1, -5,-13,-19, + 6, 8, 9, 8, 5, -1, -9,-16, 6, 8, 10, 10, 7, 2, -4,-11, + 18, 9, -1,-10,-13, -9, -4, 0, 22, 12, -1,-12,-15,-10, -4, 2, + 23, 13, 0,-10,-13, -9, -3, 2, 20, 12, 2, -6, -9, -6, -2, 2, + -6, -6, -6, -7, -7, -7, -7, -6, -6, -7, -8, -8, -9, -9, -9, -8, + -3, -3, -3, -3, -3, -3, -3, -3, 12, 15, 18, 21, 21, 19, 17, 14, + 14, 16, 18, 18, 18, 16, 15, 13, 5, 6, 6, 5, 5, 4, 4, 3, + -6, -7, -9,-10,-10,-10, -9, -7,-10,-11,-13,-14,-14,-13,-12,-10, + -27,-17, -4, 5, 9, 10, 10, 7,-32,-19, -3, 7, 11, 12, 11, 8, + -30,-16, -2, 8, 12, 12, 10, 7,-23,-12, 0, 7, 10, 11, 9, 6, + 16, 17, 16, 12, 6, -1, -8,-12, 17, 18, 15, 10, 1, -8,-15,-18, + 15, 14, 10, 4, -5,-14,-20,-23, 10, 8, 4, -1, -9,-16,-21,-22, + -10,-12,-12,-11, -5, 4, 14, 20,-11,-13,-15,-12, -4, 7, 19, 27, + -11,-13,-14,-11, -3, 8, 21, 28,-10,-11,-12, -9, -2, 8, 18, 25, + -1, -1, -1, 1, 4, 6, 6, 5, 0, 0, 0, 2, 4, 3, 1, -2, + 0, 0, 2, 4, 4, -1, -7,-10, 0, 0, 3, 5, 3, -3,-11,-15, + -14,-13, -8, -1, 3, 3, -1, -4, -5, -4, -1, 4, 8, 8, 3, 0, + 3, 2, 2, 3, 4, 5, 3, 1, 5, 3, 0, -2, -2, -1, -1, -1, + 9, 1, -6, -6, -5, -3, -2, -1, 12, 1, -6, -6, -4, -2, -1, 0, + 14, 4, -4, -4, -2, -2, -1, -1, 14, 6, -1, -1, -1, -1, -1, -1, + 4, 6, 8, 10, 11, 9, 7, 5, -1, -1, -1, 0, 0, -1, -1, -2, + -2, -4, -4, -5, -5, -5, -5, -4, -2, -3, -3, -4, -4, -3, -2, -1, + 2, 3, 4, 4, 3, 1, 0, 0, -1, 1, 4, 5, 6, 5, 4, 3, + -8, -6, -2, 2, 3, 4, 4, 3,-14,-13, -9, -5, -2, -1, 0, 0, + -3, -4, -5, -4, 0, 7, 12, 13, -3, -4, -5, -5, -2, 4, 9, 10, + -2, -3, -4, -5, -4, -1, 3, 4, -1, -1, -2, -3, -3, -2, 0, 1, + 9, 5, -2, -8,-11,-10, -7, -4, 12, 10, 6, 2, 0, -1, 0, 0, + 2, 2, 3, 4, 3, 1, 1, 1, -9, -8, -4, 0, 1, 2, 1, 0, + 6, 8, 8, 5, 1, -5,-11,-13, 0, 1, 2, 2, -1, -4, -8,-11, + -3, -2, 1, 3, 3, 1, -1, -4, -2, -1, 2, 5, 6, 6, 4, 1, + 3, 4, 5, 5, 4, 1, -3, -6, 5, 6, 4, 2, 2, 2, 0, -3, + 6, 5, 0, -5, -5, -2, -1, -2, 7, 4, -3,-11,-12, -7, -3, -2, + 1, 0, -1, -1, -1, 0, 0, 0, 2, 3, 4, 4, 5, 5, 4, 3, + -7, -9, -9,-10,-10, -9, -7, -6, 3, 4, 5, 6, 5, 5, 5, 5, + -7, -7, -7, -7, -6, -6, -5, -4, -5, -4, -3, -1, -1, -1, 0, 0, + -3, -2, 1, 4, 5, 5, 5, 5, -2, -1, 3, 6, 9, 10, 10, 9, + -14, 1, 10, 3, -2, 0, 1, 1,-16, 2, 13, 3, -3, -1, 1, 0, + -15, 2, 12, 3, -4, -2, 1, 1,-10, 3, 10, 2, -3, -1, 1, 1, + 0, 1, 4, 2, -5,-10, -3, 11, -1, 1, 4, 2, -6,-13, -2, 15, + -1, 0, 3, 1, -6,-12, -1, 15, -1, 1, 2, 1, -4, -8, 0, 11, + 10, 5, -2, -2, 2, 5, 1, -4, 7, 0, -8, -6, 1, 5, 2, -4, + 2, -5,-12, -7, 2, 7, 4, -1, -1, -7,-10, -4, 4, 9, 7, 2, + -5, -5, -4, -6, -6, -5, -5, -3, -1, -2, -2, -4, -5, -6, -5, -4, + 6, 7, 7, 4, 0, -2, -3, -3, 13, 14, 13, 10, 5, 1, -1, -2, + 1, 1, 2, 2, 2, 2, 2, 2, -5, -6, -8, -9, -9, -8, -7, -6, + 7, 9, 10, 11, 11, 9, 7, 5, -1, -2, -3, -3, -4, -4, -4, -3, + -1, -1, 0, 0, 0, 0, -1, -1, -3, -3, -4, -5, -4, -3, -3, -2, + 2, 1, -1, -3, -3, -2, -1, 0, 12, 12, 8, 3, 1, 0, 0, 1, + -6, -8, -8, -6, -2, 2, 6, 8, 1, 1, -1, -2, 0, 3, 5, 7, + 3, 3, 1, -1, -1, 0, 0, 2, 0, 1, 0, -1, -1, -1, -2, -1, + 1, 0, 0, 0, 0, 0, 2, 4, 2, 1, 3, 4, 3, 1, 0, 2, + 2, 1, 0, 0, -1, -1, 0, 3, 5, 1, -6,-12,-13, -8, -1, 4, + -2, 0, -1, -2, -1, 0, 2, 3, -6, -3, -2, 0, 1, 1, 1, 1, + -9, -5, 0, 4, 5, 3, 1, 0, -8, -3, 3, 7, 8, 4, 1, 0, + 1, 2, 2, 3, 3, 1, -1, -3, 4, 5, 5, 6, 6, 5, 2, 0, + 0, 0, 0, 0, 1, 0, -2, -4, -3, -3, -4, -3, -3, -4, -7, -8, + 14, 12, 6, -1, -3, -3, 0, 0, 7, 5, 1, -3, -5, -4, -2, -1, + -2, -2, -2, -2, -2, -2, -1, -1, -6, -4, -1, 1, 1, 1, 0, -1, + 2, 2, 1, -3, -6, -7, -6, -3, 1, 0, -1, -3, -2, 1, 4, 6, + 0, 0, 1, 2, 4, 7, 8, 7, 0, 0, 0, 0, -1, -4, -7, -8, + 0, 2, 1, -2, -3, -3, -2, -1, -1, 1, 0, -3, -5, -2, 0, 2, + -2, -1, -2, -5, -4, 1, 6, 9, -3, -2, -3, -4, -2, 5, 11, 13, + -4, -2, 2, 6, 4, -3,-10,-14, -2, -1, 1, 4, 4, 1, -1, -2, + 0, 0, -1, -2, -2, 0, 4, 6, 2, 2, 0, -3, -3, 0, 5, 9, + -4, -4, -2, 1, 6, 9, 3, -7, -2, -2, -2, -1, 4, 8, 0,-11, + 1, 1, 0, 0, 2, 6, -1,-10, 2, 2, 1, 0, 2, 4, 0, -7, + -1, -2, -3, -6, -7, -8, -8, -8, 2, 3, 3, 1, -1, -2, -3, -4, + 5, 5, 5, 4, 3, 2, 0, -1, 3, 3, 3, 3, 2, 2, 1, 1, + 3, 3, 2, -2, -3, 0, 7, 10, 1, 2, 2, -2, -5, -4, 0, 3, + 0, 3, 4, 2, -3, -5, -6, -4, 0, 2, 4, 4, 1, -4, -7, -7, + 2, 4, 5, 5, 5, 5, 6, 6, -4, -4, -3, -5, -5, -3, -3, -2, + -3, -4, -4, -5, -4, -2, -2, -2, 1, 1, 0, 0, 2, 4, 5, 4, + -2, 0, 3, 4, 4, 3, 2, 2, -9, -7, -4, 0, 3, 6, 6, 6, + -5, -5, -3, -2, 0, 1, 3, 4, 5, 5, 2, -2, -4, -6, -5, -3, + 1, -6, -4, 7, 5, -2, -2, 1, 5, -5, -4, 6, 4, -5, -4, 1, + 5, -5, -4, 6, 4, -5, -3, 1, 1, -7, -3, 8, 7, -1, -3, 1, + -8, -7, -4, 0, 2, 4, 5, 5, 5, 6, 5, 2, -1, -5, -7, -7, + 5, 6, 4, 1, -3, -5, -6, -5, -7, -7, -5, -2, 1, 6, 9, 10, + 6, 3, 0, 1, 3, 0, -8,-14, 3, 0, -1, 1, 4, 3, 0, -4, + 1, 0, 0, 1, 2, 1, 1, 1, -1, -1, 1, 2, 1, -1, -1, 0, + 1, 1, 1, 1, 0, -2, -3, 0, 1, 2, 1, 0, -2, -8, -9, -4, + 1, 3, 3, 2, 1, -3, -3, 1, 0, 1, 1, 1, 1, 1, 4, 8, + 2, 5, 9, 7, 2, -1, -1, 1, -4, -1, 1, 0, -3, -4, -1, 2, + -3, 0, 3, 3, 0, -1, 0, 2, -4, -1, 1, 1, -2, -4, -5, -4, + 1, -1, -2, -2, -1, 2, 4, 5, 2, 1, 1, 0, -1, -1, 0, 0, + 2, 3, 4, 5, 4, 2, 1, 0, -9, -9, -6, -3, -1, -1, -1, -1, + -6, -6, 4, 7, 0, -2, -1, -2, -1, -2, 5, 6, -1, -2, 0, -1, + 4, -1, 1, 0, -4, -2, 0, -2, 7, 1, -1, -2, -3, 1, 3, 1, + 4, 2, 1, 3, 3, 1, 1, 2, 2, -2, -4, 0, 3, 1, 0, 0, + 1, -4, -8, -4, 1, 2, 1, 0, 2, -3, -9, -6, 0, 3, 3, 2, + -1, -1, 0, -1, -1, 0, 1, 2, 3, 1, -4, -8, -7, -3, 1, 2, + 2, -1, -3, -2, -1, 0, 1, 0, -1, 0, 5, 11, 9, 3, -1, -3, + -1, -2, -2, -1, 1, 1, 1, 1, 0, -1, 0, 3, 6, 6, 5, 5, + 2, 1, -1, -1, -2, -5, -6, -4, 2, 2, 2, 1, -1, -4, -5, -5, + -1, -3, -6, -7, -6, -4, -1, 1, 5, 5, 3, 4, 4, 3, 4, 5, + -1, -2, -3, -2, -2, -2, 0, 1, 0, 0, 0, 0, 0, 1, 2, 3, + -6, -6, -4, -1, 2, 2, 2, 2, -6, -7, -5, -2, 0, -1, -1, 0, + 2, 2, 2, 4, 4, 3, 3, 4, 2, 1, 0, -1, 0, 0, 2, 4, + 12, 5, -5, -8, -5, 0, 2, 2, 2, -3, -6, -3, 0, 0, -1, -2, + -2, -3, -1, 3, 4, 1, -2, -3, 2, 2, 3, 4, 3, 1, -1, -1, + 3, 2, 1, 0, 1, 4, 3, 0, 4, 3, 0, -5, -6, 0, 3, 3, + 2, 3, 1, -7,-12, -6, 1, 3, 1, 3, 4, -1, -6, -4, 0, 1, + -9, -4, 2, 6, 7, 4, 1, 0, -7, -1, 4, 6, 4, 0, -3, -3, + -6, 0, 4, 4, 1, -2, -3, -2, -4, 1, 3, 2, 0, -2, -1, 0, + 0, 5, 2, -5, -3, 3, 1, -4, -2, 4, 2, -6, -3, 6, 4, -3, + -1, 5, 3, -5, -1, 7, 3, -4, -1, 2, 0, -6, -3, 5, 3, -3, + -8, -3, 3, 5, 3, 1, -2, -2, 2, 4, 4, -2, -4, -3, 1, 3, + 2, 1, -3, -5, -3, 3, 4, 3, -5, -6, -5, 3, 10, 8, -1, -5, + 0, 3, 2, -4, -9, -7, 0, 6, -5, -1, 5, 7, 4, -1, -3, -3, + -5, -5, -2, 3, 6, 5, -1, -4, 9, 6, 0, -4, -2, 1, 1, -1, + -1, -1, -1, 1, 1, 0, -1, 0, -1, 0, 0, 0, 0, -1, -1, 0, + 2, 1, -2, -1, 1, 1, 0, 0, 12, 8, 2, -1, -1, -4, -7, -7, + 2, 1, 3, 6, 7, 4, 2, 0, 1, 0, -1, 0, -1, -4, -7, -8, + 0, 0, -1, 0, 0, 0, -1, -3, 0, 0, 0, 0, 1, 1, 0, -2, + -1, 0, 1, 1, 0, 0, -1, -2, 0, 0, -1, -3, -4, -3, -1, 1, + -1, 0, 0, 0, 1, 4, 10, 12, -1, 0, -2, -2, -3, -3, -1, 1, + -3, -1, -2, -4, 2, 9, 9, 7, -3, 0, -1, -3, 0, 2, -1, 1, + -1, 1, -2, -3, 0, -1, -3, 0, 0, 0, -3, -2, 0, -1, -1, 1, + -1, -2, -1, -1, -2, -1, -1, -2, 2, -1, -2, -1, 0, 1, 0, -2, + 3, -1, -2, 2, 5, 3, -1, -3, 1, -5, -5, 1, 6, 6, 2, 0, + 1, 2, 0, -1, 0, 1, 0, -2, -5, -3, -1, 0, 1, 2, 1, -2, + -7, -5, -2, -2, -2, -2, 0, 1, -1, 0, 1, 1, 0, 3, 9, 12, + 0, 6, 5, 1, -2, -3, 0, 3, 0, 6, 5, 1, 1, 1, 2, 3, + -5, -2, -2, -3, 0, 0, 0, 0, -6, -3, -3, -2, 0, 0, -1, -2, + 4, 4, 2, 1, 0, -1, -1, 0, -2, -2, 0, 1, 2, 1, 1, 0, + 2, 2, 1, -1, -3, -5, -9,-10, 2, 1, -1, -1, 1, 4, 4, 1, + 4, 0, -2, -2, -2, -2, -1, 0, 7, 1, -4, -3, -2, 0, 1, 1, + 10, 5, -1, -2, 0, 1, 1, 0, 5, 1, -3, -4, -3, -1, -1, -2, + 2, 1, -1, -3, -3, 1, 1, -1, -2, -1, 3, 0, -1, 1, 1, 0, + -3, 1, 7, 2, -3, -2, -1, 0, -2, 4, 8, -1, -8, -5, 0, 2, + -4, -1, 1, 2, 1, -3, -4, -2, -5, -3, -2, 1, 4, 4, 4, 6, + -3, -2, -4, -3, 0, 1, 1, 2, 2, 2, 2, 1, 2, 1, -1, -1, + -4, -1, 0, -1, -3, -3, -1, -1, 1, 4, 4, 2, 0, -1, -2, -3, + 4, 6, 5, 3, 2, 1, -2, -4, 0, 1, 1, 1, 1, -1, -4, -6, + 1, 2, 2, -1, -6, -5, -1, 2, -3, -2, 1, 1, -4, -3, 2, 5, + -2, -1, 2, 2, -3, -4, 0, 3, -2, -2, 2, 6, 5, 2, 1, 2, + 2, -3, -3, 0, 0, 2, 3, 1, 3, -1, 1, 3, 1, 2, -1, -5, + -5, -7, -4, -2, 1, 8, 8, 1, -1, 0, 2, 0, -3, 0, 1, -3, + -2, -5, -5, -2, -3, -1, 0, -2, -1, -4, 0, 4, 0, 2, 4, 0, + 0, 0, 8, 10, 2, 1, 3, -1, -4, -3, 2, 3, -3, -3, 1, -1, + 1, -2, -4, 2, 7, 3, -2, -1, 6, 4, -2, -1, 2, 0, -1, 3, + 1, 1, -2, -2, -2, -5, -3, 4, -6, -2, 1, 1, -1, -4, -2, 4, + -2, -1, -2, -2, 0, 1, 0, -2, -1, 1, 0, -1, 0, 0, -1, -3, + 0, 1, -2, -4, -3, -1, 0, 0, 6, 8, 5, 0, 0, 1, 2, 3, + -2, -2, 2, 5, 2, 0, 0, 1, 2, -2, -2, -1, -1, 1, 2, 4, + 2, -1, 0, 1, 0, 0, 0, 1, -8, -7, -1, 1, -1, -1, 1, 3, + 0, 3, 6, 2, -2, 1, 2, 0,-10, -7, -1, 0, -3, -1, 2, 1, + 0, 0, 2, 2, 1, 1, 1, -1, 3, 0, -2, -2, 0, 2, 1, 0, + 8, 1, 0, 0, -2, -3, -1, 0, 2, -2, 2, 5, 1, -2, -1, 1, + -3, -6, -3, -1, -3, -3, -1, 2, 2, 0, 1, 2, 2, 1, 0, 0, + 1, -1, -1, -2, -1, 0, 1, 0, 15, 9, 2, -1, -2, -3, -3, -3, + 0, -3, -2, 0, 0, -1, -1, -1, 1, 0, 1, 0, 0, -1, -1, -1, + 0, 2, 2, -2, -3, -3, -7, -8, 0, 2, 2, 0, 1, 2, 1, 1, + 1, 2, 2, 2, 3, 1, 0, 3, 1, 0, -1, -2, -1, -2, 0, 5, + -11, -6, -1, 1, 2, 3, 1, -3, 1, 4, 3, -1, -2, 1, 2, -1, + 2, 2, 1, -1, -2, 0, 1, -1, 0, 0, -1, -1, 0, 2, 3, 2, + 1, 1, 2, 1, -1, 1, 0, -4, 0, 0, 0, -2, -2, 2, 4, -2, + -2, -3, 0, 0, -1, 2, 1, -6, 0, 2, 5, 5, 3, 2, -1, -7, + 4, 2, 0, 0, 3, 3, 1, -1, 0, -1, -1, 3, 6, 4, 1, -1, + -2, -2, 0, 2, 2, 0, -2, -2, -1, 0, -1, -5, -7, -5, -1, 1, + 5, -1, -2, 0, 2, 4, 2, -5, 0, -5, -2, 2, 1, 2, 0, -6, + 6, 1, 0, 1, -2, -1, 4, 2, 2, -3, -3, 0, -1, -2, 0, 0, + 1, -1, 0, 2, 0, 0, 6, 11, 2, -1, -1, 0, -3, -2, 3, 5, + 0, -2, -1, 0, -1, 0, 0, -3, 1, -1, -1, -1, -2, -1, -3, -7, + 1, 1, -2, -2, 1, 3, 1, -2, -1, 2, 0, -1, -1, 1, 0, 0, + -4, 2, 3, -1, -2, -2, 0, 1,-11, -2, 4, 5, 6, 2, -1, -2, + -6, -2, 1, -1, -3, -4, 1, 9, -3, 0, 3, 3, 2, -3, -3, 3, + 1, 1, 0, 0, 1, -1, -2, 3, 2, 0, -3, -3, 0, -1, -1, 3, + 1, -1, -3, 1, 2, -6, -4, 6, 0, -2, -5, -2, 0, -3, -2, 3, + 2, 2, 1, -2, -2, 1, 2, -1, -1, 1, 1, -2, -1, 6, 7, -1, + 1, 0, -4, -2, 1, -2, -3, 1, -4, 0, -3, -2, 2, 0, -3, 0, + -3, 4, 3, 1, 8, 7, 0, -1, -3, 4, 1, -4, 2, 3, -2, -3, + -3, 6, 1, -4, 1, 1, -1, -1, -2, 4, -3, -3, 3, 0, -1, -1, + 1, 2, -4, 2, 4, -3, -1, 2, 3, -1, -4, 5, 4, -6, -3, 2 }; -static const uint32 s_svq1InterCodebook8x8[1536] = { - 0x0504fdfc, 0x00010102, 0x0505fdfb, 0x00000102, - 0x0505fcfa, 0x00000102, 0x0504fcf9, 0x00000102, - 0x0403fbf8, 0x00000102, 0x0403faf8, 0x00010101, - 0x0402faf8, 0x00010102, 0x0402faf8, 0x01010101, - 0xffffffff, 0xffffffff, 0xfefefeff, 0xfefefefe, - 0xfdfdfdfe, 0xfdfdfdfd, 0xfdfdfdfe, 0xfdfcfdfd, - 0xfefefefe, 0xfefdfdfe, 0x01010101, 0xffff0001, - 0x05050504, 0x02030304, 0x08080707, 0x05060708, - 0x04020102, 0xfafc0004, 0x05020101, 0xf9fb0105, - 0x04010201, 0xf8fb0105, 0x05010101, 0xf8fa0005, - 0x05010100, 0xf7fa0106, 0x04010000, 0xf8fb0005, - 0x04010000, 0xf9fb0005, 0x04010000, 0xf9fc0104, - 0x00030201, 0xfffdfcfd, 0x00040301, 0xfffdfcfd, - 0x01050402, 0xfefdfcfd, 0x01060502, 0xfefcfbfd, - 0x01060603, 0xfefcfbfd, 0x01060603, 0xfefcfbfd, - 0x01060603, 0xfefcfbfd, 0x01050503, 0xfefcfcfd, - 0x02020202, 0xff000001, 0x03040404, 0x00010102, - 0x04040504, 0x01020303, 0x04040404, 0x02020304, - 0x03030302, 0x01020303, 0xffffffff, 0x00000000, - 0xfbfafafb, 0xfdfdfcfb, 0xf8f7f7f9, 0xfbfafaf9, - 0x06060606, 0x04050506, 0x03040404, 0x02030303, - 0xffffff00, 0xfffffefe, 0xfafafbfd, 0xfcfbfafa, - 0xf9fafbfd, 0xfcfbfafa, 0xfefefeff, 0xfffffefe, - 0x01010100, 0x01010101, 0x03030303, 0x03030303, - 0xfbfe0102, 0x050200fc, 0xfafe0102, 0x050300fb, - 0xfafe0102, 0x0603fffa, 0xf9fe0203, 0x070400fa, - 0xf9fe0102, 0x070500fb, 0xfafe0102, 0x070400fb, - 0xfafe0102, 0x060400fc, 0xfbfe0101, 0x060300fc, - 0xfcfaf7f6, 0x020302ff, 0xfdfbf7f6, 0x03040400, - 0xfffdf9f7, 0x03050502, 0x00fefbf9, 0x03050503, - 0x0100fdfa, 0x03050604, 0x0201fefc, 0x02040503, - 0x020100fe, 0x01030402, 0x020201ff, 0x01030302, - 0xfafbfbfc, 0xfbfafafa, 0xfcfcfdfd, 0xfcfcfcfc, - 0x00000000, 0xffffffff, 0x05060505, 0x02030405, - 0x07070605, 0x04050607, 0x04040303, 0x02030404, - 0x0000ff00, 0xff00ffff, 0xfcfcfdfd, 0xfdfdfcfc, - 0x01fbfe01, 0x00020405, 0x01fafd01, 0x00020506, - 0x00f9fc00, 0x01020606, 0xfff7fbff, 0x01030606, - 0xfef6faff, 0x01030606, 0xfef7faff, 0x01030605, - 0xfef7fafe, 0x01030505, 0xfef9fafe, 0x01020404, - 0xf7f8f9fb, 0xfaf9f8f7, 0xf9fafafb, 0xfbfafaf9, - 0xfcfdfdfd, 0xfcfcfbfb, 0xff0000ff, 0xffffffff, - 0x02020100, 0x01020202, 0x05040302, 0x04050505, - 0x06050403, 0x07080808, 0x06050403, 0x06070707, - 0x08070605, 0x090a0a09, 0x07060403, 0x08090908, - 0x03020100, 0x05050504, 0xfffffeff, 0x02020100, - 0xfdfdfdfe, 0x00fffefd, 0xfbfbfcfd, 0xfcfbfbfb, - 0xfafbfbfc, 0xfbfaf9f9, 0xfafbfcfd, 0xfafaf9f9, - 0xfd00070d, 0xfbfcfcfd, 0xfd00070e, 0xfcfcfcfd, - 0xfcff080f, 0xfcfbfcfc, 0xfcff080f, 0xfdfcfbfc, - 0xfcff070f, 0xfcfbfbfb, 0xfcff070e, 0xfdfcfcfc, - 0xfcff060c, 0xfdfcfcfc, 0xfcff050b, 0xfdfcfcfc, - 0x0405fcef, 0x03030404, 0x0405fbee, 0x03030404, - 0x0406fbed, 0x02030404, 0x0406fbec, 0x03030404, - 0x0406fcec, 0x03030504, 0x0406fbed, 0x03030504, - 0x0405fcee, 0x02030404, 0x0304fbef, 0x03030404, - 0xfcfafafa, 0x0b0601fe, 0xfcf9f9fa, 0x0d0802fe, - 0xfcf9f8f8, 0x0e0903fe, 0xfbf9f8f8, 0x100a04ff, - 0xfbf9f8f8, 0x110a04ff, 0xfcf9f8f8, 0x100a0500, - 0xfdfaf8f8, 0x0f090400, 0xfdfbf9f9, 0x0c080400, - 0x05070708, 0xf2f8fe02, 0x05070808, 0xf1f8fe02, - 0x05070808, 0xf0f7fd01, 0x05070808, 0xeff6fd01, - 0x05080908, 0xeff6fd01, 0x04070808, 0xf0f6fc01, - 0x04070707, 0xf2f7fd01, 0x03060706, 0xf3f7fd00, - 0xfcfc0105, 0x0000fffd, 0xfdfd0207, 0x0001fffe, - 0xfdfd0107, 0x010100ff, 0xfefd0106, 0x000101ff, - 0xfefc0006, 0x000100ff, 0xfdfc0005, 0xff0000ff, - 0xfffd0005, 0xfe000000, 0xfffe0104, 0xff000100, - 0x01010202, 0xf8f8fafe, 0x01010101, 0xf8f8fbfe, - 0x00010101, 0xfbfbfdff, 0x00000000, 0xfeffffff, - 0x0000ff00, 0x00010000, 0x00000001, 0x02030201, - 0x01010102, 0x03040302, 0x03030303, 0x04050404, - 0xfefdfcfc, 0x01010000, 0xfefdfcfc, 0x010000ff, - 0xfffefefe, 0x0000ffff, 0x00000100, 0xff000000, - 0x02020202, 0x01010202, 0x04040403, 0x03040404, - 0x03010101, 0x03030403, 0xfcfbfafb, 0xfefefdfd, - 0xfffffefc, 0x0100ffff, 0xfffffefc, 0x0100ffff, - 0xfffffefd, 0x020100ff, 0xfffefdfc, 0x030301ff, - 0xfffdfdfc, 0x050401ff, 0xfefefdfc, 0x070401ff, - 0xfffffefe, 0x08060200, 0x010000ff, 0x08070401, - 0xfefdfdfd, 0x00fffffe, 0x0100ffff, 0x03030202, - 0x04020100, 0x05060605, 0x030200ff, 0x03050605, - 0x0200ffff, 0x01020303, 0x00fffefe, 0xfcfcfdff, - 0xffff0000, 0xf9f8fcfe, 0x00010201, 0xf9fafcff, - 0xfa0104fe, 0x00000300, 0xf90105fe, 0x00000300, - 0xf80105fd, 0xffff0300, 0xf70106fe, 0xff000300, - 0xf80206fe, 0xff000400, 0xf90105fd, 0x00000401, - 0xf90104fe, 0x00010400, 0xfa0104ff, 0x00010300, - 0x03000000, 0x01040504, 0x02010101, 0x00020303, - 0x02010202, 0xfeff0102, 0x01010304, 0xfbfdff00, - 0xff010305, 0xfafcfdfe, 0xfe000305, 0xf9fafbfd, - 0xfe000304, 0xfbfbfcfd, 0xff000304, 0xfdfdfefe, - 0x00000000, 0x06fefbff, 0x01000000, 0x08fefaff, - 0x02000000, 0x09fdfa00, 0x0200ff00, 0x0afef900, - 0x0200ff00, 0x0afdf8ff, 0x02ffff00, 0x09fdf9ff, - 0x0100ff00, 0x08fdfaff, 0x01000000, 0x07fefb00, - 0x02030302, 0xffff0001, 0x02030403, 0xfeff0001, - 0x02040403, 0xfdfeff01, 0x02030302, 0xfdfeff00, - 0x010100ff, 0xfefeff00, 0xfffdfcfb, 0x01010100, - 0xfffbf8f8, 0x03040301, 0x00fbf7f6, 0x05060503, - 0x0504fffb, 0x00000103, 0x0504fffa, 0xfeff0002, - 0x0405fffa, 0xfefeff02, 0x0404fff9, 0xfdfdfe01, - 0x0405fffa, 0xfdfdfe01, 0x040400fb, 0xfefeff01, - 0x040500fc, 0xfeffff01, 0x030401fd, 0xfeffff01, - 0x01fefdfe, 0x03050604, 0x00fcfcfd, 0x02040503, - 0xfffbfbfd, 0x01030402, 0xfffcfafc, 0xff020402, - 0x01fdfcfe, 0xff020402, 0x01fefcfe, 0xfe010303, - 0x01fefdfe, 0xfe010303, 0x01fffefe, 0xfe000303, - 0xfefdfcfc, 0x070502ff, 0xfdfdfcfc, 0x070501fe, - 0xfdfefdfe, 0x0503fffd, 0xfe00ffff, 0x0402fefd, - 0xff010101, 0x0301fdfc, 0xff020304, 0x01fffdfc, - 0x00030406, 0x00fefdfd, 0x01030506, 0xfffefdfe, - 0x04080b0c, 0xfffefe00, 0x0206090a, 0x00fffeff, - 0x00020304, 0x0100ffff, 0xffffffff, 0x020100fe, - 0xfefcfbfd, 0x030200fe, 0xfefcfbfb, 0x020100ff, - 0xfefcfbfb, 0x010100ff, 0xfefdfcfc, 0x0000fffe, - 0xff020303, 0xfefdfcfd, 0xfe000203, 0xfefdfcfc, - 0xff010202, 0xfdfcfbfd, 0x01030303, 0xfdfdfdfe, - 0x03040404, 0xfefefe00, 0x03050505, 0xfefeff00, - 0x02040505, 0xfefdfeff, 0x00030303, 0xfcfcfcfe, - 0xfe04ffff, 0xfb0206fe, 0xfe0400ff, 0xfa0206fd, - 0xfe0400ff, 0xf90307fd, 0xfd04ffff, 0xf90308fc, - 0xfd04ff00, 0xfa0307fc, 0xfd04ffff, 0xfa0307fc, - 0xfd03ffff, 0xfa0306fc, 0xfe0300ff, 0xfb0306fd, - 0x02f9fe01, 0x01fffe05, 0x03f8fe01, 0x02fffd06, - 0x04f7fe02, 0x02fefc07, 0x05f7ff03, 0x03fffc07, - 0x04f7ff03, 0x02fefc07, 0x04f9ff03, 0x01fefc06, - 0x04fa0002, 0x01fffc06, 0x03fb0002, 0x01fffd04, - 0x000202fe, 0xfcfdff00, 0x010202fe, 0xfcfe0001, - 0x020202fe, 0xfeff0102, 0x030302fd, 0xfe000204, - 0x020302fd, 0xfd000204, 0x010201fc, 0xfdff0102, - 0x000100fb, 0xfdfe0101, 0x000000fc, 0xfdfe0001, - 0xfeff0000, 0x080702fe, 0xfdff0000, 0x070601fe, - 0xfdff0100, 0x050400fd, 0xff000100, 0x030100ff, - 0x01010200, 0x0100ff00, 0x020100fe, 0xffff0001, - 0x0100fefb, 0xfdfd0001, 0x01fffcfa, 0xfcfdff01, - 0x0502fefc, 0x02030406, 0x0401fdfb, 0x00000204, - 0x0200fefc, 0xfefeff01, 0x0100fffe, 0xfefdfe00, - 0x000000fe, 0xfffeffff, 0x00fffffe, 0x02010000, - 0xfffffefe, 0x04030100, 0xfffefdfe, 0x05040200, - 0xfefe0102, 0x000100ff, 0xfdfd0001, 0x000100ff, - 0xfdfdff00, 0x010101ff, 0xfffd0000, 0x03030201, - 0xfffdff00, 0x03030301, 0xfefcfefe, 0x04040301, - 0xfefcfdfd, 0x04030301, 0xfefbfdfe, 0x03030201, - 0x04030504, 0x05040404, 0x00010303, 0x01000000, - 0xfeff0101, 0xfefdfcfd, 0xfe000202, 0xfefdfcfe, - 0xff010302, 0xfefdfdff, 0x00000201, 0xfffefeff, - 0xff000100, 0xfffefdff, 0xff000101, 0xfefefeff, - 0x00fffffe, 0x00010201, 0x05030201, 0x03050506, - 0x04030201, 0x03040505, 0xfdfdfefe, 0x0000fffe, - 0xfbfcfdfd, 0xfffefdfc, 0xfefeffff, 0x0000fffe, - 0xff000100, 0x010000ff, 0xfeff00ff, 0xfffefefd, - 0x05060707, 0xfeff0204, 0x02020303, 0xfdfe0001, - 0xffffff00, 0xfefeff00, 0xfffefdff, 0x01000000, - 0xfffefe00, 0x020201ff, 0xffff0103, 0x020201ff, - 0xfdfe0103, 0x0201fffe, 0xfafbfe01, 0x00fefdfb, - 0xfdfeff00, 0xfefe00ff, 0xffff0000, 0xfeff0100, - 0xfffe0000, 0xfe000000, 0xfdfdfeff, 0xfdfdfffe, - 0xfdfdfeff, 0xfcfdfefe, 0x00000202, 0xfeff0000, - 0x02030505, 0xff000202, 0x05060808, 0x01020404, - 0xfdfaf8f9, 0xfffeffff, 0x00fdfbfb, 0x00000102, - 0x0300ffff, 0x01010304, 0x03010102, 0x02020304, - 0x02000203, 0x02010203, 0xffff0204, 0x01010100, - 0xfdfe0203, 0x0100fffe, 0xfcfd0103, 0x0100fefd, - 0x02fffefc, 0x00010303, 0xfefcfbf9, 0xfeff0000, - 0xfcfbfbfa, 0xfdfefefe, 0xffff00ff, 0xff000000, - 0x02020302, 0x00010202, 0x03040503, 0x00010001, - 0x02030403, 0xffffff00, 0x01030505, 0xffffff00, - 0xff000101, 0xfcfafbfd, 0x00000101, 0xfffdfd00, - 0x00ffff00, 0x03010001, 0xfffdfefe, 0x07040202, - 0x00fefefe, 0x06030202, 0x010000ff, 0x03000001, - 0x03030300, 0xfffdfe01, 0x03040301, 0xfcfbfd00, - 0xff000200, 0xfefefcfd, 0x00020401, 0xfffefdfe, - 0x01030603, 0xff00fefe, 0x01040704, 0x00fffdfe, - 0x00030603, 0x00fffdfd, 0xff000301, 0x0101fefd, - 0xfeff0100, 0x0202fffd, 0xfdfdfffe, 0x0201fffd, - 0x00ff0103, 0x00000001, 0xfffeff02, 0xffff0001, - 0x00feff01, 0xfdfe0001, 0x01fffe00, 0xfbfd0103, - 0x02fffe00, 0xfbfd0205, 0x04fffe00, 0xfbfe0306, - 0x0400fe00, 0xfcfe0407, 0x0400fe00, 0xfcfe0406, - 0xfcfdfefe, 0x00fffefd, 0xff000101, 0x0100ffff, - 0x02020303, 0x01010101, 0x02020202, 0x01000001, - 0x00000000, 0xffffffff, 0xfcfcfcfc, 0xfdfcfcfc, - 0xfdfefdfd, 0x00fffffe, 0x05040403, 0x07060605, - 0xfe07feff, 0x00fffffc, 0xff09feff, 0x00fffffc, - 0xff0afdff, 0x01fffffc, 0xfe0afdff, 0x02fffffd, - 0xfe0afeff, 0x02fffffc, 0xfe09feff, 0x02fffffc, - 0xfe08feff, 0x01ff00fc, 0xfe07fe00, 0x0200fffd, - 0x0301fc03, 0x0001fefd, 0x0401fb03, 0x0001fefd, - 0x0502fa03, 0x0003fffd, 0x0502fa03, 0x0002fffd, - 0x0501fa03, 0x0003fefc, 0x0501fa03, 0x0002fefd, - 0x0401fa02, 0x0001fffd, 0x0401fa02, 0x0001fffe, - 0x01010000, 0x02000001, 0x0101ff00, 0x02000001, - 0x0000ff00, 0x02000000, 0x0000ff00, 0x00ff0000, - 0x00010001, 0xfffeff00, 0x00010103, 0xfdfcfe00, - 0x01020305, 0xfcfbfd00, 0x00020405, 0xfbfbfcff, - 0xfeff0001, 0xf7fafdfe, 0xffff0002, 0xfafd0000, - 0xff000001, 0xfbfe0000, 0x01010102, 0xfdff0201, - 0x01020101, 0xff010202, 0x01020101, 0x01010101, - 0x01020000, 0x02020000, 0x02020100, 0x02020000, - 0x0100fdfc, 0x03040604, 0x0000fefd, 0x00010402, - 0x0000ffff, 0xfdfe0101, 0x00010101, 0xfbfd0101, - 0x00010101, 0xfbfd0101, 0xff0000ff, 0xfcfe0101, - 0xff0000ff, 0xfe000201, 0x000000ff, 0x00010302, - 0x040300ff, 0xfbfbfc00, 0x05040000, 0xfefdfe02, - 0x0402ff00, 0x00ffff02, 0x01fffe00, 0x0100fe00, - 0x00fefe01, 0x01ffff00, 0x00fdfe01, 0x00ff0001, - 0x01fefe01, 0x00000103, 0x02fffe01, 0x00000204, - 0x02030201, 0x01020200, 0x000100ff, 0x010101fd, - 0xfe0000ff, 0x010200fc, 0xff0202ff, 0x010200fb, - 0xff0403ff, 0x010200fb, 0x000402fe, 0x0000fffc, - 0x000200fc, 0x0000fefc, 0x0102fffb, 0x020301fe, - 0x00010001, 0xfeff0201, 0xfeff0002, 0xff000301, - 0xfcfe0003, 0x00010300, 0xfbfd0105, 0x010102fe, - 0xfbfe0106, 0x010001fe, 0xfbff0105, 0x00ff00fe, - 0xfcfe0003, 0x00ff00fe, 0xfe00ff01, 0x01000100, - 0x03020101, 0x02010102, 0x0100ffff, 0x01010001, - 0x0000fdfc, 0x02010101, 0x0200fdfc, 0x02030202, - 0x0100fcfb, 0x02010101, 0xfffffcfb, 0x00fffefe, - 0x0000fefd, 0xfffefdfe, 0x04040302, 0x00000002, - 0x0100fefc, 0x00000000, 0x0101fffd, 0x00000000, - 0x020200fe, 0x02000000, 0x010201ff, 0x050300ff, - 0xff010200, 0x060500fe, 0xfd000100, 0x060400fd, - 0xfcfe0101, 0x0201fdfc, 0xfcfe0001, 0x00fefcfb, - 0xfdfdfdff, 0xfffffefd, 0x00010203, 0x01010100, - 0x02030405, 0x02020101, 0xfe000102, 0xfffffefe, - 0xff000000, 0xfefefefe, 0x03030100, 0xffff0102, - 0x04030100, 0xff010203, 0x01fffdfc, 0xfdfdfe00, - 0xf8f9fcfd, 0x02fffcf9, 0xfcfdff00, 0x0200fefc, - 0xff000001, 0x0200fefd, 0x00010102, 0x0200ffff, - 0x01010101, 0x01000000, 0x01010101, 0x01010101, - 0x02010000, 0x02020303, 0x03010000, 0x02030404, - 0x00030303, 0x020100ff, 0xff010101, 0x01fffffe, - 0xfdfffefe, 0x00fefefd, 0xfefefcfc, 0x00fdfefe, - 0x01fffcfc, 0x02ff0001, 0x0302fffd, 0x05030304, - 0x030200fe, 0x03030303, 0x0000fefe, 0x01000000, - 0xff010200, 0xfe03fffd, 0xffff00ff, 0xfe0400fd, - 0xfefefefe, 0xfe0501fe, 0xfffdfefd, 0xfd0401fe, - 0x00ff00fe, 0xfb0300ff, 0x02010201, 0xfb020000, - 0x03020402, 0xfd030101, 0x01010201, 0xfe040100, - 0xfffcfd04, 0x03010303, 0xfffcfc04, 0x02000203, - 0x00fcfd04, 0x01ff0202, 0x01fefd04, 0x00fe0102, - 0x01fefc02, 0x00fd0002, 0x00fefd02, 0x02fe0001, - 0x00ffff03, 0x03000000, 0xfefefe02, 0x02ffffff, - 0x04030202, 0xff000103, 0x02010001, 0xfefeff01, - 0x01020102, 0xffff0001, 0x03040304, 0x01010102, - 0x02020203, 0x01010101, 0x00fffeff, 0xffffffff, - 0xfffefdfd, 0xfefefefe, 0xfdfdfcfc, 0xfdfdfcfc, - 0xfdff0102, 0x0403fefc, 0xff010202, 0x0201fefd, - 0x03030201, 0xfefffe00, 0x040200ff, 0xfdff0002, - 0x0300fefe, 0xfd000203, 0xfffdfe00, 0xff020201, - 0xfbfcff03, 0x000200fd, 0xfafe0306, 0x010300fb, - 0x00fe03fe, 0x01fefe03, 0x00fd04fd, 0x02fffe03, - 0x00fd05fd, 0x02fffe04, 0xfffc04fe, 0x02fefd03, - 0x00fd04fd, 0x02fffd03, 0x00fe05fe, 0x02fffd03, - 0x01fd04fe, 0x02fffe03, 0x01fe03fe, 0x0200fe03, - 0xff000001, 0xfffc0201, 0xff000002, 0xfefc0201, - 0xff010101, 0x00fe0402, 0xff01ff00, 0x01ff0502, - 0xfe00ff00, 0x01ff0501, 0xfeffff00, 0xfffd0300, - 0xfe000101, 0xfffd0300, 0xfd000101, 0x00fe0300, - 0x01ff0001, 0x05040201, 0x01ff0001, 0x07050101, - 0xfffe0000, 0x050300ff, 0xfffeff00, 0x0302ffff, - 0xfffdff00, 0x0201ffff, 0xfefcfeff, 0x0000fefe, - 0xfffefeff, 0x0000fefe, 0x00ffff00, 0x0000ffff, - 0xff000303, 0x040401ff, 0xfe000302, 0x010100fe, - 0xff010302, 0x000100ff, 0xff000201, 0xfe00ffff, - 0xff000100, 0xfe00fffe, 0xff000100, 0x0001fffe, - 0xfdff0101, 0x0301fdfc, 0xfdff0201, 0x0301fcfb, - 0x0100fefd, 0xfe000101, 0x01010100, 0xfdff0000, - 0x01010201, 0xfeffff00, 0xfffdff00, 0xff00ffff, - 0xfdfafd00, 0x0101fffe, 0xfdfcff02, 0x020200fe, - 0x01010405, 0x02030100, 0x01020405, 0x0100ff00, - 0xfbfe00fe, 0x0000fdfa, 0x000100fe, 0x020201ff, - 0x030100fe, 0x01020202, 0x040200fe, 0x01010203, - 0x030200fe, 0x00ff0002, 0x0101fffd, 0x01ffff00, - 0x0001fffc, 0x0200feff, 0xff00fffc, 0x0401feff, - 0xff0000fd, 0x00010101, 0xff0001fd, 0xffff0000, - 0x000303ff, 0x01000001, 0xfe0202fd, 0x010000ff, - 0xfe0000fb, 0x020001ff, 0x0001fef9, 0x02020201, - 0x020300fb, 0x02020303, 0x010402fd, 0xfdfe0000, - 0xfefe0205, 0xffffff00, 0xfdfcff02, 0xfffffeff, - 0x01fefe00, 0x0100ff02, 0x03fffeff, 0x0200ff03, - 0x03000001, 0x02fffe03, 0x03010102, 0x00fefe02, - 0x01ff0001, 0xfefdfd01, 0x02010001, 0x00000003, - 0x00fdfbfc, 0xfffeff01, 0x01fffdfe, 0x00000002, - 0x01020101, 0x01010102, 0x01030403, 0xfffffe00, - 0x00020303, 0xfefdfdfe, 0xff000101, 0xfefefcfe, - 0x00000102, 0x0100ff00, 0x01010102, 0x03010101, - 0xff000000, 0x0001fffe, 0xfefffffe, 0x0000fefd, - 0xff0000ff, 0x010100fe, 0xff000101, 0x010301ff, - 0xfe000202, 0x000302ff, 0xffff0103, 0xfe020401, - 0xfffd0002, 0xfb000503, 0x00feff01, 0xfaff0303, - 0x040300ff, 0x02010002, 0x0100fffe, 0x0100feff, - 0xfdfefdfe, 0xfdfaf9fa, 0x01030202, 0xfefdfeff, - 0x01030202, 0x00000000, 0x00010102, 0x01000101, - 0x00000001, 0x02010100, 0x00ff0001, 0x01020200, - 0x01030101, 0x01ffffff, 0x0000fffe, 0x02fffefe, - 0x0101fefe, 0x03010001, 0xff00fefe, 0x0200ff00, - 0x00010000, 0x01feffff, 0x01020203, 0x01fefe00, - 0x02030305, 0x04010101, 0xfbfcfd00, 0x01fffdfc, - 0x02fffcfa, 0xff000002, 0x0301fefc, 0x00020203, - 0x02fffefd, 0x00020303, 0x01fefefd, 0xff010102, - 0x00fefefe, 0xff010202, 0x01ffffff, 0x00020302, - 0x01feffff, 0xff020202, 0x00feff00, 0xff000102, - 0x01020406, 0x01000000, 0xfeff0204, 0xfffffefe, - 0xfeff0102, 0xfffefefe, 0xfe000202, 0x00fffefe, - 0xfeff0000, 0x0100fffe, 0xfffefdfd, 0x00fffeff, - 0x0302fefd, 0xfeff0002, 0x050400fe, 0xff000205, - 0x00020405, 0xfffffeff, 0x01020304, 0xff00ff00, - 0x01000101, 0xff010001, 0x00fffffe, 0xfdfefe00, - 0x000000ff, 0xfbfdfdff, 0xff010100, 0xfdfefeff, - 0xfeffffff, 0x010301ff, 0xfffefeff, 0x05060502, - 0x01fefdfd, 0xfffffe01, 0x04030201, 0xfdfffd01, - 0x01000203, 0xfdfffdff, 0x00ff0001, 0x0001ffff, - 0x01000101, 0x03050202, 0x02010101, 0x00030202, - 0xfefefffd, 0xfdfffdfd, 0x000101ff, 0xfe00ffff, - 0xfefe0002, 0xfe010402, 0xfffe0001, 0xff020503, - 0xfefdfeff, 0xfe010301, 0xfffffeff, 0xff010200, - 0x01010000, 0x00020201, 0x04040100, 0x01030202, - 0x0102fffe, 0xfdfefdfe, 0x000100ff, 0xfbfcfcfd, - 0xfcfd0004, 0xfffefcfc, 0x00ff0005, 0xfffefdff, - 0x01000004, 0x00000001, 0xfffefd00, 0x00010000, - 0x0000fe00, 0x01020101, 0x00000002, 0x00010101, - 0xffff0002, 0x00010101, 0xfefeff01, 0x02020200, - 0x00fefbfd, 0x00fdfdff, 0x0200fe00, 0x03000002, - 0x00feff02, 0x02ffff00, 0xffff0205, 0x02ffffff, - 0xff000205, 0x02ff00ff, 0x00000102, 0x02000100, - 0x0101ffff, 0x02010202, 0x0000fefd, 0xfffe0000, - 0x00020300, 0xfdfdfdfe, 0x01030300, 0x02010000, - 0xfeff00ff, 0x0301ffff, 0xfeff00ff, 0x0200ffff, - 0xfeff00ff, 0x02ff0000, 0xfeff00ff, 0x01feffff, - 0xfd000100, 0x02ffffff, 0xff020505, 0x0301ffff, - 0xff010000, 0x0200fefd, 0x00030101, 0x0100fefe, - 0x01030101, 0xffff0000, 0x0102ff00, 0xfdff0001, - 0x0101feff, 0xfcfe0001, 0x010200ff, 0xfdff0001, - 0x02030101, 0xfdfe0001, 0x02040202, 0xfcfeff01, - 0x02020201, 0x0200fe00, 0xfdfeffff, 0x01fdfbfc, - 0x00010100, 0x01ffffff, 0x01010100, 0x02000000, - 0x02010100, 0x02010101, 0x0200ffff, 0x03020202, - 0xfffcfcfe, 0x00fefefe, 0x01000001, 0x01000000, - 0xfefdff00, 0x01020200, 0xfdfeff00, 0x02010100, - 0xfdfe0001, 0x010000ff, 0xfeff00ff, 0x00ff0000, - 0x000101ff, 0x00000202, 0x01030200, 0x02030503, - 0xfe0101ff, 0x01010300, 0xfc0000ff, 0xfffffffc, - 0x000101ff, 0x02010201, 0x000100fd, 0x02000101, - 0xfffffdfb, 0x01000100, 0xfdfefdfc, 0x00fffffe, - 0xfeff0000, 0x00fefefe, 0x00020403, 0x01000000, - 0x00000102, 0x00ff0000, 0x03020100, 0x02030404, - 0x040704ff, 0x00000000, 0x030604ff, 0x01010100, - 0x00040300, 0x010000ff, 0xfe010100, 0xffff00ff, - 0xffff00ff, 0x000000ff, 0x00ffffff, 0x00000000, - 0x00fdfdff, 0xfffeff01, 0xfefcfcfd, 0xfffefeff, - 0x00010202, 0xfd000101, 0x0000fffe, 0xfd000101, - 0x0100fffe, 0xfe010102, 0x02020201, 0xff020303, - 0x00010201, 0xff020101, 0xfcfe0100, 0xff0100fe, - 0xfdff0101, 0xfdff00fe, 0xff000201, 0xfcff0100, - 0xfefeffff, 0x03040300, 0xfdff0101, 0x000000fe, - 0x02020202, 0xffff0102, 0x03010101, 0xfefe0003, - 0xffffff00, 0xfffffe00, 0xfdfcfdff, 0x0200fefe, - 0x0100ffff, 0x05030202, 0x00fffffe, 0x01000000, - 0x0002fdfe, 0xff010100, 0xfe01fcff, 0x000202ff, - 0xfe00fc01, 0xff0101fe, 0xff01fd02, 0xff0101ff, - 0x0103fe03, 0xff010100, 0x0102fd01, 0xff000100, - 0x0001fbff, 0x010100ff, 0x0303fd00, 0x03030201, - 0x01feff00, 0xff020505, 0xfffeff01, 0xfbfe0101, - 0xfeff0101, 0xfdffffff, 0xffff0101, 0x030402ff, - 0xffffffff, 0x030400ff, 0x0100ffff, 0xfffffdff, - 0x02000000, 0xff000002, 0x00fdfe00, 0x02030101, - 0x01020302, 0xfefe0000, 0x01000302, 0x02030301, - 0xfffd0000, 0x030202ff, 0x01fdfefe, 0x01010201, - 0x02fefffe, 0xfeff0101, 0x02000100, 0xfefe0000, - 0x02000100, 0xfefe0000, 0x00fefefd, 0xfdfefeff, - 0x03ff0100, 0xff0301ff, 0x03ff0100, 0xfd02ffff, - 0x03fe0101, 0xfd00fdff, 0x03fe0202, 0xfe01fe00, - 0x03fd0101, 0xfd01feff, 0x03fd0101, 0xfe01ff00, - 0x04ff0201, 0xfe01ff00, 0x03ff0100, 0xfd00fdff, - 0x01fffdfd, 0xfeff0102, 0x0200fefe, 0xfefe0001, - 0x0201fefd, 0xfffeff01, 0x0402fefd, 0x01fefe00, - 0x0402fffd, 0x02fefe00, 0x030401ff, 0x02fefdff, - 0x02040200, 0x02fffeff, 0x00020100, 0x030100ff, - 0x01fb0003, 0x01000004, 0x02fbfe01, 0x01feff05, - 0x030000ff, 0xff000103, 0xfe0403fe, 0xfe00fffd, - 0xfd0503fd, 0xfe0000fd, 0xfe0203ff, 0xff0202fe, - 0xff000002, 0x00000000, 0x01fefd00, 0xfefe0003 +static const int8 s_svq1InterCodebook8x8[6144] = { + -4, -3, 4, 5, 2, 1, 1, 0, -5, -3, 5, 5, 2, 1, 0, 0, + -6, -4, 5, 5, 2, 1, 0, 0, -7, -4, 4, 5, 2, 1, 0, 0, + -8, -5, 3, 4, 2, 1, 0, 0, -8, -6, 3, 4, 1, 1, 1, 0, + -8, -6, 2, 4, 2, 1, 1, 0, -8, -6, 2, 4, 1, 1, 1, 1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -2, -2, -2, + -2, -3, -3, -3, -3, -3, -3, -3, -2, -3, -3, -3, -3, -3, -4, -3, + -2, -2, -2, -2, -2, -3, -3, -2, 1, 1, 1, 1, 1, 0, -1, -1, + 4, 5, 5, 5, 4, 3, 3, 2, 7, 7, 8, 8, 8, 7, 6, 5, + 2, 1, 2, 4, 4, 0, -4, -6, 1, 1, 2, 5, 5, 1, -5, -7, + 1, 2, 1, 4, 5, 1, -5, -8, 1, 1, 1, 5, 5, 0, -6, -8, + 0, 1, 1, 5, 6, 1, -6, -9, 0, 0, 1, 4, 5, 0, -5, -8, + 0, 0, 1, 4, 5, 0, -5, -7, 0, 0, 1, 4, 4, 1, -4, -7, + 1, 2, 3, 0, -3, -4, -3, -1, 1, 3, 4, 0, -3, -4, -3, -1, + 2, 4, 5, 1, -3, -4, -3, -2, 2, 5, 6, 1, -3, -5, -4, -2, + 3, 6, 6, 1, -3, -5, -4, -2, 3, 6, 6, 1, -3, -5, -4, -2, + 3, 6, 6, 1, -3, -5, -4, -2, 3, 5, 5, 1, -3, -4, -4, -2, + 2, 2, 2, 2, 1, 0, 0, -1, 4, 4, 4, 3, 2, 1, 1, 0, + 4, 5, 4, 4, 3, 3, 2, 1, 4, 4, 4, 4, 4, 3, 2, 2, + 2, 3, 3, 3, 3, 3, 2, 1, -1, -1, -1, -1, 0, 0, 0, 0, + -5, -6, -6, -5, -5, -4, -3, -3, -7, -9, -9, -8, -7, -6, -6, -5, + 6, 6, 6, 6, 6, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 2, + 0, -1, -1, -1, -2, -2, -1, -1, -3, -5, -6, -6, -6, -6, -5, -4, + -3, -5, -6, -7, -6, -6, -5, -4, -1, -2, -2, -2, -2, -2, -1, -1, + 0, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 1, -2, -5, -4, 0, 2, 5, 2, 1, -2, -6, -5, 0, 3, 5, + 2, 1, -2, -6, -6, -1, 3, 6, 3, 2, -2, -7, -6, 0, 4, 7, + 2, 1, -2, -7, -5, 0, 5, 7, 2, 1, -2, -6, -5, 0, 4, 7, + 2, 1, -2, -6, -4, 0, 4, 6, 1, 1, -2, -5, -4, 0, 3, 6, + -10, -9, -6, -4, -1, 2, 3, 2,-10, -9, -5, -3, 0, 4, 4, 3, + -9, -7, -3, -1, 2, 5, 5, 3, -7, -5, -2, 0, 3, 5, 5, 3, + -6, -3, 0, 1, 4, 6, 5, 3, -4, -2, 1, 2, 3, 5, 4, 2, + -2, 0, 1, 2, 2, 4, 3, 1, -1, 1, 2, 2, 2, 3, 3, 1, + -4, -5, -5, -6, -6, -6, -6, -5, -3, -3, -4, -4, -4, -4, -4, -4, + 0, 0, 0, 0, -1, -1, -1, -1, 5, 5, 6, 5, 5, 4, 3, 2, + 5, 6, 7, 7, 7, 6, 5, 4, 3, 3, 4, 4, 4, 4, 3, 2, + 0, -1, 0, 0, -1, -1, 0, -1, -3, -3, -4, -4, -4, -4, -3, -3, + 1, -2, -5, 1, 5, 4, 2, 0, 1, -3, -6, 1, 6, 5, 2, 0, + 0, -4, -7, 0, 6, 6, 2, 1, -1, -5, -9, -1, 6, 6, 3, 1, + -1, -6,-10, -2, 6, 6, 3, 1, -1, -6, -9, -2, 5, 6, 3, 1, + -2, -6, -9, -2, 5, 5, 3, 1, -2, -6, -7, -2, 4, 4, 2, 1, + -5, -7, -8, -9, -9, -8, -7, -6, -5, -6, -6, -7, -7, -6, -6, -5, + -3, -3, -3, -4, -5, -5, -4, -4, -1, 0, 0, -1, -1, -1, -1, -1, + 0, 1, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 5, 5, 5, 4, + 3, 4, 5, 6, 8, 8, 8, 7, 3, 4, 5, 6, 7, 7, 7, 6, + 5, 6, 7, 8, 9, 10, 10, 9, 3, 4, 6, 7, 8, 9, 9, 8, + 0, 1, 2, 3, 4, 5, 5, 5, -1, -2, -1, -1, 0, 1, 2, 2, + -2, -3, -3, -3, -3, -2, -1, 0, -3, -4, -5, -5, -5, -5, -5, -4, + -4, -5, -5, -6, -7, -7, -6, -5, -3, -4, -5, -6, -7, -7, -6, -6, + 13, 7, 0, -3, -3, -4, -4, -5, 14, 7, 0, -3, -3, -4, -4, -4, + 15, 8, -1, -4, -4, -4, -5, -4, 15, 8, -1, -4, -4, -5, -4, -3, + 15, 7, -1, -4, -5, -5, -5, -4, 14, 7, -1, -4, -4, -4, -4, -3, + 12, 6, -1, -4, -4, -4, -4, -3, 11, 5, -1, -4, -4, -4, -4, -3, + -17, -4, 5, 4, 4, 4, 3, 3,-18, -5, 5, 4, 4, 4, 3, 3, + -19, -5, 6, 4, 4, 4, 3, 2,-20, -5, 6, 4, 4, 4, 3, 3, + -20, -4, 6, 4, 4, 5, 3, 3,-19, -5, 6, 4, 4, 5, 3, 3, + -18, -4, 5, 4, 4, 4, 3, 2,-17, -5, 4, 3, 4, 4, 3, 3, + -6, -6, -6, -4, -2, 1, 6, 11, -6, -7, -7, -4, -2, 2, 8, 13, + -8, -8, -7, -4, -2, 3, 9, 14, -8, -8, -7, -5, -1, 4, 10, 16, + -8, -8, -7, -5, -1, 4, 10, 17, -8, -8, -7, -4, 0, 5, 10, 16, + -8, -8, -6, -3, 0, 4, 9, 15, -7, -7, -5, -3, 0, 4, 8, 12, + 8, 7, 7, 5, 2, -2, -8,-14, 8, 8, 7, 5, 2, -2, -8,-15, + 8, 8, 7, 5, 1, -3, -9,-16, 8, 8, 7, 5, 1, -3,-10,-17, + 8, 9, 8, 5, 1, -3,-10,-17, 8, 8, 7, 4, 1, -4,-10,-16, + 7, 7, 7, 4, 1, -3, -9,-14, 6, 7, 6, 3, 0, -3, -9,-13, + 5, 1, -4, -4, -3, -1, 0, 0, 7, 2, -3, -3, -2, -1, 1, 0, + 7, 1, -3, -3, -1, 0, 1, 1, 6, 1, -3, -2, -1, 1, 1, 0, + 6, 0, -4, -2, -1, 0, 1, 0, 5, 0, -4, -3, -1, 0, 0, -1, + 5, 0, -3, -1, 0, 0, 0, -2, 4, 1, -2, -1, 0, 1, 0, -1, + 2, 2, 1, 1, -2, -6, -8, -8, 1, 1, 1, 1, -2, -5, -8, -8, + 1, 1, 1, 0, -1, -3, -5, -5, 0, 0, 0, 0, -1, -1, -1, -2, + 0, -1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 2, 3, 2, + 2, 1, 1, 1, 2, 3, 4, 3, 3, 3, 3, 3, 4, 4, 5, 4, + -4, -4, -3, -2, 0, 0, 1, 1, -4, -4, -3, -2, -1, 0, 0, 1, + -2, -2, -2, -1, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, -1, + 2, 2, 2, 2, 2, 2, 1, 1, 3, 4, 4, 4, 4, 4, 4, 3, + 1, 1, 1, 3, 3, 4, 3, 3, -5, -6, -5, -4, -3, -3, -2, -2, + -4, -2, -1, -1, -1, -1, 0, 1, -4, -2, -1, -1, -1, -1, 0, 1, + -3, -2, -1, -1, -1, 0, 1, 2, -4, -3, -2, -1, -1, 1, 3, 3, + -4, -3, -3, -1, -1, 1, 4, 5, -4, -3, -2, -2, -1, 1, 4, 7, + -2, -2, -1, -1, 0, 2, 6, 8, -1, 0, 0, 1, 1, 4, 7, 8, + -3, -3, -3, -2, -2, -1, -1, 0, -1, -1, 0, 1, 2, 2, 3, 3, + 0, 1, 2, 4, 5, 6, 6, 5, -1, 0, 2, 3, 5, 6, 5, 3, + -1, -1, 0, 2, 3, 3, 2, 1, -2, -2, -1, 0, -1, -3, -4, -4, + 0, 0, -1, -1, -2, -4, -8, -7, 1, 2, 1, 0, -1, -4, -6, -7, + -2, 4, 1, -6, 0, 3, 0, 0, -2, 5, 1, -7, 0, 3, 0, 0, + -3, 5, 1, -8, 0, 3, -1, -1, -2, 6, 1, -9, 0, 3, 0, -1, + -2, 6, 2, -8, 0, 4, 0, -1, -3, 5, 1, -7, 1, 4, 0, 0, + -2, 4, 1, -7, 0, 4, 1, 0, -1, 4, 1, -6, 0, 3, 1, 0, + 0, 0, 0, 3, 4, 5, 4, 1, 1, 1, 1, 2, 3, 3, 2, 0, + 2, 2, 1, 2, 2, 1, -1, -2, 4, 3, 1, 1, 0, -1, -3, -5, + 5, 3, 1, -1, -2, -3, -4, -6, 5, 3, 0, -2, -3, -5, -6, -7, + 4, 3, 0, -2, -3, -4, -5, -5, 4, 3, 0, -1, -2, -2, -3, -3, + 0, 0, 0, 0, -1, -5, -2, 6, 0, 0, 0, 1, -1, -6, -2, 8, + 0, 0, 0, 2, 0, -6, -3, 9, 0, -1, 0, 2, 0, -7, -2, 10, + 0, -1, 0, 2, -1, -8, -3, 10, 0, -1, -1, 2, -1, -7, -3, 9, + 0, -1, 0, 1, -1, -6, -3, 8, 0, 0, 0, 1, 0, -5, -2, 7, + 2, 3, 3, 2, 1, 0, -1, -1, 3, 4, 3, 2, 1, 0, -1, -2, + 3, 4, 4, 2, 1, -1, -2, -3, 2, 3, 3, 2, 0, -1, -2, -3, + -1, 0, 1, 1, 0, -1, -2, -2, -5, -4, -3, -1, 0, 1, 1, 1, + -8, -8, -5, -1, 1, 3, 4, 3,-10, -9, -5, 0, 3, 5, 6, 5, + -5, -1, 4, 5, 3, 1, 0, 0, -6, -1, 4, 5, 2, 0, -1, -2, + -6, -1, 5, 4, 2, -1, -2, -2, -7, -1, 4, 4, 1, -2, -3, -3, + -6, -1, 5, 4, 1, -2, -3, -3, -5, 0, 4, 4, 1, -1, -2, -2, + -4, 0, 5, 4, 1, -1, -1, -2, -3, 1, 4, 3, 1, -1, -1, -2, + -2, -3, -2, 1, 4, 6, 5, 3, -3, -4, -4, 0, 3, 5, 4, 2, + -3, -5, -5, -1, 2, 4, 3, 1, -4, -6, -4, -1, 2, 4, 2, -1, + -2, -4, -3, 1, 2, 4, 2, -1, -2, -4, -2, 1, 3, 3, 1, -2, + -2, -3, -2, 1, 3, 3, 1, -2, -2, -2, -1, 1, 3, 3, 0, -2, + -4, -4, -3, -2, -1, 2, 5, 7, -4, -4, -3, -3, -2, 1, 5, 7, + -2, -3, -2, -3, -3, -1, 3, 5, -1, -1, 0, -2, -3, -2, 2, 4, + 1, 1, 1, -1, -4, -3, 1, 3, 4, 3, 2, -1, -4, -3, -1, 1, + 6, 4, 3, 0, -3, -3, -2, 0, 6, 5, 3, 1, -2, -3, -2, -1, + 12, 11, 8, 4, 0, -2, -2, -1, 10, 9, 6, 2, -1, -2, -1, 0, + 4, 3, 2, 0, -1, -1, 0, 1, -1, -1, -1, -1, -2, 0, 1, 2, + -3, -5, -4, -2, -2, 0, 2, 3, -5, -5, -4, -2, -1, 0, 1, 2, + -5, -5, -4, -2, -1, 0, 1, 1, -4, -4, -3, -2, -2, -1, 0, 0, + 3, 3, 2, -1, -3, -4, -3, -2, 3, 2, 0, -2, -4, -4, -3, -2, + 2, 2, 1, -1, -3, -5, -4, -3, 3, 3, 3, 1, -2, -3, -3, -3, + 4, 4, 4, 3, 0, -2, -2, -2, 5, 5, 5, 3, 0, -1, -2, -2, + 5, 5, 4, 2, -1, -2, -3, -2, 3, 3, 3, 0, -2, -4, -4, -4, + -1, -1, 4, -2, -2, 6, 2, -5, -1, 0, 4, -2, -3, 6, 2, -6, + -1, 0, 4, -2, -3, 7, 3, -7, -1, -1, 4, -3, -4, 8, 3, -7, + 0, -1, 4, -3, -4, 7, 3, -6, -1, -1, 4, -3, -4, 7, 3, -6, + -1, -1, 3, -3, -4, 6, 3, -6, -1, 0, 3, -2, -3, 6, 3, -5, + 1, -2, -7, 2, 5, -2, -1, 1, 1, -2, -8, 3, 6, -3, -1, 2, + 2, -2, -9, 4, 7, -4, -2, 2, 3, -1, -9, 5, 7, -4, -1, 3, + 3, -1, -9, 4, 7, -4, -2, 2, 3, -1, -7, 4, 6, -4, -2, 1, + 2, 0, -6, 4, 6, -4, -1, 1, 2, 0, -5, 3, 4, -3, -1, 1, + -2, 2, 2, 0, 0, -1, -3, -4, -2, 2, 2, 1, 1, 0, -2, -4, + -2, 2, 2, 2, 2, 1, -1, -2, -3, 2, 3, 3, 4, 2, 0, -2, + -3, 2, 3, 2, 4, 2, 0, -3, -4, 1, 2, 1, 2, 1, -1, -3, + -5, 0, 1, 0, 1, 1, -2, -3, -4, 0, 0, 0, 1, 0, -2, -3, + 0, 0, -1, -2, -2, 2, 7, 8, 0, 0, -1, -3, -2, 1, 6, 7, + 0, 1, -1, -3, -3, 0, 4, 5, 0, 1, 0, -1, -1, 0, 1, 3, + 0, 2, 1, 1, 0, -1, 0, 1, -2, 0, 1, 2, 1, 0, -1, -1, + -5, -2, 0, 1, 1, 0, -3, -3, -6, -4, -1, 1, 1, -1, -3, -4, + -4, -2, 2, 5, 6, 4, 3, 2, -5, -3, 1, 4, 4, 2, 0, 0, + -4, -2, 0, 2, 1, -1, -2, -2, -2, -1, 0, 1, 0, -2, -3, -2, + -2, 0, 0, 0, -1, -1, -2, -1, -2, -1, -1, 0, 0, 0, 1, 2, + -2, -2, -1, -1, 0, 1, 3, 4, -2, -3, -2, -1, 0, 2, 4, 5, + 2, 1, -2, -2, -1, 0, 1, 0, 1, 0, -3, -3, -1, 0, 1, 0, + 0, -1, -3, -3, -1, 1, 1, 1, 0, 0, -3, -1, 1, 2, 3, 3, + 0, -1, -3, -1, 1, 3, 3, 3, -2, -2, -4, -2, 1, 3, 4, 4, + -3, -3, -4, -2, 1, 3, 3, 4, -2, -3, -5, -2, 1, 2, 3, 3, + 4, 5, 3, 4, 4, 4, 4, 5, 3, 3, 1, 0, 0, 0, 0, 1, + 1, 1, -1, -2, -3, -4, -3, -2, 2, 2, 0, -2, -2, -4, -3, -2, + 2, 3, 1, -1, -1, -3, -3, -2, 1, 2, 0, 0, -1, -2, -2, -1, + 0, 1, 0, -1, -1, -3, -2, -1, 1, 1, 0, -1, -1, -2, -2, -2, + -2, -1, -1, 0, 1, 2, 1, 0, 1, 2, 3, 5, 6, 5, 5, 3, + 1, 2, 3, 4, 5, 5, 4, 3, -2, -2, -3, -3, -2, -1, 0, 0, + -3, -3, -4, -5, -4, -3, -2, -1, -1, -1, -2, -2, -2, -1, 0, 0, + 0, 1, 0, -1, -1, 0, 0, 1, -1, 0, -1, -2, -3, -2, -2, -1, + 7, 7, 6, 5, 4, 2, -1, -2, 3, 3, 2, 2, 1, 0, -2, -3, + 0, -1, -1, -1, 0, -1, -2, -2, -1, -3, -2, -1, 0, 0, 0, 1, + 0, -2, -2, -1, -1, 1, 2, 2, 3, 1, -1, -1, -1, 1, 2, 2, + 3, 1, -2, -3, -2, -1, 1, 2, 1, -2, -5, -6, -5, -3, -2, 0, + 0, -1, -2, -3, -1, 0, -2, -2, 0, 0, -1, -1, 0, 1, -1, -2, + 0, 0, -2, -1, 0, 0, 0, -2, -1, -2, -3, -3, -2, -1, -3, -3, + -1, -2, -3, -3, -2, -2, -3, -4, 2, 2, 0, 0, 0, 0, -1, -2, + 5, 5, 3, 2, 2, 2, 0, -1, 8, 8, 6, 5, 4, 4, 2, 1, + -7, -8, -6, -3, -1, -1, -2, -1, -5, -5, -3, 0, 2, 1, 0, 0, + -1, -1, 0, 3, 4, 3, 1, 1, 2, 1, 1, 3, 4, 3, 2, 2, + 3, 2, 0, 2, 3, 2, 1, 2, 4, 2, -1, -1, 0, 1, 1, 1, + 3, 2, -2, -3, -2, -1, 0, 1, 3, 1, -3, -4, -3, -2, 0, 1, + -4, -2, -1, 2, 3, 3, 1, 0, -7, -5, -4, -2, 0, 0, -1, -2, + -6, -5, -5, -4, -2, -2, -2, -3, -1, 0, -1, -1, 0, 0, 0, -1, + 2, 3, 2, 2, 2, 2, 1, 0, 3, 5, 4, 3, 1, 0, 1, 0, + 3, 4, 3, 2, 0, -1, -1, -1, 5, 5, 3, 1, 0, -1, -1, -1, + 1, 1, 0, -1, -3, -5, -6, -4, 1, 1, 0, 0, 0, -3, -3, -1, + 0, -1, -1, 0, 1, 0, 1, 3, -2, -2, -3, -1, 2, 2, 4, 7, + -2, -2, -2, 0, 2, 2, 3, 6, -1, 0, 0, 1, 1, 0, 0, 3, + 0, 3, 3, 3, 1, -2, -3, -1, 1, 3, 4, 3, 0, -3, -5, -4, + 0, 2, 0, -1, -3, -4, -2, -2, 1, 4, 2, 0, -2, -3, -2, -1, + 3, 6, 3, 1, -2, -2, 0, -1, 4, 7, 4, 1, -2, -3, -1, 0, + 3, 6, 3, 0, -3, -3, -1, 0, 1, 3, 0, -1, -3, -2, 1, 1, + 0, 1, -1, -2, -3, -1, 2, 2, -2, -1, -3, -3, -3, -1, 1, 2, + 3, 1, -1, 0, 1, 0, 0, 0, 2, -1, -2, -1, 1, 0, -1, -1, + 1, -1, -2, 0, 1, 0, -2, -3, 0, -2, -1, 1, 3, 1, -3, -5, + 0, -2, -1, 2, 5, 2, -3, -5, 0, -2, -1, 4, 6, 3, -2, -5, + 0, -2, 0, 4, 7, 4, -2, -4, 0, -2, 0, 4, 6, 4, -2, -4, + -2, -2, -3, -4, -3, -2, -1, 0, 1, 1, 0, -1, -1, -1, 0, 1, + 3, 3, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, 1, 0, 0, 1, + 0, 0, 0, 0, -1, -1, -1, -1, -4, -4, -4, -4, -4, -4, -4, -3, + -3, -3, -2, -3, -2, -1, -1, 0, 3, 4, 4, 5, 5, 6, 6, 7, + -1, -2, 7, -2, -4, -1, -1, 0, -1, -2, 9, -1, -4, -1, -1, 0, + -1, -3, 10, -1, -4, -1, -1, 1, -1, -3, 10, -2, -3, -1, -1, 2, + -1, -2, 10, -2, -4, -1, -1, 2, -1, -2, 9, -2, -4, -1, -1, 2, + -1, -2, 8, -2, -4, 0, -1, 1, 0, -2, 7, -2, -3, -1, 0, 2, + 3, -4, 1, 3, -3, -2, 1, 0, 3, -5, 1, 4, -3, -2, 1, 0, + 3, -6, 2, 5, -3, -1, 3, 0, 3, -6, 2, 5, -3, -1, 2, 0, + 3, -6, 1, 5, -4, -2, 3, 0, 3, -6, 1, 5, -3, -2, 2, 0, + 2, -6, 1, 4, -3, -1, 1, 0, 2, -6, 1, 4, -2, -1, 1, 0, + 0, 0, 1, 1, 1, 0, 0, 2, 0, -1, 1, 1, 1, 0, 0, 2, + 0, -1, 0, 0, 0, 0, 0, 2, 0, -1, 0, 0, 0, 0, -1, 0, + 1, 0, 1, 0, 0, -1, -2, -1, 3, 1, 1, 0, 0, -2, -4, -3, + 5, 3, 2, 1, 0, -3, -5, -4, 5, 4, 2, 0, -1, -4, -5, -5, + 1, 0, -1, -2, -2, -3, -6, -9, 2, 0, -1, -1, 0, 0, -3, -6, + 1, 0, 0, -1, 0, 0, -2, -5, 2, 1, 1, 1, 1, 2, -1, -3, + 1, 1, 2, 1, 2, 2, 1, -1, 1, 1, 2, 1, 1, 1, 1, 1, + 0, 0, 2, 1, 0, 0, 2, 2, 0, 1, 2, 2, 0, 0, 2, 2, + -4, -3, 0, 1, 4, 6, 4, 3, -3, -2, 0, 0, 2, 4, 1, 0, + -1, -1, 0, 0, 1, 1, -2, -3, 1, 1, 1, 0, 1, 1, -3, -5, + 1, 1, 1, 0, 1, 1, -3, -5, -1, 0, 0, -1, 1, 1, -2, -4, + -1, 0, 0, -1, 1, 2, 0, -2, -1, 0, 0, 0, 2, 3, 1, 0, + -1, 0, 3, 4, 0, -4, -5, -5, 0, 0, 4, 5, 2, -2, -3, -2, + 0, -1, 2, 4, 2, -1, -1, 0, 0, -2, -1, 1, 0, -2, 0, 1, + 1, -2, -2, 0, 0, -1, -1, 1, 1, -2, -3, 0, 1, 0, -1, 0, + 1, -2, -2, 1, 3, 1, 0, 0, 1, -2, -1, 2, 4, 2, 0, 0, + 1, 2, 3, 2, 0, 2, 2, 1, -1, 0, 1, 0, -3, 1, 1, 1, + -1, 0, 0, -2, -4, 0, 2, 1, -1, 2, 2, -1, -5, 0, 2, 1, + -1, 3, 4, -1, -5, 0, 2, 1, -2, 2, 4, 0, -4, -1, 0, 0, + -4, 0, 2, 0, -4, -2, 0, 0, -5, -1, 2, 1, -2, 1, 3, 2, + 1, 0, 1, 0, 1, 2, -1, -2, 2, 0, -1, -2, 1, 3, 0, -1, + 3, 0, -2, -4, 0, 3, 1, 0, 5, 1, -3, -5, -2, 2, 1, 1, + 6, 1, -2, -5, -2, 1, 0, 1, 5, 1, -1, -5, -2, 0, -1, 0, + 3, 0, -2, -4, -2, 0, -1, 0, 1, -1, 0, -2, 0, 1, 0, 1, + 1, 1, 2, 3, 2, 1, 1, 2, -1, -1, 0, 1, 1, 0, 1, 1, + -4, -3, 0, 0, 1, 1, 1, 2, -4, -3, 0, 2, 2, 2, 3, 2, + -5, -4, 0, 1, 1, 1, 1, 2, -5, -4, -1, -1, -2, -2, -1, 0, + -3, -2, 0, 0, -2, -3, -2, -1, 2, 3, 4, 4, 2, 0, 0, 0, + -4, -2, 0, 1, 0, 0, 0, 0, -3, -1, 1, 1, 0, 0, 0, 0, + -2, 0, 2, 2, 0, 0, 0, 2, -1, 1, 2, 1, -1, 0, 3, 5, + 0, 2, 1, -1, -2, 0, 5, 6, 0, 1, 0, -3, -3, 0, 4, 6, + 1, 1, -2, -4, -4, -3, 1, 2, 1, 0, -2, -4, -5, -4, -2, 0, + -1, -3, -3, -3, -3, -2, -1, -1, 3, 2, 1, 0, 0, 1, 1, 1, + 5, 4, 3, 2, 1, 1, 2, 2, 2, 1, 0, -2, -2, -2, -1, -1, + 0, 0, 0, -1, -2, -2, -2, -2, 0, 1, 3, 3, 2, 1, -1, -1, + 0, 1, 3, 4, 3, 2, 1, -1, -4, -3, -1, 1, 0, -2, -3, -3, + -3, -4, -7, -8, -7, -4, -1, 2, 0, -1, -3, -4, -4, -2, 0, 2, + 1, 0, 0, -1, -3, -2, 0, 2, 2, 1, 1, 0, -1, -1, 0, 2, + 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 1, 2, 3, 3, 2, 2, 0, 0, 1, 3, 4, 4, 3, 2, + 3, 3, 3, 0, -1, 0, 1, 2, 1, 1, 1, -1, -2, -1, -1, 1, + -2, -2, -1, -3, -3, -2, -2, 0, -4, -4, -2, -2, -2, -2, -3, 0, + -4, -4, -1, 1, 1, 0, -1, 2, -3, -1, 2, 3, 4, 3, 3, 5, + -2, 0, 2, 3, 3, 3, 3, 3, -2, -2, 0, 0, 0, 0, 0, 1, + 0, 2, 1, -1, -3, -1, 3, -2, -1, 0, -1, -1, -3, 0, 4, -2, + -2, -2, -2, -2, -2, 1, 5, -2, -3, -2, -3, -1, -2, 1, 4, -3, + -2, 0, -1, 0, -1, 0, 3, -5, 1, 2, 1, 2, 0, 0, 2, -5, + 2, 4, 2, 3, 1, 1, 3, -3, 1, 2, 1, 1, 0, 1, 4, -2, + 4, -3, -4, -1, 3, 3, 1, 3, 4, -4, -4, -1, 3, 2, 0, 2, + 4, -3, -4, 0, 2, 2, -1, 1, 4, -3, -2, 1, 2, 1, -2, 0, + 2, -4, -2, 1, 2, 0, -3, 0, 2, -3, -2, 0, 1, 0, -2, 2, + 3, -1, -1, 0, 0, 0, 0, 3, 2, -2, -2, -2, -1, -1, -1, 2, + 2, 2, 3, 4, 3, 1, 0, -1, 1, 0, 1, 2, 1, -1, -2, -2, + 2, 1, 2, 1, 1, 0, -1, -1, 4, 3, 4, 3, 2, 1, 1, 1, + 3, 2, 2, 2, 1, 1, 1, 1, -1, -2, -1, 0, -1, -1, -1, -1, + -3, -3, -2, -1, -2, -2, -2, -2, -4, -4, -3, -3, -4, -4, -3, -3, + 2, 1, -1, -3, -4, -2, 3, 4, 2, 2, 1, -1, -3, -2, 1, 2, + 1, 2, 3, 3, 0, -2, -1, -2, -1, 0, 2, 4, 2, 0, -1, -3, + -2, -2, 0, 3, 3, 2, 0, -3, 0, -2, -3, -1, 1, 2, 2, -1, + 3, -1, -4, -5, -3, 0, 2, 0, 6, 3, -2, -6, -5, 0, 3, 1, + -2, 3, -2, 0, 3, -2, -2, 1, -3, 4, -3, 0, 3, -2, -1, 2, + -3, 5, -3, 0, 4, -2, -1, 2, -2, 4, -4, -1, 3, -3, -2, 2, + -3, 4, -3, 0, 3, -3, -1, 2, -2, 5, -2, 0, 3, -3, -1, 2, + -2, 4, -3, 1, 3, -2, -1, 2, -2, 3, -2, 1, 3, -2, 0, 2, + 1, 0, 0, -1, 1, 2, -4, -1, 2, 0, 0, -1, 1, 2, -4, -2, + 1, 1, 1, -1, 2, 4, -2, 0, 0, -1, 1, -1, 2, 5, -1, 1, + 0, -1, 0, -2, 1, 5, -1, 1, 0, -1, -1, -2, 0, 3, -3, -1, + 1, 1, 0, -2, 0, 3, -3, -1, 1, 1, 0, -3, 0, 3, -2, 0, + 1, 0, -1, 1, 1, 2, 4, 5, 1, 0, -1, 1, 1, 1, 5, 7, + 0, 0, -2, -1, -1, 0, 3, 5, 0, -1, -2, -1, -1, -1, 2, 3, + 0, -1, -3, -1, -1, -1, 1, 2, -1, -2, -4, -2, -2, -2, 0, 0, + -1, -2, -2, -1, -2, -2, 0, 0, 0, -1, -1, 0, -1, -1, 0, 0, + 3, 3, 0, -1, -1, 1, 4, 4, 2, 3, 0, -2, -2, 0, 1, 1, + 2, 3, 1, -1, -1, 0, 1, 0, 1, 2, 0, -1, -1, -1, 0, -2, + 0, 1, 0, -1, -2, -1, 0, -2, 0, 1, 0, -1, -2, -1, 1, 0, + 1, 1, -1, -3, -4, -3, 1, 3, 1, 2, -1, -3, -5, -4, 1, 3, + -3, -2, 0, 1, 1, 1, 0, -2, 0, 1, 1, 1, 0, 0, -1, -3, + 1, 2, 1, 1, 0, -1, -1, -2, 0, -1, -3, -1, -1, -1, 0, -1, + 0, -3, -6, -3, -2, -1, 1, 1, 2, -1, -4, -3, -2, 0, 2, 2, + 5, 4, 1, 1, 0, 1, 3, 2, 5, 4, 2, 1, 0, -1, 0, 1, + -2, 0, -2, -5, -6, -3, 0, 0, -2, 0, 1, 0, -1, 1, 2, 2, + -2, 0, 1, 3, 2, 2, 2, 1, -2, 0, 2, 4, 3, 2, 1, 1, + -2, 0, 2, 3, 2, 0, -1, 0, -3, -1, 1, 1, 0, -1, -1, 1, + -4, -1, 1, 0, -1, -2, 0, 2, -4, -1, 0, -1, -1, -2, 1, 4, + -3, 0, 0, -1, 1, 1, 1, 0, -3, 1, 0, -1, 0, 0, -1, -1, + -1, 3, 3, 0, 1, 0, 0, 1, -3, 2, 2, -2, -1, 0, 0, 1, + -5, 0, 0, -2, -1, 1, 0, 2, -7, -2, 1, 0, 1, 2, 2, 2, + -5, 0, 3, 2, 3, 3, 2, 2, -3, 2, 4, 1, 0, 0, -2, -3, + 5, 2, -2, -2, 0, -1, -1, -1, 2, -1, -4, -3, -1, -2, -1, -1, + 0, -2, -2, 1, 2, -1, 0, 1, -1, -2, -1, 3, 3, -1, 0, 2, + 1, 0, 0, 3, 3, -2, -1, 2, 2, 1, 1, 3, 2, -2, -2, 0, + 1, 0, -1, 1, 1, -3, -3, -2, 1, 0, 1, 2, 3, 0, 0, 0, + -4, -5, -3, 0, 1, -1, -2, -1, -2, -3, -1, 1, 2, 0, 0, 0, + 1, 1, 2, 1, 2, 1, 1, 1, 3, 4, 3, 1, 0, -2, -1, -1, + 3, 3, 2, 0, -2, -3, -3, -2, 1, 1, 0, -1, -2, -4, -2, -2, + 2, 1, 0, 0, 0, -1, 0, 1, 2, 1, 1, 1, 1, 1, 1, 3, + 0, 0, 0, -1, -2, -1, 1, 0, -2, -1, -1, -2, -3, -2, 0, 0, + -1, 0, 0, -1, -2, 0, 1, 1, 1, 1, 0, -1, -1, 1, 3, 1, + 2, 2, 0, -2, -1, 2, 3, 0, 3, 1, -1, -1, 1, 4, 2, -2, + 2, 0, -3, -1, 3, 5, 0, -5, 1, -1, -2, 0, 3, 3, -1, -6, + -1, 0, 3, 4, 2, 0, 1, 2, -2, -1, 0, 1, -1, -2, 0, 1, + -2, -3, -2, -3, -6, -7, -6, -3, 2, 2, 3, 1, -1, -2, -3, -2, + 2, 2, 3, 1, 0, 0, 0, 0, 2, 1, 1, 0, 1, 1, 0, 1, + 1, 0, 0, 0, 0, 1, 1, 2, 1, 0, -1, 0, 0, 2, 2, 1, + 1, 1, 3, 1, -1, -1, -1, 1, -2, -1, 0, 0, -2, -2, -1, 2, + -2, -2, 1, 1, 1, 0, 1, 3, -2, -2, 0, -1, 0, -1, 0, 2, + 0, 0, 1, 0, -1, -1, -2, 1, 3, 2, 2, 1, 0, -2, -2, 1, + 5, 3, 3, 2, 1, 1, 1, 4, 0, -3, -4, -5, -4, -3, -1, 1, + -6, -4, -1, 2, 2, 0, 0, -1, -4, -2, 1, 3, 3, 2, 2, 0, + -3, -2, -1, 2, 3, 3, 2, 0, -3, -2, -2, 1, 2, 1, 1, -1, + -2, -2, -2, 0, 2, 2, 1, -1, -1, -1, -1, 1, 2, 3, 2, 0, + -1, -1, -2, 1, 2, 2, 2, -1, 0, -1, -2, 0, 2, 1, 0, -1, + 6, 4, 2, 1, 0, 0, 0, 1, 4, 2, -1, -2, -2, -2, -1, -1, + 2, 1, -1, -2, -2, -2, -2, -1, 2, 2, 0, -2, -2, -2, -1, 0, + 0, 0, -1, -2, -2, -1, 0, 1, -3, -3, -2, -1, -1, -2, -1, 0, + -3, -2, 2, 3, 2, 0, -1, -2, -2, 0, 4, 5, 5, 2, 0, -1, + 5, 4, 2, 0, -1, -2, -1, -1, 4, 3, 2, 1, 0, -1, 0, -1, + 1, 1, 0, 1, 1, 0, 1, -1, -2, -1, -1, 0, 0, -2, -2, -3, + -1, 0, 0, 0, -1, -3, -3, -5, 0, 1, 1, -1, -1, -2, -2, -3, + -1, -1, -1, -2, -1, 1, 3, 1, -1, -2, -2, -1, 2, 5, 6, 5, + -3, -3, -2, 1, 1, -2, -1, -1, 1, 2, 3, 4, 1, -3, -1, -3, + 3, 2, 0, 1, -1, -3, -1, -3, 1, 0, -1, 0, -1, -1, 1, 0, + 1, 1, 0, 1, 2, 2, 5, 3, 1, 1, 1, 2, 2, 2, 3, 0, + -3, -1, -2, -2, -3, -3, -1, -3, -1, 1, 1, 0, -1, -1, 0, -2, + 2, 0, -2, -2, 2, 4, 1, -2, 1, 0, -2, -1, 3, 5, 2, -1, + -1, -2, -3, -2, 1, 3, 1, -2, -1, -2, -1, -1, 0, 2, 1, -1, + 0, 0, 1, 1, 1, 2, 2, 0, 0, 1, 4, 4, 2, 2, 3, 1, + -2, -1, 2, 1, -2, -3, -2, -3, -1, 0, 1, 0, -3, -4, -4, -5, + 4, 0, -3, -4, -4, -4, -2, -1, 5, 0, -1, 0, -1, -3, -2, -1, + 4, 0, 0, 1, 1, 0, 0, 0, 0, -3, -2, -1, 0, 0, 1, 0, + 0, -2, 0, 0, 1, 1, 2, 1, 2, 0, 0, 0, 1, 1, 1, 0, + 2, 0, -1, -1, 1, 1, 1, 0, 1, -1, -2, -2, 0, 2, 2, 2, + -3, -5, -2, 0, -1, -3, -3, 0, 0, -2, 0, 2, 2, 0, 0, 3, + 2, -1, -2, 0, 0, -1, -1, 2, 5, 2, -1, -1, -1, -1, -1, 2, + 5, 2, 0, -1, -1, 0, -1, 2, 2, 1, 0, 0, 0, 1, 0, 2, + -1, -1, 1, 1, 2, 2, 1, 2, -3, -2, 0, 0, 0, 0, -2, -1, + 0, 3, 2, 0, -2, -3, -3, -3, 0, 3, 3, 1, 0, 0, 1, 2, + -1, 0, -1, -2, -1, -1, 1, 3, -1, 0, -1, -2, -1, -1, 0, 2, + -1, 0, -1, -2, 0, 0, -1, 2, -1, 0, -1, -2, -1, -1, -2, 1, + 0, 1, 0, -3, -1, -1, -1, 2, 5, 5, 2, -1, -1, -1, 1, 3, + 0, 0, 1, -1, -3, -2, 0, 2, 1, 1, 3, 0, -2, -2, 0, 1, + 1, 1, 3, 1, 0, 0, -1, -1, 0, -1, 2, 1, 1, 0, -1, -3, + -1, -2, 1, 1, 1, 0, -2, -4, -1, 0, 2, 1, 1, 0, -1, -3, + 1, 1, 3, 2, 1, 0, -2, -3, 2, 2, 4, 2, 1, -1, -2, -4, + 1, 2, 2, 2, 0, -2, 0, 2, -1, -1, -2, -3, -4, -5, -3, 1, + 0, 1, 1, 0, -1, -1, -1, 1, 0, 1, 1, 1, 0, 0, 0, 2, + 0, 1, 1, 2, 1, 1, 1, 2, -1, -1, 0, 2, 2, 2, 2, 3, + -2, -4, -4, -1, -2, -2, -2, 0, 1, 0, 0, 1, 0, 0, 0, 1, + 0, -1, -3, -2, 0, 2, 2, 1, 0, -1, -2, -3, 0, 1, 1, 2, + 1, 0, -2, -3, -1, 0, 0, 1, -1, 0, -1, -2, 0, 0, -1, 0, + -1, 1, 1, 0, 2, 2, 0, 0, 0, 2, 3, 1, 3, 5, 3, 2, + -1, 1, 1, -2, 0, 3, 1, 1, -1, 0, 0, -4, -4, -1, -1, -1, + -1, 1, 1, 0, 1, 2, 1, 2, -3, 0, 1, 0, 1, 1, 0, 2, + -5, -3, -1, -1, 0, 1, 0, 1, -4, -3, -2, -3, -2, -1, -1, 0, + 0, 0, -1, -2, -2, -2, -2, 0, 3, 4, 2, 0, 0, 0, 0, 1, + 2, 1, 0, 0, 0, 0, -1, 0, 0, 1, 2, 3, 4, 4, 3, 2, + -1, 4, 7, 4, 0, 0, 0, 0, -1, 4, 6, 3, 0, 1, 1, 1, + 0, 3, 4, 0, -1, 0, 0, 1, 0, 1, 1, -2, -1, 0, -1, -1, + -1, 0, -1, -1, -1, 0, 0, 0, -1, -1, -1, 0, 0, 0, 0, 0, + -1, -3, -3, 0, 1, -1, -2, -1, -3, -4, -4, -2, -1, -2, -2, -1, + 2, 2, 1, 0, 1, 1, 0, -3, -2, -1, 0, 0, 1, 1, 0, -3, + -2, -1, 0, 1, 2, 1, 1, -2, 1, 2, 2, 2, 3, 3, 2, -1, + 1, 2, 1, 0, 1, 1, 2, -1, 0, 1, -2, -4, -2, 0, 1, -1, + 1, 1, -1, -3, -2, 0, -1, -3, 1, 2, 0, -1, 0, 1, -1, -4, + -1, -1, -2, -2, 0, 3, 4, 3, 1, 1, -1, -3, -2, 0, 0, 0, + 2, 2, 2, 2, 2, 1, -1, -1, 1, 1, 1, 3, 3, 0, -2, -2, + 0, -1, -1, -1, 0, -2, -1, -1, -1, -3, -4, -3, -2, -2, 0, 2, + -1, -1, 0, 1, 2, 2, 3, 5, -2, -1, -1, 0, 0, 0, 0, 1, + -2, -3, 2, 0, 0, 1, 1, -1, -1, -4, 1, -2, -1, 2, 2, 0, + 1, -4, 0, -2, -2, 1, 1, -1, 2, -3, 1, -1, -1, 1, 1, -1, + 3, -2, 3, 1, 0, 1, 1, -1, 1, -3, 2, 1, 0, 1, 0, -1, + -1, -5, 1, 0, -1, 0, 1, 1, 0, -3, 3, 3, 1, 2, 3, 3, + 0, -1, -2, 1, 5, 5, 2, -1, 1, -1, -2, -1, 1, 1, -2, -5, + 1, 1, -1, -2, -1, -1, -1, -3, 1, 1, -1, -1, -1, 2, 4, 3, + -1, -1, -1, -1, -1, 0, 4, 3, -1, -1, 0, 1, -1, -3, -1, -1, + 0, 0, 0, 2, 2, 0, 0, -1, 0, -2, -3, 0, 1, 1, 3, 2, + 2, 3, 2, 1, 0, 0, -2, -2, 2, 3, 0, 1, 1, 3, 3, 2, + 0, 0, -3, -1, -1, 2, 2, 3, -2, -2, -3, 1, 1, 2, 1, 1, + -2, -1, -2, 2, 1, 1, -1, -2, 0, 1, 0, 2, 0, 0, -2, -2, + 0, 1, 0, 2, 0, 0, -2, -2, -3, -2, -2, 0, -1, -2, -2, -3, + 0, 1, -1, 3, -1, 1, 3, -1, 0, 1, -1, 3, -1, -1, 2, -3, + 1, 1, -2, 3, -1, -3, 0, -3, 2, 2, -2, 3, 0, -2, 1, -2, + 1, 1, -3, 3, -1, -2, 1, -3, 1, 1, -3, 3, 0, -1, 1, -2, + 1, 2, -1, 4, 0, -1, 1, -2, 0, 1, -1, 3, -1, -3, 0, -3, + -3, -3, -1, 1, 2, 1, -1, -2, -2, -2, 0, 2, 1, 0, -2, -2, + -3, -2, 1, 2, 1, -1, -2, -1, -3, -2, 2, 4, 0, -2, -2, 1, + -3, -1, 2, 4, 0, -2, -2, 2, -1, 1, 4, 3, -1, -3, -2, 2, + 0, 2, 4, 2, -1, -2, -1, 2, 0, 1, 2, 0, -1, 0, 1, 3, + 3, 0, -5, 1, 4, 0, 0, 1, 1, -2, -5, 2, 5, -1, -2, 1, + -1, 0, 0, 3, 3, 1, 0, -1, -2, 3, 4, -2, -3, -1, 0, -2, + -3, 3, 5, -3, -3, 0, 0, -2, -1, 3, 2, -2, -2, 2, 2, -1, + 2, 0, 0, -1, 0, 0, 0, 0, 0, -3, -2, 1, 3, 0, -2, -2 }; -const uint32 *const s_svq1InterCodebooks[6] = { +static const int8 *const s_svq1InterCodebooks[6] = { s_svq1InterCodebook4x2, s_svq1InterCodebook4x4, s_svq1InterCodebook8x4, s_svq1InterCodebook8x8, 0, 0 }; -static const uint32 s_svq1IntraCodebook4x2[192] = { - 0x0b0d0d0c, 0xeff1f6f9, 0xf6f4f1f0, 0x0c0f0f0b, - 0x0f141102, 0x0d02e8d3, 0xdcfa1415, 0xe5ff100c, - 0x2d0aebee, 0x15f9ecf5, 0x00e4f82b, 0x03e4f021, - 0xfaeeeef4, 0x371cf6ec, 0xeeebeefb, 0xecfa1e38, - 0xea1d1bde, 0xe71a1de2, 0x1a21221e, 0xdfdde1e7, - 0xe0dcdde1, 0x1f25241d, 0x2226f4b9, 0x212affc1, - 0xc4e1253a, 0xc3df2237, 0x5d16c7c7, 0x5d15c6c7, - 0x3e46453b, 0xc4bcbcc1, 0xc0b9b9c0, 0x3e48493f, - 0x0f0700fe, 0x05fdf6f5, 0xf6f6f8fb, 0x090e0901, - 0xf5fc080f, 0xf4f5020c, 0x1c1300f8, 0xe6f1ff04, - 0xf2021bf1, 0xf70116f2, 0xf6f3fafc, 0x2f06f2fa, - 0x1706ecdd, 0x04060906, 0xea1702fa, 0xeb1c04f9, - 0x06feea14, 0x08fbe416, 0xf4f0eef6, 0xff021324, - 0x080400fd, 0x1717f6d3, 0xddec0f28, 0x0104fffc, - 0x18dffb09, 0x13e60308, 0xfd0604ff, 0xcff31920, - 0x070f1818, 0xf9ede5ef, 0x182700d1, 0x0407faeb, - 0xf3f600ff, 0x10050101, 0xf7fd0514, 0xfafefcff, - 0x0401f9ef, 0x0000070c, 0x0b0c0003, 0xe90001fd, - 0x00fa1104, 0x00e70306, 0x05080aef, 0x040104f2, - 0x02040a0d, 0x0201f7e9, 0x0701fd03, 0x14f9e901, - 0x0c02eef9, 0x090afcfb, 0xe8070a04, 0xf6040306, - 0x06eaf216, 0xff050500, 0xfcf503fc, 0xf2071ff9, - 0x2afff0fb, 0xfbf7fefc, 0xfdfaf805, 0xfbebfc2a, - 0xf4140cee, 0x07f6f30d, 0xeefef7f8, 0x082806f0, - 0x0400ff0a, 0xf3ff04fd, 0xf10106fe, 0x02010305, - 0x0301fefc, 0xfcf7000f, 0xfcfcfcfd, 0xfd1005fd, - 0x04030d02, 0x00f6f8fd, 0xfffcfefa, 0x17fafdfe, - 0x0107fa06, 0x0105ee04, 0x0ef101ff, 0x04fc06fb, - 0x06020202, 0x030702e8, 0x030300e6, 0x06010705, - 0xfdeefe0e, 0x02fc0507, 0x012003fa, 0xf4fafafa, - 0x0607dc05, 0x000bff09, 0x03050404, 0xda030f04, - 0xd6fb170a, 0x04040400, 0xf3fa1117, 0x1d01dbf3, - 0x01fff205, 0x01030005, 0x02fb0400, 0xf6000008, - 0xfdfe0704, 0x010103f6, 0x030dfff4, 0xfd01ff00, - 0x0103ff00, 0x0903f7fa, 0xfafc01fa, 0x0800ff08, - 0x1200fdfd, 0xfffcfffb, 0xfc03fef8, 0xfbff1100, - 0xf609fe05, 0xfb06fb01, 0x03020204, 0x01f8f20a, - 0xffeefeff, 0x020114ff, 0x01f701ff, 0xfc16f7ff, - 0xfd08fc06, 0x05ed07ff, 0xfcfc1ff9, 0xfbfb00fa, - 0xfcedf8f9, 0x20040101, 0x04f8ff26, 0xf4faf8f9, - 0x01f900ff, 0x00ff09ff, 0x00ffff09, 0xfd01fa02, - 0x010200f4, 0x00080101, 0x02000109, 0x00f501fe, - 0xf6020800, 0x00ff02ff, 0xfb00fcfe, 0x0efffffe, - 0x05ff07fd, 0x0101f600, 0xff0efbff, 0xfefd01fe, - 0x060000fa, 0x04f70302, 0xfffffb04, 0xff0803f9, - 0xf5fffc02, 0x0001020b, 0x090302ff, 0xf1000200, - 0x03ec0503, 0x0303ff03, 0x0110ff01, 0x0209e302, - 0xfdfffaf3, 0xfdf8ff24, 0x02040502, 0x030b09db +static const int8 s_svq1IntraCodebook4x2[768] = { + 12, 13, 13, 11, -7,-10,-15,-17,-16,-15,-12,-10, 11, 15, 15, 12, + 2, 17, 20, 15,-45,-24, 2, 13, 21, 20, -6,-36, 12, 16, -1,-27, + -18,-21, 10, 45,-11,-20, -7, 21, 43, -8,-28, 0, 33,-16,-28, 3, + -12,-18,-18, -6,-20,-10, 28, 55, -5,-18,-21,-18, 56, 30, -6,-20, + -34, 27, 29,-22,-30, 29, 26,-25, 30, 34, 33, 26,-25,-31,-35,-33, + -31,-35,-36,-32, 29, 36, 37, 31,-71,-12, 38, 34,-63, -1, 42, 33, + 58, 37,-31,-60, 55, 34,-33,-61,-57,-57, 22, 93,-57,-58, 21, 93, + 59, 69, 70, 62,-63,-68,-68,-60,-64,-71,-71,-64, 63, 73, 72, 62, + -2, 0, 7, 15,-11,-10, -3, 5, -5, -8,-10,-10, 1, 9, 14, 9, + 15, 8, -4,-11, 12, 2,-11,-12, -8, 0, 19, 28, 4, -1,-15,-26, + -15, 27, 2,-14,-14, 22, 1, -9, -4, -6,-13,-10, -6,-14, 6, 47, + -35,-20, 6, 23, 6, 9, 6, 4, -6, 2, 23,-22, -7, 4, 28,-21, + 20,-22, -2, 6, 22,-28, -5, 8,-10,-18,-16,-12, 36, 19, 2, -1, + -3, 0, 4, 8,-45,-10, 23, 23, 40, 15,-20,-35, -4, -1, 4, 1, + 9, -5,-33, 24, 8, 3,-26, 19, -1, 4, 6, -3, 32, 25,-13,-49, + 24, 24, 15, 7,-17,-27,-19, -7,-47, 0, 39, 24,-21, -6, 7, 4, + -1, 0,-10,-13, 1, 1, 5, 16, 20, 5, -3, -9, -1, -4, -2, -6, + -17, -7, 1, 4, 12, 7, 0, 0, 3, 0, 12, 11, -3, 1, 0,-23, + 4, 17, -6, 0, 6, 3,-25, 0,-17, 10, 8, 5,-14, 4, 1, 4, + 13, 10, 4, 2,-23, -9, 1, 2, 3, -3, 1, 7, 1,-23, -7, 20, + -7,-18, 2, 12, -5, -4, 10, 9, 4, 10, 7,-24, 6, 3, 4,-10, + 22,-14,-22, 6, 0, 5, 5, -1, -4, 3,-11, -4, -7, 31, 7,-14, + -5,-16, -1, 42, -4, -2, -9, -5, 5, -8, -6, -3, 42, -4,-21, -5, + -18, 12, 20,-12, 13,-13,-10, 7, -8, -9, -2,-18,-16, 6, 40, 8, + 10, -1, 0, 4, -3, 4, -1,-13, -2, 6, 1,-15, 5, 3, 1, 2, + -4, -2, 1, 3, 15, 0, -9, -4, -3, -4, -4, -4, -3, 5, 16, -3, + 2, 13, 3, 4, -3, -8,-10, 0, -6, -2, -4, -1, -2, -3, -6, 23, + 6, -6, 7, 1, 4,-18, 5, 1, -1, 1,-15, 14, -5, 6, -4, 4, + 2, 2, 2, 6,-24, 2, 7, 3,-26, 0, 3, 3, 5, 7, 1, 6, + 14, -2,-18, -3, 7, 5, -4, 2, -6, 3, 32, 1, -6, -6, -6,-12, + 5,-36, 7, 6, 9, -1, 11, 0, 4, 4, 5, 3, 4, 15, 3,-38, + 10, 23, -5,-42, 0, 4, 4, 4, 23, 17, -6,-13,-13,-37, 1, 29, + 5,-14, -1, 1, 5, 0, 3, 1, 0, 4, -5, 2, 8, 0, 0,-10, + 4, 7, -2, -3,-10, 3, 1, 1,-12, -1, 13, 3, 0, -1, 1, -3, + 0, -1, 3, 1, -6, -9, 3, 9, -6, 1, -4, -6, 8, -1, 0, 8, + -3, -3, 0, 18, -5, -1, -4, -1, -8, -2, 3, -4, 0, 17, -1, -5, + 5, -2, 9,-10, 1, -5, 6, -5, 4, 2, 2, 3, 10,-14, -8, 1, + -1, -2,-18, -1, -1, 20, 1, 2, -1, 1, -9, 1, -1, -9, 22, -4, + 6, -4, 8, -3, -1, 7,-19, 5, -7, 31, -4, -4, -6, 0, -5, -5, + -7, -8,-19, -4, 1, 1, 4, 32, 38, -1, -8, 4, -7, -8, -6,-12, + -1, 0, -7, 1, -1, 9, -1, 0, 9, -1, -1, 0, 2, -6, 1, -3, + -12, 0, 2, 1, 1, 1, 8, 0, 9, 1, 0, 2, -2, 1,-11, 0, + 0, 8, 2,-10, -1, 2, -1, 0, -2, -4, 0, -5, -2, -1, -1, 14, + -3, 7, -1, 5, 0,-10, 1, 1, -1, -5, 14, -1, -2, 1, -3, -2, + -6, 0, 0, 6, 2, 3, -9, 4, 4, -5, -1, -1, -7, 3, 8, -1, + 2, -4, -1,-11, 11, 2, 1, 0, -1, 2, 3, 9, 0, 2, 0,-15, + 3, 5,-20, 3, 3, -1, 3, 3, 1, -1, 16, 1, 2,-29, 9, 2, + -13, -6, -1, -3, 36, -1, -8, -3, 2, 5, 4, 2,-37, 9, 11, 3 }; -static const uint32 s_svq1IntraCodebook4x4[384] = { - 0x0603fdf5, 0x0705fff6, 0x0706fff7, 0x0604fff7, - 0xf2000705, 0xf1020906, 0xf1020906, 0xf2000604, - 0xfafb0310, 0xf8f80110, 0xf7f7ff0e, 0xf8f8000c, - 0x11100c08, 0x090602fe, 0x00fcf8f6, 0xf9f5f2f1, - 0x10fef6f9, 0x12fdf5f9, 0x14fff5f9, 0x1301f8fa, - 0xeff0f3f7, 0xf7f9fe02, 0xff04080b, 0x070b0f10, - 0x0f0dfeea, 0x100efee8, 0x0f0dfce7, 0x0d0afae7, - 0x10161a1a, 0x03090f11, 0xf2f5fafe, 0xe4e4e7ec, - 0xebe7e5e5, 0xf9f5f1f0, 0x0d0c0803, 0x1e1f1c17, - 0xdff91014, 0xddfa1316, 0xdefa1316, 0xe0fa1114, - 0x2602ecec, 0x2802eaeb, 0x2802eaeb, 0x2603ecec, - 0x1a18fcd1, 0x1b1afdce, 0x1b1afdce, 0x1a18fcd1, - 0xe5e9062d, 0xe4e70530, 0xe4e60530, 0xe5e8062c, - 0x4cf6dce2, 0x4ef5dbe1, 0x4ef5dbe1, 0x4df6dce1, - 0x3423e0cb, 0x3424deca, 0x3424deca, 0x3322dfcb, - 0x413edea3, 0x423edea3, 0x413edea3, 0x403cdea3, - 0x020200f9, 0x0303fff8, 0x050400f8, 0x050501fa, - 0x0b0b0703, 0x03030202, 0xf9fafe01, 0xf3f5fb01, - 0xfdfcfe03, 0xfbfb0007, 0xf9fb040c, 0xf9fc060e, - 0xfe030e12, 0xfd000406, 0x00fefbf8, 0x02fef5f0, - 0x1207faf8, 0x0d02f8f9, 0x06fefafc, 0x01fdfc00, - 0xeef3fd01, 0xf9fbff00, 0x070601ff, 0x110f04fe, - 0xfef9f2f1, 0x00fffbfa, 0x01030606, 0x01060d0f, - 0x0af5fe02, 0x0bf4ff02, 0x0bf4ff03, 0x0bf5fe02, - 0xfbff0ef7, 0xfbfe0ff7, 0xfbfe10f8, 0xfcff0ff9, - 0x08080602, 0x0c0903fe, 0x0a04fbf5, 0x00f8f0ed, - 0xf1f9080e, 0xf2f9070c, 0xf7fc0508, 0xfcff0305, - 0x02fef20c, 0x03fff10d, 0x03fff10e, 0x03fff20d, - 0xf30a0600, 0xf10a0600, 0xef090700, 0xf0080601, - 0xfe0ffbf8, 0xfe11faf8, 0xfd10faf8, 0xfe0ffbf8, - 0xf6f5f5f7, 0x08090a09, 0x090a0a08, 0xf9f8f7f8, - 0x07090a09, 0xf6f6f6f8, 0xf5f5f6f9, 0x080b0c0b, - 0x00070a00, 0xfa000700, 0xfafb0200, 0xfffcfffe, - 0xf7fa0005, 0x01020202, 0x070500fe, 0x0401fbfa, - 0xff02f803, 0x0003f704, 0x0003f905, 0x0003fb07, - 0x0902fdfb, 0x0801fdfa, 0x0701fdfa, 0x0400fefb, - 0x0103080d, 0xfffcfbfd, 0x00fdf9f8, 0x020301ff, - 0xf4fb0203, 0xf7fe0304, 0xfc010403, 0xff040503, - 0x00fcf8f7, 0x00020608, 0x0003080a, 0xfffdfbfa, - 0xfbf4f7fd, 0x00fbfd00, 0x04020302, 0x06070805, - 0x0c05feff, 0x0905ffff, 0xfeff0102, 0xeff5ff02, - 0xff0303f9, 0xff0403f7, 0xff0604f6, 0x000705f7, - 0x0202f9ee, 0x030501f8, 0x00010403, 0xfdfe0509, - 0x080600fe, 0xfdfbfbfc, 0xf8fafe01, 0xff03090a, - 0x00fefe00, 0x00fbfc00, 0x08fcf8fe, 0x1806f9fb, - 0x01f90109, 0x01f80109, 0x01f60008, 0xfff5ff08, - 0x03060808, 0x02030405, 0x00fffdfe, 0xfcf8f3f6, - 0xfd020400, 0xfb030600, 0xf4020a03, 0xeafc0a05, - 0x03fffc00, 0x05fffc01, 0x0800fb01, 0x07fefaff, - 0xfcfeffff, 0xfafcfeff, 0xfeffffff, 0x090a0501, - 0xfe00030a, 0xfbfeff06, 0xfafeff03, 0xfb000002, - 0x00000306, 0x01010306, 0x01fefe04, 0xfef7f700, - 0x0201fdf5, 0x050402fa, 0x040302fd, 0x020101fe, - 0xfefffcfa, 0xfeffff02, 0xfefe020a, 0xfffc020b, - 0x02fe0006, 0x00000303, 0x000303fa, 0x0005ffef, - 0x0b0a04ff, 0x0100fefd, 0xfdfbfcfd, 0xfffefeff, - 0xf4f7fd02, 0x02030303, 0x04040202, 0xfeff0102, - 0xf60509fe, 0xfb0505fd, 0x000201fe, 0x01fefeff, - 0xfe07fdfe, 0xfd07fdff, 0xfc08feff, 0xfd07fefe, - 0x0cfdf801, 0x04fefe02, 0xfb000301, 0xf90205ff, - 0xfb0103ff, 0x0103fef9, 0x02fef9fe, 0xfffb0314, - 0xfefd0005, 0x0600f9f9, 0x060700fa, 0xf9000602, - 0x01f906fe, 0x03f807fe, 0x03f907fe, 0x02fa07ff, - 0x0705fefb, 0xf8fc0104, 0xfbfe0306, 0x0703fbf9, - 0x0506ffff, 0xfc01ff00, 0xf9000102, 0xfc000001, - 0x010300f8, 0xffff01fe, 0x01fdff01, 0x0901fe01, - 0xfcfd0205, 0xfdff00ff, 0x010301fd, 0x020400fc, - 0x0cfefe02, 0x03fbfe00, 0x01fd00ff, 0x01fefffd, - 0x00030501, 0x01fefcfa, 0x02fefe00, 0xfffc0106, - 0xfffbfbfd, 0x04050503, 0xff010300, 0xfdfe01fe, - 0xfdfbfc02, 0xfefdfe04, 0xffff0006, 0x00000107, - 0x00fefefd, 0xfffbfdfe, 0xff0002fe, 0xff090bff, - 0xf6ff0100, 0xfa0001ff, 0x04010001, 0x0dfffb02, - 0x000504fe, 0x030601fb, 0x0203fefa, 0xfe00fefb, - 0xfe0101ff, 0x0200feff, 0x07050505, 0xf9f8fc00, - 0xfbff0200, 0xfd0202ff, 0xfb030500, 0xf4020803, - 0xfe000408, 0xfffcff0a, 0x00fdfa03, 0x0000fbfc, - 0x02fcf600, 0x0503faff, 0x0406fdff, 0x0204fe00, - 0xff010800, 0xfd010b00, 0xfcfe06ff, 0xfcf9fefd, - 0xffffff00, 0x05060504, 0xfbf8f7fb, 0x02030202, - 0x01060200, 0x00030002, 0xfefffe01, 0xfafdff00, - 0x00020000, 0x01020004, 0x0000fe05, 0x02fff7fe, - 0xf6000100, 0x000801ff, 0x0004feff, 0xff02ff01, - 0xff02fefd, 0xfd02fffd, 0x0001ff00, 0x03ff0108, - 0x02010100, 0x00fefc00, 0xff01fbff, 0x020bfffe, - 0xfefe0501, 0x00fc0200, 0x01fb01fe, 0x01000500, - 0x0600fdfb, 0x000002fc, 0x000105fd, 0x000003fd, - 0x01fdfe03, 0x0800fc01, 0x03fefdfe, 0xffff0201, - 0x02000101, 0x06010002, 0x0102ff01, 0xed000300, - 0x02fefd01, 0xf9fe0506, 0x010301fd, 0x0200ffff, - 0xfcfffff8, 0x02ff0101, 0x03020304, 0x000301fb, - 0x01ff0200, 0x050000fd, 0x0800fefb, 0x06fcfcfc, - 0x02010201, 0x02fd0202, 0x00f70004, 0x01f50007, - 0xfe000000, 0xfaff0303, 0xf6fd0304, 0x020602ff, - 0x05fdfe07, 0xff0300fc, 0xf90102fc, 0x03ffff02, - 0x02020203, 0xfbf9f9fb, 0x02040605, 0x0100fffe +static const int8 s_svq1IntraCodebook4x4[1536] = { + -11, -3, 3, 6,-10, -1, 5, 7, -9, -1, 6, 7, -9, -1, 4, 6, + 5, 7, 0,-14, 6, 9, 2,-15, 6, 9, 2,-15, 4, 6, 0,-14, + 16, 3, -5, -6, 16, 1, -8, -8, 14, -1, -9, -9, 12, 0, -8, -8, + 8, 12, 16, 17, -2, 2, 6, 9,-10, -8, -4, 0,-15,-14,-11, -7, + -7,-10, -2, 16, -7,-11, -3, 18, -7,-11, -1, 20, -6, -8, 1, 19, + -9,-13,-16,-17, 2, -2, -7, -9, 11, 8, 4, -1, 16, 15, 11, 7, + -22, -2, 13, 15,-24, -2, 14, 16,-25, -4, 13, 15,-25, -6, 10, 13, + 26, 26, 22, 16, 17, 15, 9, 3, -2, -6,-11,-14,-20,-25,-28,-28, + -27,-27,-25,-21,-16,-15,-11, -7, 3, 8, 12, 13, 23, 28, 31, 30, + 20, 16, -7,-33, 22, 19, -6,-35, 22, 19, -6,-34, 20, 17, -6,-32, + -20,-20, 2, 38,-21,-22, 2, 40,-21,-22, 2, 40,-20,-20, 3, 38, + -47, -4, 24, 26,-50, -3, 26, 27,-50, -3, 26, 27,-47, -4, 24, 26, + 45, 6,-23,-27, 48, 5,-25,-28, 48, 5,-26,-28, 44, 6,-24,-27, + -30,-36,-10, 76,-31,-37,-11, 78,-31,-37,-11, 78,-31,-36,-10, 77, + -53,-32, 35, 52,-54,-34, 36, 52,-54,-34, 36, 52,-53,-33, 34, 51, + -93,-34, 62, 65,-93,-34, 62, 66,-93,-34, 62, 65,-93,-34, 60, 64, + -7, 0, 2, 2, -8, -1, 3, 3, -8, 0, 4, 5, -6, 1, 5, 5, + 3, 7, 11, 11, 2, 2, 3, 3, 1, -2, -6, -7, 1, -5,-11,-13, + 3, -2, -4, -3, 7, 0, -5, -5, 12, 4, -5, -7, 14, 6, -4, -7, + 18, 14, 3, -2, 6, 4, 0, -3, -8, -5, -2, 0,-16,-11, -2, 2, + -8, -6, 7, 18, -7, -8, 2, 13, -4, -6, -2, 6, 0, -4, -3, 1, + 1, -3,-13,-18, 0, -1, -5, -7, -1, 1, 6, 7, -2, 4, 15, 17, + -15,-14, -7, -2, -6, -5, -1, 0, 6, 6, 3, 1, 15, 13, 6, 1, + 2, -2,-11, 10, 2, -1,-12, 11, 3, -1,-12, 11, 2, -2,-11, 11, + -9, 14, -1, -5, -9, 15, -2, -5, -8, 16, -2, -5, -7, 15, -1, -4, + 2, 6, 8, 8, -2, 3, 9, 12,-11, -5, 4, 10,-19,-16, -8, 0, + 14, 8, -7,-15, 12, 7, -7,-14, 8, 5, -4, -9, 5, 3, -1, -4, + 12,-14, -2, 2, 13,-15, -1, 3, 14,-15, -1, 3, 13,-14, -1, 3, + 0, 6, 10,-13, 0, 6, 10,-15, 0, 7, 9,-17, 1, 6, 8,-16, + -8, -5, 15, -2, -8, -6, 17, -2, -8, -6, 16, -3, -8, -5, 15, -2, + -9,-11,-11,-10, 9, 10, 9, 8, 8, 10, 10, 9, -8, -9, -8, -7, + 9, 10, 9, 7, -8,-10,-10,-10, -7,-10,-11,-11, 11, 12, 11, 8, + 0, 10, 7, 0, 0, 7, 0, -6, 0, 2, -5, -6, -2, -1, -4, -1, + 5, 0, -6, -9, 2, 2, 2, 1, -2, 0, 5, 7, -6, -5, 1, 4, + 3, -8, 2, -1, 4, -9, 3, 0, 5, -7, 3, 0, 7, -5, 3, 0, + -5, -3, 2, 9, -6, -3, 1, 8, -6, -3, 1, 7, -5, -2, 0, 4, + 13, 8, 3, 1, -3, -5, -4, -1, -8, -7, -3, 0, -1, 1, 3, 2, + 3, 2, -5,-12, 4, 3, -2, -9, 3, 4, 1, -4, 3, 5, 4, -1, + -9, -8, -4, 0, 8, 6, 2, 0, 10, 8, 3, 0, -6, -5, -3, -1, + -3, -9,-12, -5, 0, -3, -5, 0, 2, 3, 2, 4, 5, 8, 7, 6, + -1, -2, 5, 12, -1, -1, 5, 9, 2, 1, -1, -2, 2, -1,-11,-17, + -7, 3, 3, -1, -9, 3, 4, -1,-10, 4, 6, -1, -9, 5, 7, 0, + -18, -7, 2, 2, -8, 1, 5, 3, 3, 4, 1, 0, 9, 5, -2, -3, + -2, 0, 6, 8, -4, -5, -5, -3, 1, -2, -6, -8, 10, 9, 3, -1, + 0, -2, -2, 0, 0, -4, -5, 0, -2, -8, -4, 8, -5, -7, 6, 24, + 9, 1, -7, 1, 9, 1, -8, 1, 8, 0,-10, 1, 8, -1,-11, -1, + 8, 8, 6, 3, 5, 4, 3, 2, -2, -3, -1, 0,-10,-13, -8, -4, + 0, 4, 2, -3, 0, 6, 3, -5, 3, 10, 2,-12, 5, 10, -4,-22, + 0, -4, -1, 3, 1, -4, -1, 5, 1, -5, 0, 8, -1, -6, -2, 7, + -1, -1, -2, -4, -1, -2, -4, -6, -1, -1, -1, -2, 1, 5, 10, 9, + 10, 3, 0, -2, 6, -1, -2, -5, 3, -1, -2, -6, 2, 0, 0, -5, + 6, 3, 0, 0, 6, 3, 1, 1, 4, -2, -2, 1, 0, -9, -9, -2, + -11, -3, 1, 2, -6, 2, 4, 5, -3, 2, 3, 4, -2, 1, 1, 2, + -6, -4, -1, -2, 2, -1, -1, -2, 10, 2, -2, -2, 11, 2, -4, -1, + 6, 0, -2, 2, 3, 3, 0, 0, -6, 3, 3, 0,-17, -1, 5, 0, + -1, 4, 10, 11, -3, -2, 0, 1, -3, -4, -5, -3, -1, -2, -2, -1, + 2, -3, -9,-12, 3, 3, 3, 2, 2, 2, 4, 4, 2, 1, -1, -2, + -2, 9, 5,-10, -3, 5, 5, -5, -2, 1, 2, 0, -1, -2, -2, 1, + -2, -3, 7, -2, -1, -3, 7, -3, -1, -2, 8, -4, -2, -2, 7, -3, + 1, -8, -3, 12, 2, -2, -2, 4, 1, 3, 0, -5, -1, 5, 2, -7, + -1, 3, 1, -5, -7, -2, 3, 1, -2, -7, -2, 2, 20, 3, -5, -1, + 5, 0, -3, -2, -7, -7, 0, 6, -6, 0, 7, 6, 2, 6, 0, -7, + -2, 6, -7, 1, -2, 7, -8, 3, -2, 7, -7, 3, -1, 7, -6, 2, + -5, -2, 5, 7, 4, 1, -4, -8, 6, 3, -2, -5, -7, -5, 3, 7, + -1, -1, 6, 5, 0, -1, 1, -4, 2, 1, 0, -7, 1, 0, 0, -4, + -8, 0, 3, 1, -2, 1, -1, -1, 1, -1, -3, 1, 1, -2, 1, 9, + 5, 2, -3, -4, -1, 0, -1, -3, -3, 1, 3, 1, -4, 0, 4, 2, + 2, -2, -2, 12, 0, -2, -5, 3, -1, 0, -3, 1, -3, -1, -2, 1, + 1, 5, 3, 0, -6, -4, -2, 1, 0, -2, -2, 2, 6, 1, -4, -1, + -3, -5, -5, -1, 3, 5, 5, 4, 0, 3, 1, -1, -2, 1, -2, -3, + 2, -4, -5, -3, 4, -2, -3, -2, 6, 0, -1, -1, 7, 1, 0, 0, + -3, -2, -2, 0, -2, -3, -5, -1, -2, 2, 0, -1, -1, 11, 9, -1, + 0, 1, -1,-10, -1, 1, 0, -6, 1, 0, 1, 4, 2, -5, -1, 13, + -2, 4, 5, 0, -5, 1, 6, 3, -6, -2, 3, 2, -5, -2, 0, -2, + -1, 1, 1, -2, -1, -2, 0, 2, 5, 5, 5, 7, 0, -4, -8, -7, + 0, 2, -1, -5, -1, 2, 2, -3, 0, 5, 3, -5, 3, 8, 2,-12, + 8, 4, 0, -2, 10, -1, -4, -1, 3, -6, -3, 0, -4, -5, 0, 0, + 0,-10, -4, 2, -1, -6, 3, 5, -1, -3, 6, 4, 0, -2, 4, 2, + 0, 8, 1, -1, 0, 11, 1, -3, -1, 6, -2, -4, -3, -2, -7, -4, + 0, -1, -1, -1, 4, 5, 6, 5, -5, -9, -8, -5, 2, 2, 3, 2, + 0, 2, 6, 1, 2, 0, 3, 0, 1, -2, -1, -2, 0, -1, -3, -6, + 0, 0, 2, 0, 4, 0, 2, 1, 5, -2, 0, 0, -2, -9, -1, 2, + 0, 1, 0,-10, -1, 1, 8, 0, -1, -2, 4, 0, 1, -1, 2, -1, + -3, -2, 2, -1, -3, -1, 2, -3, 0, -1, 1, 0, 8, 1, -1, 3, + 0, 1, 1, 2, 0, -4, -2, 0, -1, -5, 1, -1, -2, -1, 11, 2, + 1, 5, -2, -2, 0, 2, -4, 0, -2, 1, -5, 1, 0, 5, 0, 1, + -5, -3, 0, 6, -4, 2, 0, 0, -3, 5, 1, 0, -3, 3, 0, 0, + 3, -2, -3, 1, 1, -4, 0, 8, -2, -3, -2, 3, 1, 2, -1, -1, + 1, 1, 0, 2, 2, 0, 1, 6, 1, -1, 2, 1, 0, 3, 0,-19, + 1, -3, -2, 2, 6, 5, -2, -7, -3, 1, 3, 1, -1, -1, 0, 2, + -8, -1, -1, -4, 1, 1, -1, 2, 4, 3, 2, 3, -5, 1, 3, 0, + 0, 2, -1, 1, -3, 0, 0, 5, -5, -2, 0, 8, -4, -4, -4, 6, + 1, 2, 1, 2, 2, 2, -3, 2, 4, 0, -9, 0, 7, 0,-11, 1, + 0, 0, 0, -2, 3, 3, -1, -6, 4, 3, -3,-10, -1, 2, 6, 2, + 7, -2, -3, 5, -4, 0, 3, -1, -4, 2, 1, -7, 2, -1, -1, 3, + 3, 2, 2, 2, -5, -7, -7, -5, 5, 6, 4, 2, -2, -1, 0, 1 }; -static const uint32 s_svq1IntraCodebook8x4[768] = { - 0x06060605, 0x08080707, 0x00000000, 0x03020100, - 0xfbfcfcfd, 0xfefdfcfb, 0xfbfcfcfc, 0xfdfdfcfc, - 0x02020201, 0x03030302, 0x04030302, 0x05050504, - 0x010100ff, 0x04040302, 0xf7f7f6f7, 0xfbfaf9f8, - 0xfafbfcfc, 0xf9f9f9fa, 0xfefeff00, 0xfcfcfdfd, - 0x03030404, 0x00010102, 0x06070707, 0x04040506, - 0x06050402, 0xfafd0104, 0x05050403, 0xf8fb0004, - 0x04040302, 0xf6f9fe02, 0x01020202, 0xf4f7fc00, - 0x01fdf9f7, 0x03030404, 0x03fef9f6, 0x03030505, - 0x03fefaf7, 0x03040506, 0x03fffaf8, 0x02030404, - 0xfbfbfbfb, 0x070401fd, 0xfcfbfbfb, 0x080601fe, - 0xfdfcfbfc, 0x0a0803ff, 0xfefdfcfd, 0x0b090501, - 0xfefefefe, 0xfefefefe, 0xfbfbfbfc, 0xfcfbfbfb, - 0xfcfcfcfd, 0xfdfcfcfc, 0x0b0a0a09, 0x0a0a0b0b, - 0xfe010407, 0xf6f7fafc, 0x00030709, 0xf7f8fcfe, - 0x0204080b, 0xf8fafd00, 0x0305090b, 0xf9fbfe01, - 0xf4f3f3f3, 0xf8f8f6f5, 0x03020100, 0x03040404, - 0x06050403, 0x04050606, 0x04040403, 0x02030303, - 0x0a0b0a0a, 0x07080909, 0x06060606, 0x02030405, - 0xff000000, 0xfcfcfdfe, 0xf4f5f6f6, 0xf2f2f2f3, - 0x10111010, 0x0b0c0d0f, 0xfcfdfeff, 0xfdfcfcfc, - 0xfafafbfc, 0xfafafafa, 0xfafafafb, 0xfbfbfafa, - 0xf4f3f3f3, 0xfaf8f6f5, 0xfaf9f8f7, 0x0100fefc, - 0x0301fffe, 0x09080705, 0x0b090705, 0x0f0f0e0d, - 0x070b0e10, 0xf7f9fd02, 0x03080c0e, 0xf5f7faff, - 0x0004090b, 0xf3f5f8fc, 0xfd010508, 0xf2f4f6fa, - 0xfdf7f1ee, 0x0b090601, 0xfff9f3ef, 0x0c0b0703, - 0x01fbf5f1, 0x0d0c0905, 0x02fdf7f3, 0x0d0b0905, - 0x0f131516, 0xf7fc030a, 0x090f1214, 0xeff4fb02, - 0x01080d10, 0xe8ecf2f9, 0xf8ff060a, 0xe5e7ebf1, - 0xf2ece9e7, 0x0e0901f9, 0xf7f0ebe9, 0x15100900, - 0xfff6f0ec, 0x19161008, 0x06fdf5f1, 0x1b19140e, - 0x0100fefc, 0x02020202, 0x0200fefb, 0x03030303, - 0x01fffcfa, 0x03030302, 0x00fefbf9, 0x02020101, - 0x01010102, 0xfdfe0001, 0x01020303, 0xfcfdff00, - 0x01020304, 0xfafcfe00, 0x01030405, 0xfafbfdff, - 0x04060605, 0xfdfe0002, 0x04040403, 0xff000103, - 0xfffffefe, 0xfefeffff, 0xfefdfcfb, 0xfdfdfefe, - 0xffffffff, 0xffffffff, 0xfcfcfcfd, 0xfdfdfdfd, - 0xffffffff, 0xfeffffff, 0x06060605, 0x03040506, - 0x04040404, 0x07060504, 0xffffff00, 0x020100ff, - 0xfdfdfdfe, 0x00fffefd, 0xfcfcfdfd, 0xfffefdfc, - 0xfcfcfe00, 0x030200fe, 0xfdfdfe00, 0x050402ff, - 0xfdfcfeff, 0x06050300, 0xfdfcfdfe, 0x050402ff, - 0xfd000409, 0x0100fffd, 0xfcff0408, 0x0201fffd, - 0xfbfd0206, 0x0100fefc, 0xfcfd0105, 0x0100fefc, - 0xff010305, 0xf6f6f8fc, 0x01020303, 0xfcfdfe00, - 0x02010101, 0x00010203, 0x020100ff, 0x02030403, - 0x02020100, 0xfdfdff01, 0x01010100, 0xfdfcfeff, - 0xfdfdfdfd, 0x02fffdfd, 0x00fdfcfc, 0x0e0c0703, - 0xfafafbfb, 0xfbfafafa, 0x01020202, 0x00000000, - 0x02030404, 0x00000001, 0x04050606, 0x01010202, - 0xfdfaf9f9, 0x08070400, 0xfdfdfeff, 0x0201fffe, - 0xff010303, 0xfffefefe, 0x02040606, 0xfefefe00, - 0x02fefbfa, 0x0c0b0905, 0x00fefcfc, 0x06050402, - 0xfefefefd, 0x0100fffe, 0xfdfefefe, 0xfefdfdfd, - 0x0301fdf9, 0xfbfd0003, 0x0503fefa, 0xfbfd0104, - 0x0604fffb, 0xfcfd0205, 0x070500fc, 0xfdff0306, - 0x00000000, 0x00000000, 0xfdfdfefe, 0xfffefdfd, - 0x09080706, 0x06070809, 0xfbfbfcfc, 0xfcfbfafa, - 0xfcfaf8f7, 0x06060300, 0x03fffcfb, 0x03050605, - 0x06060301, 0xfbfe0104, 0x01050706, 0xf5f6f9fd, - 0x0105090a, 0xfcfafafd, 0xfbff0305, 0x02fefbfa, - 0xfafafcfe, 0x0a0601fc, 0xfcf9f9fa, 0x0c0b0701, - 0x02030506, 0x00000000, 0xfeff0102, 0xfffffefd, - 0xfcfeff00, 0x01fffefc, 0xfeff0000, 0x030200ff, - 0xfefeff00, 0xfffffefe, 0x01020405, 0x00000000, - 0x01030506, 0x00000000, 0xfcfe0002, 0xfefefdfc, - 0x0200fcf9, 0x01020202, 0x0000fdf9, 0x00000000, - 0x0101fffc, 0x01000000, 0x020201ff, 0x03030202, - 0x020200fe, 0x01010101, 0x020201ff, 0xff000001, - 0x02040200, 0xfdfeff00, 0x01030201, 0xfafafcfe, - 0x04020201, 0x01040605, 0xffffff00, 0xfcfe0000, - 0xfeff0000, 0xfafcfefe, 0x00000102, 0xfdff0101, - 0x01010101, 0x03030201, 0x00010000, 0x04040201, - 0xffffffff, 0x03020100, 0xfbfbfcfc, 0x00fffdfb, - 0xfcfbfbfa, 0xfffffefd, 0x010000ff, 0x03030201, - 0x01010100, 0x04030202, 0xffff0000, 0x03020100, - 0x01010100, 0xffff0000, 0x02030301, 0xfefeff01, - 0x020200fe, 0x01010202, 0xfefcf8f7, 0x03030301, - 0xfeffffff, 0xfcfdfdfd, 0xff000000, 0xfdfdfefe, - 0x00020202, 0xffffffff, 0x03040505, 0x02020202, - 0xfcff0306, 0x0101fffd, 0xfcfdff02, 0x000202ff, - 0x01fefeff, 0xfd010404, 0x0401fffe, 0xf8fd0306, - 0x01020303, 0xfefefeff, 0xfffefcfc, 0x04040301, - 0xfcfbfbfc, 0x020200fe, 0x01040707, 0xfefdfeff, - 0x000301ff, 0x0600fafc, 0x010401fe, 0x07fffafc, - 0x020401fd, 0x06fffafd, 0x020300fe, 0x04fffbfe, - 0x01feff01, 0xf9ff0404, 0xfffcff01, 0xfa000605, - 0xfdfc0003, 0xfc020603, 0xfcfb0003, 0xfd010401, - 0x03030202, 0x02020303, 0xf9fafbfc, 0xfaf9f9f9, - 0x03030201, 0x02020303, 0x01010000, 0x01020201, - 0x03fdfd03, 0x02fefe04, 0x04fcfc03, 0x02fcfc04, - 0x04fcfc04, 0x03fdfc04, 0x03fcfd03, 0x03fdfd03, - 0xfefefefe, 0xfffffefe, 0x08080706, 0x05060708, - 0xf9f9fafb, 0xfbfaf9f8, 0x02020101, 0x01010202, - 0x00000000, 0x0000ff00, 0x000000ff, 0x0000ff00, - 0xfefefdfe, 0xfdfdfdfe, 0x06050302, 0x00010204, - 0x00020608, 0x00000000, 0x00000104, 0xffffff00, - 0x0000ff01, 0xfdfeff00, 0x00fffefe, 0xfbfcfe00, - 0xfeff0103, 0xfbfbfcfd, 0x00000102, 0x00000101, - 0x00ffff00, 0x02020202, 0x01fffeff, 0x02020202, - 0xfffeff00, 0x00ffffff, 0xfffefeff, 0x010000ff, - 0x02010102, 0x00010102, 0x01030506, 0xfcfcfe00, - 0x00fffefd, 0xff000101, 0x04030100, 0x01030505, - 0x00ffffff, 0xfeff0001, 0xfffefefe, 0xfdfeff00, - 0xfefeff00, 0x0200ffff, 0xfffeff01, 0x0200ffff, - 0xfefe0001, 0x0501fefe, 0xfefeff01, 0x0a0500fe, - 0x00000000, 0xffffff00, 0x00ffffff, 0x02010000, - 0x03020201, 0x05060404, 0xfefdfdfd, 0xfdfdfdfe, - 0xfefeff01, 0x07050300, 0xfdfe0002, 0x030200fe, - 0xfdfe0103, 0xfffffefd, 0xff000103, 0xffffffff, - 0x04050301, 0xfcfdff02, 0x0201fefd, 0xfeff0001, - 0x0200fdfb, 0x00000102, 0x0201fffd, 0x00000102, - 0xffffff00, 0x04030201, 0xfdfcfcfd, 0x010000ff, - 0xfffefdfe, 0x01010101, 0x0300fefe, 0x02030404, - 0xfefdfcfc, 0x030201ff, 0x01010100, 0xfdfdfeff, - 0x04050403, 0xfdfdff02, 0x0200fefe, 0x00010202, - 0x070500fc, 0xfcfcff04, 0x030402ff, 0xfefdfd00, - 0xff000102, 0x0100fefe, 0xfeff0000, 0x0201fffe, - 0xfffefdfc, 0x02020100, 0x0005090a, 0xfefdfcfd, - 0xfefeff01, 0x000000ff, 0x01fffefe, 0xff000101, - 0x0300fdfb, 0xfe000204, 0x0100fffe, 0xffff0001, - 0xfeff0203, 0x0101fffe, 0xfbff0507, 0x0402fefa, - 0xfd0303fe, 0xfe0201fc, 0xfd0403fd, 0xfe0302fc, - 0xfd0403fd, 0xfe0302fc, 0xfe0402fc, 0xff0201fd, - 0xfdff0304, 0x0201fffd, 0x00fcfafc, 0x01040504, - 0x06050200, 0xfcfbfd02, 0xfdff0101, 0x0402fefb, - 0x020100ff, 0x04030302, 0x010100ff, 0xffffff00, - 0x020100ff, 0xfeff0102, 0x00fffefd, 0xfdfeff00, - 0x01010101, 0x02010000, 0x00ff0001, 0x00010100, - 0xfffcfe01, 0x00010201, 0xfdf9fc01, 0x01020301, - 0x01010101, 0xff000101, 0x00010101, 0x00020201, - 0x00000101, 0xfd000200, 0xff000203, 0xf7fafeff, - 0x01000000, 0x02010000, 0x00000001, 0x0200ffff, - 0x01010100, 0x00fefdff, 0x0601fbf9, 0xffff0206, - 0xfdff0103, 0x0401fefc, 0xfdfe0002, 0x02fffdfc, - 0x01010202, 0x01000001, 0x00000101, 0x01000000, - 0xfe0101ff, 0xfffcfafb, 0x030401ff, 0x02010002, - 0x030200ff, 0x01000001, 0x000100ff, 0x00ffff00, - 0x02020100, 0x01fffe00, 0xfefffffe, 0x080602ff, - 0xfdfeffff, 0x020100fe, 0xff0000ff, 0xffff00ff, - 0x01010102, 0x00000001, 0x01010000, 0x01ffff01, - 0x020200ff, 0x03fefdff, 0x00030200, 0x04fef9fb, - 0x000000ff, 0xfdfdfeff, 0xfeff00ff, 0xfefefefe, - 0x00000101, 0xff000201, 0x02010201, 0x00020605, - 0x00fdfcfe, 0xfd000202, 0x01000103, 0xfdfe0102, - 0x00000103, 0xff000000, 0xfefeff01, 0x030301ff, - 0x02010203, 0xfe010304, 0xfdfcfcfe, 0xfdfe00ff, - 0xffff0001, 0xff000100, 0x00000203, 0x00010100, - 0x00000101, 0x00000000, 0x02030302, 0x01010202, - 0xfdfeff00, 0xfcfbfbfb, 0xff000101, 0x03030100, - 0x00fefaf7, 0x02020101, 0x0201fefa, 0x01000101, - 0x020201fe, 0x01010101, 0x01020200, 0x01010100, - 0x00000001, 0x00ff0000, 0x00000000, 0x00fefdff, - 0xfefdfdfd, 0x090703ff, 0x02020201, 0xfdfcfe00, - 0xfffe0002, 0xfaff0403, 0xfdfe0001, 0x000303ff, - 0x00030300, 0x0101fffe, 0x0203fffa, 0x0100feff, - 0xfe000305, 0x010200fd, 0x02020101, 0xf9fcfe00, - 0x0201fefd, 0xfcff0102, 0xfe000202, 0x020200fe, - 0xfdfe0000, 0x0000fffe, 0x00000000, 0x02020000, - 0x0100fffe, 0x03020100, 0x0000fefc, 0x030200ff, - 0xfffefefe, 0x040200ff, 0x00000000, 0x0100ffff, - 0xffffff00, 0x0000ffff, 0x00020406, 0xfffffeff, - 0x01010100, 0xf6fbff01, 0x01010101, 0xfc000101, - 0x01010001, 0xff010101, 0x01010102, 0x00000000, - 0x030401fd, 0x00ff0103, 0x000100fc, 0x000000ff, - 0x010200fb, 0xff000101, 0xfe0102ff, 0xff00fffe, - 0x03050402, 0x0201ff00, 0x00010000, 0xfffffefe, - 0xfefefefe, 0x00fffefd, 0x00010000, 0x02010000, - 0xfdfefe00, 0xff0202ff, 0x00000001, 0xfe030501, - 0xff00ffff, 0xfb000200, 0x000100ff, 0xfe020200, - 0xffff0103, 0x02010100, 0x01000001, 0x01010101, - 0x01fef8f6, 0x01010102, 0x010201ff, 0x00000000, - 0x0100ffff, 0x01020202, 0x00ffffff, 0xfcfbfdff, - 0x01020101, 0x02000001, 0xfffffeff, 0x040200ff, - 0x00fbf9fd, 0x00000002, 0x01feff03, 0x02010102, - 0x01fffe01, 0x01000102, 0x0300ff00, 0xffffff02, - 0x00010102, 0x00000000, 0x03fef9f7, 0x01010203, - 0xfe000203, 0x0101fffe, 0x0000ff00, 0x00000101, - 0x0101fffe, 0x00000001, 0xfe010201, 0x0201fdfc, - 0xfe010201, 0x010300fd, 0x0000ffff, 0xfc000301, - 0x01ff0002, 0x03fefe02, 0x02ff0002, 0x01fcfe03, - 0x01010100, 0xfefafe02, 0x000000ff, 0xfffe0002, - 0x0201ffff, 0xfefdfe01, 0xfffeff03, 0x020100ff, - 0x0000040a, 0xfffefeff, 0xfffeff03, 0x00ffff00, - 0x010702fb, 0x0001fefc, 0xff0302fe, 0x000200fd, - 0x00000102, 0xfeff0101, 0xfffefe01, 0x0000feff, - 0xf9fe0300, 0x000003ff, 0xfbfd0301, 0x00ff0302, - 0xfefe0200, 0x00fe0204, 0x00ff01ff, 0x01feff02, - 0xfcfd0004, 0x010201fe, 0x05030000, 0xfeff0103, - 0xff010101, 0x0101fffd, 0xfefeff01, 0xfeff0000 +static const int8 s_svq1IntraCodebook8x4[3072] = { + 5, 6, 6, 6, 7, 7, 8, 8, 0, 0, 0, 0, 0, 1, 2, 3, + -3, -4, -4, -5, -5, -4, -3, -2, -4, -4, -4, -5, -4, -4, -3, -3, + 1, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 4, 4, 5, 5, 5, + -1, 0, 1, 1, 2, 3, 4, 4, -9,-10, -9, -9, -8, -7, -6, -5, + -4, -4, -5, -6, -6, -7, -7, -7, 0, -1, -2, -2, -3, -3, -4, -4, + 4, 4, 3, 3, 2, 1, 1, 0, 7, 7, 7, 6, 6, 5, 4, 4, + 2, 4, 5, 6, 4, 1, -3, -6, 3, 4, 5, 5, 4, 0, -5, -8, + 2, 3, 4, 4, 2, -2, -7,-10, 2, 2, 2, 1, 0, -4, -9,-12, + -9, -7, -3, 1, 4, 4, 3, 3,-10, -7, -2, 3, 5, 5, 3, 3, + -9, -6, -2, 3, 6, 5, 4, 3, -8, -6, -1, 3, 4, 4, 3, 2, + -5, -5, -5, -5, -3, 1, 4, 7, -5, -5, -5, -4, -2, 1, 6, 8, + -4, -5, -4, -3, -1, 3, 8, 10, -3, -4, -3, -2, 1, 5, 9, 11, + -2, -2, -2, -2, -2, -2, -2, -2, -4, -5, -5, -5, -5, -5, -5, -4, + -3, -4, -4, -4, -4, -4, -4, -3, 9, 10, 10, 11, 11, 11, 10, 10, + 7, 4, 1, -2, -4, -6, -9,-10, 9, 7, 3, 0, -2, -4, -8, -9, + 11, 8, 4, 2, 0, -3, -6, -8, 11, 9, 5, 3, 1, -2, -5, -7, + -13,-13,-13,-12,-11,-10, -8, -8, 0, 1, 2, 3, 4, 4, 4, 3, + 3, 4, 5, 6, 6, 6, 5, 4, 3, 4, 4, 4, 3, 3, 3, 2, + 10, 10, 11, 10, 9, 9, 8, 7, 6, 6, 6, 6, 5, 4, 3, 2, + 0, 0, 0, -1, -2, -3, -4, -4,-10,-10,-11,-12,-13,-14,-14,-14, + 16, 16, 17, 16, 15, 13, 12, 11, -1, -2, -3, -4, -4, -4, -4, -3, + -4, -5, -6, -6, -6, -6, -6, -6, -5, -6, -6, -6, -6, -6, -5, -5, + -13,-13,-13,-12,-11,-10, -8, -6, -9, -8, -7, -6, -4, -2, 0, 1, + -2, -1, 1, 3, 5, 7, 8, 9, 5, 7, 9, 11, 13, 14, 15, 15, + 16, 14, 11, 7, 2, -3, -7, -9, 14, 12, 8, 3, -1, -6, -9,-11, + 11, 9, 4, 0, -4, -8,-11,-13, 8, 5, 1, -3, -6,-10,-12,-14, + -18,-15, -9, -3, 1, 6, 9, 11,-17,-13, -7, -1, 3, 7, 11, 12, + -15,-11, -5, 1, 5, 9, 12, 13,-13, -9, -3, 2, 5, 9, 11, 13, + 22, 21, 19, 15, 10, 3, -4, -9, 20, 18, 15, 9, 2, -5,-12,-17, + 16, 13, 8, 1, -7,-14,-20,-24, 10, 6, -1, -8,-15,-21,-25,-27, + -25,-23,-20,-14, -7, 1, 9, 14,-23,-21,-16, -9, 0, 9, 16, 21, + -20,-16,-10, -1, 8, 16, 22, 25,-15,-11, -3, 6, 14, 20, 25, 27, + -4, -2, 0, 1, 2, 2, 2, 2, -5, -2, 0, 2, 3, 3, 3, 3, + -6, -4, -1, 1, 2, 3, 3, 3, -7, -5, -2, 0, 1, 1, 2, 2, + 2, 1, 1, 1, 1, 0, -2, -3, 3, 3, 2, 1, 0, -1, -3, -4, + 4, 3, 2, 1, 0, -2, -4, -6, 5, 4, 3, 1, -1, -3, -5, -6, + 5, 6, 6, 4, 2, 0, -2, -3, 3, 4, 4, 4, 3, 1, 0, -1, + -2, -2, -1, -1, -1, -1, -2, -2, -5, -4, -3, -2, -2, -2, -3, -3, + -1, -1, -1, -1, -1, -1, -1, -1, -3, -4, -4, -4, -3, -3, -3, -3, + -1, -1, -1, -1, -1, -1, -1, -2, 5, 6, 6, 6, 6, 5, 4, 3, + 4, 4, 4, 4, 4, 5, 6, 7, 0, -1, -1, -1, -1, 0, 1, 2, + -2, -3, -3, -3, -3, -2, -1, 0, -3, -3, -4, -4, -4, -3, -2, -1, + 0, -2, -4, -4, -2, 0, 2, 3, 0, -2, -3, -3, -1, 2, 4, 5, + -1, -2, -4, -3, 0, 3, 5, 6, -2, -3, -4, -3, -1, 2, 4, 5, + 9, 4, 0, -3, -3, -1, 0, 1, 8, 4, -1, -4, -3, -1, 1, 2, + 6, 2, -3, -5, -4, -2, 0, 1, 5, 1, -3, -4, -4, -2, 0, 1, + 5, 3, 1, -1, -4, -8,-10,-10, 3, 3, 2, 1, 0, -2, -3, -4, + 1, 1, 1, 2, 3, 2, 1, 0, -1, 0, 1, 2, 3, 4, 3, 2, + 0, 1, 2, 2, 1, -1, -3, -3, 0, 1, 1, 1, -1, -2, -4, -3, + -3, -3, -3, -3, -3, -3, -1, 2, -4, -4, -3, 0, 3, 7, 12, 14, + -5, -5, -6, -6, -6, -6, -6, -5, 2, 2, 2, 1, 0, 0, 0, 0, + 4, 4, 3, 2, 1, 0, 0, 0, 6, 6, 5, 4, 2, 2, 1, 1, + -7, -7, -6, -3, 0, 4, 7, 8, -1, -2, -3, -3, -2, -1, 1, 2, + 3, 3, 1, -1, -2, -2, -2, -1, 6, 6, 4, 2, 0, -2, -2, -2, + -6, -5, -2, 2, 5, 9, 11, 12, -4, -4, -2, 0, 2, 4, 5, 6, + -3, -2, -2, -2, -2, -1, 0, 1, -2, -2, -2, -3, -3, -3, -3, -2, + -7, -3, 1, 3, 3, 0, -3, -5, -6, -2, 3, 5, 4, 1, -3, -5, + -5, -1, 4, 6, 5, 2, -3, -4, -4, 0, 5, 7, 6, 3, -1, -3, + 0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -3, -3, -3, -3, -2, -1, + 6, 7, 8, 9, 9, 8, 7, 6, -4, -4, -5, -5, -6, -6, -5, -4, + -9, -8, -6, -4, 0, 3, 6, 6, -5, -4, -1, 3, 5, 6, 5, 3, + 1, 3, 6, 6, 4, 1, -2, -5, 6, 7, 5, 1, -3, -7,-10,-11, + 10, 9, 5, 1, -3, -6, -6, -4, 5, 3, -1, -5, -6, -5, -2, 2, + -2, -4, -6, -6, -4, 1, 6, 10, -6, -7, -7, -4, 1, 7, 11, 12, + 6, 5, 3, 2, 0, 0, 0, 0, 2, 1, -1, -2, -3, -2, -1, -1, + 0, -1, -2, -4, -4, -2, -1, 1, 0, 0, -1, -2, -1, 0, 2, 3, + 0, -1, -2, -2, -2, -2, -1, -1, 5, 4, 2, 1, 0, 0, 0, 0, + 6, 5, 3, 1, 0, 0, 0, 0, 2, 0, -2, -4, -4, -3, -2, -2, + -7, -4, 0, 2, 2, 2, 2, 1, -7, -3, 0, 0, 0, 0, 0, 0, + -4, -1, 1, 1, 0, 0, 0, 1, -1, 1, 2, 2, 2, 2, 3, 3, + -2, 0, 2, 2, 1, 1, 1, 1, -1, 1, 2, 2, 1, 0, 0, -1, + 0, 2, 4, 2, 0, -1, -2, -3, 1, 2, 3, 1, -2, -4, -6, -6, + 1, 2, 2, 4, 5, 6, 4, 1, 0, -1, -1, -1, 0, 0, -2, -4, + 0, 0, -1, -2, -2, -2, -4, -6, 2, 1, 0, 0, 1, 1, -1, -3, + 1, 1, 1, 1, 1, 2, 3, 3, 0, 0, 1, 0, 1, 2, 4, 4, + -1, -1, -1, -1, 0, 1, 2, 3, -4, -4, -5, -5, -5, -3, -1, 0, + -6, -5, -5, -4, -3, -2, -1, -1, -1, 0, 0, 1, 1, 2, 3, 3, + 0, 1, 1, 1, 2, 2, 3, 4, 0, 0, -1, -1, 0, 1, 2, 3, + 0, 1, 1, 1, 0, 0, -1, -1, 1, 3, 3, 2, 1, -1, -2, -2, + -2, 0, 2, 2, 2, 2, 1, 1, -9, -8, -4, -2, 1, 3, 3, 3, + -1, -1, -1, -2, -3, -3, -3, -4, 0, 0, 0, -1, -2, -2, -3, -3, + 2, 2, 2, 0, -1, -1, -1, -1, 5, 5, 4, 3, 2, 2, 2, 2, + 6, 3, -1, -4, -3, -1, 1, 1, 2, -1, -3, -4, -1, 2, 2, 0, + -1, -2, -2, 1, 4, 4, 1, -3, -2, -1, 1, 4, 6, 3, -3, -8, + 3, 3, 2, 1, -1, -2, -2, -2, -4, -4, -2, -1, 1, 3, 4, 4, + -4, -5, -5, -4, -2, 0, 2, 2, 7, 7, 4, 1, -1, -2, -3, -2, + -1, 1, 3, 0, -4, -6, 0, 6, -2, 1, 4, 1, -4, -6, -1, 7, + -3, 1, 4, 2, -3, -6, -1, 6, -2, 0, 3, 2, -2, -5, -1, 4, + 1, -1, -2, 1, 4, 4, -1, -7, 1, -1, -4, -1, 5, 6, 0, -6, + 3, 0, -4, -3, 3, 6, 2, -4, 3, 0, -5, -4, 1, 4, 1, -3, + 2, 2, 3, 3, 3, 3, 2, 2, -4, -5, -6, -7, -7, -7, -7, -6, + 1, 2, 3, 3, 3, 3, 2, 2, 0, 0, 1, 1, 1, 2, 2, 1, + 3, -3, -3, 3, 4, -2, -2, 2, 3, -4, -4, 4, 4, -4, -4, 2, + 4, -4, -4, 4, 4, -4, -3, 3, 3, -3, -4, 3, 3, -3, -3, 3, + -2, -2, -2, -2, -2, -2, -1, -1, 6, 7, 8, 8, 8, 7, 6, 5, + -5, -6, -7, -7, -8, -7, -6, -5, 1, 1, 2, 2, 2, 2, 1, 1, + 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, + -2, -3, -2, -2, -2, -3, -3, -3, 2, 3, 5, 6, 4, 2, 1, 0, + 8, 6, 2, 0, 0, 0, 0, 0, 4, 1, 0, 0, 0, -1, -1, -1, + 1, -1, 0, 0, 0, -1, -2, -3, -2, -2, -1, 0, 0, -2, -4, -5, + 3, 1, -1, -2, -3, -4, -5, -5, 2, 1, 0, 0, 1, 1, 0, 0, + 0, -1, -1, 0, 2, 2, 2, 2, -1, -2, -1, 1, 2, 2, 2, 2, + 0, -1, -2, -1, -1, -1, -1, 0, -1, -2, -2, -1, -1, 0, 0, 1, + 2, 1, 1, 2, 2, 1, 1, 0, 6, 5, 3, 1, 0, -2, -4, -4, + -3, -2, -1, 0, 1, 1, 0, -1, 0, 1, 3, 4, 5, 5, 3, 1, + -1, -1, -1, 0, 1, 0, -1, -2, -2, -2, -2, -1, 0, -1, -2, -3, + 0, -1, -2, -2, -1, -1, 0, 2, 1, -1, -2, -1, -1, -1, 0, 2, + 1, 0, -2, -2, -2, -2, 1, 5, 1, -1, -2, -2, -2, 0, 5, 10, + 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, 0, 0, 0, 1, 2, + 1, 2, 2, 3, 4, 4, 6, 5, -3, -3, -3, -2, -2, -3, -3, -3, + 1, -1, -2, -2, 0, 3, 5, 7, 2, 0, -2, -3, -2, 0, 2, 3, + 3, 1, -2, -3, -3, -2, -1, -1, 3, 1, 0, -1, -1, -1, -1, -1, + 1, 3, 5, 4, 2, -1, -3, -4, -3, -2, 1, 2, 1, 0, -1, -2, + -5, -3, 0, 2, 2, 1, 0, 0, -3, -1, 1, 2, 2, 1, 0, 0, + 0, -1, -1, -1, 1, 2, 3, 4, -3, -4, -4, -3, -1, 0, 0, 1, + -2, -3, -2, -1, 1, 1, 1, 1, -2, -2, 0, 3, 4, 4, 3, 2, + -4, -4, -3, -2, -1, 1, 2, 3, 0, 1, 1, 1, -1, -2, -3, -3, + 3, 4, 5, 4, 2, -1, -3, -3, -2, -2, 0, 2, 2, 2, 1, 0, + -4, 0, 5, 7, 4, -1, -4, -4, -1, 2, 4, 3, 0, -3, -3, -2, + 2, 1, 0, -1, -2, -2, 0, 1, 0, 0, -1, -2, -2, -1, 1, 2, + -4, -3, -2, -1, 0, 1, 2, 2, 10, 9, 5, 0, -3, -4, -3, -2, + 1, -1, -2, -2, -1, 0, 0, 0, -2, -2, -1, 1, 1, 1, 0, -1, + -5, -3, 0, 3, 4, 2, 0, -2, -2, -1, 0, 1, 1, 0, -1, -1, + 3, 2, -1, -2, -2, -1, 1, 1, 7, 5, -1, -5, -6, -2, 2, 4, + -2, 3, 3, -3, -4, 1, 2, -2, -3, 3, 4, -3, -4, 2, 3, -2, + -3, 3, 4, -3, -4, 2, 3, -2, -4, 2, 4, -2, -3, 1, 2, -1, + 4, 3, -1, -3, -3, -1, 1, 2, -4, -6, -4, 0, 4, 5, 4, 1, + 0, 2, 5, 6, 2, -3, -5, -4, 1, 1, -1, -3, -5, -2, 2, 4, + -1, 0, 1, 2, 2, 3, 3, 4, -1, 0, 1, 1, 0, -1, -1, -1, + -1, 0, 1, 2, 2, 1, -1, -2, -3, -2, -1, 0, 0, -1, -2, -3, + 1, 1, 1, 1, 0, 0, 1, 2, 1, 0, -1, 0, 0, 1, 1, 0, + 1, -2, -4, -1, 1, 2, 1, 0, 1, -4, -7, -3, 1, 3, 2, 1, + 1, 1, 1, 1, 1, 1, 0, -1, 1, 1, 1, 0, 1, 2, 2, 0, + 1, 1, 0, 0, 0, 2, 0, -3, 3, 2, 0, -1, -1, -2, -6, -9, + 0, 0, 0, 1, 0, 0, 1, 2, 1, 0, 0, 0, -1, -1, 0, 2, + 0, 1, 1, 1, -1, -3, -2, 0, -7, -5, 1, 6, 6, 2, -1, -1, + 3, 1, -1, -3, -4, -2, 1, 4, 2, 0, -2, -3, -4, -3, -1, 2, + 2, 2, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, + -1, 1, 1, -2, -5, -6, -4, -1, -1, 1, 4, 3, 2, 0, 1, 2, + -1, 0, 2, 3, 1, 0, 0, 1, -1, 0, 1, 0, 0, -1, -1, 0, + 0, 1, 2, 2, 0, -2, -1, 1, -2, -1, -1, -2, -1, 2, 6, 8, + -1, -1, -2, -3, -2, 0, 1, 2, -1, 0, 0, -1, -1, 0, -1, -1, + 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, -1, -1, 1, + -1, 0, 2, 2, -1, -3, -2, 3, 0, 2, 3, 0, -5, -7, -2, 4, + -1, 0, 0, 0, -1, -2, -3, -3, -1, 0, -1, -2, -2, -2, -2, -2, + 1, 1, 0, 0, 1, 2, 0, -1, 1, 2, 1, 2, 5, 6, 2, 0, + -2, -4, -3, 0, 2, 2, 0, -3, 3, 1, 0, 1, 2, 1, -2, -3, + 3, 1, 0, 0, 0, 0, 0, -1, 1, -1, -2, -2, -1, 1, 3, 3, + 3, 2, 1, 2, 4, 3, 1, -2, -2, -4, -4, -3, -1, 0, -2, -3, + 1, 0, -1, -1, 0, 1, 0, -1, 3, 2, 0, 0, 0, 1, 1, 0, + 1, 1, 0, 0, 0, 0, 0, 0, 2, 3, 3, 2, 2, 2, 1, 1, + 0, -1, -2, -3, -5, -5, -5, -4, 1, 1, 0, -1, 0, 1, 3, 3, + -9, -6, -2, 0, 1, 1, 2, 2, -6, -2, 1, 2, 1, 1, 0, 1, + -2, 1, 2, 2, 1, 1, 1, 1, 0, 2, 2, 1, 0, 1, 1, 1, + 1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, -1, -3, -2, 0, + -3, -3, -3, -2, -1, 3, 7, 9, 1, 2, 2, 2, 0, -2, -4, -3, + 2, 0, -2, -1, 3, 4, -1, -6, 1, 0, -2, -3, -1, 3, 3, 0, + 0, 3, 3, 0, -2, -1, 1, 1, -6, -1, 3, 2, -1, -2, 0, 1, + 5, 3, 0, -2, -3, 0, 2, 1, 1, 1, 2, 2, 0, -2, -4, -7, + -3, -2, 1, 2, 2, 1, -1, -4, 2, 2, 0, -2, -2, 0, 2, 2, + 0, 0, -2, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + -2, -1, 0, 1, 0, 1, 2, 3, -4, -2, 0, 0, -1, 0, 2, 3, + -2, -2, -2, -1, -1, 0, 2, 4, 0, 0, 0, 0, -1, -1, 0, 1, + 0, -1, -1, -1, -1, -1, 0, 0, 6, 4, 2, 0, -1, -2, -1, -1, + 0, 1, 1, 1, 1, -1, -5,-10, 1, 1, 1, 1, 1, 1, 0, -4, + 1, 0, 1, 1, 1, 1, 1, -1, 2, 1, 1, 1, 0, 0, 0, 0, + -3, 1, 4, 3, 3, 1, -1, 0, -4, 0, 1, 0, -1, 0, 0, 0, + -5, 0, 2, 1, 1, 1, 0, -1, -1, 2, 1, -2, -2, -1, 0, -1, + 2, 4, 5, 3, 0, -1, 1, 2, 0, 0, 1, 0, -2, -2, -1, -1, + -2, -2, -2, -2, -3, -2, -1, 0, 0, 0, 1, 0, 0, 0, 1, 2, + 0, -2, -2, -3, -1, 2, 2, -1, 1, 0, 0, 0, 1, 5, 3, -2, + -1, -1, 0, -1, 0, 2, 0, -5, -1, 0, 1, 0, 0, 2, 2, -2, + 3, 1, -1, -1, 0, 1, 1, 2, 1, 0, 0, 1, 1, 1, 1, 1, + -10, -8, -2, 1, 2, 1, 1, 1, -1, 1, 2, 1, 0, 0, 0, 0, + -1, -1, 0, 1, 2, 2, 2, 1, -1, -1, -1, 0, -1, -3, -5, -4, + 1, 1, 2, 1, 1, 0, 0, 2, -1, -2, -1, -1, -1, 0, 2, 4, + -3, -7, -5, 0, 2, 0, 0, 0, 3, -1, -2, 1, 2, 1, 1, 2, + 1, -2, -1, 1, 2, 1, 0, 1, 0, -1, 0, 3, 2, -1, -1, -1, + 2, 1, 1, 0, 0, 0, 0, 0, -9, -7, -2, 3, 3, 2, 1, 1, + 3, 2, 0, -2, -2, -1, 1, 1, 0, -1, 0, 0, 1, 1, 0, 0, + -2, -1, 1, 1, 1, 0, 0, 0, 1, 2, 1, -2, -4, -3, 1, 2, + 1, 2, 1, -2, -3, 0, 3, 1, -1, -1, 0, 0, 1, 3, 0, -4, + 2, 0, -1, 1, 2, -2, -2, 3, 2, 0, -1, 2, 3, -2, -4, 1, + 0, 1, 1, 1, 2, -2, -6, -2, -1, 0, 0, 0, 2, 0, -2, -1, + -1, -1, 1, 2, 1, -2, -3, -2, 3, -1, -2, -1, -1, 0, 1, 2, + 10, 4, 0, 0, -1, -2, -2, -1, 3, -1, -2, -1, 0, -1, -1, 0, + -5, 2, 7, 1, -4, -2, 1, 0, -2, 2, 3, -1, -3, 0, 2, 0, + 2, 1, 0, 0, 1, 1, -1, -2, 1, -2, -2, -1, -1, -2, 0, 0, + 0, 3, -2, -7, -1, 3, 0, 0, 1, 3, -3, -5, 2, 3, -1, 0, + 0, 2, -2, -2, 4, 2, -2, 0, -1, 1, -1, 0, 2, -1, -2, 1, + 4, 0, -3, -4, -2, 1, 2, 1, 0, 0, 3, 5, 3, 1, -1, -2, + 1, 1, 1, -1, -3, -1, 1, 1, 1, -1, -2, -2, 0, 0, -1, -2 }; -static const uint32 s_svq1IntraCodebook8x8[1536] = { - 0x02030404, 0xff000102, 0x02030304, 0xffff0001, - 0x02020303, 0xfeff0001, 0x01020203, 0xfdfeff00, - 0x00010202, 0xfdfeffff, 0x00000102, 0xfcfdfeff, - 0xff000001, 0xfcfcfdfe, 0xfeff0000, 0xfcfcfdfe, - 0x03030302, 0x03030303, 0x02020202, 0x03030202, - 0x02020201, 0x02020202, 0x01010100, 0x01010101, - 0x000000ff, 0x01010000, 0xfffffefe, 0xffffffff, - 0xfdfdfdfd, 0xfefefdfd, 0xfcfcfcfb, 0xfdfcfcfc, - 0x00fffefc, 0x03020201, 0x00fffefc, 0x03030201, - 0x00fffdfc, 0x03030201, 0x00fffdfc, 0x03030201, - 0x00fffdfb, 0x03030201, 0x00fffdfb, 0x03030201, - 0x00fffdfb, 0x03020101, 0xfffefdfb, 0x03020100, - 0x05050404, 0x07070606, 0x03020202, 0x04040403, - 0x00000000, 0x02010101, 0xfefefefe, 0x00ffffff, - 0xfefefefe, 0xfefefefe, 0xfefefefe, 0xfefefefe, - 0xfefefeff, 0xfefefefe, 0xffffffff, 0xfefefefe, - 0xff010305, 0xfdfdfdfe, 0xff010305, 0xfdfdfdfe, - 0xff010305, 0xfdfdfdfe, 0xff010305, 0xfdfdfdfe, - 0x00010405, 0xfdfdfdfe, 0x00020406, 0xfdfdfefe, - 0x00020406, 0xfdfefeff, 0x01020406, 0xfefefeff, - 0x030301ff, 0xfafd0002, 0x040301ff, 0xfafd0003, - 0x040401ff, 0xfafd0103, 0x040301ff, 0xfafd0103, - 0x040301fe, 0xfafd0103, 0x040301fe, 0xf9fd0103, - 0x030301fe, 0xf9fd0002, 0x030200fe, 0xfafd0002, - 0x0608090a, 0x04040506, 0x03040506, 0x01020202, - 0xff000102, 0xfffefefe, 0xfcfdfeff, 0xfdfcfcfc, - 0xfcfcfdfe, 0xfdfcfcfb, 0xfdfdfefe, 0xfefefdfd, - 0xffffffff, 0x00ffffff, 0x01010101, 0x02010101, - 0x0201fffe, 0x08070504, 0x0100fefd, 0x08070503, - 0x00fffdfc, 0x07060402, 0xfffefcfb, 0x07050301, - 0xfefdfbfa, 0x06040200, 0xfefcfbfa, 0x050301ff, - 0xfdfbfaf9, 0x030200fe, 0xfcfbf9f8, 0x0201fffd, - 0x0507090b, 0xffff0103, 0x0306080a, 0xfefe0001, - 0x02050709, 0xfcfdfe00, 0x01030608, 0xfcfcfdff, - 0xff020406, 0xfbfbfcfd, 0xfe000305, 0xfafafbfc, - 0xfdff0103, 0xf9f9fafb, 0xfcfe0002, 0xf9f9fafa, - 0x07070605, 0x08080807, 0x05050403, 0x06060606, - 0x03020200, 0x05040404, 0x0100fffe, 0x03030202, - 0xfffefdfc, 0x02010100, 0xfdfcfbfa, 0x00fffefe, - 0xfafaf9f8, 0xfdfdfcfb, 0xf8f8f7f6, 0xfbfafaf9, - 0x01030506, 0xf8fafdff, 0x02040506, 0xf8fafdff, - 0x02040506, 0xf8fafd00, 0x02040506, 0xf8fafd00, - 0x02040606, 0xf8fafd00, 0x02040506, 0xf8fafd00, - 0x02040506, 0xf8fafd00, 0x02040506, 0xf8fbfdff, - 0x08090a0b, 0x04050607, 0x06070808, 0x02030405, - 0x04040506, 0x00010202, 0x01020303, 0xfeff0000, - 0xff000101, 0xfdfdfefe, 0xfdfeffff, 0xfbfbfcfc, - 0xfbfcfcfd, 0xf9f9fafa, 0xf9fafbfb, 0xf8f8f8f8, - 0xf5f4f3f2, 0xfcfaf9f7, 0xf7f6f5f4, 0xfffdfbf9, - 0xfaf9f7f6, 0x0200fefd, 0xfefcfaf8, 0x05040200, - 0x0200fdfb, 0x08070504, 0x040200fe, 0x0a090806, - 0x07050300, 0x0c0b0a08, 0x08070503, 0x0c0c0b0a, - 0xeeeeeded, 0xf2f1f0ef, 0xf3f2f1f1, 0xf7f6f5f4, - 0xf8f7f6f5, 0xfdfcfbfa, 0xfefdfbfa, 0x020100ff, - 0x030200ff, 0x06060504, 0x08070604, 0x0a0a0a09, - 0x0c0b0a09, 0x0e0e0e0d, 0x0f0e0e0c, 0x10101010, - 0x11131516, 0x05090b0e, 0x0e111314, 0x0104080b, - 0x0a0d0f11, 0xfc000306, 0x05080b0d, 0xf7fbfe01, - 0xff030609, 0xf3f5f9fc, 0xfafd0004, 0xeff1f4f7, - 0xf5f8fbfe, 0xeceef0f2, 0xf0f3f6f8, 0xeaebedef, - 0x12121211, 0x0e101011, 0x0f0f1010, 0x0b0c0d0e, - 0x0a0b0c0c, 0x05070809, 0x04060607, 0xff010203, - 0xfeff0001, 0xfafbfcfd, 0xf8f9fafb, 0xf4f5f6f7, - 0xf2f3f4f5, 0xeff0f0f1, 0xeeefeff0, 0xecececed, - 0x00000000, 0xfdfeffff, 0x00000001, 0xfdfeff00, - 0x00000101, 0xfefeffff, 0x00010101, 0xfeffff00, - 0x01010102, 0xfeffff00, 0x01010202, 0xfeff0000, - 0x01010202, 0xffff0001, 0x01010202, 0xfe000001, - 0x00ffff00, 0x03020100, 0x00ffff00, 0x02020101, - 0xffffffff, 0x02020100, 0xfffeffff, 0x02010100, - 0xfffefeff, 0x02010000, 0xfefefeff, 0x020100ff, - 0xfffeffff, 0x02010000, 0xffffffff, 0x02010100, - 0x02020203, 0x00000101, 0x02020203, 0x00000102, - 0x01020202, 0x00000101, 0x01010202, 0xff000001, - 0x00010101, 0xffff0000, 0xffff0000, 0xffffffff, - 0xfefefefe, 0xfefefefe, 0xfdfdfdfe, 0xfefefefe, - 0x00000205, 0x000000ff, 0xff000204, 0xff00ffff, - 0xffff0104, 0xfffffffe, 0xffff0104, 0xfffffffe, - 0xfeff0104, 0xfffffffe, 0xfeff0104, 0xfffffffe, - 0xffff0104, 0xffffffff, 0xff000204, 0xff000000, - 0x0100fffe, 0x01010101, 0x0100fffd, 0x01010101, - 0x0100fffd, 0x01010101, 0x0100fffd, 0x01010101, - 0x0100fefd, 0x01010202, 0x0100fefc, 0x02020202, - 0x01fffdfb, 0x02010201, 0x00fefdfb, 0x01010101, - 0x00010303, 0xfbfcfcfe, 0x00020303, 0xfcfdfeff, - 0x01010202, 0xfefeff00, 0x01010101, 0x00000001, - 0x01000000, 0x01010101, 0x00fffffe, 0x02020100, - 0xfffefefd, 0x03020100, 0xfffefdfd, 0x03020100, - 0xfdfdfdfd, 0xfefefefd, 0xfefefdfd, 0xfffffffe, - 0xfffefefe, 0xffffffff, 0x00ffffff, 0x00000000, - 0x00000000, 0x01010101, 0x01010000, 0x02020202, - 0x02010101, 0x03030302, 0x02020202, 0x03030303, - 0xfdfbf9f8, 0xff00fffe, 0x00fffdfc, 0x01010201, - 0x030201ff, 0x01020203, 0x03030201, 0x00010202, - 0x02030302, 0xff000001, 0x00010201, 0xffffffff, - 0xff000101, 0xfffefeff, 0x00000101, 0xff00ffff, - 0x00fefdfc, 0x03030201, 0x00fefdfc, 0x02020201, - 0xfffefdfd, 0x01010100, 0xfffefefe, 0x000000ff, - 0xffffff00, 0xffffffff, 0x00010102, 0xfeffff00, - 0x01030303, 0xfefeff00, 0x02040405, 0xfeff0001, - 0x00000000, 0x03030201, 0x0000ff00, 0x03030201, - 0x0000ff00, 0x02030201, 0x01000000, 0x02020201, - 0x01010102, 0x00010101, 0x01020202, 0xfeff0000, - 0x00000102, 0xfafbfdfe, 0xfdffff00, 0xf7f8fafb, - 0x020100fe, 0xfcff0102, 0x020200fe, 0xfcff0102, - 0x020200fe, 0xfdff0102, 0x020200fe, 0xfdff0102, - 0x0202fffe, 0xfdff0102, 0x0201fffe, 0xfdff0102, - 0x0201fffd, 0xfdff0102, 0x0201fffe, 0xfdff0102, - 0xff0101ff, 0x0400fdfd, 0xff0101ff, 0x0400fdfd, - 0x000101ff, 0x0400fdfd, 0x000201ff, 0x0500fdfd, - 0x00020100, 0x0400fcfd, 0x00020100, 0x0500fcfd, - 0x00020100, 0x0400fdfd, 0xff020100, 0x0400fefe, - 0x06050606, 0x05050505, 0x02020202, 0x02020202, - 0x00000000, 0x00000000, 0xffffffff, 0xfefefefe, - 0xfefefefe, 0xfefefefe, 0xfefefefe, 0xfefefefe, - 0xfffeffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x02020202, 0x02020202, 0x00010100, 0x00000000, - 0xfefefeff, 0xfffefefe, 0xfdfdfdfd, 0xfefdfdfd, - 0xfdfcfcfd, 0xfefefdfd, 0xfefefefe, 0x0000ffff, - 0x01010100, 0x03030202, 0x05040403, 0x06060605, - 0xfdfe0104, 0x0301fffd, 0xfcfe0104, 0x0301fffd, - 0xfcfe0105, 0x0401fffd, 0xfdfe0105, 0x0402fffd, - 0xfdfe0105, 0x0402fffd, 0xfcfd0004, 0x0402fffd, - 0xfdfd0004, 0x0301fffd, 0xfdfe0003, 0x0301fffe, - 0xfcfcfcfd, 0xfcfcfcfc, 0xffffffff, 0xfefeffff, - 0x02010102, 0x01010102, 0x04030303, 0x03030304, - 0x04030303, 0x03030404, 0x02010201, 0x02020202, - 0xfffefefe, 0x0000ffff, 0xfcfcfcfc, 0xfdfdfdfd, - 0xfdfdfeff, 0x00fffefe, 0xfefeff00, 0x0100fffe, - 0xffff0102, 0x0100ffff, 0xff000103, 0x010000ff, - 0xff000203, 0x01000000, 0xff000103, 0x01000000, - 0xff000103, 0x01000000, 0x00000102, 0x01000000, - 0x01000000, 0x04030201, 0x00ff0000, 0x03020000, - 0xffffff00, 0x0100ffff, 0xffffff00, 0x00ffffff, - 0xffff0000, 0xfffefeff, 0xff000001, 0xfffefeff, - 0x00010202, 0xffffffff, 0x01020303, 0x00ffff00, - 0x00010001, 0xfffeff00, 0x00000000, 0xfffeffff, - 0x0000ff00, 0xffffffff, 0x00ffffff, 0x00000000, - 0x00ffffff, 0x01010000, 0x00ffffff, 0x03020101, - 0x00fffefe, 0x04030201, 0x00fffefe, 0x05040201, - 0x0001fffd, 0x0100ff00, 0x000100fd, 0x0200ffff, - 0x000100fd, 0x0200ffff, 0x000201fe, 0x0200ffff, - 0x000201fe, 0x0200ffff, 0x000201fe, 0x0200ffff, - 0x000202ff, 0x0200ffff, 0x000101ff, 0x01ffffff, - 0x01fffefe, 0x01030403, 0x00fffefe, 0x00020302, - 0x00fffefe, 0xff010201, 0x00ffffff, 0xff010201, - 0x00ffffff, 0xfe000101, 0x00ffff00, 0xff000101, - 0x00ffff00, 0xff010101, 0x00ffff00, 0xff000100, - 0x0100fffe, 0x01010101, 0x0000fffe, 0x00000000, - 0x00fffffe, 0xfefeffff, 0xfffffffe, 0xfdfefeff, - 0x010100ff, 0xfefeff00, 0x03030201, 0x00000102, - 0x03030201, 0x00010203, 0x01010000, 0x00000101, - 0xffffff00, 0x00000000, 0x00000001, 0x01010000, - 0x01010101, 0x01010101, 0x02020101, 0x01010101, - 0x01010101, 0x01010101, 0x010000ff, 0x00000001, - 0xfffffefd, 0xff00ffff, 0xfdfcfbfb, 0xfffefefe, - 0x01010101, 0xff000102, 0x02010101, 0xff000101, - 0x01010101, 0xfe000101, 0x01010102, 0xfe000101, - 0x00000101, 0xfdff0000, 0x00000101, 0xfdfeff00, - 0x00000101, 0xfcfeffff, 0xff000001, 0xfcfdfefe, - 0x03050708, 0x01010102, 0x00000102, 0xfffeffff, - 0xfeffffff, 0xfffefefe, 0xffffffff, 0x00ffff00, - 0x01000000, 0x00000001, 0x01010000, 0x00000001, - 0x000000ff, 0xffff0000, 0xfffffefe, 0xfffefeff, - 0xfe000409, 0xfffffefe, 0xfeff0207, 0x0000fffe, - 0xfefe0004, 0x010100ff, 0xfefefe01, 0x010100ff, - 0xfffefeff, 0x01010100, 0x00fffeff, 0x00010101, - 0x0100ffff, 0xff000101, 0x0100ff00, 0xffff0000, - 0x01010100, 0x00000101, 0x02020201, 0x00000001, - 0x02020202, 0xffff0001, 0x00010101, 0xfefefeff, - 0xff000000, 0xfefefdfe, 0xfeffffff, 0x00fffefe, - 0xffffffff, 0x02010000, 0x00ffffff, 0x04030201, - 0x0000ffff, 0xfdfdfeff, 0x0000ffff, 0xffffff00, - 0x00fffefe, 0x01010101, 0x00fefefe, 0x03030201, - 0x00ffffff, 0x03030301, 0x00000001, 0x02020101, - 0x00010202, 0xffffff00, 0x00010203, 0xfdfdfeff, - 0xfeffffff, 0xfbfcfdfe, 0xff000000, 0xfcfdfdff, - 0x00010101, 0xfdfeff00, 0x01020202, 0xffff0001, - 0x02020202, 0xff000101, 0x02020202, 0x00000102, - 0x01020101, 0x00000101, 0x01010000, 0xff000000, - 0x010302fe, 0xff0101ff, 0x000302fd, 0xff0101ff, - 0x000302fd, 0xff0101ff, 0x000302fc, 0xfe0101ff, - 0x000301fc, 0xfe0101ff, 0xff0301fc, 0xfe0101fe, - 0x000201fd, 0xfe0101ff, 0x000201fd, 0xff0101ff, - 0xfeffffff, 0xfefefefe, 0x01010101, 0x00000000, - 0x02020201, 0x02020202, 0x01010000, 0x02020201, - 0xfffffefe, 0x000000ff, 0xfdfdfdfd, 0xfefdfdfd, - 0xffffffff, 0xfefefefe, 0x04040404, 0x02030304, - 0xfffefdfd, 0x05020100, 0xfefdfdfd, 0x060301ff, - 0xfefefdfd, 0x05030200, 0xfefefefd, 0x05030100, - 0xfffefefe, 0x050301ff, 0xfffffefe, 0x04020100, - 0xffffffff, 0x04010100, 0xffffffff, 0x03020100, - 0x0100ff00, 0xffff0001, 0x01000000, 0xffff0002, - 0x00ff0001, 0x00000001, 0xfffeff01, 0x00000000, - 0xfffdfe01, 0x01000000, 0xfefdff01, 0x02010100, - 0xfffeff01, 0x02010100, 0x00ff0002, 0x02020101, - 0x01010101, 0x02010000, 0xff0000ff, 0x01000000, - 0xfffffefd, 0x010100ff, 0x00fffefc, 0x01010100, - 0x0000fefd, 0x01010101, 0x0100fffd, 0x00000101, - 0x010100ff, 0xff000001, 0x02020100, 0xff000001, - 0xfdfcfcfc, 0xfffffffe, 0xfffefefe, 0x00000000, - 0x000000ff, 0x01010101, 0x01010000, 0x01010101, - 0x01010000, 0x00010202, 0x01010000, 0x00010101, - 0x01000000, 0x00010101, 0x010000ff, 0x00000101, - 0x02020201, 0xfcfeff01, 0x02020101, 0xfcfe0001, - 0x01010100, 0xfdff0001, 0x010100ff, 0xfeff0000, - 0x010100ff, 0xff000001, 0x0000fffe, 0xff000000, - 0x0100ffff, 0x00000001, 0x010100ff, 0x00010101, - 0xff000202, 0xfefffffe, 0xfeff0101, 0xfefffffe, - 0xfeff0101, 0xff0000fe, 0xfe000101, 0x000101ff, - 0xff000101, 0x010201ff, 0xff000101, 0x010201ff, - 0xff000101, 0x010101ff, 0xff000101, 0x01010100, - 0xfeff0000, 0xfcfcfcfc, 0x02030303, 0x00000001, - 0x03030303, 0x02020202, 0x00000000, 0x01000000, - 0xffffffff, 0x00ffffff, 0x0000ff00, 0x000000ff, - 0x00000000, 0x00000000, 0x00000000, 0x00ffff00, - 0xff00ffff, 0xff0201ff, 0x00000101, 0xff030200, - 0xff000101, 0xff0301ff, 0xfe000101, 0xfe0100fe, - 0xfe000001, 0xfd0100fe, 0x00000000, 0xfd0101ff, - 0x00010100, 0xfd010201, 0x010100ff, 0xfc010201, - 0x0100fdfc, 0x00000101, 0x0100fefc, 0xff000101, - 0x0101fffd, 0xffff0001, 0x010101ff, 0x00ff0001, - 0x01020201, 0x0000ff00, 0x00010202, 0x0100ffff, - 0xff000102, 0x0100fffe, 0xff000202, 0x0101fffe, - 0x00000101, 0xffffffff, 0xffffff00, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffff0000, 0xffffffff, - 0xff000001, 0xffffffff, 0x00000102, 0xffffffff, - 0x01020305, 0x00000000, 0x02030506, 0x00000001, - 0x01030404, 0x01000000, 0x01020303, 0x01000000, - 0x00010202, 0x0100ffff, 0xff000000, 0x0100ffff, - 0xffff0000, 0x0200fffe, 0xfeffff00, 0x0100fefe, - 0xfeffff00, 0x00fffefe, 0xfeff0000, 0x00fffefe, - 0xffff0000, 0x030200ff, 0xfefeff00, 0x0201ffff, - 0xffff0001, 0x000000ff, 0x00010101, 0xffff0000, - 0x00010201, 0xffffff00, 0x000000ff, 0xffffffff, - 0xfffffefd, 0x02010100, 0x01fffdfc, 0x05050302, - 0x00000000, 0x00000000, 0x01010101, 0x01010101, - 0xff000000, 0x01000000, 0xfefeffff, 0x00fffffe, - 0x00000000, 0x01010100, 0x02020202, 0x03030302, - 0x01010101, 0x01010202, 0xfcfcfdfc, 0xfdfdfcfc, - 0x020100ff, 0x03030302, 0xffffffff, 0x00000000, - 0xfeff0000, 0xfefdfdfe, 0x00010203, 0xfefefeff, - 0x01020304, 0x00000001, 0x01010202, 0x01010100, - 0xffffff00, 0x010000ff, 0xfefefefe, 0x0000fffe, - 0x0200ff01, 0x01fffe01, 0x0200ff01, 0x01fefe01, - 0x0300ff01, 0x01fffe02, 0x0300fe00, 0x01fefe02, - 0x0300fe00, 0x01fefe02, 0x0300fe00, 0x01fffe01, - 0x0200fe00, 0x01fefe01, 0x0200ff00, 0x01fffe01, - 0x02020100, 0x02020303, 0x02010100, 0x01020303, - 0x02010000, 0x01020202, 0x010000ff, 0x01010101, - 0x0000ffff, 0x00000000, 0xffffffff, 0xffffffff, - 0xfefefefe, 0xfffefefe, 0xfefefefe, 0xfffefefe, - 0xfeff0000, 0x050300ff, 0xffff0000, 0x040200ff, - 0x00000101, 0x0201ffff, 0x01010201, 0x00ffff00, - 0x01020100, 0xfefeff00, 0x020100ff, 0xfdfd0001, - 0x0201fffe, 0xfcfe0002, 0x0200fffe, 0xfdff0102, - 0x00000000, 0xffff0000, 0x00ff0000, 0x00000000, - 0xffffffff, 0x00000000, 0xffffffff, 0x00ffffff, - 0xffffffff, 0x00ffffff, 0x000000ff, 0x00ffff00, - 0x01010000, 0x01000000, 0x04030303, 0x03030303, - 0xfefe0105, 0xff000000, 0xfffdff04, 0xff000000, - 0x00ffff03, 0xff000101, 0x01000002, 0xfe000101, - 0x01000001, 0xfe000101, 0xffffff00, 0xff000000, - 0xffffff00, 0xff0000ff, 0x00000102, 0x00000100, - 0x01010001, 0x00000101, 0x01000001, 0x00000001, - 0x00ffff01, 0x00000000, 0xffff0002, 0x00ffffff, - 0xffff0103, 0xfffefefe, 0x00010204, 0xfffefeff, - 0x00000102, 0x0000ffff, 0xffffff00, 0x010100ff, - 0x02020100, 0xfdff0102, 0x01010000, 0xfeff0001, - 0x00000000, 0xffff0000, 0x00ff0000, 0x00010100, - 0x00ff0000, 0x01010101, 0x00000000, 0x00010101, - 0x01010000, 0xfdff0102, 0x01000000, 0xfbfcff01, - 0xfffefefe, 0x02020200, 0x00000000, 0x00010101, - 0x01010101, 0xfdfe0001, 0x01010000, 0xfcfdff00, - 0x0100ffff, 0xfdfe0000, 0x0100ffff, 0xff000101, - 0x01000000, 0x00010101, 0x01010101, 0x00000000, - 0x00000100, 0x02010101, 0x00000201, 0x01ff0000, - 0xff000200, 0x00ff0001, 0x00000100, 0x01000102, - 0x00ff0100, 0x01000202, 0xffff00ff, 0x02010102, - 0xfefdfefe, 0x01010100, 0xfdfdfefe, 0x00ffffff, - 0x0100fffd, 0x00010102, 0x0100fffd, 0x01010102, - 0x010000fe, 0x01010101, 0x000000ff, 0x00000000, - 0x000000fe, 0x00ffff00, 0x000000fe, 0xffff0000, - 0x010100fd, 0x01000101, 0x0100fefb, 0x02010202, - 0x00fffffe, 0x03020100, 0x01010000, 0x02010000, - 0x00010000, 0x0100ffff, 0xffffffff, 0x00fffefe, - 0xfefefefe, 0x0100fffe, 0xff000000, 0x02020100, - 0x00000102, 0x02020100, 0xff000102, 0x0000ffff, - 0x01010100, 0xfcff0101, 0x0100ffff, 0xfd000101, - 0x0000fffe, 0xfe020201, 0x000000ff, 0xff030200, - 0x000000ff, 0x00020100, 0xfeff0000, 0x000101ff, - 0xfeff0000, 0x010200fe, 0xfeff0000, 0x020201ff, - 0x00000001, 0xfdfefdfe, 0x00010000, 0xfffffefe, - 0x0101ff00, 0x0000ffff, 0x0101ff00, 0x0000ffff, - 0x01020100, 0x0100ffff, 0x02030201, 0x02010000, - 0x010200ff, 0x03020000, 0x0000fffe, 0x020100ff, - 0xff000101, 0x01fffefe, 0xff010101, 0x0200fefe, - 0xff010101, 0x0200ffff, 0x00000000, 0x02010000, - 0x00ffffff, 0x02010000, 0x01fffeff, 0x00000101, - 0x01fffeff, 0xff000202, 0x02fffeff, 0xff000202, - 0xfeffffff, 0x0100ffff, 0xffff0000, 0x020100ff, - 0x00000001, 0x02010100, 0x00000101, 0x01010101, - 0x01000101, 0x01010001, 0x01010101, 0xffffff00, - 0x00010201, 0xfdfefeff, 0x00010202, 0xfcfcfdfe, - 0x0101fefc, 0x00000101, 0x000100fe, 0x00000000, - 0xfe010100, 0x0100fffe, 0xfe010202, 0x0201fffe, - 0xfe010201, 0x0201fffe, 0xff0101ff, 0x0100ffff, - 0x010100fe, 0x00ffff00, 0x020200fe, 0x00ffff01, - 0x00000101, 0x00000100, 0xfefdfdfe, 0x0000fffe, - 0xfefdfcfd, 0x000000ff, 0x0100ffff, 0x01020302, - 0x03020100, 0x01020303, 0x02010101, 0xff000001, - 0x00000000, 0xffffffff, 0x00ffff00, 0x00000000, - 0x00000101, 0x0200ffff, 0x00010000, 0x0101ffff, - 0x0100fffe, 0x01010101, 0x0200fdfd, 0x00010102, - 0x0100fefe, 0x00000101, 0x00000001, 0xffff0000, - 0xfdff0103, 0x0100fffe, 0xfdff0204, 0x0201fffd, - 0xff000000, 0xffffffff, 0x00010201, 0xffff0000, - 0x02030302, 0xffff0001, 0x02040403, 0xfeff0001, - 0x01020303, 0xfefeff00, 0xff000101, 0xfdfefeff, - 0xff000000, 0xfefefeff, 0xffffffff, 0xfffefeff, - 0x02020201, 0x02020102, 0x01010100, 0x00000001, - 0x01000000, 0xfeff0001, 0x00000000, 0xfcff0001, - 0x00000001, 0xfbfe0000, 0x00000001, 0xfcff0000, - 0x00ff0001, 0xfdff0000, 0x00ffff00, 0xff010101, - 0x0000fffe, 0xfeffffff, 0x000000ff, 0xfefeffff, - 0x00010100, 0xfeffffff, 0x00010100, 0xffff0000, - 0x00000100, 0x00010101, 0x00000101, 0x01020201, - 0x00000101, 0x01020201, 0xff000101, 0x00010100, - 0x00010204, 0x01010100, 0x00010204, 0x01000000, - 0x00000103, 0x00ffffff, 0xff000001, 0x00fffeff, - 0x00000000, 0x00ffffff, 0x0000ffff, 0x0100ffff, - 0xff00fffe, 0x010000ff, 0xfefffefe, 0x010000ff, - 0x01010100, 0xff000102, 0x00ffffff, 0xfefeff00, - 0x00ff00ff, 0xfffeff00, 0x00000000, 0x02010000, - 0x00000000, 0x03020000, 0xffff00ff, 0x0300ffff, - 0xff0000ff, 0x0300feff, 0x00000000, 0x0401ffff, - 0x00000202, 0x01000000, 0xfeff0101, 0x01fffeff, - 0xfefeffff, 0x00fefdfe, 0xffff00ff, 0x01fffeff, - 0x00000101, 0x01000001, 0x00000202, 0x01000001, - 0x00000202, 0xffff0000, 0x00000202, 0xffff0001, - 0x010100ff, 0xffffff00, 0x02030201, 0x00000001, - 0x01010100, 0x0000ff00, 0x00fffefe, 0x00000001, - 0x02fffefe, 0x00010202, 0x0100fffe, 0xff000001, - 0x0000ffff, 0xfefffeff, 0x01010100, 0x01010000, - 0xfefdfdfd, 0xfefeffff, 0x0100ffff, 0x00000102, - 0x02010101, 0x00000102, 0x01010101, 0x01ff0001, - 0xffff0001, 0x01ff0000, 0xffffff00, 0x01ffff00, - 0x00ff0001, 0x0200ff00, 0x00ff0002, 0x02000000, - 0xfffe0001, 0x00010100, 0xffff0002, 0x00010100, - 0xfffe0001, 0xff000100, 0xffff0001, 0xff000100, - 0x00010100, 0x00000101, 0x010201fe, 0x01000000, - 0x010200fb, 0x0100ff00, 0x0102fffa, 0x0000ff00, - 0xff000305, 0xfffffffe, 0xff000101, 0xffff00ff, - 0x010100ff, 0x00010202, 0x0100fffe, 0x01010102, - 0xfffffffe, 0x0100ff00, 0x00000100, 0x0000ffff, - 0x01010100, 0x00000001, 0x0100fefd, 0xff000001, - 0x000100ff, 0x030200ff, 0xfe0000ff, 0x00fffefc, - 0x00010100, 0xff00fffe, 0x01030201, 0x00010100, - 0x010100ff, 0x00010101, 0x00fefdfe, 0x00010000, - 0x00fefeff, 0xff000001, 0x00000103, 0xffff0001, - 0x0000fffe, 0x0000ffff, 0x000000ff, 0x01010100, - 0x00ffffff, 0x01010101, 0xfffdfe00, 0x00000001, - 0xfffdff01, 0xff000101, 0x01ff0103, 0xff000202, - 0x01000103, 0x00010102, 0xfffefe00, 0x000000ff, - 0xffff0001, 0x00010201, 0xfffeff00, 0x01020201, - 0x00ffffff, 0x00020100, 0x000000fe, 0xff010000, - 0x000100ff, 0xffffffff, 0x02010100, 0x00fffe00, - 0x02020201, 0x00ffff01, 0x01010100, 0xfffefe00, - 0xffff0000, 0xfefeffff, 0x00ff0000, 0x01020201, - 0xffff0000, 0x02020100, 0xfeff0101, 0xffffffff, - 0x00010202, 0xfefeff00, 0x01020201, 0xfefe0000, - 0x00000000, 0xff000101, 0xffffff00, 0x01020302, - 0x0201fe00, 0x010000ff, 0x0302feff, 0x000000ff, - 0x0302fe00, 0x0000ffff, 0x0203ff00, 0x000100fe, - 0x0103ff00, 0x000100fe, 0x0102ff00, 0xff0001ff, - 0xff010000, 0xff0000fe, 0xfe000001, 0xfffffffe, - 0x01010101, 0xfeffff01, 0x01000000, 0x01010101, - 0x01000000, 0x03020101, 0xff000001, 0x02010000, - 0xfeffff00, 0x020100ff, 0xfefefefe, 0x010100ff, - 0xffffffff, 0xff000000, 0x00020202, 0xfcfeffff, - 0xfffffeff, 0x03020100, 0xffffffff, 0x03020100, - 0x00ff0001, 0x020100ff, 0x00000001, 0x020200ff, - 0xffff0001, 0x020100fe, 0xfefefe00, 0x0100fffd, - 0xfefefe00, 0x0101fffe, 0x00000000, 0x02020100 +static const int8 s_svq1IntraCodebook8x8[6144] = { + 4, 4, 3, 2, 2, 1, 0, -1, 4, 3, 3, 2, 1, 0, -1, -1, + 3, 3, 2, 2, 1, 0, -1, -2, 3, 2, 2, 1, 0, -1, -2, -3, + 2, 2, 1, 0, -1, -1, -2, -3, 2, 1, 0, 0, -1, -2, -3, -4, + 1, 0, 0, -1, -2, -3, -4, -4, 0, 0, -1, -2, -2, -3, -4, -4, + 2, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 3, 3, + 1, 2, 2, 2, 2, 2, 2, 2, 0, 1, 1, 1, 1, 1, 1, 1, + -1, 0, 0, 0, 0, 0, 1, 1, -2, -2, -1, -1, -1, -1, -1, -1, + -3, -3, -3, -3, -3, -3, -2, -2, -5, -4, -4, -4, -4, -4, -4, -3, + -4, -2, -1, 0, 1, 2, 2, 3, -4, -2, -1, 0, 1, 2, 3, 3, + -4, -3, -1, 0, 1, 2, 3, 3, -4, -3, -1, 0, 1, 2, 3, 3, + -5, -3, -1, 0, 1, 2, 3, 3, -5, -3, -1, 0, 1, 2, 3, 3, + -5, -3, -1, 0, 1, 1, 2, 3, -5, -3, -2, -1, 0, 1, 2, 3, + 4, 4, 5, 5, 6, 6, 7, 7, 2, 2, 2, 3, 3, 4, 4, 4, + 0, 0, 0, 0, 1, 1, 1, 2, -2, -2, -2, -2, -1, -1, -1, 0, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -1, -2, -2, -2, -2, -2, -2, -2, -1, -1, -1, -1, -2, -2, -2, -2, + 5, 3, 1, -1, -2, -3, -3, -3, 5, 3, 1, -1, -2, -3, -3, -3, + 5, 3, 1, -1, -2, -3, -3, -3, 5, 3, 1, -1, -2, -3, -3, -3, + 5, 4, 1, 0, -2, -3, -3, -3, 6, 4, 2, 0, -2, -2, -3, -3, + 6, 4, 2, 0, -1, -2, -2, -3, 6, 4, 2, 1, -1, -2, -2, -2, + -1, 1, 3, 3, 2, 0, -3, -6, -1, 1, 3, 4, 3, 0, -3, -6, + -1, 1, 4, 4, 3, 1, -3, -6, -1, 1, 3, 4, 3, 1, -3, -6, + -2, 1, 3, 4, 3, 1, -3, -6, -2, 1, 3, 4, 3, 1, -3, -7, + -2, 1, 3, 3, 2, 0, -3, -7, -2, 0, 2, 3, 2, 0, -3, -6, + 10, 9, 8, 6, 6, 5, 4, 4, 6, 5, 4, 3, 2, 2, 2, 1, + 2, 1, 0, -1, -2, -2, -2, -1, -1, -2, -3, -4, -4, -4, -4, -3, + -2, -3, -4, -4, -5, -4, -4, -3, -2, -2, -3, -3, -3, -3, -2, -2, + -1, -1, -1, -1, -1, -1, -1, 0, 1, 1, 1, 1, 1, 1, 1, 2, + -2, -1, 1, 2, 4, 5, 7, 8, -3, -2, 0, 1, 3, 5, 7, 8, + -4, -3, -1, 0, 2, 4, 6, 7, -5, -4, -2, -1, 1, 3, 5, 7, + -6, -5, -3, -2, 0, 2, 4, 6, -6, -5, -4, -2, -1, 1, 3, 5, + -7, -6, -5, -3, -2, 0, 2, 3, -8, -7, -5, -4, -3, -1, 1, 2, + 11, 9, 7, 5, 3, 1, -1, -1, 10, 8, 6, 3, 1, 0, -2, -2, + 9, 7, 5, 2, 0, -2, -3, -4, 8, 6, 3, 1, -1, -3, -4, -4, + 6, 4, 2, -1, -3, -4, -5, -5, 5, 3, 0, -2, -4, -5, -6, -6, + 3, 1, -1, -3, -5, -6, -7, -7, 2, 0, -2, -4, -6, -6, -7, -7, + 5, 6, 7, 7, 7, 8, 8, 8, 3, 4, 5, 5, 6, 6, 6, 6, + 0, 2, 2, 3, 4, 4, 4, 5, -2, -1, 0, 1, 2, 2, 3, 3, + -4, -3, -2, -1, 0, 1, 1, 2, -6, -5, -4, -3, -2, -2, -1, 0, + -8, -7, -6, -6, -5, -4, -3, -3,-10, -9, -8, -8, -7, -6, -6, -5, + 6, 5, 3, 1, -1, -3, -6, -8, 6, 5, 4, 2, -1, -3, -6, -8, + 6, 5, 4, 2, 0, -3, -6, -8, 6, 5, 4, 2, 0, -3, -6, -8, + 6, 6, 4, 2, 0, -3, -6, -8, 6, 5, 4, 2, 0, -3, -6, -8, + 6, 5, 4, 2, 0, -3, -6, -8, 6, 5, 4, 2, -1, -3, -5, -8, + 11, 10, 9, 8, 7, 6, 5, 4, 8, 8, 7, 6, 5, 4, 3, 2, + 6, 5, 4, 4, 2, 2, 1, 0, 3, 3, 2, 1, 0, 0, -1, -2, + 1, 1, 0, -1, -2, -2, -3, -3, -1, -1, -2, -3, -4, -4, -5, -5, + -3, -4, -4, -5, -6, -6, -7, -7, -5, -5, -6, -7, -8, -8, -8, -8, + -14,-13,-12,-11, -9, -7, -6, -4,-12,-11,-10, -9, -7, -5, -3, -1, + -10, -9, -7, -6, -3, -2, 0, 2, -8, -6, -4, -2, 0, 2, 4, 5, + -5, -3, 0, 2, 4, 5, 7, 8, -2, 0, 2, 4, 6, 8, 9, 10, + 0, 3, 5, 7, 8, 10, 11, 12, 3, 5, 7, 8, 10, 11, 12, 12, + -19,-19,-18,-18,-17,-16,-15,-14,-15,-15,-14,-13,-12,-11,-10, -9, + -11,-10, -9, -8, -6, -5, -4, -3, -6, -5, -3, -2, -1, 0, 1, 2, + -1, 0, 2, 3, 4, 5, 6, 6, 4, 6, 7, 8, 9, 10, 10, 10, + 9, 10, 11, 12, 13, 14, 14, 14, 12, 14, 14, 15, 16, 16, 16, 16, + 22, 21, 19, 17, 14, 11, 9, 5, 20, 19, 17, 14, 11, 8, 4, 1, + 17, 15, 13, 10, 6, 3, 0, -4, 13, 11, 8, 5, 1, -2, -5, -9, + 9, 6, 3, -1, -4, -7,-11,-13, 4, 0, -3, -6, -9,-12,-15,-17, + -2, -5, -8,-11,-14,-16,-18,-20, -8,-10,-13,-16,-17,-19,-21,-22, + 17, 18, 18, 18, 17, 16, 16, 14, 16, 16, 15, 15, 14, 13, 12, 11, + 12, 12, 11, 10, 9, 8, 7, 5, 7, 6, 6, 4, 3, 2, 1, -1, + 1, 0, -1, -2, -3, -4, -5, -6, -5, -6, -7, -8, -9,-10,-11,-12, + -11,-12,-13,-14,-15,-16,-16,-17,-16,-17,-17,-18,-19,-20,-20,-20, + 0, 0, 0, 0, -1, -1, -2, -3, 1, 0, 0, 0, 0, -1, -2, -3, + 1, 1, 0, 0, -1, -1, -2, -2, 1, 1, 1, 0, 0, -1, -1, -2, + 2, 1, 1, 1, 0, -1, -1, -2, 2, 2, 1, 1, 0, 0, -1, -2, + 2, 2, 1, 1, 1, 0, -1, -1, 2, 2, 1, 1, 1, 0, 0, -2, + 0, -1, -1, 0, 0, 1, 2, 3, 0, -1, -1, 0, 1, 1, 2, 2, + -1, -1, -1, -1, 0, 1, 2, 2, -1, -1, -2, -1, 0, 1, 1, 2, + -1, -2, -2, -1, 0, 0, 1, 2, -1, -2, -2, -2, -1, 0, 1, 2, + -1, -1, -2, -1, 0, 0, 1, 2, -1, -1, -1, -1, 0, 1, 1, 2, + 3, 2, 2, 2, 1, 1, 0, 0, 3, 2, 2, 2, 2, 1, 0, 0, + 2, 2, 2, 1, 1, 1, 0, 0, 2, 2, 1, 1, 1, 0, 0, -1, + 1, 1, 1, 0, 0, 0, -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -3, -3, -3, -2, -2, -2, -2, + 5, 2, 0, 0, -1, 0, 0, 0, 4, 2, 0, -1, -1, -1, 0, -1, + 4, 1, -1, -1, -2, -1, -1, -1, 4, 1, -1, -1, -2, -1, -1, -1, + 4, 1, -1, -2, -2, -1, -1, -1, 4, 1, -1, -2, -2, -1, -1, -1, + 4, 1, -1, -1, -1, -1, -1, -1, 4, 2, 0, -1, 0, 0, 0, -1, + -2, -1, 0, 1, 1, 1, 1, 1, -3, -1, 0, 1, 1, 1, 1, 1, + -3, -1, 0, 1, 1, 1, 1, 1, -3, -1, 0, 1, 1, 1, 1, 1, + -3, -2, 0, 1, 2, 2, 1, 1, -4, -2, 0, 1, 2, 2, 2, 2, + -5, -3, -1, 1, 1, 2, 1, 2, -5, -3, -2, 0, 1, 1, 1, 1, + 3, 3, 1, 0, -2, -4, -4, -5, 3, 3, 2, 0, -1, -2, -3, -4, + 2, 2, 1, 1, 0, -1, -2, -2, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, -2, -1, -1, 0, 0, 1, 2, 2, + -3, -2, -2, -1, 0, 1, 2, 3, -3, -3, -2, -1, 0, 1, 2, 3, + -3, -3, -3, -3, -3, -2, -2, -2, -3, -3, -2, -2, -2, -1, -1, -1, + -2, -2, -2, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 2, 2, 2, 2, + 1, 1, 1, 2, 2, 3, 3, 3, 2, 2, 2, 2, 3, 3, 3, 3, + -8, -7, -5, -3, -2, -1, 0, -1, -4, -3, -1, 0, 1, 2, 1, 1, + -1, 1, 2, 3, 3, 2, 2, 1, 1, 2, 3, 3, 2, 2, 1, 0, + 2, 3, 3, 2, 1, 0, 0, -1, 1, 2, 1, 0, -1, -1, -1, -1, + 1, 1, 0, -1, -1, -2, -2, -1, 1, 1, 0, 0, -1, -1, 0, -1, + -4, -3, -2, 0, 1, 2, 3, 3, -4, -3, -2, 0, 1, 2, 2, 2, + -3, -3, -2, -1, 0, 1, 1, 1, -2, -2, -2, -1, -1, 0, 0, 0, + 0, -1, -1, -1, -1, -1, -1, -1, 2, 1, 1, 0, 0, -1, -1, -2, + 3, 3, 3, 1, 0, -1, -2, -2, 5, 4, 4, 2, 1, 0, -1, -2, + 0, 0, 0, 0, 1, 2, 3, 3, 0, -1, 0, 0, 1, 2, 3, 3, + 0, -1, 0, 0, 1, 2, 3, 2, 0, 0, 0, 1, 1, 2, 2, 2, + 2, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 1, 0, 0, -1, -2, + 2, 1, 0, 0, -2, -3, -5, -6, 0, -1, -1, -3, -5, -6, -8, -9, + -2, 0, 1, 2, 2, 1, -1, -4, -2, 0, 2, 2, 2, 1, -1, -4, + -2, 0, 2, 2, 2, 1, -1, -3, -2, 0, 2, 2, 2, 1, -1, -3, + -2, -1, 2, 2, 2, 1, -1, -3, -2, -1, 1, 2, 2, 1, -1, -3, + -3, -1, 1, 2, 2, 1, -1, -3, -2, -1, 1, 2, 2, 1, -1, -3, + -1, 1, 1, -1, -3, -3, 0, 4, -1, 1, 1, -1, -3, -3, 0, 4, + -1, 1, 1, 0, -3, -3, 0, 4, -1, 1, 2, 0, -3, -3, 0, 5, + 0, 1, 2, 0, -3, -4, 0, 4, 0, 1, 2, 0, -3, -4, 0, 5, + 0, 1, 2, 0, -3, -3, 0, 4, 0, 1, 2, -1, -2, -2, 0, 4, + 6, 6, 5, 6, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -2, -2, -2, -2, + -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, + -1, -1, -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 1, 0, 0, 0, 0, 0, + -1, -2, -2, -2, -2, -2, -2, -1, -3, -3, -3, -3, -3, -3, -3, -2, + -3, -4, -4, -3, -3, -3, -2, -2, -2, -2, -2, -2, -1, -1, 0, 0, + 0, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, + 4, 1, -2, -3, -3, -1, 1, 3, 4, 1, -2, -4, -3, -1, 1, 3, + 5, 1, -2, -4, -3, -1, 1, 4, 5, 1, -2, -3, -3, -1, 2, 4, + 5, 1, -2, -3, -3, -1, 2, 4, 4, 0, -3, -4, -3, -1, 2, 4, + 4, 0, -3, -3, -3, -1, 1, 3, 3, 0, -2, -3, -2, -1, 1, 3, + -3, -4, -4, -4, -4, -4, -4, -4, -1, -1, -1, -1, -1, -1, -2, -2, + 2, 1, 1, 2, 2, 1, 1, 1, 3, 3, 3, 4, 4, 3, 3, 3, + 3, 3, 3, 4, 4, 4, 3, 3, 1, 2, 1, 2, 2, 2, 2, 2, + -2, -2, -2, -1, -1, -1, 0, 0, -4, -4, -4, -4, -3, -3, -3, -3, + -1, -2, -3, -3, -2, -2, -1, 0, 0, -1, -2, -2, -2, -1, 0, 1, + 2, 1, -1, -1, -1, -1, 0, 1, 3, 1, 0, -1, -1, 0, 0, 1, + 3, 2, 0, -1, 0, 0, 0, 1, 3, 1, 0, -1, 0, 0, 0, 1, + 3, 1, 0, -1, 0, 0, 0, 1, 2, 1, 0, 0, 0, 0, 0, 1, + 0, 0, 0, 1, 1, 2, 3, 4, 0, 0, -1, 0, 0, 0, 2, 3, + 0, -1, -1, -1, -1, -1, 0, 1, 0, -1, -1, -1, -1, -1, -1, 0, + 0, 0, -1, -1, -1, -2, -2, -1, 1, 0, 0, -1, -1, -2, -2, -1, + 2, 2, 1, 0, -1, -1, -1, -1, 3, 3, 2, 1, 0, -1, -1, 0, + 1, 0, 1, 0, 0, -1, -2, -1, 0, 0, 0, 0, -1, -1, -2, -1, + 0, -1, 0, 0, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, + -1, -1, -1, 0, 0, 0, 1, 1, -1, -1, -1, 0, 1, 1, 2, 3, + -2, -2, -1, 0, 1, 2, 3, 4, -2, -2, -1, 0, 1, 2, 4, 5, + -3, -1, 1, 0, 0, -1, 0, 1, -3, 0, 1, 0, -1, -1, 0, 2, + -3, 0, 1, 0, -1, -1, 0, 2, -2, 1, 2, 0, -1, -1, 0, 2, + -2, 1, 2, 0, -1, -1, 0, 2, -2, 1, 2, 0, -1, -1, 0, 2, + -1, 2, 2, 0, -1, -1, 0, 2, -1, 1, 1, 0, -1, -1, -1, 1, + -2, -2, -1, 1, 3, 4, 3, 1, -2, -2, -1, 0, 2, 3, 2, 0, + -2, -2, -1, 0, 1, 2, 1, -1, -1, -1, -1, 0, 1, 2, 1, -1, + -1, -1, -1, 0, 1, 1, 0, -2, 0, -1, -1, 0, 1, 1, 0, -1, + 0, -1, -1, 0, 1, 1, 1, -1, 0, -1, -1, 0, 0, 1, 0, -1, + -2, -1, 0, 1, 1, 1, 1, 1, -2, -1, 0, 0, 0, 0, 0, 0, + -2, -1, -1, 0, -1, -1, -2, -2, -2, -1, -1, -1, -1, -2, -2, -3, + -1, 0, 1, 1, 0, -1, -2, -2, 1, 2, 3, 3, 2, 1, 0, 0, + 1, 2, 3, 3, 3, 2, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, + 0, -1, -1, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, -1, 0, 0, 1, 1, 0, 0, 0, + -3, -2, -1, -1, -1, -1, 0, -1, -5, -5, -4, -3, -2, -2, -2, -1, + 1, 1, 1, 1, 2, 1, 0, -1, 1, 1, 1, 2, 1, 1, 0, -1, + 1, 1, 1, 1, 1, 1, 0, -2, 2, 1, 1, 1, 1, 1, 0, -2, + 1, 1, 0, 0, 0, 0, -1, -3, 1, 1, 0, 0, 0, -1, -2, -3, + 1, 1, 0, 0, -1, -1, -2, -4, 1, 0, 0, -1, -2, -2, -3, -4, + 8, 7, 5, 3, 2, 1, 1, 1, 2, 1, 0, 0, -1, -1, -2, -1, + -1, -1, -1, -2, -2, -2, -2, -1, -1, -1, -1, -1, 0, -1, -1, 0, + 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, + -1, 0, 0, 0, 0, 0, -1, -1, -2, -2, -1, -1, -1, -2, -2, -1, + 9, 4, 0, -2, -2, -2, -1, -1, 7, 2, -1, -2, -2, -1, 0, 0, + 4, 0, -2, -2, -1, 0, 1, 1, 1, -2, -2, -2, -1, 0, 1, 1, + -1, -2, -2, -1, 0, 1, 1, 1, -1, -2, -1, 0, 1, 1, 1, 0, + -1, -1, 0, 1, 1, 1, 0, -1, 0, -1, 0, 1, 0, 0, -1, -1, + 0, 1, 1, 1, 1, 1, 0, 0, 1, 2, 2, 2, 1, 0, 0, 0, + 2, 2, 2, 2, 1, 0, -1, -1, 1, 1, 1, 0, -1, -2, -2, -2, + 0, 0, 0, -1, -2, -3, -2, -2, -1, -1, -1, -2, -2, -2, -1, 0, + -1, -1, -1, -1, 0, 0, 1, 2, -1, -1, -1, 0, 1, 2, 3, 4, + -1, -1, 0, 0, -1, -2, -3, -3, -1, -1, 0, 0, 0, -1, -1, -1, + -2, -2, -1, 0, 1, 1, 1, 1, -2, -2, -2, 0, 1, 2, 3, 3, + -1, -1, -1, 0, 1, 3, 3, 3, 1, 0, 0, 0, 1, 1, 2, 2, + 2, 2, 1, 0, 0, -1, -1, -1, 3, 2, 1, 0, -1, -2, -3, -3, + -1, -1, -1, -2, -2, -3, -4, -5, 0, 0, 0, -1, -1, -3, -3, -4, + 1, 1, 1, 0, 0, -1, -2, -3, 2, 2, 2, 1, 1, 0, -1, -1, + 2, 2, 2, 2, 1, 1, 0, -1, 2, 2, 2, 2, 2, 1, 0, 0, + 1, 1, 2, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, -1, + -2, 2, 3, 1, -1, 1, 1, -1, -3, 2, 3, 0, -1, 1, 1, -1, + -3, 2, 3, 0, -1, 1, 1, -1, -4, 2, 3, 0, -1, 1, 1, -2, + -4, 1, 3, 0, -1, 1, 1, -2, -4, 1, 3, -1, -2, 1, 1, -2, + -3, 1, 2, 0, -1, 1, 1, -2, -3, 1, 2, 0, -1, 1, 1, -1, + -1, -1, -1, -2, -2, -2, -2, -2, 1, 1, 1, 1, 0, 0, 0, 0, + 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, 1, 1, 1, 2, 2, 2, + -2, -2, -1, -1, -1, 0, 0, 0, -3, -3, -3, -3, -3, -3, -3, -2, + -1, -1, -1, -1, -2, -2, -2, -2, 4, 4, 4, 4, 4, 3, 3, 2, + -3, -3, -2, -1, 0, 1, 2, 5, -3, -3, -3, -2, -1, 1, 3, 6, + -3, -3, -2, -2, 0, 2, 3, 5, -3, -2, -2, -2, 0, 1, 3, 5, + -2, -2, -2, -1, -1, 1, 3, 5, -2, -2, -1, -1, 0, 1, 2, 4, + -1, -1, -1, -1, 0, 1, 1, 4, -1, -1, -1, -1, 0, 1, 2, 3, + 0, -1, 0, 1, 1, 0, -1, -1, 0, 0, 0, 1, 2, 0, -1, -1, + 1, 0, -1, 0, 1, 0, 0, 0, 1, -1, -2, -1, 0, 0, 0, 0, + 1, -2, -3, -1, 0, 0, 0, 1, 1, -1, -3, -2, 0, 1, 1, 2, + 1, -1, -2, -1, 0, 1, 1, 2, 2, 0, -1, 0, 1, 1, 2, 2, + 1, 1, 1, 1, 0, 0, 1, 2, -1, 0, 0, -1, 0, 0, 0, 1, + -3, -2, -1, -1, -1, 0, 1, 1, -4, -2, -1, 0, 0, 1, 1, 1, + -3, -2, 0, 0, 1, 1, 1, 1, -3, -1, 0, 1, 1, 1, 0, 0, + -1, 0, 1, 1, 1, 0, 0, -1, 0, 1, 2, 2, 1, 0, 0, -1, + -4, -4, -4, -3, -2, -1, -1, -1, -2, -2, -2, -1, 0, 0, 0, 0, + -1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, + 0, 0, 1, 1, 2, 2, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, + 0, 0, 0, 1, 1, 1, 1, 0, -1, 0, 0, 1, 1, 1, 0, 0, + 1, 2, 2, 2, 1, -1, -2, -4, 1, 1, 2, 2, 1, 0, -2, -4, + 0, 1, 1, 1, 1, 0, -1, -3, -1, 0, 1, 1, 0, 0, -1, -2, + -1, 0, 1, 1, 1, 0, 0, -1, -2, -1, 0, 0, 0, 0, 0, -1, + -1, -1, 0, 1, 1, 0, 0, 0, -1, 0, 1, 1, 1, 1, 1, 0, + 2, 2, 0, -1, -2, -1, -1, -2, 1, 1, -1, -2, -2, -1, -1, -2, + 1, 1, -1, -2, -2, 0, 0, -1, 1, 1, 0, -2, -1, 1, 1, 0, + 1, 1, 0, -1, -1, 1, 2, 1, 1, 1, 0, -1, -1, 1, 2, 1, + 1, 1, 0, -1, -1, 1, 1, 1, 1, 1, 0, -1, 0, 1, 1, 1, + 0, 0, -1, -2, -4, -4, -4, -4, 3, 3, 3, 2, 1, 0, 0, 0, + 3, 3, 3, 3, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, + -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1, 0, + -1, -1, 0, -1, -1, 1, 2, -1, 1, 1, 0, 0, 0, 2, 3, -1, + 1, 1, 0, -1, -1, 1, 3, -1, 1, 1, 0, -2, -2, 0, 1, -2, + 1, 0, 0, -2, -2, 0, 1, -3, 0, 0, 0, 0, -1, 1, 1, -3, + 0, 1, 1, 0, 1, 2, 1, -3, -1, 0, 1, 1, 1, 2, 1, -4, + -4, -3, 0, 1, 1, 1, 0, 0, -4, -2, 0, 1, 1, 1, 0, -1, + -3, -1, 1, 1, 1, 0, -1, -1, -1, 1, 1, 1, 1, 0, -1, 0, + 1, 2, 2, 1, 0, -1, 0, 0, 2, 2, 1, 0, -1, -1, 0, 1, + 2, 1, 0, -1, -2, -1, 0, 1, 2, 2, 0, -1, -2, -1, 1, 1, + 1, 1, 0, 0, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, -1, -1, -1, -1, -1, + 1, 0, 0, -1, -1, -1, -1, -1, 2, 1, 0, 0, -1, -1, -1, -1, + 5, 3, 2, 1, 0, 0, 0, 0, 6, 5, 3, 2, 1, 0, 0, 0, + 4, 4, 3, 1, 0, 0, 0, 1, 3, 3, 2, 1, 0, 0, 0, 1, + 2, 2, 1, 0, -1, -1, 0, 1, 0, 0, 0, -1, -1, -1, 0, 1, + 0, 0, -1, -1, -2, -1, 0, 2, 0, -1, -1, -2, -2, -2, 0, 1, + 0, -1, -1, -2, -2, -2, -1, 0, 0, 0, -1, -2, -2, -2, -1, 0, + 0, 0, -1, -1, -1, 0, 2, 3, 0, -1, -2, -2, -1, -1, 1, 2, + 1, 0, -1, -1, -1, 0, 0, 0, 1, 1, 1, 0, 0, 0, -1, -1, + 1, 2, 1, 0, 0, -1, -1, -1, -1, 0, 0, 0, -1, -1, -1, -1, + -3, -2, -1, -1, 0, 1, 1, 2, -4, -3, -1, 1, 2, 3, 5, 5, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, -1, 0, 0, 0, 1, -1, -1, -2, -2, -2, -1, -1, 0, + 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, + 1, 1, 1, 1, 2, 2, 1, 1, -4, -3, -4, -4, -4, -4, -3, -3, + -1, 0, 1, 2, 2, 3, 3, 3, -1, -1, -1, -1, 0, 0, 0, 0, + 0, 0, -1, -2, -2, -3, -3, -2, 3, 2, 1, 0, -1, -2, -2, -2, + 4, 3, 2, 1, 1, 0, 0, 0, 2, 2, 1, 1, 0, 1, 1, 1, + 0, -1, -1, -1, -1, 0, 0, 1, -2, -2, -2, -2, -2, -1, 0, 0, + 1, -1, 0, 2, 1, -2, -1, 1, 1, -1, 0, 2, 1, -2, -2, 1, + 1, -1, 0, 3, 2, -2, -1, 1, 0, -2, 0, 3, 2, -2, -2, 1, + 0, -2, 0, 3, 2, -2, -2, 1, 0, -2, 0, 3, 1, -2, -1, 1, + 0, -2, 0, 2, 1, -2, -2, 1, 0, -1, 0, 2, 1, -2, -1, 1, + 0, 1, 2, 2, 3, 3, 2, 2, 0, 1, 1, 2, 3, 3, 2, 1, + 0, 0, 1, 2, 2, 2, 2, 1, -1, 0, 0, 1, 1, 1, 1, 1, + -1, -1, 0, 0, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, + -2, -2, -2, -2, -2, -2, -2, -1, -2, -2, -2, -2, -2, -2, -2, -1, + 0, 0, -1, -2, -1, 0, 3, 5, 0, 0, -1, -1, -1, 0, 2, 4, + 1, 1, 0, 0, -1, -1, 1, 2, 1, 2, 1, 1, 0, -1, -1, 0, + 0, 1, 2, 1, 0, -1, -2, -2, -1, 0, 1, 2, 1, 0, -3, -3, + -2, -1, 1, 2, 2, 0, -2, -4, -2, -1, 0, 2, 2, 1, -1, -3, + 0, 0, 0, 0, 0, 0, -1, -1, 0, 0, -1, 0, 0, 0, 0, 0, + -1, -1, -1, -1, 0, 0, 0, 0, -1, -1, -1, -1, -1, -1, -1, 0, + -1, -1, -1, -1, -1, -1, -1, 0, -1, 0, 0, 0, 0, -1, -1, 0, + 0, 0, 1, 1, 0, 0, 0, 1, 3, 3, 3, 4, 3, 3, 3, 3, + 5, 1, -2, -2, 0, 0, 0, -1, 4, -1, -3, -1, 0, 0, 0, -1, + 3, -1, -1, 0, 1, 1, 0, -1, 2, 0, 0, 1, 1, 1, 0, -2, + 1, 0, 0, 1, 1, 1, 0, -2, 0, -1, -1, -1, 0, 0, 0, -1, + 0, -1, -1, -1, -1, 0, 0, -1, 2, 1, 0, 0, 0, 1, 0, 0, + 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, + 1, -1, -1, 0, 0, 0, 0, 0, 2, 0, -1, -1, -1, -1, -1, 0, + 3, 1, -1, -1, -2, -2, -2, -1, 4, 2, 1, 0, -1, -2, -2, -1, + 2, 1, 0, 0, -1, -1, 0, 0, 0, -1, -1, -1, -1, 0, 1, 1, + 0, 1, 2, 2, 2, 1, -1, -3, 0, 0, 1, 1, 1, 0, -1, -2, + 0, 0, 0, 0, 0, 0, -1, -1, 0, 0, -1, 0, 0, 1, 1, 0, + 0, 0, -1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, + 0, 0, 1, 1, 2, 1, -1, -3, 0, 0, 0, 1, 1, -1, -4, -5, + -2, -2, -2, -1, 0, 2, 2, 2, 0, 0, 0, 0, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 0, -2, -3, 0, 0, 1, 1, 0, -1, -3, -4, + -1, -1, 0, 1, 0, 0, -2, -3, -1, -1, 0, 1, 1, 1, 0, -1, + 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 1, 0, 0, 1, 1, 1, 2, 1, 2, 0, 0, 0, 0, -1, 1, + 0, 2, 0, -1, 1, 0, -1, 0, 0, 1, 0, 0, 2, 1, 0, 1, + 0, 1, -1, 0, 2, 2, 0, 1, -1, 0, -1, -1, 2, 1, 1, 2, + -2, -2, -3, -2, 0, 1, 1, 1, -2, -2, -3, -3, -1, -1, -1, 0, + -3, -1, 0, 1, 2, 1, 1, 0, -3, -1, 0, 1, 2, 1, 1, 1, + -2, 0, 0, 1, 1, 1, 1, 1, -1, 0, 0, 0, 0, 0, 0, 0, + -2, 0, 0, 0, 0, -1, -1, 0, -2, 0, 0, 0, 0, 0, -1, -1, + -3, 0, 1, 1, 1, 1, 0, 1, -5, -2, 0, 1, 2, 2, 1, 2, + -2, -1, -1, 0, 0, 1, 2, 3, 0, 0, 1, 1, 0, 0, 1, 2, + 0, 0, 1, 0, -1, -1, 0, 1, -1, -1, -1, -1, -2, -2, -1, 0, + -2, -2, -2, -2, -2, -1, 0, 1, 0, 0, 0, -1, 0, 1, 2, 2, + 2, 1, 0, 0, 0, 1, 2, 2, 2, 1, 0, -1, -1, -1, 0, 0, + 0, 1, 1, 1, 1, 1, -1, -4, -1, -1, 0, 1, 1, 1, 0, -3, + -2, -1, 0, 0, 1, 2, 2, -2, -1, 0, 0, 0, 0, 2, 3, -1, + -1, 0, 0, 0, 0, 1, 2, 0, 0, 0, -1, -2, -1, 1, 1, 0, + 0, 0, -1, -2, -2, 0, 2, 1, 0, 0, -1, -2, -1, 1, 2, 2, + 1, 0, 0, 0, -2, -3, -2, -3, 0, 0, 1, 0, -2, -2, -1, -1, + 0, -1, 1, 1, -1, -1, 0, 0, 0, -1, 1, 1, -1, -1, 0, 0, + 0, 1, 2, 1, -1, -1, 0, 1, 1, 2, 3, 2, 0, 0, 1, 2, + -1, 0, 2, 1, 0, 0, 2, 3, -2, -1, 0, 0, -1, 0, 1, 2, + 1, 1, 0, -1, -2, -2, -1, 1, 1, 1, 1, -1, -2, -2, 0, 2, + 1, 1, 1, -1, -1, -1, 0, 2, 0, 0, 0, 0, 0, 0, 1, 2, + -1, -1, -1, 0, 0, 0, 1, 2, -1, -2, -1, 1, 1, 1, 0, 0, + -1, -2, -1, 1, 2, 2, 0, -1, -1, -2, -1, 2, 2, 2, 0, -1, + -1, -1, -1, -2, -1, -1, 0, 1, 0, 0, -1, -1, -1, 0, 1, 2, + 1, 0, 0, 0, 0, 1, 1, 2, 1, 1, 0, 0, 1, 1, 1, 1, + 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, -1, -1, -1, + 1, 2, 1, 0, -1, -2, -2, -3, 2, 2, 1, 0, -2, -3, -4, -4, + -4, -2, 1, 1, 1, 1, 0, 0, -2, 0, 1, 0, 0, 0, 0, 0, + 0, 1, 1, -2, -2, -1, 0, 1, 2, 2, 1, -2, -2, -1, 1, 2, + 1, 2, 1, -2, -2, -1, 1, 2, -1, 1, 1, -1, -1, -1, 0, 1, + -2, 0, 1, 1, 0, -1, -1, 0, -2, 0, 2, 2, 1, -1, -1, 0, + 1, 1, 0, 0, 0, 1, 0, 0, -2, -3, -3, -2, -2, -1, 0, 0, + -3, -4, -3, -2, -1, 0, 0, 0, -1, -1, 0, 1, 2, 3, 2, 1, + 0, 1, 2, 3, 3, 3, 2, 1, 1, 1, 1, 2, 1, 0, 0, -1, + 0, 0, 0, 0, -1, -1, -1, -1, 0, -1, -1, 0, 0, 0, 0, 0, + 1, 1, 0, 0, -1, -1, 0, 2, 0, 0, 1, 0, -1, -1, 1, 1, + -2, -1, 0, 1, 1, 1, 1, 1, -3, -3, 0, 2, 2, 1, 1, 0, + -2, -2, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, -1, -1, + 3, 1, -1, -3, -2, -1, 0, 1, 4, 2, -1, -3, -3, -1, 1, 2, + 0, 0, 0, -1, -1, -1, -1, -1, 1, 2, 1, 0, 0, 0, -1, -1, + 2, 3, 3, 2, 1, 0, -1, -1, 3, 4, 4, 2, 1, 0, -1, -2, + 3, 3, 2, 1, 0, -1, -2, -2, 1, 1, 0, -1, -1, -2, -2, -3, + 0, 0, 0, -1, -1, -2, -2, -2, -1, -1, -1, -1, -1, -2, -2, -1, + 1, 2, 2, 2, 2, 1, 2, 2, 0, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 0, 1, 1, 0, -1, -2, 0, 0, 0, 0, 1, 0, -1, -4, + 1, 0, 0, 0, 0, 0, -2, -5, 1, 0, 0, 0, 0, 0, -1, -4, + 1, 0, -1, 0, 0, 0, -1, -3, 0, -1, -1, 0, 1, 1, 1, -1, + -2, -1, 0, 0, -1, -1, -1, -2, -1, 0, 0, 0, -1, -1, -2, -2, + 0, 1, 1, 0, -1, -1, -1, -2, 0, 1, 1, 0, 0, 0, -1, -1, + 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 2, 2, 1, + 1, 1, 0, 0, 1, 2, 2, 1, 1, 1, 0, -1, 0, 1, 1, 0, + 4, 2, 1, 0, 0, 1, 1, 1, 4, 2, 1, 0, 0, 0, 0, 1, + 3, 1, 0, 0, -1, -1, -1, 0, 1, 0, 0, -1, -1, -2, -1, 0, + 0, 0, 0, 0, -1, -1, -1, 0, -1, -1, 0, 0, -1, -1, 0, 1, + -2, -1, 0, -1, -1, 0, 0, 1, -2, -2, -1, -2, -1, 0, 0, 1, + 0, 1, 1, 1, 2, 1, 0, -1, -1, -1, -1, 0, 0, -1, -2, -2, + -1, 0, -1, 0, 0, -1, -2, -1, 0, 0, 0, 0, 0, 0, 1, 2, + 0, 0, 0, 0, 0, 0, 2, 3, -1, 0, -1, -1, -1, -1, 0, 3, + -1, 0, 0, -1, -1, -2, 0, 3, 0, 0, 0, 0, -1, -1, 1, 4, + 2, 2, 0, 0, 0, 0, 0, 1, 1, 1, -1, -2, -1, -2, -1, 1, + -1, -1, -2, -2, -2, -3, -2, 0, -1, 0, -1, -1, -1, -2, -1, 1, + 1, 1, 0, 0, 1, 0, 0, 1, 2, 2, 0, 0, 1, 0, 0, 1, + 2, 2, 0, 0, 0, 0, -1, -1, 2, 2, 0, 0, 1, 0, -1, -1, + -1, 0, 1, 1, 0, -1, -1, -1, 1, 2, 3, 2, 1, 0, 0, 0, + 0, 1, 1, 1, 0, -1, 0, 0, -2, -2, -1, 0, 1, 0, 0, 0, + -2, -2, -1, 2, 2, 2, 1, 0, -2, -1, 0, 1, 1, 0, 0, -1, + -1, -1, 0, 0, -1, -2, -1, -2, 0, 1, 1, 1, 0, 0, 1, 1, + -3, -3, -3, -2, -1, -1, -2, -2, -1, -1, 0, 1, 2, 1, 0, 0, + 1, 1, 1, 2, 2, 1, 0, 0, 1, 1, 1, 1, 1, 0, -1, 1, + 1, 0, -1, -1, 0, 0, -1, 1, 0, -1, -1, -1, 0, -1, -1, 1, + 1, 0, -1, 0, 0, -1, 0, 2, 2, 0, -1, 0, 0, 0, 0, 2, + 1, 0, -2, -1, 0, 1, 1, 0, 2, 0, -1, -1, 0, 1, 1, 0, + 1, 0, -2, -1, 0, 1, 0, -1, 1, 0, -1, -1, 0, 1, 0, -1, + 0, 1, 1, 0, 1, 1, 0, 0, -2, 1, 2, 1, 0, 0, 0, 1, + -5, 0, 2, 1, 0, -1, 0, 1, -6, -1, 2, 1, 0, -1, 0, 0, + 5, 3, 0, -1, -2, -1, -1, -1, 1, 1, 0, -1, -1, 0, -1, -1, + -1, 0, 1, 1, 2, 2, 1, 0, -2, -1, 0, 1, 2, 1, 1, 1, + -2, -1, -1, -1, 0, -1, 0, 1, 0, 1, 0, 0, -1, -1, 0, 0, + 0, 1, 1, 1, 1, 0, 0, 0, -3, -2, 0, 1, 1, 0, 0, -1, + -1, 0, 1, 0, -1, 0, 2, 3, -1, 0, 0, -2, -4, -2, -1, 0, + 0, 1, 1, 0, -2, -1, 0, -1, 1, 2, 3, 1, 0, 1, 1, 0, + -1, 0, 1, 1, 1, 1, 1, 0, -2, -3, -2, 0, 0, 0, 1, 0, + -1, -2, -2, 0, 1, 0, 0, -1, 3, 1, 0, 0, 1, 0, -1, -1, + -2, -1, 0, 0, -1, -1, 0, 0, -1, 0, 0, 0, 0, 1, 1, 1, + -1, -1, -1, 0, 1, 1, 1, 1, 0, -2, -3, -1, 1, 0, 0, 0, + 1, -1, -3, -1, 1, 1, 0, -1, 3, 1, -1, 1, 2, 2, 0, -1, + 3, 1, 0, 1, 2, 1, 1, 0, 0, -2, -2, -1, -1, 0, 0, 0, + 1, 0, -1, -1, 1, 2, 1, 0, 0, -1, -2, -1, 1, 2, 2, 1, + -1, -1, -1, 0, 0, 1, 2, 0, -2, 0, 0, 0, 0, 0, 1, -1, + -1, 0, 1, 0, -1, -1, -1, -1, 0, 1, 1, 2, 0, -2, -1, 0, + 1, 2, 2, 2, 1, -1, -1, 0, 0, 1, 1, 1, 0, -2, -2, -1, + 0, 0, -1, -1, -1, -1, -2, -2, 0, 0, -1, 0, 1, 2, 2, 1, + 0, 0, -1, -1, 0, 1, 2, 2, 1, 1, -1, -2, -1, -1, -1, -1, + 2, 2, 1, 0, 0, -1, -2, -2, 1, 2, 2, 1, 0, 0, -2, -2, + 0, 0, 0, 0, 1, 1, 0, -1, 0, -1, -1, -1, 2, 3, 2, 1, + 0, -2, 1, 2, -1, 0, 0, 1, -1, -2, 2, 3, -1, 0, 0, 0, + 0, -2, 2, 3, -1, -1, 0, 0, 0, -1, 3, 2, -2, 0, 1, 0, + 0, -1, 3, 1, -2, 0, 1, 0, 0, -1, 2, 1, -1, 1, 0, -1, + 0, 0, 1, -1, -2, 0, 0, -1, 1, 0, 0, -2, -2, -1, -1, -1, + 1, 1, 1, 1, 1, -1, -1, -2, 0, 0, 0, 1, 1, 1, 1, 1, + 0, 0, 0, 1, 1, 1, 2, 3, 1, 0, 0, -1, 0, 0, 1, 2, + 0, -1, -1, -2, -1, 0, 1, 2, -2, -2, -2, -2, -1, 0, 1, 1, + -1, -1, -1, -1, 0, 0, 0, -1, 2, 2, 2, 0, -1, -1, -2, -4, + -1, -2, -1, -1, 0, 1, 2, 3, -1, -1, -1, -1, 0, 1, 2, 3, + 1, 0, -1, 0, -1, 0, 1, 2, 1, 0, 0, 0, -1, 0, 2, 2, + 1, 0, -1, -1, -2, 0, 1, 2, 0, -2, -2, -2, -3, -1, 0, 1, + 0, -2, -2, -2, -2, -1, 1, 1, 0, 0, 0, 0, 0, 1, 2, 2 }; -const uint32 *const s_svq1IntraCodebooks[6] = { +static const int8 *const s_svq1IntraCodebooks[6] = { s_svq1IntraCodebook4x2, s_svq1IntraCodebook4x4, s_svq1IntraCodebook8x4, s_svq1IntraCodebook8x8, 0, 0 diff --git a/video/coktel_decoder.cpp b/video/coktel_decoder.cpp index 0c7ade1b8a..5d7efe87af 100644 --- a/video/coktel_decoder.cpp +++ b/video/coktel_decoder.cpp @@ -53,7 +53,8 @@ CoktelDecoder::CoktelDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundT _mixer(mixer), _soundType(soundType), _width(0), _height(0), _x(0), _y(0), _defaultX(0), _defaultY(0), _features(0), _frameCount(0), _paletteDirty(false), _ownSurface(true), _frameRate(12), _hasSound(false), _soundEnabled(false), - _soundStage(kSoundNone), _audioStream(0) { + _soundStage(kSoundNone), _audioStream(0), _startTime(0), _pauseStartTime(0), + _isPaused(false) { assert(_mixer); @@ -261,6 +262,10 @@ bool CoktelDecoder::isPaletted() const { return true; } +int CoktelDecoder::getCurFrame() const { + return _curFrame; +} + void CoktelDecoder::close() { disableSound(); freeSurface(); @@ -273,9 +278,22 @@ void CoktelDecoder::close() { _features = 0; - _frameCount = 0; + _curFrame = -1; + _frameCount = 0; + + _startTime = 0; _hasSound = false; + + _isPaused = false; +} + +Audio::Mixer::SoundType CoktelDecoder::getSoundType() const { + return _soundType; +} + +Audio::AudioStream *CoktelDecoder::getAudioStream() const { + return _audioStream; } uint16 CoktelDecoder::getWidth() const { @@ -291,6 +309,7 @@ uint32 CoktelDecoder::getFrameCount() const { } const byte *CoktelDecoder::getPalette() { + _paletteDirty = false; return _palette; } @@ -625,14 +644,45 @@ Common::Rational CoktelDecoder::getFrameRate() const { return _frameRate; } +uint32 CoktelDecoder::getTimeToNextFrame() const { + if (endOfVideo() || _curFrame < 0) + return 0; + + uint32 elapsedTime = g_system->getMillis() - _startTime; + uint32 nextFrameStartTime = (Common::Rational((_curFrame + 1) * 1000) / getFrameRate()).toInt(); + + if (nextFrameStartTime <= elapsedTime) + return 0; + + return nextFrameStartTime - elapsedTime; +} + uint32 CoktelDecoder::getStaticTimeToNextFrame() const { return (1000 / _frameRate).toInt(); } +void CoktelDecoder::pauseVideo(bool pause) { + if (_isPaused != pause) { + if (_isPaused) { + // Add the time we were paused to the initial starting time + _startTime += g_system->getMillis() - _pauseStartTime; + } else { + // Store the time we paused for use later + _pauseStartTime = g_system->getMillis(); + } + + _isPaused = pause; + } +} + inline void CoktelDecoder::unsignedToSigned(byte *buffer, int length) { while (length-- > 0) *buffer++ ^= 0x80; } +bool CoktelDecoder::endOfVideo() const { + return !isVideoLoaded() || (getCurFrame() >= (int32)getFrameCount() - 1); +} + PreIMDDecoder::PreIMDDecoder(uint16 width, uint16 height, Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : CoktelDecoder(mixer, soundType), @@ -705,8 +755,6 @@ bool PreIMDDecoder::loadStream(Common::SeekableReadStream *stream) { } void PreIMDDecoder::close() { - reset(); - CoktelDecoder::close(); delete _stream; @@ -1159,8 +1207,6 @@ bool IMDDecoder::loadFrameTables(uint32 framePosPos, uint32 frameCoordsPos) { } void IMDDecoder::close() { - reset(); - CoktelDecoder::close(); delete _stream; @@ -1225,8 +1271,6 @@ void IMDDecoder::processFrame() { _dirtyRects.clear(); - _paletteDirty = false; - uint32 cmd = 0; bool hasNextCmd = false; bool startSound = false; @@ -1273,7 +1317,7 @@ void IMDDecoder::processFrame() { // Set palette if (cmd == kCommandPalette) { _stream->skip(2); - + _paletteDirty = true; for (int i = 0; i < 768; i++) @@ -1322,7 +1366,7 @@ void IMDDecoder::processFrame() { // Start the audio stream if necessary if (startSound && _soundEnabled) { _mixer->playStream(_soundType, &_audioHandle, _audioStream, - -1, getVolume(), getBalance(), DisposeAfterUse::NO); + -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO); _soundStage = kSoundPlaying; } @@ -1504,16 +1548,6 @@ Graphics::PixelFormat IMDDecoder::getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } -void IMDDecoder::updateVolume() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) - g_system->getMixer()->setChannelVolume(_audioHandle, getVolume()); -} - -void IMDDecoder::updateBalance() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) - g_system->getMixer()->setChannelBalance(_audioHandle, getBalance()); -} - VMDDecoder::File::File() { offset = 0; @@ -1552,7 +1586,7 @@ VMDDecoder::VMDDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : _soundLastFilledFrame(0), _audioFormat(kAudioFormat8bitRaw), _hasVideo(false), _videoCodec(0), _blitMode(0), _bytesPerPixel(0), _firstFramePos(0), _videoBufferSize(0), _externalCodec(false), _codec(0), - _subtitle(-1), _isPaletted(true) { + _subtitle(-1), _isPaletted(true), _autoStartSound(true) { _videoBuffer [0] = 0; _videoBuffer [1] = 0; @@ -2014,8 +2048,6 @@ bool VMDDecoder::readFiles() { } void VMDDecoder::close() { - reset(); - CoktelDecoder::close(); delete _stream; @@ -2095,7 +2127,6 @@ void VMDDecoder::processFrame() { _dirtyRects.clear(); - _paletteDirty = false; _subtitle = -1; bool startSound = false; @@ -2215,8 +2246,9 @@ void VMDDecoder::processFrame() { if (startSound && _soundEnabled) { if (_hasSound && _audioStream) { - _mixer->playStream(_soundType, &_audioHandle, _audioStream, - -1, getVolume(), getBalance(), DisposeAfterUse::NO); + if (_autoStartSound) + _mixer->playStream(_soundType, &_audioHandle, _audioStream, + -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO); _soundStage = kSoundPlaying; } else _soundStage = kSoundNone; @@ -2742,14 +2774,92 @@ bool VMDDecoder::isPaletted() const { return _isPaletted; } -void VMDDecoder::updateVolume() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) - g_system->getMixer()->setChannelVolume(_audioHandle, getVolume()); +void VMDDecoder::setAutoStartSound(bool autoStartSound) { + _autoStartSound = autoStartSound; +} + +AdvancedVMDDecoder::AdvancedVMDDecoder(Audio::Mixer::SoundType soundType) { + _decoder = new VMDDecoder(g_system->getMixer(), soundType); + _decoder->setAutoStartSound(false); +} + +AdvancedVMDDecoder::~AdvancedVMDDecoder() { + close(); + delete _decoder; +} + +bool AdvancedVMDDecoder::loadStream(Common::SeekableReadStream *stream) { + close(); + + if (!_decoder->loadStream(stream)) + return false; + + if (_decoder->hasVideo()) { + _videoTrack = new VMDVideoTrack(_decoder); + addTrack(_videoTrack); + } + + if (_decoder->hasSound()) { + _audioTrack = new VMDAudioTrack(_decoder); + addTrack(_audioTrack); + } + + return true; +} + +void AdvancedVMDDecoder::close() { + VideoDecoder::close(); + _decoder->close(); +} + +AdvancedVMDDecoder::VMDVideoTrack::VMDVideoTrack(VMDDecoder *decoder) : _decoder(decoder) { +} + +uint16 AdvancedVMDDecoder::VMDVideoTrack::getWidth() const { + return _decoder->getWidth(); +} + +uint16 AdvancedVMDDecoder::VMDVideoTrack::getHeight() const { + return _decoder->getHeight(); +} + +Graphics::PixelFormat AdvancedVMDDecoder::VMDVideoTrack::getPixelFormat() const { + return _decoder->getPixelFormat(); +} + +int AdvancedVMDDecoder::VMDVideoTrack::getCurFrame() const { + return _decoder->getCurFrame(); +} + +int AdvancedVMDDecoder::VMDVideoTrack::getFrameCount() const { + return _decoder->getFrameCount(); +} + +const Graphics::Surface *AdvancedVMDDecoder::VMDVideoTrack::decodeNextFrame() { + return _decoder->decodeNextFrame(); +} + +const byte *AdvancedVMDDecoder::VMDVideoTrack::getPalette() const { + return _decoder->getPalette(); +} + +bool AdvancedVMDDecoder::VMDVideoTrack::hasDirtyPalette() const { + return _decoder->hasDirtyPalette(); +} + +Common::Rational AdvancedVMDDecoder::VMDVideoTrack::getFrameRate() const { + return _decoder->getFrameRate(); +} + +AdvancedVMDDecoder::VMDAudioTrack::VMDAudioTrack(VMDDecoder *decoder) : _decoder(decoder) { +} + +Audio::Mixer::SoundType AdvancedVMDDecoder::VMDAudioTrack::getSoundType() const { + return _decoder->getSoundType(); } -void VMDDecoder::updateBalance() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) - g_system->getMixer()->setChannelBalance(_audioHandle, getBalance()); +Audio::AudioStream *AdvancedVMDDecoder::VMDAudioTrack::getAudioStream() const { + return _decoder->getAudioStream(); } } // End of namespace Video diff --git a/video/coktel_decoder.h b/video/coktel_decoder.h index c88d982191..91d52b65e6 100644 --- a/video/coktel_decoder.h +++ b/video/coktel_decoder.h @@ -64,7 +64,7 @@ class Codec; * - gob * - sci */ -class CoktelDecoder : public FixedRateVideoDecoder { +class CoktelDecoder { public: struct State { /** Set accordingly to what was done. */ @@ -77,7 +77,7 @@ public: CoktelDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); - ~CoktelDecoder(); + virtual ~CoktelDecoder(); /** Replace the current video stream with this identical one. */ virtual bool reloadStream(Common::SeekableReadStream *stream) = 0; @@ -98,6 +98,8 @@ public: /** Override the video's frame rate. */ void setFrameRate(Common::Rational frameRate); + /** Get the video's frame rate. */ + Common::Rational getFrameRate() const; /** Get the video's default X position. */ uint16 getDefaultX() const; @@ -138,21 +140,52 @@ public: /** Is the video paletted or true color? */ virtual bool isPaletted() const; + /** + * Get the current frame + * @see VideoDecoder::getCurFrame() + */ + int getCurFrame() const; + + /** + * Decode the next frame + * @see VideoDecoder::decodeNextFrame() + */ + virtual const Graphics::Surface *decodeNextFrame() = 0; + + /** + * Load a video from a stream + * @see VideoDecoder::loadStream() + */ + virtual bool loadStream(Common::SeekableReadStream *stream) = 0; - // VideoDecoder interface + /** Has a video been loaded? */ + virtual bool isVideoLoaded() const = 0; + /** Has the end of the video been reached? */ + bool endOfVideo() const; + + /** Close the video. */ void close(); + /** Get the Mixer SoundType audio is being played with. */ + Audio::Mixer::SoundType getSoundType() const; + /** Get the AudioStream for the audio. */ + Audio::AudioStream *getAudioStream() const; + uint16 getWidth() const; uint16 getHeight() const; + virtual Graphics::PixelFormat getPixelFormat() const = 0; uint32 getFrameCount() const; const byte *getPalette(); bool hasDirtyPalette() const; + uint32 getTimeToNextFrame() const; uint32 getStaticTimeToNextFrame() const; + void pauseVideo(bool pause); + protected: enum SoundStage { kSoundNone = 0, ///< No sound. @@ -186,8 +219,11 @@ protected: uint32 _features; + int32 _curFrame; uint32 _frameCount; + uint32 _startTime; + byte _palette[768]; bool _paletteDirty; @@ -228,10 +264,9 @@ protected: // Sound helper functions inline void unsignedToSigned(byte *buffer, int length); - - // FixedRateVideoDecoder interface - - Common::Rational getFrameRate() const; +private: + uint32 _pauseStartTime; + bool _isPaused; }; class PreIMDDecoder : public CoktelDecoder { @@ -244,9 +279,6 @@ public: bool seek(int32 frame, int whence = SEEK_SET, bool restart = false); - - // VideoDecoder interface - bool loadStream(Common::SeekableReadStream *stream); void close(); @@ -279,9 +311,6 @@ public: void setXY(uint16 x, uint16 y); - - // VideoDecoder interface - bool loadStream(Common::SeekableReadStream *stream); void close(); @@ -291,11 +320,6 @@ public: Graphics::PixelFormat getPixelFormat() const; -protected: - // VideoDecoder API - void updateVolume(); - void updateBalance(); - private: enum Command { kCommandNextSound = 0xFF00, @@ -367,6 +391,8 @@ private: }; class VMDDecoder : public CoktelDecoder { +friend class AdvancedVMDDecoder; + public: VMDDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); ~VMDDecoder(); @@ -390,9 +416,6 @@ public: bool hasVideo() const; bool isPaletted() const; - - // VideoDecoder interface - bool loadStream(Common::SeekableReadStream *stream); void close(); @@ -403,9 +426,7 @@ public: Graphics::PixelFormat getPixelFormat() const; protected: - // VideoDecoder API - void updateVolume(); - void updateBalance(); + void setAutoStartSound(bool autoStartSound); private: enum PartType { @@ -478,6 +499,7 @@ private: uint32 _soundDataSize; uint32 _soundLastFilledFrame; AudioFormat _audioFormat; + bool _autoStartSound; // Video properties bool _hasVideo; @@ -532,6 +554,57 @@ private: bool getPartCoords(int16 frame, PartType type, int16 &x, int16 &y, int16 &width, int16 &height); }; +/** + * A wrapper around the VMD code that implements the VideoDecoder + * API. + */ +class AdvancedVMDDecoder : public VideoDecoder { +public: + AdvancedVMDDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType); + ~AdvancedVMDDecoder(); + + bool loadStream(Common::SeekableReadStream *stream); + void close(); + +private: + class VMDVideoTrack : public FixedRateVideoTrack { + public: + VMDVideoTrack(VMDDecoder *decoder); + + uint16 getWidth() const; + uint16 getHeight() const; + Graphics::PixelFormat getPixelFormat() const; + int getCurFrame() const; + int getFrameCount() const; + const Graphics::Surface *decodeNextFrame(); + const byte *getPalette() const; + bool hasDirtyPalette() const; + + protected: + Common::Rational getFrameRate() const; + + private: + VMDDecoder *_decoder; + }; + + class VMDAudioTrack : public AudioTrack { + public: + VMDAudioTrack(VMDDecoder *decoder); + + Audio::Mixer::SoundType getSoundType() const; + + protected: + virtual Audio::AudioStream *getAudioStream() const; + + private: + VMDDecoder *_decoder; + }; + + VMDDecoder *_decoder; + VMDVideoTrack *_videoTrack; + VMDAudioTrack *_audioTrack; +}; + } // End of namespace Video #endif // VIDEO_COKTELDECODER_H diff --git a/video/dxa_decoder.cpp b/video/dxa_decoder.cpp index 7d1112a59c..5ac9bd2088 100644 --- a/video/dxa_decoder.cpp +++ b/video/dxa_decoder.cpp @@ -37,41 +37,43 @@ namespace Video { DXADecoder::DXADecoder() { - _fileStream = 0; - _surface = 0; - _dirtyPalette = false; +} - _frameBuffer1 = 0; - _frameBuffer2 = 0; - _scaledBuffer = 0; +DXADecoder::~DXADecoder() { + close(); +} - _inBuffer = 0; - _inBufferSize = 0; +bool DXADecoder::loadStream(Common::SeekableReadStream *stream) { + close(); - _decompBuffer = 0; - _decompBufferSize = 0; + uint32 tag = stream->readUint32BE(); - _width = 0; - _height = 0; + if (tag != MKTAG('D','E','X','A')) { + close(); + return false; + } - _frameSize = 0; - _frameCount = 0; - _frameRate = 0; + DXAVideoTrack *track = new DXAVideoTrack(stream); + addTrack(track); - _scaleMode = S_NONE; -} + readSoundData(stream); -DXADecoder::~DXADecoder() { - close(); + track->setFrameStartPos(); + return true; } -bool DXADecoder::loadStream(Common::SeekableReadStream *stream) { - close(); +void DXADecoder::readSoundData(Common::SeekableReadStream *stream) { + // Skip over the tag by default + stream->readUint32BE(); +} +DXADecoder::DXAVideoTrack::DXAVideoTrack(Common::SeekableReadStream *stream) { _fileStream = stream; - - uint32 tag = _fileStream->readUint32BE(); - assert(tag == MKTAG('D','E','X','A')); + _curFrame = -1; + _frameStartOffset = 0; + _decompBuffer = 0; + _inBuffer = 0; + memset(_palette, 0, 256 * 3); uint8 flags = _fileStream->readByte(); _frameCount = _fileStream->readUint16BE(); @@ -105,18 +107,14 @@ bool DXADecoder::loadStream(Common::SeekableReadStream *stream) { _frameSize = _width * _height; _decompBufferSize = _frameSize; - _frameBuffer1 = (uint8 *)malloc(_frameSize); + _frameBuffer1 = new byte[_frameSize]; memset(_frameBuffer1, 0, _frameSize); - _frameBuffer2 = (uint8 *)malloc(_frameSize); + _frameBuffer2 = new byte[_frameSize]; memset(_frameBuffer2, 0, _frameSize); - if (!_frameBuffer1 || !_frameBuffer2) - error("DXADecoder: Error allocating frame buffers (size %u)", _frameSize); _scaledBuffer = 0; if (_scaleMode != S_NONE) { - _scaledBuffer = (uint8 *)malloc(_frameSize); - if (!_scaledBuffer) - error("Error allocating scale buffer (size %u)", _frameSize); + _scaledBuffer = new byte[_frameSize]; memset(_scaledBuffer, 0, _frameSize); } @@ -148,36 +146,33 @@ bool DXADecoder::loadStream(Common::SeekableReadStream *stream) { } while (tag != 0); } #endif - - // Read the sound header - _soundTag = _fileStream->readUint32BE(); - - return true; } -void DXADecoder::close() { - if (!_fileStream) - return; - +DXADecoder::DXAVideoTrack::~DXAVideoTrack() { delete _fileStream; - _fileStream = 0; - delete _surface; - _surface = 0; + delete[] _frameBuffer1; + delete[] _frameBuffer2; + delete[] _scaledBuffer; + delete[] _inBuffer; + delete[] _decompBuffer; +} - free(_frameBuffer1); - free(_frameBuffer2); - free(_scaledBuffer); - free(_inBuffer); - free(_decompBuffer); +bool DXADecoder::DXAVideoTrack::rewind() { + _curFrame = -1; + _fileStream->seek(_frameStartOffset); + return true; +} - _inBuffer = 0; - _decompBuffer = 0; +Graphics::PixelFormat DXADecoder::DXAVideoTrack::getPixelFormat() const { + return _surface->format; +} - reset(); +void DXADecoder::DXAVideoTrack::setFrameStartPos() { + _frameStartOffset = _fileStream->pos(); } -void DXADecoder::decodeZlib(byte *data, int size, int totalSize) { +void DXADecoder::DXAVideoTrack::decodeZlib(byte *data, int size, int totalSize) { #ifdef USE_ZLIB unsigned long dstLen = totalSize; Common::uncompress(data, &dstLen, _inBuffer, size); @@ -187,14 +182,13 @@ void DXADecoder::decodeZlib(byte *data, int size, int totalSize) { #define BLOCKW 4 #define BLOCKH 4 -void DXADecoder::decode12(int size) { +void DXADecoder::DXAVideoTrack::decode12(int size) { #ifdef USE_ZLIB - if (_decompBuffer == NULL) { - _decompBuffer = (byte *)malloc(_decompBufferSize); + if (!_decompBuffer) { + _decompBuffer = new byte[_decompBufferSize]; memset(_decompBuffer, 0, _decompBufferSize); - if (_decompBuffer == NULL) - error("Error allocating decomp buffer (size %u)", _decompBufferSize); } + /* decompress the input data */ decodeZlib(_decompBuffer, size, _decompBufferSize); @@ -287,15 +281,13 @@ void DXADecoder::decode12(int size) { #endif } -void DXADecoder::decode13(int size) { +void DXADecoder::DXAVideoTrack::decode13(int size) { #ifdef USE_ZLIB uint8 *codeBuf, *dataBuf, *motBuf, *maskBuf; - if (_decompBuffer == NULL) { - _decompBuffer = (byte *)malloc(_decompBufferSize); + if (!_decompBuffer) { + _decompBuffer = new byte[_decompBufferSize]; memset(_decompBuffer, 0, _decompBufferSize); - if (_decompBuffer == NULL) - error("Error allocating decomp buffer (size %u)", _decompBufferSize); } /* decompress the input data */ @@ -475,7 +467,7 @@ void DXADecoder::decode13(int size) { #endif } -const Graphics::Surface *DXADecoder::decodeNextFrame() { +const Graphics::Surface *DXADecoder::DXAVideoTrack::decodeNextFrame() { uint32 tag = _fileStream->readUint32BE(); if (tag == MKTAG('C','M','A','P')) { _fileStream->read(_palette, 256 * 3); @@ -486,11 +478,10 @@ const Graphics::Surface *DXADecoder::decodeNextFrame() { if (tag == MKTAG('F','R','A','M')) { byte type = _fileStream->readByte(); uint32 size = _fileStream->readUint32BE(); - if ((_inBuffer == NULL) || (_inBufferSize < size)) { - free(_inBuffer); - _inBuffer = (byte *)malloc(size); - if (_inBuffer == NULL) - error("Error allocating input buffer (size %u)", size); + + if (!_inBuffer || _inBufferSize < size) { + delete[] _inBuffer; + _inBuffer = new byte[size]; memset(_inBuffer, 0, size); _inBufferSize = size; } @@ -551,9 +542,6 @@ const Graphics::Surface *DXADecoder::decodeNextFrame() { _curFrame++; - if (_curFrame == 0) - _startTime = g_system->getMillis(); - return _surface; } diff --git a/video/dxa_decoder.h b/video/dxa_decoder.h index d13cd3076c..b3f2eca5e2 100644 --- a/video/dxa_decoder.h +++ b/video/dxa_decoder.h @@ -41,62 +41,74 @@ namespace Video { * - sword1 * - sword2 */ -class DXADecoder : public FixedRateVideoDecoder { +class DXADecoder : public VideoDecoder { public: DXADecoder(); virtual ~DXADecoder(); bool loadStream(Common::SeekableReadStream *stream); - void close(); - - bool isVideoLoaded() const { return _fileStream != 0; } - uint16 getWidth() const { return _width; } - uint16 getHeight() const { return _height; } - uint32 getFrameCount() const { return _frameCount; } - const Graphics::Surface *decodeNextFrame(); - Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } - const byte *getPalette() { _dirtyPalette = false; return _palette; } - bool hasDirtyPalette() const { return _dirtyPalette; } +protected: /** - * Get the sound chunk tag of the loaded DXA file + * Read the sound data out of the given DXA stream */ - uint32 getSoundTag() { return _soundTag; } - -protected: - Common::Rational getFrameRate() const { return _frameRate; } - - Common::SeekableReadStream *_fileStream; + virtual void readSoundData(Common::SeekableReadStream *stream); private: - void decodeZlib(byte *data, int size, int totalSize); - void decode12(int size); - void decode13(int size); - - enum ScaleMode { - S_NONE, - S_INTERLACED, - S_DOUBLE + class DXAVideoTrack : public FixedRateVideoTrack { + public: + DXAVideoTrack(Common::SeekableReadStream *stream); + ~DXAVideoTrack(); + + bool isRewindable() const { return true; } + bool rewind(); + + uint16 getWidth() const { return _width; } + uint16 getHeight() const { return _height; } + Graphics::PixelFormat getPixelFormat() const; + int getCurFrame() const { return _curFrame; } + int getFrameCount() const { return _frameCount; } + const Graphics::Surface *decodeNextFrame(); + const byte *getPalette() const { _dirtyPalette = false; return _palette; } + bool hasDirtyPalette() const { return _dirtyPalette; } + + void setFrameStartPos(); + + protected: + Common::Rational getFrameRate() const { return _frameRate; } + + private: + void decodeZlib(byte *data, int size, int totalSize); + void decode12(int size); + void decode13(int size); + + enum ScaleMode { + S_NONE, + S_INTERLACED, + S_DOUBLE + }; + + Common::SeekableReadStream *_fileStream; + Graphics::Surface *_surface; + + byte *_frameBuffer1; + byte *_frameBuffer2; + byte *_scaledBuffer; + byte *_inBuffer; + uint32 _inBufferSize; + byte *_decompBuffer; + uint32 _decompBufferSize; + uint16 _curHeight; + uint32 _frameSize; + ScaleMode _scaleMode; + uint16 _width, _height; + uint32 _frameRate; + uint32 _frameCount; + byte _palette[256 * 3]; + mutable bool _dirtyPalette; + int _curFrame; + uint32 _frameStartOffset; }; - - Graphics::Surface *_surface; - byte _palette[256 * 3]; - bool _dirtyPalette; - - byte *_frameBuffer1; - byte *_frameBuffer2; - byte *_scaledBuffer; - byte *_inBuffer; - uint32 _inBufferSize; - byte *_decompBuffer; - uint32 _decompBufferSize; - uint16 _curHeight; - uint32 _frameSize; - ScaleMode _scaleMode; - uint32 _soundTag; - uint16 _width, _height; - uint32 _frameRate; - uint32 _frameCount; }; } // End of namespace Video diff --git a/video/flic_decoder.cpp b/video/flic_decoder.cpp index bdcdedc142..1a0627615b 100644 --- a/video/flic_decoder.cpp +++ b/video/flic_decoder.cpp @@ -26,13 +26,11 @@ #include "common/stream.h" #include "common/system.h" #include "common/textconsole.h" +#include "graphics/surface.h" namespace Video { FlicDecoder::FlicDecoder() { - _paletteChanged = false; - _fileStream = 0; - _surface = 0; } FlicDecoder::~FlicDecoder() { @@ -42,35 +40,59 @@ FlicDecoder::~FlicDecoder() { bool FlicDecoder::loadStream(Common::SeekableReadStream *stream) { close(); - _fileStream = stream; - - /* uint32 frameSize = */ _fileStream->readUint32LE(); - uint16 frameType = _fileStream->readUint16LE(); + /* uint32 frameSize = */ stream->readUint32LE(); + uint16 frameType = stream->readUint16LE(); // Check FLC magic number if (frameType != 0xAF12) { - warning("FlicDecoder::FlicDecoder(): attempted to load non-FLC data (type = 0x%04X)", frameType); - delete _fileStream; - _fileStream = 0; + warning("FlicDecoder::loadStream(): attempted to load non-FLC data (type = 0x%04X)", frameType); return false; } - - _frameCount = _fileStream->readUint16LE(); - uint16 width = _fileStream->readUint16LE(); - uint16 height = _fileStream->readUint16LE(); - uint16 colorDepth = _fileStream->readUint16LE(); + uint16 frameCount = stream->readUint16LE(); + uint16 width = stream->readUint16LE(); + uint16 height = stream->readUint16LE(); + uint16 colorDepth = stream->readUint16LE(); if (colorDepth != 8) { - warning("FlicDecoder::FlicDecoder(): attempted to load an FLC with a palette of color depth %d. Only 8-bit color palettes are supported", frameType); - delete _fileStream; - _fileStream = 0; + warning("FlicDecoder::loadStream(): attempted to load an FLC with a palette of color depth %d. Only 8-bit color palettes are supported", colorDepth); return false; } + addTrack(new FlicVideoTrack(stream, frameCount, width, height)); + return true; +} + +const Common::List<Common::Rect> *FlicDecoder::getDirtyRects() const { + const Track *track = getTrack(0); + + if (track) + return ((const FlicVideoTrack *)track)->getDirtyRects(); + + return 0; +} + +void FlicDecoder::clearDirtyRects() { + Track *track = getTrack(0); + + if (track) + ((FlicVideoTrack *)track)->clearDirtyRects(); +} + +void FlicDecoder::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) { + Track *track = getTrack(0); + + if (track) + ((FlicVideoTrack *)track)->copyDirtyRectsToBuffer(dst, pitch); +} + +FlicDecoder::FlicVideoTrack::FlicVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height) { + _fileStream = stream; + _frameCount = frameCount; + _fileStream->readUint16LE(); // flags // Note: The normal delay is a 32-bit integer (dword), whereas the overridden delay is a 16-bit integer (word) // the frame delay is the FLIC "speed", in milliseconds. - _frameRate = Common::Rational(1000, _fileStream->readUint32LE()); + _frameDelay = _startFrameDelay = _fileStream->readUint32LE(); _fileStream->seek(80); _offsetFrame1 = _fileStream->readUint32LE(); @@ -78,112 +100,53 @@ bool FlicDecoder::loadStream(Common::SeekableReadStream *stream) { _surface = new Graphics::Surface(); _surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8()); - _palette = (byte *)malloc(3 * 256); + _palette = new byte[3 * 256]; memset(_palette, 0, 3 * 256); - _paletteChanged = false; + _dirtyPalette = false; + + _curFrame = -1; + _nextFrameStartTime = 0; + _atRingFrame = false; // Seek to the first frame _fileStream->seek(_offsetFrame1); - return true; } -void FlicDecoder::close() { - if (!_fileStream) - return; - +FlicDecoder::FlicVideoTrack::~FlicVideoTrack() { delete _fileStream; - _fileStream = 0; + delete[] _palette; _surface->free(); delete _surface; - _surface = 0; - - free(_palette); - _dirtyRects.clear(); - - reset(); } -void FlicDecoder::decodeByteRun(uint8 *data) { - byte *ptr = (byte *)_surface->pixels; - while ((int32)(ptr - (byte *)_surface->pixels) < (getWidth() * getHeight())) { - int chunks = *data++; - while (chunks--) { - int count = (int8)*data++; - if (count > 0) { - memset(ptr, *data++, count); - } else { - count = -count; - memcpy(ptr, data, count); - data += count; - } - ptr += count; - } - } - - // Redraw - _dirtyRects.clear(); - _dirtyRects.push_back(Common::Rect(0, 0, getWidth(), getHeight())); +bool FlicDecoder::FlicVideoTrack::endOfTrack() const { + return getCurFrame() >= getFrameCount() - 1; } -#define OP_PACKETCOUNT 0 -#define OP_UNDEFINED 1 -#define OP_LASTPIXEL 2 -#define OP_LINESKIPCOUNT 3 - -void FlicDecoder::decodeDeltaFLC(uint8 *data) { - uint16 linesInChunk = READ_LE_UINT16(data); data += 2; - uint16 currentLine = 0; - uint16 packetCount = 0; - - while (linesInChunk--) { - uint16 opcode; +bool FlicDecoder::FlicVideoTrack::rewind() { + _curFrame = -1; + _nextFrameStartTime = 0; - // First process all the opcodes. - do { - opcode = READ_LE_UINT16(data); data += 2; + if (endOfTrack() && _fileStream->pos() < _fileStream->size()) + _atRingFrame = true; + else + _fileStream->seek(_offsetFrame1); - switch ((opcode >> 14) & 3) { - case OP_PACKETCOUNT: - packetCount = opcode; - break; - case OP_UNDEFINED: - break; - case OP_LASTPIXEL: - *((byte *)_surface->pixels + currentLine * getWidth() + getWidth() - 1) = (opcode & 0xFF); - _dirtyRects.push_back(Common::Rect(getWidth() - 1, currentLine, getWidth(), currentLine + 1)); - break; - case OP_LINESKIPCOUNT: - currentLine += -(int16)opcode; - break; - } - } while (((opcode >> 14) & 3) != OP_PACKETCOUNT); + _frameDelay = _startFrameDelay; + return true; +} - uint16 column = 0; +uint16 FlicDecoder::FlicVideoTrack::getWidth() const { + return _surface->w; +} - // Now interpret the RLE data - while (packetCount--) { - column += *data++; - int rleCount = (int8)*data++; - if (rleCount > 0) { - memcpy((byte *)_surface->pixels + (currentLine * getWidth()) + column, data, rleCount * 2); - data += rleCount * 2; - _dirtyRects.push_back(Common::Rect(column, currentLine, column + rleCount * 2, currentLine + 1)); - } else if (rleCount < 0) { - rleCount = -rleCount; - uint16 dataWord = READ_UINT16(data); data += 2; - for (int i = 0; i < rleCount; ++i) { - WRITE_UINT16((byte *)_surface->pixels + currentLine * getWidth() + column + i * 2, dataWord); - } - _dirtyRects.push_back(Common::Rect(column, currentLine, column + rleCount * 2, currentLine + 1)); - } else { // End of cutscene ? - return; - } - column += rleCount * 2; - } +uint16 FlicDecoder::FlicVideoTrack::getHeight() const { + return _surface->h; +} - currentLine++; - } +Graphics::PixelFormat FlicDecoder::FlicVideoTrack::getPixelFormat() const { + return _surface->format; } #define FLI_SETPAL 4 @@ -192,7 +155,7 @@ void FlicDecoder::decodeDeltaFLC(uint8 *data) { #define PSTAMP 18 #define FRAME_TYPE 0xF1FA -const Graphics::Surface *FlicDecoder::decodeNextFrame() { +const Graphics::Surface *FlicDecoder::FlicVideoTrack::decodeNextFrame() { // Read chunk uint32 frameSize = _fileStream->readUint32LE(); uint16 frameType = _fileStream->readUint16LE(); @@ -201,15 +164,12 @@ const Graphics::Surface *FlicDecoder::decodeNextFrame() { switch (frameType) { case FRAME_TYPE: { - // FIXME: FLIC should be switched over to a variable frame rate VideoDecoder to handle - // this properly. - chunkCount = _fileStream->readUint16LE(); // Note: The overridden delay is a 16-bit integer (word), whereas the normal delay is a 32-bit integer (dword) // the frame delay is the FLIC "speed", in milliseconds. uint16 newFrameDelay = _fileStream->readUint16LE(); // "speed", in milliseconds if (newFrameDelay > 0) - _frameRate = Common::Rational(1000, newFrameDelay); + _frameDelay = newFrameDelay; _fileStream->readUint16LE(); // reserved, always 0 uint16 newWidth = _fileStream->readUint16LE(); @@ -240,10 +200,11 @@ const Graphics::Surface *FlicDecoder::decodeNextFrame() { frameType = _fileStream->readUint16LE(); uint8 *data = new uint8[frameSize - 6]; _fileStream->read(data, frameSize - 6); + switch (frameType) { case FLI_SETPAL: unpackPalette(data); - _paletteChanged = true; + _dirtyPalette = true; break; case FLI_SS2: decodeDeltaFLC(data); @@ -264,26 +225,111 @@ const Graphics::Surface *FlicDecoder::decodeNextFrame() { } _curFrame++; + _nextFrameStartTime += _frameDelay; - // If we just processed the ring frame, set the next frame - if (_curFrame == (int32)_frameCount) { - _curFrame = 0; + if (_atRingFrame) { + // If we decoded the ring frame, seek to the second frame + _atRingFrame = false; _fileStream->seek(_offsetFrame2); } - if (_curFrame == 0) - _startTime = g_system->getMillis(); - return _surface; } -void FlicDecoder::reset() { - FixedRateVideoDecoder::reset(); - if (_fileStream) - _fileStream->seek(_offsetFrame1); +void FlicDecoder::FlicVideoTrack::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) { + for (Common::List<Common::Rect>::const_iterator it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) { + for (int y = (*it).top; y < (*it).bottom; ++y) { + const int x = (*it).left; + memcpy(dst + y * pitch + x, (byte *)_surface->pixels + y * getWidth() + x, (*it).right - x); + } + } + + clearDirtyRects(); } -void FlicDecoder::unpackPalette(uint8 *data) { +void FlicDecoder::FlicVideoTrack::decodeByteRun(uint8 *data) { + byte *ptr = (byte *)_surface->pixels; + while ((int32)(ptr - (byte *)_surface->pixels) < (getWidth() * getHeight())) { + int chunks = *data++; + while (chunks--) { + int count = (int8)*data++; + if (count > 0) { + memset(ptr, *data++, count); + } else { + count = -count; + memcpy(ptr, data, count); + data += count; + } + ptr += count; + } + } + + // Redraw + _dirtyRects.clear(); + _dirtyRects.push_back(Common::Rect(0, 0, getWidth(), getHeight())); +} + +#define OP_PACKETCOUNT 0 +#define OP_UNDEFINED 1 +#define OP_LASTPIXEL 2 +#define OP_LINESKIPCOUNT 3 + +void FlicDecoder::FlicVideoTrack::decodeDeltaFLC(uint8 *data) { + uint16 linesInChunk = READ_LE_UINT16(data); data += 2; + uint16 currentLine = 0; + uint16 packetCount = 0; + + while (linesInChunk--) { + uint16 opcode; + + // First process all the opcodes. + do { + opcode = READ_LE_UINT16(data); data += 2; + + switch ((opcode >> 14) & 3) { + case OP_PACKETCOUNT: + packetCount = opcode; + break; + case OP_UNDEFINED: + break; + case OP_LASTPIXEL: + *((byte *)_surface->pixels + currentLine * getWidth() + getWidth() - 1) = (opcode & 0xFF); + _dirtyRects.push_back(Common::Rect(getWidth() - 1, currentLine, getWidth(), currentLine + 1)); + break; + case OP_LINESKIPCOUNT: + currentLine += -(int16)opcode; + break; + } + } while (((opcode >> 14) & 3) != OP_PACKETCOUNT); + + uint16 column = 0; + + // Now interpret the RLE data + while (packetCount--) { + column += *data++; + int rleCount = (int8)*data++; + if (rleCount > 0) { + memcpy((byte *)_surface->pixels + (currentLine * getWidth()) + column, data, rleCount * 2); + data += rleCount * 2; + _dirtyRects.push_back(Common::Rect(column, currentLine, column + rleCount * 2, currentLine + 1)); + } else if (rleCount < 0) { + rleCount = -rleCount; + uint16 dataWord = READ_UINT16(data); data += 2; + for (int i = 0; i < rleCount; ++i) { + WRITE_UINT16((byte *)_surface->pixels + currentLine * getWidth() + column + i * 2, dataWord); + } + _dirtyRects.push_back(Common::Rect(column, currentLine, column + rleCount * 2, currentLine + 1)); + } else { // End of cutscene ? + return; + } + column += rleCount * 2; + } + + currentLine++; + } +} + +void FlicDecoder::FlicVideoTrack::unpackPalette(uint8 *data) { uint16 numPackets = READ_LE_UINT16(data); data += 2; if (0 == READ_LE_UINT16(data)) { //special case @@ -308,14 +354,4 @@ void FlicDecoder::unpackPalette(uint8 *data) { } } -void FlicDecoder::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) { - for (Common::List<Common::Rect>::const_iterator it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) { - for (int y = (*it).top; y < (*it).bottom; ++y) { - const int x = (*it).left; - memcpy(dst + y * pitch + x, (byte *)_surface->pixels + y * getWidth() + x, (*it).right - x); - } - } - _dirtyRects.clear(); -} - } // End of namespace Video diff --git a/video/flic_decoder.h b/video/flic_decoder.h index 9badc3da2e..9037af05d6 100644 --- a/video/flic_decoder.h +++ b/video/flic_decoder.h @@ -25,15 +25,17 @@ #include "video/video_decoder.h" #include "common/list.h" -#include "common/rational.h" #include "common/rect.h" -#include "graphics/pixelformat.h" -#include "graphics/surface.h" namespace Common { class SeekableReadStream; } +namespace Graphics { +struct PixelFormat; +struct Surface; +} + namespace Video { /** @@ -42,58 +44,63 @@ namespace Video { * Video decoder used in engines: * - tucker */ -class FlicDecoder : public FixedRateVideoDecoder { +class FlicDecoder : public VideoDecoder { public: FlicDecoder(); virtual ~FlicDecoder(); - /** - * Load a video file - * @param stream the stream to load - */ bool loadStream(Common::SeekableReadStream *stream); - void close(); - - /** - * Decode the next frame and return the frame's surface - * @note the return surface should *not* be freed - * @note this may return 0, in which case the last frame should be kept on screen - */ - const Graphics::Surface *decodeNextFrame(); - - bool isVideoLoaded() const { return _fileStream != 0; } - uint16 getWidth() const { return _surface->w; } - uint16 getHeight() const { return _surface->h; } - uint32 getFrameCount() const { return _frameCount; } - Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } - - const Common::List<Common::Rect> *getDirtyRects() const { return &_dirtyRects; } - void clearDirtyRects() { _dirtyRects.clear(); } - void copyDirtyRectsToBuffer(uint8 *dst, uint pitch); - - const byte *getPalette() { _paletteChanged = false; return _palette; } - bool hasDirtyPalette() const { return _paletteChanged; } - void reset(); -protected: - Common::Rational getFrameRate() const { return _frameRate; } + const Common::List<Common::Rect> *getDirtyRects() const; + void clearDirtyRects(); + void copyDirtyRectsToBuffer(uint8 *dst, uint pitch); private: - uint16 _offsetFrame1; - uint16 _offsetFrame2; - byte *_palette; - bool _paletteChanged; - - void decodeByteRun(uint8 *data); - void decodeDeltaFLC(uint8 *data); - void unpackPalette(uint8 *mem); - - Common::SeekableReadStream *_fileStream; - Graphics::Surface *_surface; - uint32 _frameCount; - Common::Rational _frameRate; - - Common::List<Common::Rect> _dirtyRects; + class FlicVideoTrack : public VideoTrack { + public: + FlicVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height); + ~FlicVideoTrack(); + + bool endOfTrack() const; + bool isRewindable() const { return true; } + bool rewind(); + + uint16 getWidth() const; + uint16 getHeight() const; + Graphics::PixelFormat getPixelFormat() const; + int getCurFrame() const { return _curFrame; } + int getFrameCount() const { return _frameCount; } + uint32 getNextFrameStartTime() const { return _nextFrameStartTime; } + const Graphics::Surface *decodeNextFrame(); + const byte *getPalette() const { _dirtyPalette = false; return _palette; } + bool hasDirtyPalette() const { return _dirtyPalette; } + + const Common::List<Common::Rect> *getDirtyRects() const { return &_dirtyRects; } + void clearDirtyRects() { _dirtyRects.clear(); } + void copyDirtyRectsToBuffer(uint8 *dst, uint pitch); + + private: + Common::SeekableReadStream *_fileStream; + Graphics::Surface *_surface; + + int _curFrame; + bool _atRingFrame; + + uint16 _offsetFrame1; + uint16 _offsetFrame2; + byte *_palette; + mutable bool _dirtyPalette; + + uint32 _frameCount; + uint32 _frameDelay, _startFrameDelay; + uint32 _nextFrameStartTime; + + Common::List<Common::Rect> _dirtyRects; + + void decodeByteRun(uint8 *data); + void decodeDeltaFLC(uint8 *data); + void unpackPalette(uint8 *mem); + }; }; } // End of namespace Video diff --git a/video/module.mk b/video/module.mk index cebd403ca2..287e14ce18 100644 --- a/video/module.mk +++ b/video/module.mk @@ -26,5 +26,10 @@ MODULE_OBJS += \ bink_decoder.o endif +ifdef USE_THEORADEC +MODULE_OBJS += \ + theora_decoder.o +endif + # Include common rules include $(srcdir)/rules.mk diff --git a/video/psx_decoder.cpp b/video/psx_decoder.cpp index df91a2badd..fa7f1e8cfe 100644 --- a/video/psx_decoder.cpp +++ b/video/psx_decoder.cpp @@ -149,22 +149,12 @@ static const uint32 s_huffmanACSymbols[AC_CODE_COUNT] = { END_OF_BLOCK }; -PSXStreamDecoder::PSXStreamDecoder(CDSpeed speed, uint32 frameCount) : _nextFrameStartTime(0, speed), _frameCount(frameCount) { +PSXStreamDecoder::PSXStreamDecoder(CDSpeed speed, uint32 frameCount) : _speed(speed), _frameCount(frameCount) { _stream = 0; - _audStream = 0; - _surface = new Graphics::Surface(); - _yBuffer = _cbBuffer = _crBuffer = 0; - _acHuffman = new Common::Huffman(0, AC_CODE_COUNT, s_huffmanACCodes, s_huffmanACLengths, s_huffmanACSymbols); - _dcHuffmanChroma = new Common::Huffman(0, DC_CODE_COUNT, s_huffmanDCChromaCodes, s_huffmanDCChromaLengths, s_huffmanDCSymbols); - _dcHuffmanLuma = new Common::Huffman(0, DC_CODE_COUNT, s_huffmanDCLumaCodes, s_huffmanDCLumaLengths, s_huffmanDCSymbols); } PSXStreamDecoder::~PSXStreamDecoder() { close(); - delete _surface; - delete _acHuffman; - delete _dcHuffmanLuma; - delete _dcHuffmanChroma; } #define RAW_CD_SECTOR_SIZE 2352 @@ -178,95 +168,30 @@ bool PSXStreamDecoder::loadStream(Common::SeekableReadStream *stream) { close(); _stream = stream; - - Common::SeekableReadStream *sector = readSector(); - - if (!sector) { - close(); - return false; - } - - // Rip out video info from the first frame - sector->seek(18); - byte sectorType = sector->readByte() & CDXA_TYPE_MASK; - - if (sectorType != CDXA_TYPE_VIDEO && sectorType != CDXA_TYPE_DATA) { - close(); - return false; - } - - sector->seek(40); - - uint16 width = sector->readUint16LE(); - uint16 height = sector->readUint16LE(); - _surface->create(width, height, g_system->getScreenFormat()); - - _macroBlocksW = (width + 15) / 16; - _macroBlocksH = (height + 15) / 16; - _yBuffer = new byte[_macroBlocksW * _macroBlocksH * 16 * 16]; - _cbBuffer = new byte[_macroBlocksW * _macroBlocksH * 8 * 8]; - _crBuffer = new byte[_macroBlocksW * _macroBlocksH * 8 * 8]; - - delete sector; - _stream->seek(0); + readNextPacket(); return true; } void PSXStreamDecoder::close() { - if (!_stream) - return; + VideoDecoder::close(); + _audioTrack = 0; + _videoTrack = 0; + _frameCount = 0; delete _stream; _stream = 0; - - // Deinitialize sound - g_system->getMixer()->stopHandle(_audHandle); - _audStream = 0; - - _surface->free(); - - memset(&_adpcmStatus, 0, sizeof(_adpcmStatus)); - - _macroBlocksW = _macroBlocksH = 0; - delete[] _yBuffer; _yBuffer = 0; - delete[] _cbBuffer; _cbBuffer = 0; - delete[] _crBuffer; _crBuffer = 0; - - reset(); -} - -uint32 PSXStreamDecoder::getTime() const { - // TODO: Currently, the audio is always after the video so using this - // can often lead to gaps in the audio... - //if (_audStream) - // return _mixer->getSoundElapsedTime(_audHandle); - - return VideoDecoder::getTime(); -} - -uint32 PSXStreamDecoder::getTimeToNextFrame() const { - if (!isVideoLoaded() || endOfVideo()) - return 0; - - uint32 nextTimeMillis = _nextFrameStartTime.msecs(); - uint32 elapsedTime = getTime(); - - if (elapsedTime > nextTimeMillis) - return 0; - - return nextTimeMillis - elapsedTime; } #define VIDEO_DATA_CHUNK_SIZE 2016 #define VIDEO_DATA_HEADER_SIZE 56 -const Graphics::Surface *PSXStreamDecoder::decodeNextFrame() { +void PSXStreamDecoder::readNextPacket() { Common::SeekableReadStream *sector = 0; byte *partialFrame = 0; int sectorsRead = 0; - while (!endOfVideo()) { + while (_stream->pos() < _stream->size()) { sector = readSector(); sectorsRead++; @@ -284,6 +209,11 @@ const Graphics::Surface *PSXStreamDecoder::decodeNextFrame() { case CDXA_TYPE_DATA: case CDXA_TYPE_VIDEO: if (track == 1) { + if (!_videoTrack) { + _videoTrack = new PSXVideoTrack(sector, _speed, _frameCount); + addTrack(_videoTrack); + } + sector->seek(28); uint16 curSector = sector->readUint16LE(); uint16 sectorCount = sector->readUint16LE(); @@ -303,35 +233,27 @@ const Graphics::Surface *PSXStreamDecoder::decodeNextFrame() { // Done assembling the frame Common::SeekableReadStream *frame = new Common::MemoryReadStream(partialFrame, frameSize, DisposeAfterUse::YES); - decodeFrame(frame); + _videoTrack->decodeFrame(frame, sectorsRead); delete frame; delete sector; - - _curFrame++; - if (_curFrame == 0) - _startTime = g_system->getMillis(); - - // Increase the time by the amount of sectors we read - // One may notice that this is still not the most precise - // method since a frame takes up the time its sectors took - // up instead of the amount of time it takes the next frame - // to be read from the sectors. The actual frame rate should - // be constant instead of variable, so the slight difference - // in a frame's showing time is negligible (1/150 of a second). - _nextFrameStartTime = _nextFrameStartTime.addFrames(sectorsRead); - - return _surface; + return; } } else error("Unhandled multi-track video"); break; case CDXA_TYPE_AUDIO: // We only handle one audio channel so far - if (track == 1) - queueAudioFromSector(sector); - else + if (track == 1) { + if (!_audioTrack) { + _audioTrack = new PSXAudioTrack(sector); + addTrack(_audioTrack); + } + + _audioTrack->queueAudioFromSector(sector); + } else { warning("Unhandled multi-track audio"); + } break; default: // This shows up way too often, but the other sectors @@ -343,7 +265,19 @@ const Graphics::Surface *PSXStreamDecoder::decodeNextFrame() { delete sector; } - return 0; + if (_stream->pos() >= _stream->size()) { + if (_videoTrack) + _videoTrack->setEndOfTrack(); + + if (_audioTrack) + _audioTrack->setEndOfTrack(); + } +} + +bool PSXStreamDecoder::useAudioSync() const { + // Audio sync is disabled since most audio data comes after video + // data. + return false; } static const byte s_syncHeader[12] = { 0x00, 0xff ,0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; @@ -373,20 +307,29 @@ static const int s_xaTable[5][2] = { { 122, -60 } }; -void PSXStreamDecoder::queueAudioFromSector(Common::SeekableReadStream *sector) { +PSXStreamDecoder::PSXAudioTrack::PSXAudioTrack(Common::SeekableReadStream *sector) { assert(sector); + _endOfTrack = false; - if (!_audStream) { - // Initialize audio stream - sector->seek(19); - byte format = sector->readByte(); + sector->seek(19); + byte format = sector->readByte(); + bool stereo = (format & (1 << 0)) != 0; + uint rate = (format & (1 << 2)) ? 18900 : 37800; + _audStream = Audio::makeQueuingAudioStream(rate, stereo); - bool stereo = (format & (1 << 0)) != 0; - uint rate = (format & (1 << 2)) ? 18900 : 37800; + memset(&_adpcmStatus, 0, sizeof(_adpcmStatus)); +} - _audStream = Audio::makeQueuingAudioStream(rate, stereo); - g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_audHandle, _audStream, -1, getVolume(), getBalance()); - } +PSXStreamDecoder::PSXAudioTrack::~PSXAudioTrack() { + delete _audStream; +} + +bool PSXStreamDecoder::PSXAudioTrack::endOfTrack() const { + return AudioTrack::endOfTrack() && _endOfTrack; +} + +void PSXStreamDecoder::PSXAudioTrack::queueAudioFromSector(Common::SeekableReadStream *sector) { + assert(sector); sector->seek(24); @@ -472,7 +415,54 @@ void PSXStreamDecoder::queueAudioFromSector(Common::SeekableReadStream *sector) delete[] buf; } -void PSXStreamDecoder::decodeFrame(Common::SeekableReadStream *frame) { +Audio::AudioStream *PSXStreamDecoder::PSXAudioTrack::getAudioStream() const { + return _audStream; +} + + +PSXStreamDecoder::PSXVideoTrack::PSXVideoTrack(Common::SeekableReadStream *firstSector, CDSpeed speed, int frameCount) : _nextFrameStartTime(0, speed), _frameCount(frameCount) { + assert(firstSector); + + firstSector->seek(40); + uint16 width = firstSector->readUint16LE(); + uint16 height = firstSector->readUint16LE(); + _surface = new Graphics::Surface(); + _surface->create(width, height, g_system->getScreenFormat()); + + _macroBlocksW = (width + 15) / 16; + _macroBlocksH = (height + 15) / 16; + _yBuffer = new byte[_macroBlocksW * _macroBlocksH * 16 * 16]; + _cbBuffer = new byte[_macroBlocksW * _macroBlocksH * 8 * 8]; + _crBuffer = new byte[_macroBlocksW * _macroBlocksH * 8 * 8]; + + _endOfTrack = false; + _curFrame = -1; + _acHuffman = new Common::Huffman(0, AC_CODE_COUNT, s_huffmanACCodes, s_huffmanACLengths, s_huffmanACSymbols); + _dcHuffmanChroma = new Common::Huffman(0, DC_CODE_COUNT, s_huffmanDCChromaCodes, s_huffmanDCChromaLengths, s_huffmanDCSymbols); + _dcHuffmanLuma = new Common::Huffman(0, DC_CODE_COUNT, s_huffmanDCLumaCodes, s_huffmanDCLumaLengths, s_huffmanDCSymbols); +} + +PSXStreamDecoder::PSXVideoTrack::~PSXVideoTrack() { + _surface->free(); + delete _surface; + + delete[] _yBuffer; + delete[] _cbBuffer; + delete[] _crBuffer; + delete _acHuffman; + delete _dcHuffmanChroma; + delete _dcHuffmanLuma; +} + +uint32 PSXStreamDecoder::PSXVideoTrack::getNextFrameStartTime() const { + return _nextFrameStartTime.msecs(); +} + +const Graphics::Surface *PSXStreamDecoder::PSXVideoTrack::decodeNextFrame() { + return _surface; +} + +void PSXStreamDecoder::PSXVideoTrack::decodeFrame(Common::SeekableReadStream *frame, uint sectorCount) { // A frame is essentially an MPEG-1 intra frame Common::BitStream16LEMSB bits(frame); @@ -494,9 +484,20 @@ void PSXStreamDecoder::decodeFrame(Common::SeekableReadStream *frame) { // Output data onto the frame Graphics::convertYUV420ToRGB(_surface, _yBuffer, _cbBuffer, _crBuffer, _surface->w, _surface->h, _macroBlocksW * 16, _macroBlocksW * 8); + + _curFrame++; + + // Increase the time by the amount of sectors we read + // One may notice that this is still not the most precise + // method since a frame takes up the time its sectors took + // up instead of the amount of time it takes the next frame + // to be read from the sectors. The actual frame rate should + // be constant instead of variable, so the slight difference + // in a frame's showing time is negligible (1/150 of a second). + _nextFrameStartTime = _nextFrameStartTime.addFrames(sectorCount); } -void PSXStreamDecoder::decodeMacroBlock(Common::BitStream *bits, int mbX, int mbY, uint16 scale, uint16 version) { +void PSXStreamDecoder::PSXVideoTrack::decodeMacroBlock(Common::BitStream *bits, int mbX, int mbY, uint16 scale, uint16 version) { int pitchY = _macroBlocksW * 16; int pitchC = _macroBlocksW * 8; @@ -533,7 +534,7 @@ static const byte s_quantizationTable[8 * 8] = { 27, 29, 35, 38, 46, 56, 69, 83 }; -void PSXStreamDecoder::dequantizeBlock(int *coefficients, float *block, uint16 scale) { +void PSXStreamDecoder::PSXVideoTrack::dequantizeBlock(int *coefficients, float *block, uint16 scale) { // Dequantize the data, un-zig-zagging as we go along for (int i = 0; i < 8 * 8; i++) { if (i == 0) // Special case for the DC coefficient @@ -543,7 +544,7 @@ void PSXStreamDecoder::dequantizeBlock(int *coefficients, float *block, uint16 s } } -int PSXStreamDecoder::readDC(Common::BitStream *bits, uint16 version, PlaneType plane) { +int PSXStreamDecoder::PSXVideoTrack::readDC(Common::BitStream *bits, uint16 version, PlaneType plane) { // Version 2 just has its coefficient as 10-bits if (version == 2) return readSignedCoefficient(bits); @@ -573,7 +574,7 @@ int PSXStreamDecoder::readDC(Common::BitStream *bits, uint16 version, PlaneType if (count > 63) \ error("PSXStreamDecoder::readAC(): Too many coefficients") -void PSXStreamDecoder::readAC(Common::BitStream *bits, int *block) { +void PSXStreamDecoder::PSXVideoTrack::readAC(Common::BitStream *bits, int *block) { // Clear the block first for (int i = 0; i < 63; i++) block[i] = 0; @@ -608,7 +609,7 @@ void PSXStreamDecoder::readAC(Common::BitStream *bits, int *block) { } } -int PSXStreamDecoder::readSignedCoefficient(Common::BitStream *bits) { +int PSXStreamDecoder::PSXVideoTrack::readSignedCoefficient(Common::BitStream *bits) { uint val = bits->getBits(10); // extend the sign @@ -630,7 +631,7 @@ static const double s_idct8x8[8][8] = { { 0.353553390593274, -0.490392640201615, 0.461939766255643, -0.415734806151273, 0.353553390593273, -0.277785116509801, 0.191341716182545, -0.097545161008064 } }; -void PSXStreamDecoder::idct(float *dequantData, float *result) { +void PSXStreamDecoder::PSXVideoTrack::idct(float *dequantData, float *result) { // IDCT code based on JPEG's IDCT code // TODO: Switch to the integer-based one mentioned in the docs // This is by far the costliest operation here @@ -669,7 +670,7 @@ void PSXStreamDecoder::idct(float *dequantData, float *result) { } } -void PSXStreamDecoder::decodeBlock(Common::BitStream *bits, byte *block, int pitch, uint16 scale, uint16 version, PlaneType plane) { +void PSXStreamDecoder::PSXVideoTrack::decodeBlock(Common::BitStream *bits, byte *block, int pitch, uint16 scale, uint16 version, PlaneType plane) { // Version 2 just has signed 10 bits for DC // Version 3 has them huffman coded int coefficients[8 * 8]; @@ -686,22 +687,13 @@ void PSXStreamDecoder::decodeBlock(Common::BitStream *bits, byte *block, int pit // Now output the data for (int y = 0; y < 8; y++) { - byte *start = block + pitch * y; + byte *dst = block + pitch * y; // Convert the result to be in the range [0, 255] for (int x = 0; x < 8; x++) - *start++ = (int)CLIP<float>(idctData[y * 8 + x], -128.0f, 127.0f) + 128; + *dst++ = (int)CLIP<float>(idctData[y * 8 + x], -128.0f, 127.0f) + 128; } } -void PSXStreamDecoder::updateVolume() { - if (g_system->getMixer()->isSoundHandleActive(_audHandle)) - g_system->getMixer()->setChannelVolume(_audHandle, getVolume()); -} - -void PSXStreamDecoder::updateBalance() { - if (g_system->getMixer()->isSoundHandleActive(_audHandle)) - g_system->getMixer()->setChannelBalance(_audHandle, getBalance()); -} } // End of namespace Video diff --git a/video/psx_decoder.h b/video/psx_decoder.h index 4364ec4bbb..11f311594d 100644 --- a/video/psx_decoder.h +++ b/video/psx_decoder.h @@ -71,59 +71,85 @@ public: bool loadStream(Common::SeekableReadStream *stream); void close(); - bool isVideoLoaded() const { return _stream != 0; } - uint16 getWidth() const { return _surface->w; } - uint16 getHeight() const { return _surface->h; } - uint32 getFrameCount() const { return _frameCount; } - uint32 getTime() const; - uint32 getTimeToNextFrame() const; - const Graphics::Surface *decodeNextFrame(); - Graphics::PixelFormat getPixelFormat() const { return _surface->format; } - bool endOfVideo() const { return _stream->pos() >= _stream->size(); } - protected: - // VideoDecoder API - void updateVolume(); - void updateBalance(); + void readNextPacket(); + bool useAudioSync() const; private: - void initCommon(); - Common::SeekableReadStream *_stream; - Graphics::Surface *_surface; + class PSXVideoTrack : public VideoTrack { + public: + PSXVideoTrack(Common::SeekableReadStream *firstSector, CDSpeed speed, int frameCount); + ~PSXVideoTrack(); + + uint16 getWidth() const { return _surface->w; } + uint16 getHeight() const { return _surface->h; } + Graphics::PixelFormat getPixelFormat() const { return _surface->format; } + bool endOfTrack() const { return _endOfTrack; } + int getCurFrame() const { return _curFrame; } + int getFrameCount() const { return _frameCount; } + uint32 getNextFrameStartTime() const; + const Graphics::Surface *decodeNextFrame(); + + void setEndOfTrack() { _endOfTrack = true; } + void decodeFrame(Common::SeekableReadStream *frame, uint sectorCount); + + private: + Graphics::Surface *_surface; + uint32 _frameCount; + Audio::Timestamp _nextFrameStartTime; + bool _endOfTrack; + int _curFrame; + + enum PlaneType { + kPlaneY = 0, + kPlaneU = 1, + kPlaneV = 2 + }; + + uint16 _macroBlocksW, _macroBlocksH; + byte *_yBuffer, *_cbBuffer, *_crBuffer; + void decodeMacroBlock(Common::BitStream *bits, int mbX, int mbY, uint16 scale, uint16 version); + void decodeBlock(Common::BitStream *bits, byte *block, int pitch, uint16 scale, uint16 version, PlaneType plane); + + void readAC(Common::BitStream *bits, int *block); + Common::Huffman *_acHuffman; + + int readDC(Common::BitStream *bits, uint16 version, PlaneType plane); + Common::Huffman *_dcHuffmanLuma, *_dcHuffmanChroma; + int _lastDC[3]; + + void dequantizeBlock(int *coefficients, float *block, uint16 scale); + void idct(float *dequantData, float *result); + int readSignedCoefficient(Common::BitStream *bits); + }; - uint32 _frameCount; - Audio::Timestamp _nextFrameStartTime; + class PSXAudioTrack : public AudioTrack { + public: + PSXAudioTrack(Common::SeekableReadStream *sector); + ~PSXAudioTrack(); - Audio::SoundHandle _audHandle; - Audio::QueuingAudioStream *_audStream; - void queueAudioFromSector(Common::SeekableReadStream *sector); + bool endOfTrack() const; - enum PlaneType { - kPlaneY = 0, - kPlaneU = 1, - kPlaneV = 2 - }; + void setEndOfTrack() { _endOfTrack = true; } + void queueAudioFromSector(Common::SeekableReadStream *sector); - uint16 _macroBlocksW, _macroBlocksH; - byte *_yBuffer, *_cbBuffer, *_crBuffer; - void decodeFrame(Common::SeekableReadStream *frame); - void decodeMacroBlock(Common::BitStream *bits, int mbX, int mbY, uint16 scale, uint16 version); - void decodeBlock(Common::BitStream *bits, byte *block, int pitch, uint16 scale, uint16 version, PlaneType plane); + private: + Audio::AudioStream *getAudioStream() const; - void readAC(Common::BitStream *bits, int *block); - Common::Huffman *_acHuffman; + Audio::QueuingAudioStream *_audStream; - int readDC(Common::BitStream *bits, uint16 version, PlaneType plane); - Common::Huffman *_dcHuffmanLuma, *_dcHuffmanChroma; - int _lastDC[3]; + struct ADPCMStatus { + int16 sample[2]; + } _adpcmStatus[2]; - void dequantizeBlock(int *coefficients, float *block, uint16 scale); - void idct(float *dequantData, float *result); - int readSignedCoefficient(Common::BitStream *bits); + bool _endOfTrack; + }; - struct ADPCMStatus { - int16 sample[2]; - } _adpcmStatus[2]; + CDSpeed _speed; + uint32 _frameCount; + Common::SeekableReadStream *_stream; + PSXVideoTrack *_videoTrack; + PSXAudioTrack *_audioTrack; Common::SeekableReadStream *readSector(); }; diff --git a/video/qt_decoder.cpp b/video/qt_decoder.cpp index aba545abc0..87c530dba0 100644 --- a/video/qt_decoder.cpp +++ b/video/qt_decoder.cpp @@ -33,14 +33,12 @@ #include "audio/audiostream.h" #include "common/debug.h" -#include "common/endian.h" #include "common/memstream.h" #include "common/system.h" #include "common/textconsole.h" #include "common/util.h" // Video codecs -#include "video/codecs/codec.h" #include "video/codecs/cinepak.h" #include "video/codecs/mjpeg.h" #include "video/codecs/qtrle.h" @@ -56,97 +54,43 @@ namespace Video { //////////////////////////////////////////// QuickTimeDecoder::QuickTimeDecoder() { - _setStartTime = false; _scaledSurface = 0; - _dirtyPalette = false; - _palette = 0; _width = _height = 0; - _needUpdate = false; } QuickTimeDecoder::~QuickTimeDecoder() { close(); } -int32 QuickTimeDecoder::getCurFrame() const { - // TODO: This is rather simplistic and doesn't take edits that - // repeat sections of the media into account. Doing that - // over-complicates things and shouldn't be necessary, but - // it would be nice to have in the future. - - int32 frame = -1; - - for (uint32 i = 0; i < _handlers.size(); i++) - if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeVideo) - frame += ((VideoTrackHandler *)_handlers[i])->getCurFrame() + 1; - - return frame; -} - -uint32 QuickTimeDecoder::getFrameCount() const { - uint32 count = 0; - - for (uint32 i = 0; i < _handlers.size(); i++) - if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeVideo) - count += ((VideoTrackHandler *)_handlers[i])->getFrameCount(); - - return count; -} - -void QuickTimeDecoder::startAudio() { - updateAudioBuffer(); - - for (uint32 i = 0; i < _audioTracks.size(); i++) { - g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_audioHandles[i], _audioTracks[i], -1, getVolume(), getBalance(), DisposeAfterUse::NO); +bool QuickTimeDecoder::loadFile(const Common::String &filename) { + if (!Common::QuickTimeParser::parseFile(filename)) + return false; - // Pause the audio again if we're still paused - if (isPaused()) - g_system->getMixer()->pauseHandle(_audioHandles[i], true); - } + init(); + return true; } -void QuickTimeDecoder::stopAudio() { - for (uint32 i = 0; i < _audioHandles.size(); i++) - g_system->getMixer()->stopHandle(_audioHandles[i]); -} +bool QuickTimeDecoder::loadStream(Common::SeekableReadStream *stream) { + if (!Common::QuickTimeParser::parseStream(stream)) + return false; -void QuickTimeDecoder::pauseVideoIntern(bool pause) { - for (uint32 i = 0; i < _audioHandles.size(); i++) - g_system->getMixer()->pauseHandle(_audioHandles[i], pause); + init(); + return true; } -QuickTimeDecoder::VideoTrackHandler *QuickTimeDecoder::findNextVideoTrack() const { - VideoTrackHandler *bestTrack = 0; - uint32 bestTime = 0xffffffff; - - for (uint32 i = 0; i < _handlers.size(); i++) { - if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeVideo && !_handlers[i]->endOfTrack()) { - VideoTrackHandler *track = (VideoTrackHandler *)_handlers[i]; - uint32 time = track->getNextFrameStartTime(); +void QuickTimeDecoder::close() { + VideoDecoder::close(); + Common::QuickTimeParser::close(); - if (time < bestTime) { - bestTime = time; - bestTrack = track; - } - } + if (_scaledSurface) { + _scaledSurface->free(); + delete _scaledSurface; + _scaledSurface = 0; } - - return bestTrack; } const Graphics::Surface *QuickTimeDecoder::decodeNextFrame() { - if (!_nextVideoTrack) - return 0; - - const Graphics::Surface *frame = _nextVideoTrack->decodeNextFrame(); - - if (!_setStartTime) { - _startTime = g_system->getMillis(); - _setStartTime = true; - } - - _nextVideoTrack = findNextVideoTrack(); - _needUpdate = false; + const Graphics::Surface *frame = VideoDecoder::decodeNextFrame(); // Update audio buffers too // (needs to be done after we find the next track) @@ -166,138 +110,7 @@ const Graphics::Surface *QuickTimeDecoder::decodeNextFrame() { return frame; } -void QuickTimeDecoder::scaleSurface(const Graphics::Surface *src, Graphics::Surface *dst, Common::Rational scaleFactorX, Common::Rational scaleFactorY) { - assert(src && dst); - - for (int32 j = 0; j < dst->h; j++) - for (int32 k = 0; k < dst->w; k++) - memcpy(dst->getBasePtr(k, j), src->getBasePtr((k * scaleFactorX).toInt() , (j * scaleFactorY).toInt()), src->format.bytesPerPixel); -} - -bool QuickTimeDecoder::endOfVideo() const { - if (!isVideoLoaded()) - return true; - - for (uint32 i = 0; i < _handlers.size(); i++) - if (!_handlers[i]->endOfTrack()) - return false; - - return true; -} - -uint32 QuickTimeDecoder::getTime() const { - // Try to base sync off an active audio track - for (uint32 i = 0; i < _audioHandles.size(); i++) { - if (g_system->getMixer()->isSoundHandleActive(_audioHandles[i])) { - uint32 time = g_system->getMixer()->getSoundElapsedTime(_audioHandles[i]) + _audioStartOffset.msecs(); - if (Audio::Timestamp(time, 1000) < _audioTracks[i]->getLength()) - return time; - } - } - - // Just use time elapsed since the beginning - return SeekableVideoDecoder::getTime(); -} - -uint32 QuickTimeDecoder::getTimeToNextFrame() const { - if (_needUpdate) - return 0; - - if (_nextVideoTrack) { - uint32 nextFrameStartTime = _nextVideoTrack->getNextFrameStartTime(); - - if (nextFrameStartTime == 0) - return 0; - - // TODO: Add support for rate modification - - uint32 elapsedTime = getTime(); - - if (elapsedTime < nextFrameStartTime) - return nextFrameStartTime - elapsedTime; - } - - return 0; -} - -bool QuickTimeDecoder::loadFile(const Common::String &filename) { - if (!Common::QuickTimeParser::parseFile(filename)) - return false; - - init(); - return true; -} - -bool QuickTimeDecoder::loadStream(Common::SeekableReadStream *stream) { - if (!Common::QuickTimeParser::parseStream(stream)) - return false; - - init(); - return true; -} - -void QuickTimeDecoder::updateVolume() { - for (uint32 i = 0; i < _audioHandles.size(); i++) - if (g_system->getMixer()->isSoundHandleActive(_audioHandles[i])) - g_system->getMixer()->setChannelVolume(_audioHandles[i], getVolume()); -} - -void QuickTimeDecoder::updateBalance() { - for (uint32 i = 0; i < _audioHandles.size(); i++) - if (g_system->getMixer()->isSoundHandleActive(_audioHandles[i])) - g_system->getMixer()->setChannelBalance(_audioHandles[i], getBalance()); -} - -void QuickTimeDecoder::init() { - Audio::QuickTimeAudioDecoder::init(); - - _startTime = 0; - _setStartTime = false; - - // Initialize all the audio tracks - if (!_audioTracks.empty()) { - _audioHandles.resize(_audioTracks.size()); - - for (uint32 i = 0; i < _audioTracks.size(); i++) - _handlers.push_back(new AudioTrackHandler(this, _audioTracks[i])); - } - - // Initialize all the video tracks - for (uint32 i = 0; i < _tracks.size(); i++) { - if (_tracks[i]->codecType == CODEC_TYPE_VIDEO) { - for (uint32 j = 0; j < _tracks[i]->sampleDescs.size(); j++) - ((VideoSampleDesc *)_tracks[i]->sampleDescs[j])->initCodec(); - - _handlers.push_back(new VideoTrackHandler(this, _tracks[i])); - } - } - - // Prepare the first video track - _nextVideoTrack = findNextVideoTrack(); - - if (_nextVideoTrack) { - if (_scaleFactorX != 1 || _scaleFactorY != 1) { - // We have to take the scale into consideration when setting width/height - _width = (_nextVideoTrack->getWidth() / _scaleFactorX).toInt(); - _height = (_nextVideoTrack->getHeight() / _scaleFactorY).toInt(); - } else { - _width = _nextVideoTrack->getWidth().toInt(); - _height = _nextVideoTrack->getHeight().toInt(); - } - - _needUpdate = true; - } else { - _needUpdate = false; - } - - // Now start any audio - if (!_audioTracks.empty()) { - startAudio(); - _audioStartOffset = Audio::Timestamp(0); - } -} - -Common::QuickTimeParser::SampleDesc *QuickTimeDecoder::readSampleDesc(Track *track, uint32 format) { +Common::QuickTimeParser::SampleDesc *QuickTimeDecoder::readSampleDesc(Common::QuickTimeParser::Track *track, uint32 format) { if (track->codecType == CODEC_TYPE_VIDEO) { debug(0, "Video Codec FourCC: \'%s\'", tag2str(format)); @@ -395,61 +208,52 @@ Common::QuickTimeParser::SampleDesc *QuickTimeDecoder::readSampleDesc(Track *tra return Audio::QuickTimeAudioDecoder::readSampleDesc(track, format); } -void QuickTimeDecoder::close() { - stopAudio(); - freeAllTrackHandlers(); - - if (_scaledSurface) { - _scaledSurface->free(); - delete _scaledSurface; - _scaledSurface = 0; - } - - _width = _height = 0; - - Common::QuickTimeParser::close(); - SeekableVideoDecoder::reset(); -} - -void QuickTimeDecoder::freeAllTrackHandlers() { - for (uint32 i = 0; i < _handlers.size(); i++) - delete _handlers[i]; - - _handlers.clear(); -} +void QuickTimeDecoder::init() { + Audio::QuickTimeAudioDecoder::init(); -void QuickTimeDecoder::seekToTime(const Audio::Timestamp &time) { - stopAudio(); - _audioStartOffset = time; + // Initialize all the audio tracks + for (uint32 i = 0; i < _audioTracks.size(); i++) + addTrack(new AudioTrackHandler(this, _audioTracks[i])); - // Sets all tracks to this time - for (uint32 i = 0; i < _handlers.size(); i++) - _handlers[i]->seekToTime(time); + // Initialize all the video tracks + Common::Array<Common::QuickTimeParser::Track *> &tracks = Common::QuickTimeParser::_tracks; + for (uint32 i = 0; i < tracks.size(); i++) { + if (tracks[i]->codecType == CODEC_TYPE_VIDEO) { + for (uint32 j = 0; j < tracks[i]->sampleDescs.size(); j++) + ((VideoSampleDesc *)tracks[i]->sampleDescs[j])->initCodec(); - startAudio(); + addTrack(new VideoTrackHandler(this, tracks[i])); + } + } - // Reset our start time - _startTime = g_system->getMillis() - time.msecs(); - _setStartTime = true; - resetPauseStartTime(); + // Prepare the first video track + VideoTrackHandler *nextVideoTrack = (VideoTrackHandler *)findNextVideoTrack(); - // Reset the next video track too - _nextVideoTrack = findNextVideoTrack(); - _needUpdate = _nextVideoTrack != 0; + if (nextVideoTrack) { + if (_scaleFactorX != 1 || _scaleFactorY != 1) { + // We have to take the scale into consideration when setting width/height + _width = (nextVideoTrack->getScaledWidth() / _scaleFactorX).toInt(); + _height = (nextVideoTrack->getScaledHeight() / _scaleFactorY).toInt(); + } else { + _width = nextVideoTrack->getWidth(); + _height = nextVideoTrack->getHeight(); + } + } } void QuickTimeDecoder::updateAudioBuffer() { // Updates the audio buffers for all audio tracks - for (uint32 i = 0; i < _handlers.size(); i++) - if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeAudio) - ((AudioTrackHandler *)_handlers[i])->updateBuffer(); + for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++) + if ((*it)->getTrackType() == VideoDecoder::Track::kTrackTypeAudio) + ((AudioTrackHandler *)*it)->updateBuffer(); } -Graphics::PixelFormat QuickTimeDecoder::getPixelFormat() const { - if (_nextVideoTrack) - return _nextVideoTrack->getPixelFormat(); +void QuickTimeDecoder::scaleSurface(const Graphics::Surface *src, Graphics::Surface *dst, const Common::Rational &scaleFactorX, const Common::Rational &scaleFactorY) { + assert(src && dst); - return Graphics::PixelFormat(); + for (int32 j = 0; j < dst->h; j++) + for (int32 k = 0; k < dst->w; k++) + memcpy(dst->getBasePtr(k, j), src->getBasePtr((k * scaleFactorX).toInt() , (j * scaleFactorY).toInt()), src->format.bytesPerPixel); } QuickTimeDecoder::VideoSampleDesc::VideoSampleDesc(Common::QuickTimeParser::Track *parentTrack, uint32 codecTag) : Common::QuickTimeParser::SampleDesc(parentTrack, codecTag) { @@ -504,25 +308,8 @@ void QuickTimeDecoder::VideoSampleDesc::initCodec() { } } -bool QuickTimeDecoder::endOfVideoTracks() const { - for (uint32 i = 0; i < _handlers.size(); i++) - if (_handlers[i]->getTrackType() == TrackHandler::kTrackTypeVideo && !_handlers[i]->endOfTrack()) - return false; - - return true; -} - -QuickTimeDecoder::TrackHandler::TrackHandler(QuickTimeDecoder *decoder, Track *parent) : _decoder(decoder), _parent(parent), _fd(_decoder->_fd) { - _curEdit = 0; -} - -bool QuickTimeDecoder::TrackHandler::endOfTrack() { - // A track is over when we've finished going through all edits - return _curEdit == _parent->editCount; -} - QuickTimeDecoder::AudioTrackHandler::AudioTrackHandler(QuickTimeDecoder *decoder, QuickTimeAudioTrack *audioTrack) - : TrackHandler(decoder, audioTrack->getParent()), _audioTrack(audioTrack) { + : _decoder(decoder), _audioTrack(audioTrack) { } void QuickTimeDecoder::AudioTrackHandler::updateBuffer() { @@ -532,21 +319,20 @@ void QuickTimeDecoder::AudioTrackHandler::updateBuffer() { _audioTrack->queueAudio(Audio::Timestamp(_decoder->getTimeToNextFrame() + 500, 1000)); } -bool QuickTimeDecoder::AudioTrackHandler::endOfTrack() { - return _audioTrack->endOfData(); -} - -void QuickTimeDecoder::AudioTrackHandler::seekToTime(Audio::Timestamp time) { - _audioTrack->seek(time); +Audio::SeekableAudioStream *QuickTimeDecoder::AudioTrackHandler::getSeekableAudioStream() const { + return _audioTrack; } -QuickTimeDecoder::VideoTrackHandler::VideoTrackHandler(QuickTimeDecoder *decoder, Common::QuickTimeParser::Track *parent) : TrackHandler(decoder, parent) { +QuickTimeDecoder::VideoTrackHandler::VideoTrackHandler(QuickTimeDecoder *decoder, Common::QuickTimeParser::Track *parent) : _decoder(decoder), _parent(parent) { + _curEdit = 0; enterNewEditList(false); _holdNextFrameStartTime = false; _curFrame = -1; _durationOverride = -1; _scaledSurface = 0; + _curPalette = 0; + _dirtyPalette = false; } QuickTimeDecoder::VideoTrackHandler::~VideoTrackHandler() { @@ -556,6 +342,88 @@ QuickTimeDecoder::VideoTrackHandler::~VideoTrackHandler() { } } +bool QuickTimeDecoder::VideoTrackHandler::endOfTrack() const { + // A track is over when we've finished going through all edits + return _curEdit == _parent->editCount; +} + +bool QuickTimeDecoder::VideoTrackHandler::seek(const Audio::Timestamp &requestedTime) { + // First, figure out what edit we're in + Audio::Timestamp time = requestedTime.convertToFramerate(_parent->timeScale); + + // Continue until we get to where we need to be + for (_curEdit = 0; !endOfTrack(); _curEdit++) + if ((uint32)time.totalNumberOfFrames() >= getCurEditTimeOffset() && (uint32)time.totalNumberOfFrames() < getCurEditTimeOffset() + getCurEditTrackDuration()) + break; + + // This track is done + if (endOfTrack()) + return true; + + enterNewEditList(false); + + // One extra check for the end of a track + if (endOfTrack()) + return true; + + // Now we're in the edit and need to figure out what frame we need + while (getRateAdjustedFrameTime() < (uint32)time.totalNumberOfFrames()) { + _curFrame++; + if (_durationOverride >= 0) { + _nextFrameStartTime += _durationOverride; + _durationOverride = -1; + } else { + _nextFrameStartTime += getFrameDuration(); + } + } + + // All that's left is to figure out what our starting time is going to be + // Compare the starting point for the frame to where we need to be + _holdNextFrameStartTime = getRateAdjustedFrameTime() != (uint32)time.totalNumberOfFrames(); + + // If we went past the time, go back a frame + if (_holdNextFrameStartTime) + _curFrame--; + + // Handle the keyframe here + int32 destinationFrame = _curFrame + 1; + + assert(destinationFrame < (int32)_parent->frameCount); + _curFrame = findKeyFrame(destinationFrame) - 1; + while (_curFrame < destinationFrame - 1) + bufferNextFrame(); + + return true; +} + +Audio::Timestamp QuickTimeDecoder::VideoTrackHandler::getDuration() const { + return Audio::Timestamp(0, _parent->duration, _decoder->_timeScale); +} + +uint16 QuickTimeDecoder::VideoTrackHandler::getWidth() const { + return getScaledWidth().toInt(); +} + +uint16 QuickTimeDecoder::VideoTrackHandler::getHeight() const { + return getScaledHeight().toInt(); +} + +Graphics::PixelFormat QuickTimeDecoder::VideoTrackHandler::getPixelFormat() const { + return ((VideoSampleDesc *)_parent->sampleDescs[0])->_videoCodec->getPixelFormat(); +} + +int QuickTimeDecoder::VideoTrackHandler::getFrameCount() const { + return _parent->frameCount; +} + +uint32 QuickTimeDecoder::VideoTrackHandler::getNextFrameStartTime() const { + if (endOfTrack()) + return 0; + + // Convert to milliseconds so the tracks can be compared + return getRateAdjustedFrameTime() * 1000 / _parent->timeScale; +} + const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame() { if (endOfTrack()) return 0; @@ -586,7 +454,7 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame() if (frame && (_parent->scaleFactorX != 1 || _parent->scaleFactorY != 1)) { if (!_scaledSurface) { _scaledSurface = new Graphics::Surface(); - _scaledSurface->create(getWidth().toInt(), getHeight().toInt(), getPixelFormat()); + _scaledSurface->create(getScaledWidth().toInt(), getScaledHeight().toInt(), getPixelFormat()); } _decoder->scaleSurface(frame, _scaledSurface, _parent->scaleFactorX, _parent->scaleFactorY); @@ -596,6 +464,85 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::decodeNextFrame() return frame; } +Common::Rational QuickTimeDecoder::VideoTrackHandler::getScaledWidth() const { + return Common::Rational(_parent->width) / _parent->scaleFactorX; +} + +Common::Rational QuickTimeDecoder::VideoTrackHandler::getScaledHeight() const { + return Common::Rational(_parent->height) / _parent->scaleFactorY; +} + +Common::SeekableReadStream *QuickTimeDecoder::VideoTrackHandler::getNextFramePacket(uint32 &descId) { + // First, we have to track down which chunk holds the sample and which sample in the chunk contains the frame we are looking for. + int32 totalSampleCount = 0; + int32 sampleInChunk = 0; + int32 actualChunk = -1; + uint32 sampleToChunkIndex = 0; + + for (uint32 i = 0; i < _parent->chunkCount; i++) { + if (sampleToChunkIndex < _parent->sampleToChunkCount && i >= _parent->sampleToChunk[sampleToChunkIndex].first) + sampleToChunkIndex++; + + totalSampleCount += _parent->sampleToChunk[sampleToChunkIndex - 1].count; + + if (totalSampleCount > _curFrame) { + actualChunk = i; + descId = _parent->sampleToChunk[sampleToChunkIndex - 1].id; + sampleInChunk = _parent->sampleToChunk[sampleToChunkIndex - 1].count - totalSampleCount + _curFrame; + break; + } + } + + if (actualChunk < 0) { + warning("Could not find data for frame %d", _curFrame); + return 0; + } + + // Next seek to that frame + Common::SeekableReadStream *stream = _decoder->_fd; + stream->seek(_parent->chunkOffsets[actualChunk]); + + // Then, if the chunk holds more than one frame, seek to where the frame we want is located + for (int32 i = _curFrame - sampleInChunk; i < _curFrame; i++) { + if (_parent->sampleSize != 0) + stream->skip(_parent->sampleSize); + else + stream->skip(_parent->sampleSizes[i]); + } + + // Finally, read in the raw data for the frame + //debug("Frame Data[%d]: Offset = %d, Size = %d", _curFrame, stream->pos(), _parent->sampleSizes[_curFrame]); + + if (_parent->sampleSize != 0) + return stream->readStream(_parent->sampleSize); + + return stream->readStream(_parent->sampleSizes[_curFrame]); +} + +uint32 QuickTimeDecoder::VideoTrackHandler::getFrameDuration() { + uint32 curFrameIndex = 0; + for (int32 i = 0; i < _parent->timeToSampleCount; i++) { + curFrameIndex += _parent->timeToSample[i].count; + if ((uint32)_curFrame < curFrameIndex) { + // Ok, now we have what duration this frame has. + return _parent->timeToSample[i].duration; + } + } + + // This should never occur + error("Cannot find duration for frame %d", _curFrame); + return 0; +} + +uint32 QuickTimeDecoder::VideoTrackHandler::findKeyFrame(uint32 frame) const { + for (int i = _parent->keyframeCount - 1; i >= 0; i--) + if (_parent->keyframes[i] <= frame) + return _parent->keyframes[i]; + + // If none found, we'll assume the requested frame is a key frame + return frame; +} + void QuickTimeDecoder::VideoTrackHandler::enterNewEditList(bool bufferFrames) { // Bypass all empty edit lists first while (!endOfTrack() && _parent->editList[_curEdit].mediaTime == -1) @@ -667,166 +614,25 @@ const Graphics::Surface *QuickTimeDecoder::VideoTrackHandler::bufferNextFrame() if (entry->_videoCodec->containsPalette()) { // The codec itself contains a palette if (entry->_videoCodec->hasDirtyPalette()) { - _decoder->_palette = entry->_videoCodec->getPalette(); - _decoder->_dirtyPalette = true; + _curPalette = entry->_videoCodec->getPalette(); + _dirtyPalette = true; } } else { // Check if the video description has been updated byte *palette = entry->_palette; - if (palette !=_decoder-> _palette) { - _decoder->_palette = palette; - _decoder->_dirtyPalette = true; - } - } - - return frame; -} - -uint32 QuickTimeDecoder::VideoTrackHandler::getNextFrameStartTime() { - if (endOfTrack()) - return 0; - - // Convert to milliseconds so the tracks can be compared - return getRateAdjustedFrameTime() * 1000 / _parent->timeScale; -} - -uint32 QuickTimeDecoder::VideoTrackHandler::getFrameCount() { - return _parent->frameCount; -} - -uint32 QuickTimeDecoder::VideoTrackHandler::getFrameDuration() { - uint32 curFrameIndex = 0; - for (int32 i = 0; i < _parent->timeToSampleCount; i++) { - curFrameIndex += _parent->timeToSample[i].count; - if ((uint32)_curFrame < curFrameIndex) { - // Ok, now we have what duration this frame has. - return _parent->timeToSample[i].duration; - } - } - - // This should never occur - error("Cannot find duration for frame %d", _curFrame); - return 0; -} - -Common::SeekableReadStream *QuickTimeDecoder::VideoTrackHandler::getNextFramePacket(uint32 &descId) { - // First, we have to track down which chunk holds the sample and which sample in the chunk contains the frame we are looking for. - int32 totalSampleCount = 0; - int32 sampleInChunk = 0; - int32 actualChunk = -1; - uint32 sampleToChunkIndex = 0; - - for (uint32 i = 0; i < _parent->chunkCount; i++) { - if (sampleToChunkIndex < _parent->sampleToChunkCount && i >= _parent->sampleToChunk[sampleToChunkIndex].first) - sampleToChunkIndex++; - - totalSampleCount += _parent->sampleToChunk[sampleToChunkIndex - 1].count; - - if (totalSampleCount > _curFrame) { - actualChunk = i; - descId = _parent->sampleToChunk[sampleToChunkIndex - 1].id; - sampleInChunk = _parent->sampleToChunk[sampleToChunkIndex - 1].count - totalSampleCount + _curFrame; - break; + if (palette != _curPalette) { + _curPalette = palette; + _dirtyPalette = true; } } - if (actualChunk < 0) { - warning("Could not find data for frame %d", _curFrame); - return 0; - } - - // Next seek to that frame - _fd->seek(_parent->chunkOffsets[actualChunk]); - - // Then, if the chunk holds more than one frame, seek to where the frame we want is located - for (int32 i = _curFrame - sampleInChunk; i < _curFrame; i++) { - if (_parent->sampleSize != 0) - _fd->skip(_parent->sampleSize); - else - _fd->skip(_parent->sampleSizes[i]); - } - - // Finally, read in the raw data for the frame - //debug("Frame Data[%d]: Offset = %d, Size = %d", _curFrame, _fd->pos(), _parent->sampleSizes[_curFrame]); - - if (_parent->sampleSize != 0) - return _fd->readStream(_parent->sampleSize); - - return _fd->readStream(_parent->sampleSizes[_curFrame]); -} - -uint32 QuickTimeDecoder::VideoTrackHandler::findKeyFrame(uint32 frame) const { - for (int i = _parent->keyframeCount - 1; i >= 0; i--) - if (_parent->keyframes[i] <= frame) - return _parent->keyframes[i]; - - // If none found, we'll assume the requested frame is a key frame return frame; } -void QuickTimeDecoder::VideoTrackHandler::seekToTime(Audio::Timestamp time) { - // First, figure out what edit we're in - time = time.convertToFramerate(_parent->timeScale); - - // Continue until we get to where we need to be - for (_curEdit = 0; !endOfTrack(); _curEdit++) - if ((uint32)time.totalNumberOfFrames() >= getCurEditTimeOffset() && (uint32)time.totalNumberOfFrames() < getCurEditTimeOffset() + getCurEditTrackDuration()) - break; - - // This track is done - if (endOfTrack()) - return; - - enterNewEditList(false); - - // One extra check for the end of a track - if (endOfTrack()) - return; - - // Now we're in the edit and need to figure out what frame we need - while (getRateAdjustedFrameTime() < (uint32)time.totalNumberOfFrames()) { - _curFrame++; - if (_durationOverride >= 0) { - _nextFrameStartTime += _durationOverride; - _durationOverride = -1; - } else { - _nextFrameStartTime += getFrameDuration(); - } - } - - // All that's left is to figure out what our starting time is going to be - // Compare the starting point for the frame to where we need to be - _holdNextFrameStartTime = getRateAdjustedFrameTime() != (uint32)time.totalNumberOfFrames(); - - // If we went past the time, go back a frame - if (_holdNextFrameStartTime) - _curFrame--; - - // Handle the keyframe here - int32 destinationFrame = _curFrame + 1; - - assert(destinationFrame < (int32)_parent->frameCount); - _curFrame = findKeyFrame(destinationFrame) - 1; - while (_curFrame < destinationFrame - 1) - bufferNextFrame(); -} - -Common::Rational QuickTimeDecoder::VideoTrackHandler::getWidth() const { - return Common::Rational(_parent->width) / _parent->scaleFactorX; -} - -Common::Rational QuickTimeDecoder::VideoTrackHandler::getHeight() const { - return Common::Rational(_parent->height) / _parent->scaleFactorY; -} - -Graphics::PixelFormat QuickTimeDecoder::VideoTrackHandler::getPixelFormat() const { - return ((VideoSampleDesc *)_parent->sampleDescs[0])->_videoCodec->getPixelFormat(); -} - uint32 QuickTimeDecoder::VideoTrackHandler::getRateAdjustedFrameTime() const { // Figure out what time the next frame is at taking the edit list rate into account - uint32 convertedTime = (Common::Rational(_nextFrameStartTime - getCurEditTimeOffset()) / _parent->editList[_curEdit].mediaRate).toInt(); + uint32 convertedTime = (Common::Rational(_nextFrameStartTime - getCurEditTimeOffset()) / _parent->editList[_curEdit].mediaRate).toInt(); return convertedTime + getCurEditTimeOffset(); } diff --git a/video/qt_decoder.h b/video/qt_decoder.h index ce32562d64..71d33711a6 100644 --- a/video/qt_decoder.h +++ b/video/qt_decoder.h @@ -31,16 +31,17 @@ #ifndef VIDEO_QT_DECODER_H #define VIDEO_QT_DECODER_H -#include "audio/mixer.h" #include "audio/decoders/quicktime_intern.h" #include "common/scummsys.h" -#include "common/rational.h" -#include "graphics/pixelformat.h" #include "video/video_decoder.h" namespace Common { - class Rational; +class Rational; +} + +namespace Graphics { +struct PixelFormat; } namespace Video { @@ -54,68 +55,33 @@ class Codec; * - mohawk * - sci */ -class QuickTimeDecoder : public SeekableVideoDecoder, public Audio::QuickTimeAudioDecoder { +class QuickTimeDecoder : public VideoDecoder, public Audio::QuickTimeAudioDecoder { public: QuickTimeDecoder(); virtual ~QuickTimeDecoder(); - /** - * Returns the width of the video - * @return the width of the video - */ - uint16 getWidth() const { return _width; } - - /** - * Returns the height of the video - * @return the height of the video - */ - uint16 getHeight() const { return _height; } - - /** - * Returns the amount of frames in the video - * @return the amount of frames in the video - */ - uint32 getFrameCount() const; - - /** - * Load a video file - * @param filename the filename to load - */ bool loadFile(const Common::String &filename); - - /** - * Load a QuickTime video file from a SeekableReadStream - * @param stream the stream to load - */ bool loadStream(Common::SeekableReadStream *stream); - - /** - * Close a QuickTime encoded video file - */ void close(); + uint16 getWidth() const { return _width; } + uint16 getHeight() const { return _height; } + const Graphics::Surface *decodeNextFrame(); + Audio::Timestamp getDuration() const { return Audio::Timestamp(0, _duration, _timeScale); } - /** - * Returns the palette of the video - * @return the palette of the video - */ - const byte *getPalette() { _dirtyPalette = false; return _palette; } - bool hasDirtyPalette() const { return _dirtyPalette; } +protected: + Common::QuickTimeParser::SampleDesc *readSampleDesc(Common::QuickTimeParser::Track *track, uint32 format); - int32 getCurFrame() const; +private: + void init(); - bool isVideoLoaded() const { return isOpen(); } - const Graphics::Surface *decodeNextFrame(); - bool endOfVideo() const; - uint32 getTime() const; - uint32 getTimeToNextFrame() const; - Graphics::PixelFormat getPixelFormat() const; + void updateAudioBuffer(); - // SeekableVideoDecoder API - void seekToFrame(uint32 frame); - void seekToTime(const Audio::Timestamp &time); - uint32 getDuration() const { return _duration * 1000 / _timeScale; } + uint16 _width, _height; + + Graphics::Surface *_scaledSurface; + void scaleSurface(const Graphics::Surface *src, Graphics::Surface *dst, + const Common::Rational &scaleFactorX, const Common::Rational &scaleFactorY); -protected: class VideoSampleDesc : public Common::QuickTimeParser::SampleDesc { public: VideoSampleDesc(Common::QuickTimeParser::Track *parentTrack, uint32 codecTag); @@ -131,110 +97,59 @@ protected: Codec *_videoCodec; }; - Common::QuickTimeParser::SampleDesc *readSampleDesc(Track *track, uint32 format); - - // VideoDecoder API - void updateVolume(); - void updateBalance(); - -private: - void init(); - - void startAudio(); - void stopAudio(); - void updateAudioBuffer(); - void readNextAudioChunk(); - Common::Array<Audio::SoundHandle> _audioHandles; - Audio::Timestamp _audioStartOffset; - - Codec *createCodec(uint32 codecTag, byte bitsPerPixel); - uint32 findKeyFrame(uint32 frame) const; - - bool _dirtyPalette; - const byte *_palette; - bool _setStartTime; - bool _needUpdate; - - uint16 _width, _height; - - Graphics::Surface *_scaledSurface; - void scaleSurface(const Graphics::Surface *src, Graphics::Surface *dst, - Common::Rational scaleFactorX, Common::Rational scaleFactorY); - - void pauseVideoIntern(bool pause); - bool endOfVideoTracks() const; - - // The TrackHandler is a class that wraps around a QuickTime Track - // and handles playback in this decoder class. - class TrackHandler { - public: - TrackHandler(QuickTimeDecoder *decoder, Track *parent); - virtual ~TrackHandler() {} - - enum TrackType { - kTrackTypeAudio, - kTrackTypeVideo - }; - - virtual TrackType getTrackType() const = 0; - - virtual void seekToTime(Audio::Timestamp time) = 0; - - virtual bool endOfTrack(); - - protected: - uint32 _curEdit; - QuickTimeDecoder *_decoder; - Common::SeekableReadStream *_fd; - Track *_parent; - }; - // The AudioTrackHandler is currently just a wrapper around some // QuickTimeDecoder functions. - class AudioTrackHandler : public TrackHandler { + class AudioTrackHandler : public SeekableAudioTrack { public: AudioTrackHandler(QuickTimeDecoder *decoder, QuickTimeAudioTrack *audioTrack); - TrackType getTrackType() const { return kTrackTypeAudio; } void updateBuffer(); - void seekToTime(Audio::Timestamp time); - bool endOfTrack(); + + protected: + Audio::SeekableAudioStream *getSeekableAudioStream() const; private: + QuickTimeDecoder *_decoder; QuickTimeAudioTrack *_audioTrack; }; // The VideoTrackHandler is the bridge between the time of playback // and the media for the given track. It calculates when to start // tracks and at what rate to play the media using the edit list. - class VideoTrackHandler : public TrackHandler { + class VideoTrackHandler : public VideoTrack { public: - VideoTrackHandler(QuickTimeDecoder *decoder, Track *parent); + VideoTrackHandler(QuickTimeDecoder *decoder, Common::QuickTimeParser::Track *parent); ~VideoTrackHandler(); - TrackType getTrackType() const { return kTrackTypeVideo; } - - const Graphics::Surface *decodeNextFrame(); - - uint32 getNextFrameStartTime(); - - uint32 getFrameCount(); - - int32 getCurFrame() { return _curFrame; } + bool endOfTrack() const; + bool isSeekable() const { return true; } + bool seek(const Audio::Timestamp &time); + Audio::Timestamp getDuration() const; + uint16 getWidth() const; + uint16 getHeight() const; Graphics::PixelFormat getPixelFormat() const; + int getCurFrame() const { return _curFrame; } + int getFrameCount() const; + uint32 getNextFrameStartTime() const; + const Graphics::Surface *decodeNextFrame(); + const byte *getPalette() const { _dirtyPalette = false; return _curPalette; } + bool hasDirtyPalette() const { return _curPalette; } - void seekToTime(Audio::Timestamp time); - - Common::Rational getWidth() const; - Common::Rational getHeight() const; + Common::Rational getScaledWidth() const; + Common::Rational getScaledHeight() const; private: + QuickTimeDecoder *_decoder; + Common::QuickTimeParser::Track *_parent; + uint32 _curEdit; int32 _curFrame; uint32 _nextFrameStartTime; Graphics::Surface *_scaledSurface; bool _holdNextFrameStartTime; int32 _durationOverride; + const byte *_curPalette; + mutable bool _dirtyPalette; Common::SeekableReadStream *getNextFramePacket(uint32 &descId); uint32 getFrameDuration(); @@ -245,12 +160,6 @@ private: uint32 getCurEditTimeOffset() const; uint32 getCurEditTrackDuration() const; }; - - Common::Array<TrackHandler *> _handlers; - VideoTrackHandler *_nextVideoTrack; - VideoTrackHandler *findNextVideoTrack() const; - - void freeAllTrackHandlers(); }; } // End of namespace Video diff --git a/video/smk_decoder.cpp b/video/smk_decoder.cpp index 359f4cb9bd..bea65142a1 100644 --- a/video/smk_decoder.cpp +++ b/video/smk_decoder.cpp @@ -204,8 +204,7 @@ BigHuffmanTree::BigHuffmanTree(Common::BitStream &bs, int allocSize) delete _hiBytes; } -BigHuffmanTree::~BigHuffmanTree() -{ +BigHuffmanTree::~BigHuffmanTree() { delete[] _tree; } @@ -278,24 +277,17 @@ uint32 BigHuffmanTree::getCode(Common::BitStream &bs) { return v; } -SmackerDecoder::SmackerDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) - : _audioStarted(false), _audioStream(0), _mixer(mixer), _soundType(soundType) { - _surface = 0; +SmackerDecoder::SmackerDecoder(Audio::Mixer::SoundType soundType) : _soundType(soundType) { _fileStream = 0; - _dirtyPalette = false; + _firstFrameStart = 0; + _frameTypes = 0; + _frameSizes = 0; } SmackerDecoder::~SmackerDecoder() { close(); } -uint32 SmackerDecoder::getTime() const { - if (_audioStream && _audioStarted) - return _mixer->getSoundElapsedTime(_audioHandle); - - return FixedRateVideoDecoder::getTime(); -} - bool SmackerDecoder::loadStream(Common::SeekableReadStream *stream) { close(); @@ -309,16 +301,17 @@ bool SmackerDecoder::loadStream(Common::SeekableReadStream *stream) { uint32 width = _fileStream->readUint32LE(); uint32 height = _fileStream->readUint32LE(); - _frameCount = _fileStream->readUint32LE(); - int32 frameRate = _fileStream->readSint32LE(); - - // framerate contains 2 digits after the comma, so 1497 is actually 14.97 fps - if (frameRate > 0) - _frameRate = Common::Rational(1000, frameRate); - else if (frameRate < 0) - _frameRate = Common::Rational(100000, -frameRate); + uint32 frameCount = _fileStream->readUint32LE(); + int32 frameDelay = _fileStream->readSint32LE(); + + // frame rate contains 2 digits after the comma, so 1497 is actually 14.97 fps + Common::Rational frameRate; + if (frameDelay > 0) + frameRate = Common::Rational(1000, frameDelay); + else if (frameDelay < 0) + frameRate = Common::Rational(100000, -frameDelay); else - _frameRate = 1000; + frameRate = 1000; // Flags are determined by which bit is set, which can be one of the following: // 0 - set to 1 if file contains a ring frame. @@ -328,6 +321,9 @@ bool SmackerDecoder::loadStream(Common::SeekableReadStream *stream) { // before it is displayed. _header.flags = _fileStream->readUint32LE(); + SmackerVideoTrack *videoTrack = createVideoTrack(width, height, frameCount, frameRate, _header.flags, _header.signature); + addTrack(videoTrack); + // TODO: should we do any extra processing for Smacker files with ring frames? // TODO: should we do any extra processing for Y-doubled videos? Are they the @@ -374,92 +370,77 @@ bool SmackerDecoder::loadStream(Common::SeekableReadStream *stream) { warning("Unhandled Smacker v2 audio compression"); if (i == 0) - _audioStream = Audio::makeQueuingAudioStream(_header.audioInfo[0].sampleRate, _header.audioInfo[0].isStereo); + addTrack(new SmackerAudioTrack(_header.audioInfo[i], _soundType)); } } _header.dummy = _fileStream->readUint32LE(); - _frameSizes = new uint32[_frameCount]; - for (i = 0; i < _frameCount; ++i) + _frameSizes = new uint32[frameCount]; + for (i = 0; i < frameCount; ++i) _frameSizes[i] = _fileStream->readUint32LE(); - _frameTypes = new byte[_frameCount]; - for (i = 0; i < _frameCount; ++i) + _frameTypes = new byte[frameCount]; + for (i = 0; i < frameCount; ++i) _frameTypes[i] = _fileStream->readByte(); byte *huffmanTrees = (byte *) malloc(_header.treesSize); _fileStream->read(huffmanTrees, _header.treesSize); Common::BitStream8LSB bs(new Common::MemoryReadStream(huffmanTrees, _header.treesSize, DisposeAfterUse::YES), true); + videoTrack->readTrees(bs, _header.mMapSize, _header.mClrSize, _header.fullSize, _header.typeSize); - _MMapTree = new BigHuffmanTree(bs, _header.mMapSize); - _MClrTree = new BigHuffmanTree(bs, _header.mClrSize); - _FullTree = new BigHuffmanTree(bs, _header.fullSize); - _TypeTree = new BigHuffmanTree(bs, _header.typeSize); - - _surface = new Graphics::Surface(); + _firstFrameStart = _fileStream->pos(); - // Height needs to be doubled if we have flags (Y-interlaced or Y-doubled) - _surface->create(width, height * (_header.flags ? 2 : 1), Graphics::PixelFormat::createFormatCLUT8()); - - memset(_palette, 0, 3 * 256); return true; } void SmackerDecoder::close() { - if (!_fileStream) - return; - - if (_audioStream) { - if (_audioStarted) { - // The mixer will delete the stream. - _mixer->stopHandle(_audioHandle); - _audioStarted = false; - } else { - delete _audioStream; - } - _audioStream = 0; - } + VideoDecoder::close(); delete _fileStream; _fileStream = 0; - _surface->free(); - delete _surface; - _surface = 0; - - delete _MMapTree; - delete _MClrTree; - delete _FullTree; - delete _TypeTree; + delete[] _frameTypes; + _frameTypes = 0; delete[] _frameSizes; - delete[] _frameTypes; + _frameSizes = 0; +} + +bool SmackerDecoder::rewind() { + // Call the parent method to rewind the tracks first + if (!VideoDecoder::rewind()) + return false; - reset(); + // And seek back to where the first frame begins + _fileStream->seek(_firstFrameStart); + return true; } -const Graphics::Surface *SmackerDecoder::decodeNextFrame() { +void SmackerDecoder::readNextPacket() { + SmackerVideoTrack *videoTrack = (SmackerVideoTrack *)getTrack(0); + + if (videoTrack->endOfTrack()) + return; + + videoTrack->increaseCurFrame(); + uint i; uint32 chunkSize = 0; uint32 dataSizeUnpacked = 0; uint32 startPos = _fileStream->pos(); - _curFrame++; - // Check if we got a frame with palette data, and // call back the virtual setPalette function to set // the current palette - if (_frameTypes[_curFrame] & 1) { - unpackPalette(); - _dirtyPalette = true; - } + if (_frameTypes[videoTrack->getCurFrame()] & 1) + videoTrack->unpackPalette(_fileStream); // Load audio tracks for (i = 0; i < 7; ++i) { - if (!(_frameTypes[_curFrame] & (2 << i))) + if (!(_frameTypes[videoTrack->getCurFrame()] & (2 << i))) continue; chunkSize = _fileStream->readUint32LE(); @@ -475,29 +456,109 @@ const Graphics::Surface *SmackerDecoder::decodeNextFrame() { handleAudioTrack(i, chunkSize, dataSizeUnpacked); } - uint32 frameSize = _frameSizes[_curFrame] & ~3; -// uint32 remainder = _frameSizes[_curFrame] & 3; + uint32 frameSize = _frameSizes[videoTrack->getCurFrame()] & ~3; +// uint32 remainder = _frameSizes[videoTrack->getCurFrame()] & 3; if (_fileStream->pos() - startPos > frameSize) error("Smacker actual frame size exceeds recorded frame size"); uint32 frameDataSize = frameSize - (_fileStream->pos() - startPos); - _frameData = (byte *)malloc(frameDataSize + 1); + byte *frameData = (byte *)malloc(frameDataSize + 1); // Padding to keep the BigHuffmanTrees from reading past the data end - _frameData[frameDataSize] = 0x00; + frameData[frameDataSize] = 0x00; + + _fileStream->read(frameData, frameDataSize); + + Common::BitStream8LSB bs(new Common::MemoryReadStream(frameData, frameDataSize + 1, DisposeAfterUse::YES), true); + videoTrack->decodeFrame(bs); + + _fileStream->seek(startPos + frameSize); +} - _fileStream->read(_frameData, frameDataSize); +void SmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize) { + if (_header.audioInfo[track].hasAudio && chunkSize > 0 && track == 0) { + // Get the audio track, which start at offset 1 (first track is video) + SmackerAudioTrack *audioTrack = (SmackerAudioTrack *)getTrack(track + 1); - Common::BitStream8LSB bs(new Common::MemoryReadStream(_frameData, frameDataSize + 1, DisposeAfterUse::YES), true); + // If it's track 0, play the audio data + byte *soundBuffer = (byte *)malloc(chunkSize + 1); + // Padding to keep the SmallHuffmanTrees from reading past the data end + soundBuffer[chunkSize] = 0x00; + _fileStream->read(soundBuffer, chunkSize); + + if (_header.audioInfo[track].compression == kCompressionRDFT || _header.audioInfo[track].compression == kCompressionDCT) { + // TODO: Compressed audio (Bink RDFT/DCT encoded) + free(soundBuffer); + return; + } else if (_header.audioInfo[track].compression == kCompressionDPCM) { + // Compressed audio (Huffman DPCM encoded) + audioTrack->queueCompressedBuffer(soundBuffer, chunkSize + 1, unpackedSize); + free(soundBuffer); + } else { + // Uncompressed audio (PCM) + audioTrack->queuePCM(soundBuffer, chunkSize); + } + } else { + // Ignore the rest of the audio tracks, if they exist + // TODO: Are there any Smacker videos with more than one audio stream? + // If yes, we should play the rest of the audio streams as well + if (chunkSize > 0) + _fileStream->skip(chunkSize); + } +} + +SmackerDecoder::SmackerVideoTrack::SmackerVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, uint32 flags, uint32 signature) { + _surface = new Graphics::Surface(); + _surface->create(width, height * (flags ? 2 : 1), Graphics::PixelFormat::createFormatCLUT8()); + _frameCount = frameCount; + _frameRate = frameRate; + _flags = flags; + _signature = signature; + _curFrame = -1; + _dirtyPalette = false; + _MMapTree = _MClrTree = _FullTree = _TypeTree = 0; + memset(_palette, 0, 3 * 256); +} + +SmackerDecoder::SmackerVideoTrack::~SmackerVideoTrack() { + _surface->free(); + delete _surface; + + delete _MMapTree; + delete _MClrTree; + delete _FullTree; + delete _TypeTree; +} + +uint16 SmackerDecoder::SmackerVideoTrack::getWidth() const { + return _surface->w; +} + +uint16 SmackerDecoder::SmackerVideoTrack::getHeight() const { + return _surface->h; +} + +Graphics::PixelFormat SmackerDecoder::SmackerVideoTrack::getPixelFormat() const { + return _surface->format; +} + +void SmackerDecoder::SmackerVideoTrack::readTrees(Common::BitStream &bs, uint32 mMapSize, uint32 mClrSize, uint32 fullSize, uint32 typeSize) { + _MMapTree = new BigHuffmanTree(bs, mMapSize); + _MClrTree = new BigHuffmanTree(bs, mClrSize); + _FullTree = new BigHuffmanTree(bs, fullSize); + _TypeTree = new BigHuffmanTree(bs, typeSize); +} + +void SmackerDecoder::SmackerVideoTrack::decodeFrame(Common::BitStream &bs) { _MMapTree->reset(); _MClrTree->reset(); _FullTree->reset(); _TypeTree->reset(); // Height needs to be doubled if we have flags (Y-interlaced or Y-doubled) - uint doubleY = _header.flags ? 2 : 1; + uint doubleY = _flags ? 2 : 1; uint bw = getWidth() / 4; uint bh = getHeight() / doubleY / 4; @@ -508,6 +569,7 @@ const Graphics::Surface *SmackerDecoder::decodeNextFrame() { uint type, run, j, mode; uint32 p1, p2, clr, map; byte hi, lo; + uint i; while (block < blocks) { type = _TypeTree->getCode(bs); @@ -536,7 +598,7 @@ const Graphics::Surface *SmackerDecoder::decodeNextFrame() { break; case SMK_BLOCK_FULL: // Smacker v2 has one mode, Smacker v4 has three - if (_header.signature == MKTAG('S','M','K','2')) { + if (_signature == MKTAG('S','M','K','2')) { mode = 0; } else { // 00 - mode 0 @@ -628,60 +690,81 @@ const Graphics::Surface *SmackerDecoder::decodeNextFrame() { break; } } +} - _fileStream->seek(startPos + frameSize); +void SmackerDecoder::SmackerVideoTrack::unpackPalette(Common::SeekableReadStream *stream) { + uint startPos = stream->pos(); + uint32 len = 4 * stream->readByte(); - if (_curFrame == 0) - _startTime = g_system->getMillis(); + byte *chunk = (byte *)malloc(len); + stream->read(chunk, len); + byte *p = chunk; - return _surface; -} + byte oldPalette[3 * 256]; + memcpy(oldPalette, _palette, 3 * 256); -void SmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize) { - if (_header.audioInfo[track].hasAudio && chunkSize > 0 && track == 0) { - // If it's track 0, play the audio data - byte *soundBuffer = (byte *)malloc(chunkSize + 1); - // Padding to keep the SmallHuffmanTrees from reading past the data end - soundBuffer[chunkSize] = 0x00; + byte *pal = _palette; - _fileStream->read(soundBuffer, chunkSize); + int sz = 0; + byte b0; + while (sz < 256) { + b0 = *p++; + if (b0 & 0x80) { // if top bit is 1 (0x80 = 10000000) + sz += (b0 & 0x7f) + 1; // get lower 7 bits + 1 (0x7f = 01111111) + pal += 3 * ((b0 & 0x7f) + 1); + } else if (b0 & 0x40) { // if top 2 bits are 01 (0x40 = 01000000) + byte c = (b0 & 0x3f) + 1; // get lower 6 bits + 1 (0x3f = 00111111) + uint s = 3 * *p++; + sz += c; - if (_header.audioInfo[track].compression == kCompressionRDFT || _header.audioInfo[track].compression == kCompressionDCT) { - // TODO: Compressed audio (Bink RDFT/DCT encoded) - free(soundBuffer); - return; - } else if (_header.audioInfo[track].compression == kCompressionDPCM) { - // Compressed audio (Huffman DPCM encoded) - queueCompressedBuffer(soundBuffer, chunkSize + 1, unpackedSize, track); - free(soundBuffer); - } else { - // Uncompressed audio (PCM) - byte flags = 0; - if (_header.audioInfo[track].is16Bits) - flags = flags | Audio::FLAG_16BITS; - if (_header.audioInfo[track].isStereo) - flags = flags | Audio::FLAG_STEREO; - - _audioStream->queueBuffer(soundBuffer, chunkSize, DisposeAfterUse::YES, flags); - // The sound buffer will be deleted by QueuingAudioStream - } + while (c--) { + *pal++ = oldPalette[s + 0]; + *pal++ = oldPalette[s + 1]; + *pal++ = oldPalette[s + 2]; + s += 3; + } + } else { // top 2 bits are 00 + sz++; + // get the lower 6 bits for each component (0x3f = 00111111) + byte b = b0 & 0x3f; + byte g = (*p++) & 0x3f; + byte r = (*p++) & 0x3f; - if (!_audioStarted) { - _mixer->playStream(_soundType, &_audioHandle, _audioStream, -1, getVolume(), getBalance()); - _audioStarted = true; + assert(g < 0xc0 && b < 0xc0); + + // upscale to full 8-bit color values by multiplying by 4 + *pal++ = b * 4; + *pal++ = g * 4; + *pal++ = r * 4; } - } else { - // Ignore the rest of the audio tracks, if they exist - // TODO: Are there any Smacker videos with more than one audio stream? - // If yes, we should play the rest of the audio streams as well - if (chunkSize > 0) - _fileStream->skip(chunkSize); } + + stream->seek(startPos + len); + free(chunk); + + _dirtyPalette = true; +} + +SmackerDecoder::SmackerAudioTrack::SmackerAudioTrack(const AudioInfo &audioInfo, Audio::Mixer::SoundType soundType) : + _audioInfo(audioInfo), _soundType(soundType) { + _audioStream = Audio::makeQueuingAudioStream(_audioInfo.sampleRate, _audioInfo.isStereo); +} + +SmackerDecoder::SmackerAudioTrack::~SmackerAudioTrack() { + delete _audioStream; } -void SmackerDecoder::queueCompressedBuffer(byte *buffer, uint32 bufferSize, - uint32 unpackedSize, int streamNum) { +bool SmackerDecoder::SmackerAudioTrack::rewind() { + delete _audioStream; + _audioStream = Audio::makeQueuingAudioStream(_audioInfo.sampleRate, _audioInfo.isStereo); + return true; +} +Audio::AudioStream *SmackerDecoder::SmackerAudioTrack::getAudioStream() const { + return _audioStream; +} + +void SmackerDecoder::SmackerAudioTrack::queueCompressedBuffer(byte *buffer, uint32 bufferSize, uint32 unpackedSize) { Common::BitStream8LSB audioBS(new Common::MemoryReadStream(buffer, bufferSize), true); bool dataPresent = audioBS.getBit(); @@ -689,9 +772,9 @@ void SmackerDecoder::queueCompressedBuffer(byte *buffer, uint32 bufferSize, return; bool isStereo = audioBS.getBit(); - assert(isStereo == _header.audioInfo[streamNum].isStereo); + assert(isStereo == _audioInfo.isStereo); bool is16Bits = audioBS.getBit(); - assert(is16Bits == _header.audioInfo[streamNum].is16Bits); + assert(is16Bits == _audioInfo.is16Bits); int numBytes = 1 * (isStereo ? 2 : 1) * (is16Bits ? 2 : 1); @@ -759,74 +842,21 @@ void SmackerDecoder::queueCompressedBuffer(byte *buffer, uint32 bufferSize, for (int k = 0; k < numBytes; k++) delete audioTrees[k]; - byte flags = 0; - if (_header.audioInfo[0].is16Bits) - flags = flags | Audio::FLAG_16BITS; - if (_header.audioInfo[0].isStereo) - flags = flags | Audio::FLAG_STEREO; - _audioStream->queueBuffer(unpackedBuffer, unpackedSize, DisposeAfterUse::YES, flags); - // unpackedBuffer will be deleted by QueuingAudioStream + queuePCM(unpackedBuffer, unpackedSize); } -void SmackerDecoder::unpackPalette() { - uint startPos = _fileStream->pos(); - uint32 len = 4 * _fileStream->readByte(); - - byte *chunk = (byte *)malloc(len); - _fileStream->read(chunk, len); - byte *p = chunk; - - byte oldPalette[3*256]; - memcpy(oldPalette, _palette, 3 * 256); - - byte *pal = _palette; - - int sz = 0; - byte b0; - while (sz < 256) { - b0 = *p++; - if (b0 & 0x80) { // if top bit is 1 (0x80 = 10000000) - sz += (b0 & 0x7f) + 1; // get lower 7 bits + 1 (0x7f = 01111111) - pal += 3 * ((b0 & 0x7f) + 1); - } else if (b0 & 0x40) { // if top 2 bits are 01 (0x40 = 01000000) - byte c = (b0 & 0x3f) + 1; // get lower 6 bits + 1 (0x3f = 00111111) - uint s = 3 * *p++; - sz += c; - - while (c--) { - *pal++ = oldPalette[s + 0]; - *pal++ = oldPalette[s + 1]; - *pal++ = oldPalette[s + 2]; - s += 3; - } - } else { // top 2 bits are 00 - sz++; - // get the lower 6 bits for each component (0x3f = 00111111) - byte b = b0 & 0x3f; - byte g = (*p++) & 0x3f; - byte r = (*p++) & 0x3f; - - assert(g < 0xc0 && b < 0xc0); - - // upscale to full 8-bit color values by multiplying by 4 - *pal++ = b * 4; - *pal++ = g * 4; - *pal++ = r * 4; - } - } - - _fileStream->seek(startPos + len); - free(chunk); -} +void SmackerDecoder::SmackerAudioTrack::queuePCM(byte *buffer, uint32 bufferSize) { + byte flags = 0; + if (_audioInfo.is16Bits) + flags |= Audio::FLAG_16BITS; + if (_audioInfo.isStereo) + flags |= Audio::FLAG_STEREO; -void SmackerDecoder::updateVolume() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) - g_system->getMixer()->setChannelVolume(_audioHandle, getVolume()); + _audioStream->queueBuffer(buffer, bufferSize, DisposeAfterUse::YES, flags); } -void SmackerDecoder::updateBalance() { - if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) - g_system->getMixer()->setChannelBalance(_audioHandle, getBalance()); +SmackerDecoder::SmackerVideoTrack *SmackerDecoder::createVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, uint32 flags, uint32 signature) const { + return new SmackerVideoTrack(width, height, frameCount, frameRate, flags, signature); } } // End of namespace Video diff --git a/video/smk_decoder.h b/video/smk_decoder.h index 516882e7c8..7227238373 100644 --- a/video/smk_decoder.h +++ b/video/smk_decoder.h @@ -34,6 +34,7 @@ class QueuingAudioStream; } namespace Common { +class BitStream; class SeekableReadStream; } @@ -56,42 +57,72 @@ class BigHuffmanTree; * - sword2 * - toon */ -class SmackerDecoder : public FixedRateVideoDecoder { +class SmackerDecoder : public VideoDecoder { public: - SmackerDecoder(Audio::Mixer *mixer, - Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType); + SmackerDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType); virtual ~SmackerDecoder(); - bool loadStream(Common::SeekableReadStream *stream); + virtual bool loadStream(Common::SeekableReadStream *stream); void close(); - bool isVideoLoaded() const { return _fileStream != 0; } - uint16 getWidth() const { return _surface->w; } - uint16 getHeight() const { return _surface->h; } - uint32 getFrameCount() const { return _frameCount; } - uint32 getTime() const; - const Graphics::Surface *decodeNextFrame(); - Graphics::PixelFormat getPixelFormat() const { return Graphics::PixelFormat::createFormatCLUT8(); } - const byte *getPalette() { _dirtyPalette = false; return _palette; } - bool hasDirtyPalette() const { return _dirtyPalette; } - virtual void handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize); + bool rewind(); protected: - Common::SeekableReadStream *_fileStream; + void readNextPacket(); + + virtual void handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize); - // VideoDecoder API - void updateVolume(); - void updateBalance(); + class SmackerVideoTrack : public FixedRateVideoTrack { + public: + SmackerVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, uint32 flags, uint32 signature); + ~SmackerVideoTrack(); - // FixedRateVideoDecoder API - Common::Rational getFrameRate() const { return _frameRate; } + bool isRewindable() const { return true; } + bool rewind() { _curFrame = -1; return true; } -protected: - void unpackPalette(); - // Possible runs of blocks - uint getBlockRun(int index) { return (index <= 58) ? index + 1 : 128 << (index - 59); } - void queueCompressedBuffer(byte *buffer, uint32 bufferSize, uint32 unpackedSize, int streamNum); + uint16 getWidth() const; + uint16 getHeight() const; + Graphics::PixelFormat getPixelFormat() const; + int getCurFrame() const { return _curFrame; } + int getFrameCount() const { return _frameCount; } + const Graphics::Surface *decodeNextFrame() { return _surface; } + const byte *getPalette() const { _dirtyPalette = false; return _palette; } + bool hasDirtyPalette() const { return _dirtyPalette; } + + void readTrees(Common::BitStream &bs, uint32 mMapSize, uint32 mClrSize, uint32 fullSize, uint32 typeSize); + void increaseCurFrame() { _curFrame++; } + void decodeFrame(Common::BitStream &bs); + void unpackPalette(Common::SeekableReadStream *stream); + + protected: + Common::Rational getFrameRate() const { return _frameRate; } + + Graphics::Surface *_surface; + + private: + Common::Rational _frameRate; + uint32 _flags, _signature; + + byte _palette[3 * 256]; + mutable bool _dirtyPalette; + + int _curFrame; + uint32 _frameCount; + + BigHuffmanTree *_MMapTree; + BigHuffmanTree *_MClrTree; + BigHuffmanTree *_FullTree; + BigHuffmanTree *_TypeTree; + // Possible runs of blocks + static uint getBlockRun(int index) { return (index <= 58) ? index + 1 : 128 << (index - 59); } + }; + + virtual SmackerVideoTrack *createVideoTrack(uint32 width, uint32 height, uint32 frameCount, const Common::Rational &frameRate, uint32 flags, uint32 signature) const; + + Common::SeekableReadStream *_fileStream; + +private: enum AudioCompression { kCompressionNone, kCompressionDPCM, @@ -120,6 +151,28 @@ protected: uint32 dummy; } _header; + class SmackerAudioTrack : public AudioTrack { + public: + SmackerAudioTrack(const AudioInfo &audioInfo, Audio::Mixer::SoundType soundType); + ~SmackerAudioTrack(); + + bool isRewindable() const { return true; } + bool rewind(); + + Audio::Mixer::SoundType getSoundType() const { return _soundType; } + + void queueCompressedBuffer(byte *buffer, uint32 bufferSize, uint32 unpackedSize); + void queuePCM(byte *buffer, uint32 bufferSize); + + protected: + Audio::AudioStream *getAudioStream() const; + + private: + Audio::Mixer::SoundType _soundType; + Audio::QueuingAudioStream *_audioStream; + AudioInfo _audioInfo; + }; + uint32 *_frameSizes; // The FrameTypes section of a Smacker file contains an array of bytes, where // the 8 bits of each byte describe the contents of the corresponding frame. @@ -127,25 +180,10 @@ protected: // and so on), so there can be up to 7 different audio tracks. When the lowest bit // (bit 0) is set, it denotes a frame that contains a palette record byte *_frameTypes; - byte *_frameData; - // The RGB palette - byte _palette[3 * 256]; - bool _dirtyPalette; - Common::Rational _frameRate; - uint32 _frameCount; - Graphics::Surface *_surface; + uint32 _firstFrameStart; Audio::Mixer::SoundType _soundType; - Audio::Mixer *_mixer; - bool _audioStarted; - Audio::QueuingAudioStream *_audioStream; - Audio::SoundHandle _audioHandle; - - BigHuffmanTree *_MMapTree; - BigHuffmanTree *_MClrTree; - BigHuffmanTree *_FullTree; - BigHuffmanTree *_TypeTree; }; } // End of namespace Video diff --git a/video/theora_decoder.cpp b/video/theora_decoder.cpp new file mode 100644 index 0000000000..d7260469e6 --- /dev/null +++ b/video/theora_decoder.cpp @@ -0,0 +1,487 @@ +/* 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 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. + * + */ + +/* + * Source is based on the player example from libvorbis package, + * available at: http://svn.xiph.org/trunk/theora/examples/player_example.c + * + * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. + * + * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2009 + * by the Xiph.Org Foundation and contributors http://www.xiph.org/ + * + */ + +#include "video/theora_decoder.h" + +#include "audio/audiostream.h" +#include "audio/decoders/raw.h" +#include "common/stream.h" +#include "common/system.h" +#include "common/textconsole.h" +#include "common/util.h" +#include "graphics/pixelformat.h" +#include "graphics/yuv_to_rgb.h" + +namespace Video { + +TheoraDecoder::TheoraDecoder(Audio::Mixer::SoundType soundType) : _soundType(soundType) { + _fileStream = 0; + + _videoTrack = 0; + _audioTrack = 0; + _hasVideo = _hasAudio = false; +} + +TheoraDecoder::~TheoraDecoder() { + close(); +} + +bool TheoraDecoder::loadStream(Common::SeekableReadStream *stream) { + close(); + + _fileStream = stream; + + // start up Ogg stream synchronization layer + ogg_sync_init(&_oggSync); + + // init supporting Vorbis structures needed in header parsing + vorbis_info_init(&_vorbisInfo); + vorbis_comment vorbisComment; + vorbis_comment_init(&vorbisComment); + + // init supporting Theora structures needed in header parsing + th_info theoraInfo; + th_info_init(&theoraInfo); + th_comment theoraComment; + th_comment_init(&theoraComment); + th_setup_info *theoraSetup = 0; + + uint theoraPackets = 0, vorbisPackets = 0; + + // Ogg file open; parse the headers + // Only interested in Vorbis/Theora streams + bool foundHeader = false; + while (!foundHeader) { + int ret = bufferData(); + + if (ret == 0) + break; // FIXME: Shouldn't this error out? + + while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) { + ogg_stream_state test; + + // is this a mandated initial header? If not, stop parsing + if (!ogg_page_bos(&_oggPage)) { + // don't leak the page; get it into the appropriate stream + queuePage(&_oggPage); + foundHeader = true; + break; + } + + ogg_stream_init(&test, ogg_page_serialno(&_oggPage)); + ogg_stream_pagein(&test, &_oggPage); + ogg_stream_packetout(&test, &_oggPacket); + + // identify the codec: try theora + if (theoraPackets == 0 && th_decode_headerin(&theoraInfo, &theoraComment, &theoraSetup, &_oggPacket) >= 0) { + // it is theora + memcpy(&_theoraOut, &test, sizeof(test)); + theoraPackets = 1; + _hasVideo = true; + } else if (vorbisPackets == 0 && vorbis_synthesis_headerin(&_vorbisInfo, &vorbisComment, &_oggPacket) >= 0) { + // it is vorbis + memcpy(&_vorbisOut, &test, sizeof(test)); + vorbisPackets = 1; + _hasAudio = true; + } else { + // whatever it is, we don't care about it + ogg_stream_clear(&test); + } + } + // fall through to non-bos page parsing + } + + // we're expecting more header packets. + while ((theoraPackets && theoraPackets < 3) || (vorbisPackets && vorbisPackets < 3)) { + int ret; + + // look for further theora headers + while (theoraPackets && (theoraPackets < 3) && (ret = ogg_stream_packetout(&_theoraOut, &_oggPacket))) { + if (ret < 0) + error("Error parsing Theora stream headers; corrupt stream?"); + + if (!th_decode_headerin(&theoraInfo, &theoraComment, &theoraSetup, &_oggPacket)) + error("Error parsing Theora stream headers; corrupt stream?"); + + theoraPackets++; + } + + // look for more vorbis header packets + while (vorbisPackets && (vorbisPackets < 3) && (ret = ogg_stream_packetout(&_vorbisOut, &_oggPacket))) { + if (ret < 0) + error("Error parsing Vorbis stream headers; corrupt stream?"); + + if (vorbis_synthesis_headerin(&_vorbisInfo, &vorbisComment, &_oggPacket)) + error("Error parsing Vorbis stream headers; corrupt stream?"); + + vorbisPackets++; + + if (vorbisPackets == 3) + break; + } + + // The header pages/packets will arrive before anything else we + // care about, or the stream is not obeying spec + + if (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) { + queuePage(&_oggPage); // demux into the appropriate stream + } else { + ret = bufferData(); // someone needs more data + + if (ret == 0) + error("End of file while searching for codec headers."); + } + } + + // And now we have it all. Initialize decoders next + if (_hasVideo) { + _videoTrack = new TheoraVideoTrack(getDefaultHighColorFormat(), theoraInfo, theoraSetup); + addTrack(_videoTrack); + } + + th_info_clear(&theoraInfo); + th_comment_clear(&theoraComment); + th_setup_free(theoraSetup); + + if (_hasAudio) { + _audioTrack = new VorbisAudioTrack(_soundType, _vorbisInfo); + + // Get enough audio data to start us off + while (!_audioTrack->hasAudio()) { + // Queue more data + bufferData(); + while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) + queuePage(&_oggPage); + + queueAudio(); + } + + addTrack(_audioTrack); + } + + vorbis_comment_clear(&vorbisComment); + + return true; +} + +void TheoraDecoder::close() { + VideoDecoder::close(); + + if (!_fileStream) + return; + + if (_videoTrack) { + ogg_stream_clear(&_theoraOut); + _videoTrack = 0; + } + + if (_audioTrack) { + ogg_stream_clear(&_vorbisOut); + _audioTrack = 0; + } + + ogg_sync_clear(&_oggSync); + vorbis_info_clear(&_vorbisInfo); + + delete _fileStream; + _fileStream = 0; + + _hasVideo = _hasAudio = false; +} + +void TheoraDecoder::readNextPacket() { + // First, let's get our frame + if (_hasVideo) { + while (!_videoTrack->endOfTrack()) { + // theora is one in, one out... + if (ogg_stream_packetout(&_theoraOut, &_oggPacket) > 0) { + if (_videoTrack->decodePacket(_oggPacket)) + break; + } else if (_theoraOut.e_o_s || _fileStream->eos()) { + // If we can't get any more frames, we're done. + _videoTrack->setEndOfVideo(); + } else { + // Queue more data + bufferData(); + while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) + queuePage(&_oggPage); + } + + // Update audio if we can + queueAudio(); + } + } + + // Then make sure we have enough audio buffered + ensureAudioBufferSize(); +} + +TheoraDecoder::TheoraVideoTrack::TheoraVideoTrack(const Graphics::PixelFormat &format, th_info &theoraInfo, th_setup_info *theoraSetup) { + _theoraDecode = th_decode_alloc(&theoraInfo, theoraSetup); + + if (theoraInfo.pixel_fmt != TH_PF_420) + error("Only theora YUV420 is supported"); + + int postProcessingMax; + th_decode_ctl(_theoraDecode, TH_DECCTL_GET_PPLEVEL_MAX, &postProcessingMax, sizeof(postProcessingMax)); + th_decode_ctl(_theoraDecode, TH_DECCTL_SET_PPLEVEL, &postProcessingMax, sizeof(postProcessingMax)); + + _surface.create(theoraInfo.frame_width, theoraInfo.frame_height, format); + + // Set up a display surface + _displaySurface.pixels = _surface.getBasePtr(theoraInfo.pic_x, theoraInfo.pic_y); + _displaySurface.w = theoraInfo.pic_width; + _displaySurface.h = theoraInfo.pic_height; + _displaySurface.format = format; + _displaySurface.pitch = _surface.pitch; + + // Set the frame rate + _frameRate = Common::Rational(theoraInfo.fps_numerator, theoraInfo.fps_denominator); + + _endOfVideo = false; + _nextFrameStartTime = 0.0; + _curFrame = -1; +} + +TheoraDecoder::TheoraVideoTrack::~TheoraVideoTrack() { + th_decode_free(_theoraDecode); + + _surface.free(); + _displaySurface.pixels = 0; +} + +bool TheoraDecoder::TheoraVideoTrack::decodePacket(ogg_packet &oggPacket) { + if (th_decode_packetin(_theoraDecode, &oggPacket, 0) == 0) { + _curFrame++; + + // Convert YUV data to RGB data + th_ycbcr_buffer yuv; + th_decode_ycbcr_out(_theoraDecode, yuv); + translateYUVtoRGBA(yuv); + + double time = th_granule_time(_theoraDecode, oggPacket.granulepos); + + // We need to calculate when the next frame should be shown + // This is all in floating point because that's what the Ogg code gives us + // Ogg is a lossy container format, so it doesn't always list the time to the + // next frame. In such cases, we need to calculate it ourselves. + if (time == -1.0) + _nextFrameStartTime += _frameRate.getInverse().toDouble(); + else + _nextFrameStartTime = time; + + return true; + } + + return false; +} + +enum TheoraYUVBuffers { + kBufferY = 0, + kBufferU = 1, + kBufferV = 2 +}; + +void TheoraDecoder::TheoraVideoTrack::translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer) { + // Width and height of all buffers have to be divisible by 2. + assert((YUVBuffer[kBufferY].width & 1) == 0); + assert((YUVBuffer[kBufferY].height & 1) == 0); + assert((YUVBuffer[kBufferU].width & 1) == 0); + assert((YUVBuffer[kBufferV].width & 1) == 0); + + // UV images have to have a quarter of the Y image resolution + assert(YUVBuffer[kBufferU].width == YUVBuffer[kBufferY].width >> 1); + assert(YUVBuffer[kBufferV].width == YUVBuffer[kBufferY].width >> 1); + assert(YUVBuffer[kBufferU].height == YUVBuffer[kBufferY].height >> 1); + assert(YUVBuffer[kBufferV].height == YUVBuffer[kBufferY].height >> 1); + + Graphics::convertYUV420ToRGB(&_surface, YUVBuffer[kBufferY].data, YUVBuffer[kBufferU].data, YUVBuffer[kBufferV].data, YUVBuffer[kBufferY].width, YUVBuffer[kBufferY].height, YUVBuffer[kBufferY].stride, YUVBuffer[kBufferU].stride); +} + +static vorbis_info *info = 0; + +TheoraDecoder::VorbisAudioTrack::VorbisAudioTrack(Audio::Mixer::SoundType soundType, vorbis_info &vorbisInfo) : _soundType(soundType) { + vorbis_synthesis_init(&_vorbisDSP, &vorbisInfo); + vorbis_block_init(&_vorbisDSP, &_vorbisBlock); + info = &vorbisInfo; + + _audStream = Audio::makeQueuingAudioStream(vorbisInfo.rate, vorbisInfo.channels); + + _audioBufferFill = 0; + _audioBuffer = 0; + _endOfAudio = false; +} + +TheoraDecoder::VorbisAudioTrack::~VorbisAudioTrack() { + vorbis_dsp_clear(&_vorbisDSP); + vorbis_block_clear(&_vorbisBlock); + delete _audStream; + free(_audioBuffer); +} + +Audio::AudioStream *TheoraDecoder::VorbisAudioTrack::getAudioStream() const { + return _audStream; +} + +#define AUDIOFD_FRAGSIZE 10240 + +static double rint(double v) { + return floor(v + 0.5); +} + +bool TheoraDecoder::VorbisAudioTrack::decodeSamples() { + float **pcm; + + // if there's pending, decoded audio, grab it + int ret = vorbis_synthesis_pcmout(&_vorbisDSP, &pcm); + + if (ret > 0) { + if (!_audioBuffer) { + _audioBuffer = (ogg_int16_t *)malloc(AUDIOFD_FRAGSIZE * sizeof(ogg_int16_t)); + assert(_audioBuffer); + } + + int channels = _audStream->isStereo() ? 2 : 1; + int count = _audioBufferFill / 2; + int maxsamples = ((AUDIOFD_FRAGSIZE - _audioBufferFill) / channels) >> 1; + int i; + + for (i = 0; i < ret && i < maxsamples; i++) { + for (int j = 0; j < channels; j++) { + int val = CLIP((int)rint(pcm[j][i] * 32767.f), -32768, 32767); + _audioBuffer[count++] = val; + } + } + + vorbis_synthesis_read(&_vorbisDSP, i); + _audioBufferFill += (i * channels) << 1; + + if (_audioBufferFill == AUDIOFD_FRAGSIZE) { + byte flags = Audio::FLAG_16BITS; + + if (_audStream->isStereo()) + flags |= Audio::FLAG_STEREO; + +#ifdef SCUMM_LITTLE_ENDIAN + flags |= Audio::FLAG_LITTLE_ENDIAN; +#endif + + _audStream->queueBuffer((byte *)_audioBuffer, AUDIOFD_FRAGSIZE, DisposeAfterUse::YES, flags); + + // The audio mixer is now responsible for the old audio buffer. + // We need to create a new one. + _audioBuffer = 0; + _audioBufferFill = 0; + } + + return true; + } + + return false; +} + +bool TheoraDecoder::VorbisAudioTrack::hasAudio() const { + return _audStream->numQueuedStreams() > 0; +} + +bool TheoraDecoder::VorbisAudioTrack::needsAudio() const { + // TODO: 5 is very arbitrary. We probably should do something like QuickTime does. + return !_endOfAudio && _audStream->numQueuedStreams() < 5; +} + +void TheoraDecoder::VorbisAudioTrack::synthesizePacket(ogg_packet &oggPacket) { + if (vorbis_synthesis(&_vorbisBlock, &oggPacket) == 0) // test for success + vorbis_synthesis_blockin(&_vorbisDSP, &_vorbisBlock); +} + +void TheoraDecoder::queuePage(ogg_page *page) { + if (_hasVideo) + ogg_stream_pagein(&_theoraOut, page); + + if (_hasAudio) + ogg_stream_pagein(&_vorbisOut, page); +} + +int TheoraDecoder::bufferData() { + char *buffer = ogg_sync_buffer(&_oggSync, 4096); + int bytes = _fileStream->read(buffer, 4096); + + ogg_sync_wrote(&_oggSync, bytes); + + return bytes; +} + +bool TheoraDecoder::queueAudio() { + if (!_hasAudio) + return false; + + bool queuedAudio = false; + + for (;;) { + if (_audioTrack->decodeSamples()) { + // we queued some pending audio + queuedAudio = true; + } else if (ogg_stream_packetout(&_vorbisOut, &_oggPacket) > 0) { + // no pending audio; is there a pending packet to decode? + _audioTrack->synthesizePacket(_oggPacket); + } else { + // we've buffered all we have, break out for now + break; + } + } + + return queuedAudio; +} + +void TheoraDecoder::ensureAudioBufferSize() { + if (!_hasAudio) + return; + + // Force at least some audio to be buffered + while (_audioTrack->needsAudio()) { + bufferData(); + while (ogg_sync_pageout(&_oggSync, &_oggPage) > 0) + queuePage(&_oggPage); + + bool queuedAudio = queueAudio(); + if ((_vorbisOut.e_o_s || _fileStream->eos()) && !queuedAudio) { + _audioTrack->setEndOfAudio(); + break; + } + } +} + +} // End of namespace Video diff --git a/video/theora_decoder.h b/video/theora_decoder.h new file mode 100644 index 0000000000..7e36d829e7 --- /dev/null +++ b/video/theora_decoder.h @@ -0,0 +1,157 @@ +/* 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 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/scummsys.h" // for USE_THEORADEC + +#ifdef USE_THEORADEC + +#ifndef VIDEO_THEORA_DECODER_H +#define VIDEO_THEORA_DECODER_H + +#include "common/rational.h" +#include "video/video_decoder.h" +#include "audio/mixer.h" +#include "graphics/surface.h" + +#include <theora/theoradec.h> +#include <vorbis/codec.h> + +namespace Common { +class SeekableReadStream; +} + +namespace Audio { +class AudioStream; +class QueuingAudioStream; +} + +namespace Video { + +/** + * + * Decoder for Theora videos. + * Video decoder used in engines: + * - sword25 + */ +class TheoraDecoder : public VideoDecoder { +public: + TheoraDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kMusicSoundType); + virtual ~TheoraDecoder(); + + /** + * Load a video file + * @param stream the stream to load + */ + bool loadStream(Common::SeekableReadStream *stream); + void close(); + +protected: + void readNextPacket(); + +private: + class TheoraVideoTrack : public VideoTrack { + public: + TheoraVideoTrack(const Graphics::PixelFormat &format, th_info &theoraInfo, th_setup_info *theoraSetup); + ~TheoraVideoTrack(); + + bool endOfTrack() const { return _endOfVideo; } + uint16 getWidth() const { return _displaySurface.w; } + uint16 getHeight() const { return _displaySurface.h; } + Graphics::PixelFormat getPixelFormat() const { return _displaySurface.format; } + int getCurFrame() const { return _curFrame; } + uint32 getNextFrameStartTime() const { return (uint32)(_nextFrameStartTime * 1000); } + const Graphics::Surface *decodeNextFrame() { return &_displaySurface; } + + bool decodePacket(ogg_packet &oggPacket); + void setEndOfVideo() { _endOfVideo = true; } + + private: + int _curFrame; + bool _endOfVideo; + Common::Rational _frameRate; + double _nextFrameStartTime; + + Graphics::Surface _surface; + Graphics::Surface _displaySurface; + + th_dec_ctx *_theoraDecode; + + void translateYUVtoRGBA(th_ycbcr_buffer &YUVBuffer); + }; + + class VorbisAudioTrack : public AudioTrack { + public: + VorbisAudioTrack(Audio::Mixer::SoundType soundType, vorbis_info &vorbisInfo); + ~VorbisAudioTrack(); + + Audio::Mixer::SoundType getSoundType() const { return _soundType; } + + bool decodeSamples(); + bool hasAudio() const; + bool needsAudio() const; + void synthesizePacket(ogg_packet &oggPacket); + void setEndOfAudio() { _endOfAudio = true; } + + protected: + Audio::AudioStream *getAudioStream() const; + + private: + // single audio fragment audio buffering + int _audioBufferFill; + ogg_int16_t *_audioBuffer; + + Audio::Mixer::SoundType _soundType; + Audio::QueuingAudioStream *_audStream; + + vorbis_block _vorbisBlock; + vorbis_dsp_state _vorbisDSP; + + bool _endOfAudio; + }; + + void queuePage(ogg_page *page); + int bufferData(); + bool queueAudio(); + void ensureAudioBufferSize(); + + Common::SeekableReadStream *_fileStream; + + Audio::Mixer::SoundType _soundType; + + ogg_sync_state _oggSync; + ogg_page _oggPage; + ogg_packet _oggPacket; + + ogg_stream_state _theoraOut, _vorbisOut; + bool _hasVideo, _hasAudio; + + vorbis_info _vorbisInfo; + + TheoraVideoTrack *_videoTrack; + VorbisAudioTrack *_audioTrack; +}; + +} // End of namespace Video + +#endif + +#endif diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index 44d7917652..559880acee 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -22,6 +22,7 @@ #include "video/video_decoder.h" +#include "audio/audiostream.h" #include "audio/mixer.h" // for kMaxChannelVolume #include "common/rational.h" @@ -33,7 +34,45 @@ namespace Video { VideoDecoder::VideoDecoder() { - reset(); + _startTime = 0; + _needsRewind = false; + _dirtyPalette = false; + _palette = 0; + _isPlaying = false; + _audioVolume = Audio::Mixer::kMaxChannelVolume; + _audioBalance = 0; + _pauseLevel = 0; + _needsUpdate = false; + _lastTimeChange = 0; + _endTime = 0; + _endTimeSet = false; + + // Find the best format for output + _defaultHighColorFormat = g_system->getScreenFormat(); + + if (_defaultHighColorFormat.bytesPerPixel == 1) + _defaultHighColorFormat = Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0); +} + +void VideoDecoder::close() { + if (isPlaying()) + stop(); + + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + delete *it; + + _tracks.clear(); + _needsRewind = false; + _dirtyPalette = false; + _palette = 0; + _startTime = 0; + _audioVolume = Audio::Mixer::kMaxChannelVolume; + _audioBalance = 0; + _pauseLevel = 0; + _needsUpdate = false; + _lastTimeChange = 0; + _endTime = 0; + _endTimeSet = false; } bool VideoDecoder::loadFile(const Common::String &filename) { @@ -47,30 +86,10 @@ bool VideoDecoder::loadFile(const Common::String &filename) { return loadStream(file); } -uint32 VideoDecoder::getTime() const { - return g_system->getMillis() - _startTime; -} - -void VideoDecoder::setSystemPalette() { - g_system->getPaletteManager()->setPalette(getPalette(), 0, 256); -} - bool VideoDecoder::needsUpdate() const { return !endOfVideo() && getTimeToNextFrame() == 0; } -void VideoDecoder::reset() { - _curFrame = -1; - _startTime = 0; - _pauseLevel = 0; - _audioVolume = Audio::Mixer::kMaxChannelVolume; - _audioBalance = 0; -} - -bool VideoDecoder::endOfVideo() const { - return !isVideoLoaded() || (getCurFrame() >= (int32)getFrameCount() - 1); -} - void VideoDecoder::pauseVideo(bool pause) { if (pause) { _pauseLevel++; @@ -86,10 +105,14 @@ void VideoDecoder::pauseVideo(bool pause) { if (_pauseLevel == 1 && pause) { _pauseStartTime = g_system->getMillis(); // Store the starting time from pausing to keep it for later - pauseVideoIntern(true); + + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + (*it)->pause(true); } else if (_pauseLevel == 0) { - pauseVideoIntern(false); - addPauseTime(g_system->getMillis() - _pauseStartTime); + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + (*it)->pause(false); + + _startTime += (g_system->getMillis() - _pauseStartTime); } } @@ -100,33 +123,560 @@ void VideoDecoder::resetPauseStartTime() { void VideoDecoder::setVolume(byte volume) { _audioVolume = volume; - updateVolume(); + + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeAudio) + ((AudioTrack *)*it)->setVolume(_audioVolume); } void VideoDecoder::setBalance(int8 balance) { _audioBalance = balance; - updateBalance(); + + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeAudio) + ((AudioTrack *)*it)->setBalance(_audioBalance); +} + +bool VideoDecoder::isVideoLoaded() const { + return !_tracks.empty(); +} + +uint16 VideoDecoder::getWidth() const { + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeVideo) + return ((VideoTrack *)*it)->getWidth(); + + return 0; +} + +uint16 VideoDecoder::getHeight() const { + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeVideo) + return ((VideoTrack *)*it)->getHeight(); + + return 0; +} + +Graphics::PixelFormat VideoDecoder::getPixelFormat() const { + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeVideo) + return ((VideoTrack *)*it)->getPixelFormat(); + + return Graphics::PixelFormat(); } -uint32 FixedRateVideoDecoder::getTimeToNextFrame() const { - if (endOfVideo() || _curFrame < 0) +const Graphics::Surface *VideoDecoder::decodeNextFrame() { + _needsUpdate = false; + + readNextPacket(); + VideoTrack *track = findNextVideoTrack(); + + if (!track) + return 0; + + const Graphics::Surface *frame = track->decodeNextFrame(); + + if (track->hasDirtyPalette()) { + _palette = track->getPalette(); + _dirtyPalette = true; + } + + return frame; +} + +const byte *VideoDecoder::getPalette() { + _dirtyPalette = false; + return _palette; +} + +int VideoDecoder::getCurFrame() const { + int32 frame = -1; + + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeVideo) + frame += ((VideoTrack *)*it)->getCurFrame() + 1; + + return frame; +} + +uint32 VideoDecoder::getFrameCount() const { + int count = 0; + + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeVideo) + count += ((VideoTrack *)*it)->getFrameCount(); + + return count; +} + +uint32 VideoDecoder::getTime() const { + if (!isPlaying()) + return _lastTimeChange.msecs(); + + if (isPaused()) + return _pauseStartTime - _startTime; + + if (useAudioSync()) { + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) { + if ((*it)->getTrackType() == Track::kTrackTypeAudio && !(*it)->endOfTrack()) { + uint32 time = ((const AudioTrack *)*it)->getRunningTime(); + + if (time != 0) + return time + _lastTimeChange.msecs(); + } + } + } + + return g_system->getMillis() - _startTime; +} + +uint32 VideoDecoder::getTimeToNextFrame() const { + if (endOfVideo() || _needsUpdate) + return 0; + + const VideoTrack *track = findNextVideoTrack(); + + if (!track) return 0; uint32 elapsedTime = getTime(); - uint32 nextFrameStartTime = getFrameBeginTime(_curFrame + 1); + uint32 nextFrameStartTime = track->getNextFrameStartTime(); - // If the time that the next frame should be shown has past - // the frame should be shown ASAP. if (nextFrameStartTime <= elapsedTime) return 0; return nextFrameStartTime - elapsedTime; } -uint32 FixedRateVideoDecoder::getFrameBeginTime(uint32 frame) const { - Common::Rational beginTime = frame * 1000; - beginTime /= getFrameRate(); - return beginTime.toInt(); +bool VideoDecoder::endOfVideo() const { + if (!isVideoLoaded()) + return true; + + if (_endTimeSet) { + const VideoTrack *track = findNextVideoTrack(); + + if (track && track->getNextFrameStartTime() >= (uint)_endTime.msecs()) + return true; + } + + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) + if (!(*it)->endOfTrack()) + return false; + + return true; +} + +bool VideoDecoder::isRewindable() const { + if (!isVideoLoaded()) + return false; + + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) + if (!(*it)->isRewindable()) + return false; + + return true; +} + +bool VideoDecoder::rewind() { + if (!isRewindable()) + return false; + + _needsRewind = false; + + // Stop all tracks so they can be rewound + if (isPlaying()) + stopAudio(); + + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + if (!(*it)->rewind()) + return false; + + // Now that we've rewound, start all tracks again + if (isPlaying()) + startAudio(); + + _lastTimeChange = 0; + _startTime = g_system->getMillis(); + resetPauseStartTime(); + return true; +} + +bool VideoDecoder::isSeekable() const { + if (!isVideoLoaded()) + return false; + + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) + if (!(*it)->isSeekable()) + return false; + + return true; +} + +bool VideoDecoder::seek(const Audio::Timestamp &time) { + if (!isSeekable()) + return false; + + _needsRewind = false; + + // Stop all tracks so they can be seeked + if (isPlaying()) + stopAudio(); + + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + if (!(*it)->seek(time)) + return false; + + _lastTimeChange = time; + + // Now that we've seeked, start all tracks again + // Also reset our start time + if (isPlaying()) { + startAudio(); + _startTime = g_system->getMillis() - time.msecs(); + } + + resetPauseStartTime(); + _needsUpdate = true; + return true; +} + +void VideoDecoder::start() { + if (isPlaying() || !isVideoLoaded()) + return; + + _isPlaying = true; + _startTime = g_system->getMillis(); + + // If someone previously called stop(), we'll rewind it. + if (_needsRewind) + rewind(); + + // Adjust start time if we've seeked to something besides zero time + if (_lastTimeChange.totalNumberOfFrames() != 0) + _startTime -= _lastTimeChange.msecs(); + + startAudio(); +} + +void VideoDecoder::stop() { + if (!isPlaying()) + return; + + _isPlaying = false; + _startTime = 0; + _palette = 0; + _dirtyPalette = false; + _needsUpdate = false; + + stopAudio(); + + // Also reset the pause state. + _pauseLevel = 0; + + // If this is a rewindable video, don't close it too. We'll just rewind() the video + // the next time someone calls start(). Otherwise, since it can't be rewound, we + // just close it. + if (isRewindable()) { + _lastTimeChange = getTime(); + _needsRewind = true; + } else { + close(); + } +} + +Audio::Timestamp VideoDecoder::getDuration() const { + Audio::Timestamp maxDuration(0, 1000); + + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) { + Audio::Timestamp duration = (*it)->getDuration(); + + if (duration > maxDuration) + maxDuration = duration; + } + + return maxDuration; +} + +VideoDecoder::Track::Track() { + _paused = false; +} + +bool VideoDecoder::Track::isRewindable() const { + return isSeekable(); +} + +bool VideoDecoder::Track::rewind() { + return seek(Audio::Timestamp(0, 1000)); +} + +Audio::Timestamp VideoDecoder::Track::getDuration() const { + return Audio::Timestamp(0, 1000); +} + +bool VideoDecoder::VideoTrack::endOfTrack() const { + return getCurFrame() >= (getFrameCount() - 1); +} + +uint32 VideoDecoder::FixedRateVideoTrack::getNextFrameStartTime() const { + if (endOfTrack() || getCurFrame() < 0) + return 0; + + Common::Rational time = (getCurFrame() + 1) * 1000; + time /= getFrameRate(); + return time.toInt(); +} + +Audio::Timestamp VideoDecoder::FixedRateVideoTrack::getDuration() const { + // Since Audio::Timestamp doesn't support a fractional frame rate, we're currently + // just converting to milliseconds. + Common::Rational time = getFrameCount() * 1000; + time /= getFrameRate(); + return time.toInt(); +} + +bool VideoDecoder::AudioTrack::endOfTrack() const { + Audio::AudioStream *stream = getAudioStream(); + return !stream || !g_system->getMixer()->isSoundHandleActive(_handle) || stream->endOfData(); +} + +void VideoDecoder::AudioTrack::setVolume(byte volume) { + _volume = volume; + + if (g_system->getMixer()->isSoundHandleActive(_handle)) + g_system->getMixer()->setChannelVolume(_handle, _volume); +} + +void VideoDecoder::AudioTrack::setBalance(int8 balance) { + _balance = balance; + + if (g_system->getMixer()->isSoundHandleActive(_handle)) + g_system->getMixer()->setChannelBalance(_handle, _balance); +} + +void VideoDecoder::AudioTrack::start() { + stop(); + + Audio::AudioStream *stream = getAudioStream(); + assert(stream); + + g_system->getMixer()->playStream(getSoundType(), &_handle, stream, -1, getVolume(), getBalance(), DisposeAfterUse::NO); + + // Pause the audio again if we're still paused + if (isPaused()) + g_system->getMixer()->pauseHandle(_handle, true); +} + +void VideoDecoder::AudioTrack::stop() { + g_system->getMixer()->stopHandle(_handle); +} + +void VideoDecoder::AudioTrack::start(const Audio::Timestamp &limit) { + stop(); + + Audio::AudioStream *stream = getAudioStream(); + assert(stream); + + stream = Audio::makeLimitingAudioStream(stream, limit, DisposeAfterUse::NO); + + g_system->getMixer()->playStream(getSoundType(), &_handle, stream, -1, getVolume(), getBalance(), DisposeAfterUse::YES); + + // Pause the audio again if we're still paused + if (isPaused()) + g_system->getMixer()->pauseHandle(_handle, true); +} + +uint32 VideoDecoder::AudioTrack::getRunningTime() const { + if (g_system->getMixer()->isSoundHandleActive(_handle)) + return g_system->getMixer()->getSoundElapsedTime(_handle); + + return 0; +} + +void VideoDecoder::AudioTrack::pauseIntern(bool shouldPause) { + if (g_system->getMixer()->isSoundHandleActive(_handle)) + g_system->getMixer()->pauseHandle(_handle, shouldPause); +} + +Audio::AudioStream *VideoDecoder::RewindableAudioTrack::getAudioStream() const { + return getRewindableAudioStream(); +} + +bool VideoDecoder::RewindableAudioTrack::rewind() { + Audio::RewindableAudioStream *stream = getRewindableAudioStream(); + assert(stream); + return stream->rewind(); +} + +Audio::Timestamp VideoDecoder::SeekableAudioTrack::getDuration() const { + Audio::SeekableAudioStream *stream = getSeekableAudioStream(); + assert(stream); + return stream->getLength(); +} + +Audio::AudioStream *VideoDecoder::SeekableAudioTrack::getAudioStream() const { + return getSeekableAudioStream(); +} + +bool VideoDecoder::SeekableAudioTrack::seek(const Audio::Timestamp &time) { + Audio::SeekableAudioStream *stream = getSeekableAudioStream(); + assert(stream); + return stream->seek(time); +} + +VideoDecoder::StreamFileAudioTrack::StreamFileAudioTrack() { + _stream = 0; +} + +VideoDecoder::StreamFileAudioTrack::~StreamFileAudioTrack() { + delete _stream; +} + +bool VideoDecoder::StreamFileAudioTrack::loadFromFile(const Common::String &baseName) { + // TODO: Make sure the stream isn't being played + delete _stream; + _stream = Audio::SeekableAudioStream::openStreamFile(baseName); + return _stream != 0; +} + +void VideoDecoder::addTrack(Track *track) { + _tracks.push_back(track); + + // Update volume settings if it's an audio track + if (track->getTrackType() == Track::kTrackTypeAudio) { + ((AudioTrack *)track)->setVolume(_audioVolume); + ((AudioTrack *)track)->setBalance(_audioBalance); + } + + // Keep the track paused if we're paused + if (isPaused()) + track->pause(true); + + // Start the track if we're playing + if (isPlaying() && track->getTrackType() == Track::kTrackTypeAudio) + ((AudioTrack *)track)->start(); +} + +bool VideoDecoder::addStreamFileTrack(const Common::String &baseName) { + // Only allow adding external tracks if a video is already loaded + if (!isVideoLoaded()) + return false; + + StreamFileAudioTrack *track = new StreamFileAudioTrack(); + + bool result = track->loadFromFile(baseName); + + if (result) + addTrack(track); + + return result; +} + +void VideoDecoder::setEndTime(const Audio::Timestamp &endTime) { + Audio::Timestamp startTime = 0; + + if (isPlaying()) { + startTime = getTime(); + stopAudio(); + } + + _endTime = endTime; + _endTimeSet = true; + + if (startTime > endTime) + return; + + if (isPlaying()) { + // We'll assume the audio track is going to start up at the same time it just was + // and therefore not do any seeking. + // Might want to set it anyway if we're seekable. + startAudioLimit(_endTime.msecs() - startTime.msecs()); + _lastTimeChange = startTime; + } +} + +VideoDecoder::Track *VideoDecoder::getTrack(uint track) { + if (track > _tracks.size()) + return 0; + + return _tracks[track]; +} + +const VideoDecoder::Track *VideoDecoder::getTrack(uint track) const { + if (track > _tracks.size()) + return 0; + + return _tracks[track]; +} + +bool VideoDecoder::endOfVideoTracks() const { + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeVideo && !(*it)->endOfTrack()) + return false; + + return true; +} + +VideoDecoder::VideoTrack *VideoDecoder::findNextVideoTrack() { + VideoTrack *bestTrack = 0; + uint32 bestTime = 0xFFFFFFFF; + + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) { + if ((*it)->getTrackType() == Track::kTrackTypeVideo && !(*it)->endOfTrack()) { + VideoTrack *track = (VideoTrack *)*it; + uint32 time = track->getNextFrameStartTime(); + + if (time < bestTime) { + bestTime = time; + bestTrack = track; + } + } + } + + return bestTrack; +} + +const VideoDecoder::VideoTrack *VideoDecoder::findNextVideoTrack() const { + const VideoTrack *bestTrack = 0; + uint32 bestTime = 0xFFFFFFFF; + + for (TrackList::const_iterator it = _tracks.begin(); it != _tracks.end(); it++) { + if ((*it)->getTrackType() == Track::kTrackTypeVideo && !(*it)->endOfTrack()) { + const VideoTrack *track = (const VideoTrack *)*it; + uint32 time = track->getNextFrameStartTime(); + + if (time < bestTime) { + bestTime = time; + bestTrack = track; + } + } + } + + return bestTrack; +} + +void VideoDecoder::startAudio() { + if (_endTimeSet) { + // HACK: Timestamp's subtraction asserts out when subtracting two times + // with different rates. + startAudioLimit(_endTime - _lastTimeChange.convertToFramerate(_endTime.framerate())); + return; + } + + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeAudio) + ((AudioTrack *)*it)->start(); +} + +void VideoDecoder::stopAudio() { + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeAudio) + ((AudioTrack *)*it)->stop(); +} + +void VideoDecoder::startAudioLimit(const Audio::Timestamp &limit) { + for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeAudio) + ((AudioTrack *)*it)->start(limit); } } // End of namespace Video diff --git a/video/video_decoder.h b/video/video_decoder.h index 3bb75ade09..5abe1d917c 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -23,10 +23,17 @@ #ifndef VIDEO_DECODER_H #define VIDEO_DECODER_H -#include "common/str.h" - +#include "audio/mixer.h" #include "audio/timestamp.h" // TODO: Move this to common/ ? +#include "common/array.h" +#include "common/str.h" +#include "graphics/pixelformat.h" +namespace Audio { +class AudioStream; +class RewindableAudioStream; +class SeekableAudioStream; +} namespace Common { class Rational; @@ -34,7 +41,6 @@ class SeekableReadStream; } namespace Graphics { -struct PixelFormat; struct Surface; } @@ -48,10 +54,14 @@ public: VideoDecoder(); virtual ~VideoDecoder() {} + ///////////////////////////////////////// + // Opening/Closing a Video + ///////////////////////////////////////// + /** * Load a video from a file with the given name. * - * A default implementation using loadStream is provided. + * A default implementation using Common::File and loadStream is provided. * * @param filename the filename to load * @return whether loading the file succeeded @@ -62,6 +72,10 @@ public: * Load a video from a generic read stream. The ownership of the * stream object transfers to this VideoDecoder instance, which is * hence also responsible for eventually deleting it. + * + * Implementations of this function are required to call addTrack() + * for each track in the video upon success. + * * @param stream the stream to load * @return whether loading the stream succeeded */ @@ -69,60 +83,133 @@ public: /** * Close the active video stream and free any associated resources. + * + * All subclasses that need to close their own resources should still + * call the base class' close() function at the start of their function. */ - virtual void close() = 0; + virtual void close(); /** * Returns if a video stream is currently loaded or not. */ - virtual bool isVideoLoaded() const = 0; + bool isVideoLoaded() const; + ///////////////////////////////////////// + // Playback Control + ///////////////////////////////////////// /** - * Returns the width of the video's frames. - * @return the width of the video's frames + * Begin playback of the video. + * + * @note This has no effect is the video is already playing. */ - virtual uint16 getWidth() const = 0; + void start(); /** - * Returns the height of the video's frames. - * @return the height of the video's frames + * Stop playback of the video. + * + * @note This will close() the video if it is not rewindable. + * @note If the video is rewindable, the video will be rewound on the + * next start() call unless rewind() or seek() is called before then. */ - virtual uint16 getHeight() const = 0; + void stop(); /** - * Get the pixel format of the currently loaded video. + * Returns if the video is currently playing or not. + * + * This is not equivalent to the inverse of endOfVideo(). A video keeps + * its playing status even after reaching the end of the video. This will + * return true after calling start() and will continue to return true + * until stop() (or close()) is called. */ - virtual Graphics::PixelFormat getPixelFormat() const = 0; + bool isPlaying() const { return _isPlaying; } /** - * Get the palette for the video in RGB format (if 8bpp or less). + * Returns if a video is rewindable or not. The default implementation + * polls each track for rewindability. */ - virtual const byte *getPalette() { return 0; } + virtual bool isRewindable() const; /** - * Returns if the palette is dirty or not. + * Rewind a video to its beginning. + * + * If the video is playing, it will continue to play. The default + * implementation will rewind each track. + * + * @return true on success, false otherwise + */ + virtual bool rewind(); + + /** + * Returns if a video is seekable or not. The default implementation + * polls each track for seekability. + */ + virtual bool isSeekable() const; + + /** + * Seek to a given time in the video. + * + * If the video is playing, it will continue to play. The default + * implementation will seek each track and must still be called + * from any other implementation. + * + * @param time The time to seek to + * @return true on success, false otherwise */ - virtual bool hasDirtyPalette() const { return false; } + virtual bool seek(const Audio::Timestamp &time); /** - * Set the system palette to the palette returned by getPalette. - * @see getPalette + * Pause or resume the video. This should stop/resume any audio playback + * and other stuff. The initial pause time is kept so that any timing + * variables can be updated appropriately. + * + * This is a convenience method which automatically keeps track on how + * often the video has been paused, ensuring that after pausing an video + * e.g. twice, it has to be unpaused twice before actuallying resuming. + * + * @param pause true to pause the video, false to resume it */ - void setSystemPalette(); + void pauseVideo(bool pause); + + /** + * Return whether the video is currently paused or not. + */ + bool isPaused() const { return _pauseLevel != 0; } + + /** + * Set the time for this video to end at. At this time in the video, + * all audio will stop and endOfVideo() will return true. + */ + void setEndTime(const Audio::Timestamp &endTime); + + /** + * Get the stop time of the video (if not set, zero) + */ + Audio::Timestamp getEndTime() const { return _endTime; } + + + ///////////////////////////////////////// + // Playback Status + ///////////////////////////////////////// + + /** + * Returns if the video has reached the end or not. + * @return true if the video has finished playing or if none is loaded, false otherwise + */ + bool endOfVideo() const; /** * Returns the current frame number of the video. * @return the last frame decoded by the video */ - virtual int32 getCurFrame() const { return _curFrame; } + int32 getCurFrame() const; /** * Returns the number of frames in the video. * @return the number of frames in the video */ - virtual uint32 getFrameCount() const = 0; + uint32 getFrameCount() const; /** * Returns the time position (in ms) of the current video. @@ -138,103 +225,456 @@ public: * completely accurate (since our mixer does not have precise * timing). */ - virtual uint32 getTime() const; + uint32 getTime() const; + + + ///////////////////////////////////////// + // Video Info + ///////////////////////////////////////// + + /** + * Returns the width of the video's frames. + * + * By default, this finds the largest width between all of the loaded + * tracks. However, a subclass may override this if it does any kind + * of post-processing on it. + * + * @return the width of the video's frames + */ + virtual uint16 getWidth() const; + + /** + * Returns the height of the video's frames. + * + * By default, this finds the largest height between all of the loaded + * tracks. However, a subclass may override this if it does any kind + * of post-processing on it. + * + * @return the height of the video's frames + */ + virtual uint16 getHeight() const; + + /** + * Get the pixel format of the currently loaded video. + */ + Graphics::PixelFormat getPixelFormat() const; + + /** + * Get the duration of the video. + * + * If the duration is unknown, this will return 0. If this is not + * overriden, it will take the length of the longest track. + */ + virtual Audio::Timestamp getDuration() const; + + + ///////////////////////////////////////// + // Frame Decoding + ///////////////////////////////////////// + + /** + * Get the palette for the video in RGB format (if 8bpp or less). + * + * The palette's format is the same as PaletteManager's palette + * (interleaved RGB values). + */ + const byte *getPalette(); + + /** + * Returns if the palette is dirty or not. + */ + bool hasDirtyPalette() const { return _dirtyPalette; } /** * Return the time (in ms) until the next frame should be displayed. */ - virtual uint32 getTimeToNextFrame() const = 0; + uint32 getTimeToNextFrame() const; /** * Check whether a new frame should be decoded, i.e. because enough * time has elapsed since the last frame was decoded. * @return whether a new frame should be decoded or not */ - virtual bool needsUpdate() const; + bool needsUpdate() const; /** * Decode the next frame into a surface and return the latter. + * + * A subclass may override this, but must still call this function. As an + * example, a subclass may do this to apply some global video scale to + * individual track's frame. + * + * Note that this will call readNextPacket() internally first before calling + * the next video track's decodeNextFrame() function. + * * @return a surface containing the decoded frame, or 0 * @note Ownership of the returned surface stays with the VideoDecoder, * hence the caller must *not* free it. * @note this may return 0, in which case the last frame should be kept on screen */ - virtual const Graphics::Surface *decodeNextFrame() = 0; - - /** - * Returns if the video has finished playing or not. - * @return true if the video has finished playing or if none is loaded, false otherwise - */ - virtual bool endOfVideo() const; + virtual const Graphics::Surface *decodeNextFrame(); /** - * Pause or resume the video. This should stop/resume any audio playback - * and other stuff. The initial pause time is kept so that any timing - * variables can be updated appropriately. + * Set the default high color format for videos that convert from YUV. * - * This is a convenience method which automatically keeps track on how - * often the video has been paused, ensuring that after pausing an video - * e.g. twice, it has to be unpaused twice before actuallying resuming. + * By default, VideoDecoder will attempt to use the screen format + * if it's >8bpp and use a 32bpp format when not. * - * @param pause true to pause the video, false to resume it + * This must be set before calling loadStream(). */ - void pauseVideo(bool pause); + void setDefaultHighColorFormat(const Graphics::PixelFormat &format) { _defaultHighColorFormat = format; } - /** - * Return whether the video is currently paused or not. - */ - bool isPaused() const { return _pauseLevel != 0; } + + ///////////////////////////////////////// + // Audio Control + ///////////////////////////////////////// /** * Get the current volume at which the audio in the video is being played * @return the current volume at which the audio in the video is being played */ - virtual byte getVolume() const { return _audioVolume; } + byte getVolume() const { return _audioVolume; } /** * Set the volume at which the audio in the video should be played. - * This setting remains until reset() is called (which may be called - * from loadStream() or close()). The default volume is the maximum. - * - * @note This function calls updateVolume() by default. + * This setting remains until close() is called (which may be called + * from loadStream()). The default volume is the maximum. * * @param volume The volume at which to play the audio in the video */ - virtual void setVolume(byte volume); + void setVolume(byte volume); /** * Get the current balance at which the audio in the video is being played * @return the current balance at which the audio in the video is being played */ - virtual int8 getBalance() const { return _audioBalance; } + int8 getBalance() const { return _audioBalance; } /** * Set the balance at which the audio in the video should be played. - * This setting remains until reset() is called (which may be called - * from loadStream() or close()). The default balance is 0. - * - * @note This function calls updateBalance() by default. + * This setting remains until close() is called (which may be called + * from loadStream()). The default balance is 0. * * @param balance The balance at which to play the audio in the video */ - virtual void setBalance(int8 balance); + void setBalance(int8 balance); + + /** + * Add an audio track from a stream file. + * + * This calls SeekableAudioStream::openStreamFile() internally + */ + bool addStreamFileTrack(const Common::String &baseName); + + + // Future API + //void setRate(const Common::Rational &rate); + //Common::Rational getRate() const; protected: /** - * Resets _curFrame and _startTime. Should be called from every close() function. + * An abstract representation of a track in a movie. + */ + class Track { + public: + Track(); + virtual ~Track() {} + + /** + * The types of tracks this class can be. + */ + enum TrackType { + kTrackTypeNone, + kTrackTypeVideo, + kTrackTypeAudio + }; + + /** + * Get the type of track. + */ + virtual TrackType getTrackType() const = 0; + + /** + * Return if the track has finished. + */ + virtual bool endOfTrack() const = 0; + + /** + * Return if the track is rewindable. + * + * If a video is seekable, it does not need to implement this + * for it to also be rewindable. + */ + virtual bool isRewindable() const; + + /** + * Rewind the video to the beginning. + * + * If a video is seekable, it does not need to implement this + * for it to also be rewindable. + * + * @return true on success, false otherwise. + */ + virtual bool rewind(); + + /** + * Return if the track is seekable. + */ + virtual bool isSeekable() const { return false; } + + /** + * Seek to the given time. + * @param time The time to seek to, from the beginning of the video. + * @return true on success, false otherwise. + */ + virtual bool seek(const Audio::Timestamp &time) { return false; } + + /** + * Set the pause status of the track. + */ + void pause(bool shouldPause) {} + + /** + * Return if the track is paused. + */ + bool isPaused() const { return _paused; } + + /** + * Get the duration of the track (starting from this track's start time). + * + * By default, this returns 0 for unknown. + */ + virtual Audio::Timestamp getDuration() const; + + protected: + /** + * Function called by pause() for subclasses to implement. + */ + void pauseIntern(bool pause); + + private: + bool _paused; + }; + + /** + * An abstract representation of a video track. + */ + class VideoTrack : public Track { + public: + VideoTrack() {} + virtual ~VideoTrack() {} + + TrackType getTrackType() const { return kTrackTypeVideo; } + virtual bool endOfTrack() const; + + /** + * Get the width of this track + */ + virtual uint16 getWidth() const = 0; + + /** + * Get the height of this track + */ + virtual uint16 getHeight() const = 0; + + /** + * Get the pixel format of this track + */ + virtual Graphics::PixelFormat getPixelFormat() const = 0; + + /** + * Get the current frame of this track + * + * @see VideoDecoder::getCurFrame() + */ + virtual int getCurFrame() const = 0; + + /** + * Get the frame count of this track + * + * @note If the frame count is unknown, return 0 (which is also + * the default implementation of the function). However, one must + * also implement endOfTrack() in that case. + */ + virtual int getFrameCount() const { return 0; } + + /** + * Get the start time of the next frame in milliseconds since + * the start of the video + */ + virtual uint32 getNextFrameStartTime() const = 0; + + /** + * Decode the next frame + */ + virtual const Graphics::Surface *decodeNextFrame() = 0; + + /** + * Get the palette currently in use by this track + */ + virtual const byte *getPalette() const { return 0; } + + /** + * Does the palette currently in use by this track need to be updated? + */ + virtual bool hasDirtyPalette() const { return false; } + }; + + /** + * A VideoTrack that is played at a constant rate. + * + * If the frame count is unknown, you must override endOfTrack(). + */ + class FixedRateVideoTrack : public VideoTrack { + public: + FixedRateVideoTrack() {} + virtual ~FixedRateVideoTrack() {} + + uint32 getNextFrameStartTime() const; + virtual Audio::Timestamp getDuration() const; + + protected: + /** + * Get the rate at which this track is played. + */ + virtual Common::Rational getFrameRate() const = 0; + }; + + /** + * An abstract representation of an audio track. */ - void reset(); + class AudioTrack : public Track { + public: + AudioTrack() {} + virtual ~AudioTrack() {} + + TrackType getTrackType() const { return kTrackTypeAudio; } + + virtual bool endOfTrack() const; + + /** + * Start playing this track + */ + void start(); + + /** + * Stop playing this track + */ + void stop(); + + void start(const Audio::Timestamp &limit); + + /** + * Get the volume for this track + */ + byte getVolume() const { return _volume; } + + /** + * Set the volume for this track + */ + void setVolume(byte volume); + + /** + * Get the balance for this track + */ + int8 getBalance() const { return _balance; } + + /** + * Set the balance for this track + */ + void setBalance(int8 balance); + + /** + * Get the time the AudioStream behind this track has been + * running + */ + uint32 getRunningTime() const; + + /** + * Get the sound type to be used when playing this audio track + */ + virtual Audio::Mixer::SoundType getSoundType() const { return Audio::Mixer::kPlainSoundType; } + + protected: + void pauseIntern(bool pause); + + /** + * Get the AudioStream that is the representation of this AudioTrack + */ + virtual Audio::AudioStream *getAudioStream() const = 0; + + private: + Audio::SoundHandle _handle; + byte _volume; + int8 _balance; + }; /** - * Actual implementation of pause by subclasses. See pause() - * for details. + * An AudioTrack that implements isRewindable() and rewind() using + * RewindableAudioStream. */ - virtual void pauseVideoIntern(bool pause) {} + class RewindableAudioTrack : public AudioTrack { + public: + RewindableAudioTrack() {} + virtual ~RewindableAudioTrack() {} + + bool isRewindable() const { return true; } + bool rewind(); + + protected: + Audio::AudioStream *getAudioStream() const; + + /** + * Get the RewindableAudioStream pointer to be used by this class + * for rewind() and getAudioStream() + */ + virtual Audio::RewindableAudioStream *getRewindableAudioStream() const = 0; + }; /** - * Add the time the video has been paused to maintain sync + * An AudioTrack that implements isSeekable() and seek() using + * SeekableAudioStream. */ - virtual void addPauseTime(uint32 ms) { _startTime += ms; } + class SeekableAudioTrack : public AudioTrack { + public: + SeekableAudioTrack() {} + virtual ~SeekableAudioTrack() {} + + bool isSeekable() const { return true; } + bool seek(const Audio::Timestamp &time); + + Audio::Timestamp getDuration() const; + + protected: + Audio::AudioStream *getAudioStream() const; + + /** + * Get the SeekableAudioStream pointer to be used by this class + * for seek(), getDuration(), and getAudioStream() + */ + virtual Audio::SeekableAudioStream *getSeekableAudioStream() const = 0; + }; + + /** + * A SeekableAudioTrack that constructs its SeekableAudioStream using + * SeekableAudioStream::openStreamFile() + */ + class StreamFileAudioTrack : public SeekableAudioTrack { + public: + StreamFileAudioTrack(); + ~StreamFileAudioTrack(); + + /** + * Load the track from a file with the given base name. + * + * @return true on success, false otherwise + */ + bool loadFromFile(const Common::String &baseName); + + protected: + Audio::SeekableAudioStream *_stream; + Audio::SeekableAudioStream *getSeekableAudioStream() const { return _stream; } + }; /** * Reset the pause start time (which should be called when seeking) @@ -242,79 +682,107 @@ protected: void resetPauseStartTime(); /** - * Update currently playing audio tracks with the new volume setting + * Decode enough data for the next frame and enough audio to last that long. + * + * This function is used by the decodeNextFrame() function. A subclass + * of a Track may decide to just have its decodeNextFrame() function read + * and decode the frame. */ - virtual void updateVolume() {} + virtual void readNextPacket() {} /** - * Update currently playing audio tracks with the new balance setting + * Define a track to be used by this class. + * + * The pointer is then owned by this base class. */ - virtual void updateBalance() {} + void addTrack(Track *track); - int32 _curFrame; - int32 _startTime; + /** + * Whether or not getTime() will sync with a playing audio track. + * + * A subclass can override this to disable this feature. + */ + virtual bool useAudioSync() const { return true; } -private: - uint32 _pauseLevel; - uint32 _pauseStartTime; - byte _audioVolume; - int8 _audioBalance; -}; + /** + * Get the given track based on its index. + * + * @return A valid track pointer on success, 0 otherwise + */ + Track *getTrack(uint track); -/** - * A VideoDecoder wrapper that implements getTimeToNextFrame() based on getFrameRate(). - */ -class FixedRateVideoDecoder : public virtual VideoDecoder { -public: - uint32 getTimeToNextFrame() const; + /** + * Get the given track based on its index + * + * @return A valid track pointer on success, 0 otherwise + */ + const Track *getTrack(uint track) const; -protected: /** - * Return the frame rate in frames per second. - * This returns a Rational because videos can have rates that are not integers and - * there are some videos with frame rates < 1. + * Find out if all video tracks have finished + * + * This is useful if one wants to figure out if they need to buffer all + * remaining audio in a file. */ - virtual Common::Rational getFrameRate() const = 0; + bool endOfVideoTracks() const; -private: - uint32 getFrameBeginTime(uint32 frame) const; -}; + /** + * Get the default high color format + */ + Graphics::PixelFormat getDefaultHighColorFormat() const { return _defaultHighColorFormat; } -/** - * A VideoDecoder that can be rewound back to the beginning. - */ -class RewindableVideoDecoder : public virtual VideoDecoder { -public: /** - * Rewind to the beginning of the video. + * Find the video track with the lowest start time for the next frame */ - virtual void rewind() = 0; -}; + VideoTrack *findNextVideoTrack(); -/** - * A VideoDecoder that can seek to a frame or point in time. - */ -class SeekableVideoDecoder : public virtual RewindableVideoDecoder { -public: /** - * Seek to the specified time. + * Find the video track with the lowest start time for the next frame */ - virtual void seekToTime(const Audio::Timestamp &time) = 0; + const VideoTrack *findNextVideoTrack() const; /** - * Seek to the specified time (in ms). + * Typedef helpers for accessing tracks */ - void seekToTime(uint32 msecs) { seekToTime(Audio::Timestamp(msecs, 1000)); } + typedef Common::Array<Track *> TrackList; + typedef TrackList::iterator TrackListIterator; /** - * Implementation of RewindableVideoDecoder::rewind(). + * Get the begin iterator of the tracks */ - virtual void rewind() { seekToTime(0); } + TrackListIterator getTrackListBegin() { return _tracks.begin(); } /** - * Get the total duration of the video (in ms). + * Get the end iterator of the tracks */ - virtual uint32 getDuration() const = 0; + TrackListIterator getTrackListEnd() { return _tracks.end(); } + +private: + // Tracks owned by this VideoDecoder + TrackList _tracks; + + // Current playback status + bool _isPlaying, _needsRewind, _needsUpdate; + Audio::Timestamp _lastTimeChange, _endTime; + bool _endTimeSet; + + // Palette settings from individual tracks + mutable bool _dirtyPalette; + const byte *_palette; + + // Default PixelFormat settings + Graphics::PixelFormat _defaultHighColorFormat; + + // Internal helper functions + void stopAudio(); + void startAudio(); + void startAudioLimit(const Audio::Timestamp &limit); + + int32 _startTime; + uint32 _pauseLevel; + uint32 _pauseStartTime; + byte _audioVolume; + int8 _audioBalance; }; } // End of namespace Video |