From f06f150c76f43f1dc97eadea5af7bf46ddba9ba4 Mon Sep 17 00:00:00 2001 From: Sven Hesse Date: Mon, 30 Jul 2007 15:53:38 +0000 Subject: Restructured and cleaned-up IMD playing svn-id: r28327 --- engines/gob/coktelvideo.cpp | 935 +++++++++++++++++++++++++++++++ engines/gob/coktelvideo.h | 248 +++++++++ engines/gob/dataio.cpp | 99 +++- engines/gob/dataio.h | 34 +- engines/gob/game.cpp | 8 +- engines/gob/game.h | 3 +- engines/gob/game_v2.cpp | 52 +- engines/gob/gob.cpp | 8 +- engines/gob/gob.h | 4 +- engines/gob/imd.cpp | 1249 ------------------------------------------ engines/gob/imd.h | 143 ----- engines/gob/init.cpp | 10 +- engines/gob/inter_bargon.cpp | 42 +- engines/gob/inter_v2.cpp | 64 +-- engines/gob/module.mk | 3 +- engines/gob/mult_v2.cpp | 15 +- engines/gob/util.cpp | 10 +- engines/gob/videoplayer.cpp | 334 +++++++++++ engines/gob/videoplayer.h | 86 +++ 19 files changed, 1836 insertions(+), 1511 deletions(-) create mode 100644 engines/gob/coktelvideo.cpp create mode 100644 engines/gob/coktelvideo.h delete mode 100644 engines/gob/imd.cpp delete mode 100644 engines/gob/imd.h create mode 100644 engines/gob/videoplayer.cpp create mode 100644 engines/gob/videoplayer.h diff --git a/engines/gob/coktelvideo.cpp b/engines/gob/coktelvideo.cpp new file mode 100644 index 0000000000..8f17810430 --- /dev/null +++ b/engines/gob/coktelvideo.cpp @@ -0,0 +1,935 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "common/stdafx.h" +#include "common/endian.h" +#include "common/system.h" + +#include "gob/coktelvideo.h" + +namespace Gob { + +Imd::Imd() { + clear(false); +} + +Imd::~Imd() { + clear(); +} + +bool Imd::load(Common::SeekableReadStream &stream) { + unload(); + + _stream = &stream; + + // Version + uint16 handle = _stream->readUint16LE(); + _version = _stream->readByte(); + + // Version checking + if ((handle != 0) || (_version < 2)) { + warning("IMD Version incorrect (%d,%X)", handle, _version); + unload(); + return false; + } + + // Rest header + _features = _stream->readByte(); + _framesCount = _stream->readUint16LE(); + _x = _stream->readUint16LE(); + _y = _stream->readUint16LE(); + _width = _stream->readUint16LE(); + _height = _stream->readUint16LE(); + _flags = _stream->readUint16LE(); + _firstFramePos = _stream->readUint16LE(); + + // Palette + _stream->read((byte *) _palette, 768); + + // Standard coordinates + if (_version >= 3) { + _stdX = _stream->readUint16LE(); + if (_stdX > 1) { + warning("IMD: More than one standard coordinate quad found (%d)", _stdX); + unload(); + return false; + } + if (_stdX != 0) { + _stdX = _stream->readUint16LE(); + _stdY = _stream->readUint16LE(); + _stdWidth = _stream->readUint16LE(); + _stdHeight = _stream->readUint16LE(); + _features |= kFeaturesStdCoords; + } else + _stdX = -1; + } else + _stdX = -1; + + // Offset to frame positions table + uint32 framesPosPos = 0; + if (_version >= 4) { + framesPosPos = _stream->readUint32LE(); + if (framesPosPos != 0) { + _framesPos = new int32[_framesCount]; + assert(_framesPos); + _features |= kFeaturesFramesPos; + } + } + + // Offset to frame coordinates + uint32 framesCoordsPos = 0; + if (_features & kFeaturesFrameCoords) + framesCoordsPos = _stream->readUint32LE(); + + // Sound + if (_features & kFeaturesSound) { + _soundFreq = _stream->readUint16LE(); + _soundSliceSize = _stream->readUint16LE(); + _soundSlicesCount = _stream->readUint16LE(); + + if (_soundFreq < 0) + _soundFreq = -_soundFreq; + + if (_soundSlicesCount < 0) + _soundSlicesCount = -_soundSlicesCount - 1; + + if (_soundSlicesCount > 40) { + warning("IMD: More than 40 sound slices found (%d)", _soundSlicesCount); + unload(); + return false; + } + + _soundSliceLength = 1000 / (_soundFreq / _soundSliceSize); + _frameLength = _soundSliceLength; + + _soundStage = 1; + _hasSound = true; + + _audioStream = Audio::makeAppendableAudioStream(_soundFreq, 0); + } else + _frameLength = 1000 / 12; // 12 FPS for a video without sound + + // Sizes of the frame data and extra video buffer + if (_features & kFeaturesDataSize) { + _frameDataSize = _stream->readUint16LE(); + if (_frameDataSize == 0) { + _frameDataSize = _stream->readUint32LE(); + _vidBufferSize = _stream->readUint32LE(); + } else + _vidBufferSize = _stream->readUint16LE(); + } else { + _frameDataSize = _width * _height + 500; + if (!(_flags & 0x100) || (_flags & 0x1000)) + _vidBufferSize = _frameDataSize; + } + + // Frame positions table + if (_framesPos) { + _stream->seek(framesPosPos, SEEK_SET); + for (int i = 0; i < _framesCount; i++) + _framesPos[i] = _stream->readUint32LE(); + } + + // Frame coordinates table + if (_features & kFeaturesFrameCoords) { + _stream->seek(framesCoordsPos, SEEK_SET); + _frameCoords = new Coord[_framesCount]; + assert(_frameCoords); + for (int i = 0; i < _framesCount; i++) { + _frameCoords[i].left = _stream->readUint16LE(); + _frameCoords[i].top = _stream->readUint16LE(); + _frameCoords[i].right = _stream->readUint16LE(); + _frameCoords[i].bottom = _stream->readUint16LE(); + } + } + + // Seek to the first frame + _stream->seek(_firstFramePos, SEEK_SET); + + // Allocating working memory + _frameData = new byte[_frameDataSize + 500]; + assert(_frameData); + memset(_frameData, 0, _frameDataSize + 500); + _vidBuffer = new byte[_vidBufferSize + 500]; + assert(_vidBuffer); + memset(_vidBuffer, 0, _vidBufferSize + 500); + + return true; +} + +void Imd::unload() { + clear(); +} + +void Imd::setXY(int16 x, int16 y) { + // Adjusting the standard coordinates + if (_stdX != -1) { + if (x != -1) + _stdX = _stdX - _x + x; + if (y != -1) + _stdY = _stdY - _y + y; + } + + // Going through the coordinate table as well + if (_frameCoords) { + for (int i = 0; i < _framesCount; i++) { + if (_frameCoords[i].left != -1) { + if (x != -1) { + _frameCoords[i].left = _frameCoords[i].left - _x + x; + _frameCoords[i].right = _frameCoords[i].right - _x + x; + } + if (y != -1) { + _frameCoords[i].top = _frameCoords[i].top - _y + y; + _frameCoords[i].bottom = _frameCoords[i].bottom - _y + y; + } + } + } + } + + if (x != -1) + _x = x; + if (y != -1) + _y = y; +} + +void Imd::setVideoMemory(byte *vidMem, uint16 width, uint16 height) { + deleteVidMem(); + + _hasOwnVidMem = false; + _vidMem = vidMem; + _vidMemWidth = width; + _vidMemHeight = height; +} + +void Imd::setVideoMemory() { + deleteVidMem(); + + if ((_width > 0) && (_height > 0)) { + setXY(0, 0); + _hasOwnVidMem = true; + _vidMem = new byte[_width * _height]; + _vidMemWidth = _width; + _vidMemHeight = _height; + } +} + +void Imd::enableSound(Audio::Mixer &mixer) { + // Only possible on the first frame + if (_curFrame > 0) + return; + + _mixer = &mixer; + _soundEnabled = true; +} + +void Imd::disableSound() { + if (_audioStream) { + + if (_soundStage == 2) { + _audioStream->finish(); + _mixer->stopHandle(_audioHandle); + } else + delete _audioStream; + + _audioStream = 0; + } + _soundEnabled = false; + _mixer = 0; +} + +void Imd::seekFrame(int16 frame, int16 whence, bool restart) { + if (!_stream) + // Nothing to do + return; + + // Find the frame to which to seek + if (whence == SEEK_CUR) + frame += _curFrame; + else if (whence == SEEK_END) + frame = _framesCount - frame - 1; + else if (whence != SEEK_SET) + return; + + if ((frame >= _framesCount) || (frame == _curFrame)) + // Nothing to do + return; + + // Try every possible way to find a file offset to that frame + uint32 framePos = 0; + if (frame == 0) { + framePos = _firstFramePos; + } else if (frame == 1) { + framePos = _firstFramePos; + _stream->seek(framePos, SEEK_SET); + framePos += _stream->readUint16LE() + 4; + } else if (_framesPos) { + framePos = _framesPos[frame]; + } else if (restart && (_soundStage == 0)) { + for (int i = ((frame > _curFrame) ? _curFrame : 0); i <= frame; i++) + processFrame(i); + } else + error("Frame %d is not directly accessible", frame); + + // Seek + _stream->seek(framePos, SEEK_SET); + _curFrame = frame; +} + +CoktelVideo::State Imd::nextFrame() { + return processFrame(_curFrame); +} + +void Imd::waitEndFrame() { + if (_soundEnabled && _hasSound) { + if (_soundStage != 2) + return; + + if (_skipFrames == 0) { + int32 waitTime = (_curFrame * _soundSliceLength) - + (g_system->getMillis() - _soundStartTime); + + if (waitTime < 0) { + _skipFrames = -waitTime / _soundSliceLength; + warning("IMD A/V sync broken, skipping %d frame(s)", _skipFrames + 1); + } else if (waitTime > 0) + g_system->delayMillis(waitTime); + + } else + _skipFrames--; + } else + g_system->delayMillis(_frameLength); +} + +void Imd::copyCurrentFrame(byte *dest, uint16 x, uint16 y, uint16 width, int16 transp) { + if (!_vidMem) + return; + + dest += width * y; + + uint16 copyWidth = MIN(width - x, _width); + uint16 destPitch = width - x; + byte *vidMem = _vidMem; + + if (transp < 0) { + // No transparency + if ((x > 0) || (_width != width)) { + // Copy row-by-row + for (int i = 0; i < _height; i++) { + dest += x; + memcpy(dest, vidMem, copyWidth); + dest += destPitch; + vidMem += _width; + } + + } else + // Dimensions fit, copy everything at once + memcpy(dest, _vidMem, _width * _height); + + return; + } + + // Transparency, copy per pixel + for (int i = 0; i < _height; i++) { + byte *s = vidMem; + byte *d = dest; + + d += x; + for (int j = 0; j < _width; j++) { + if (*s != transp) + *d = *s; + + s++; + d++; + } + + dest += width;; + vidMem += _width; + } +} + +void Imd::deleteVidMem(bool del) { + if (del) { + if (_hasOwnVidMem) + delete[] _vidMem; + } + + _hasOwnVidMem = false; + _vidMem = 0; + _vidMemWidth = _vidMemHeight = 0; +} + +void Imd::clear(bool del) { + if (del) { + delete[] _framesPos; + delete[] _frameCoords; + delete[] _frameData; + delete[] _vidBuffer; + + disableSound(); + } + + _stream = 0; + + _version = 0; + _features = 0; + _flags = 0; + _x = _y = _width = _height = 0; + _stdX = _stdY = _stdWidth = _stdHeight = 0; + _framesCount = _curFrame = 0; + _framesPos = 0; + _firstFramePos = 0; + _frameCoords = 0; + + _frameDataSize = _vidBufferSize = 0; + _frameData = _vidBuffer = 0; + + memset(_palette, 0, 768); + + deleteVidMem(del); + + _hasSound = false; + _soundEnabled = false; + _soundStage = 0; + _soundStartTime = 0; + _skipFrames = 0; + + _soundFreq = 0; + _soundSliceSize = 0; + _soundSlicesCount = 0; + _soundSliceLength = 0; + + _audioStream = 0; + + _frameLength = 0; + _lastFrameTime = 0; +} + +CoktelVideo::State Imd::processFrame(int16 frame) { + State state; + uint32 cmd = 0; + int16 xBak, yBak, heightBak, widthBak; + bool hasNextCmd = false; + bool startSound = false; + + if (!_stream || (frame >= _framesCount)) { + state.flags = kStateBreak; + return state; + } + + if (frame != _curFrame) { + state.flags |= kStateSeeked; + seekFrame(frame, SEEK_SET); + } + + state.left = xBak = _x; + state.top = yBak = _y; + state.bottom = heightBak = _height; + state.right = widthBak = _width; + state.right += state.left - 1; + state.bottom += state.top - 1; + +/* if ((frame == 0) && (_features & 0x8)) + _vm->_video->setPalette(_palette);*/ + + do { + if (frame != 0) { + if (_stdX != -1) { + state.left = _x = _stdX; + state.top = _y = _stdY; + state.right = _width = _stdWidth; + state.bottom = _height = _stdHeight; + state.right += state.left - 1; + state.bottom += state.top - 1; + state.flags |= kStateStdCoords; + } + if (_frameCoords && + (_frameCoords[frame].left != -1)) { + state.left = _x = _frameCoords[frame].left; + state.top = _y = _frameCoords[frame].top; + state.right = _width = + _frameCoords[frame].right - _x + 1; + state.bottom = _height = + _frameCoords[frame].bottom - _y + 1; + state.right += state.left - 1; + state.bottom += state.top - 1; + state.flags |= kStateFrameCoords; + } + } + + cmd = _stream->readUint16LE(); + + if ((cmd & 0xFFF8) == 0xFFF0) { + if (cmd == 0xFFF0) { + _stream->seek(2, SEEK_CUR); + cmd = _stream->readUint16LE(); + } + + if (cmd == 0xFFF1) { + state.flags = kStateBreak; + continue; + } else if (cmd == 0xFFF2) { // Skip (16 bit) + cmd = _stream->readUint16LE(); + _stream->seek(cmd, SEEK_CUR); + state.flags = kStateBreak; + continue; + } else if (cmd == 0xFFF3) { // Skip (32 bit) + cmd = _stream->readUint32LE(); + _stream->seek(cmd, SEEK_CUR); + state.flags = kStateBreak; + continue; + } + } + + if (_soundStage != 0) { + byte *soundBuf; + +/* if (!hasNextCmd) + waitEndSoundSlice();*/ + + // Next sound slice data + if (cmd == 0xFF00) { + + if (!hasNextCmd && _soundEnabled) { + soundBuf = new byte[_soundSliceSize]; + assert(soundBuf); + + _stream->read(soundBuf, _soundSliceSize); + unsignedToSigned(soundBuf, _soundSliceSize); + _audioStream->queueBuffer(soundBuf, _soundSliceSize); + } else + _stream->seek(_soundSliceSize, SEEK_CUR); + + cmd = _stream->readUint16LE(); + + // Initial sound data (all slices) + } else if (cmd == 0xFF01) { + int dataLength = _soundSliceSize * _soundSlicesCount; + + if (!hasNextCmd && _soundEnabled) { + soundBuf = new byte[dataLength]; + assert(soundBuf); + + _stream->read(soundBuf, dataLength); + unsignedToSigned(soundBuf, dataLength); + + _soundStage = 1; + startSound = true; + _audioStream->queueBuffer(soundBuf, dataLength); + } else + _stream->seek(dataLength, SEEK_CUR); + + cmd = _stream->readUint16LE(); + + // Empty sound slice + } else if (!hasNextCmd && (_soundEnabled)) { + soundBuf = new byte[_soundSliceSize]; + assert(soundBuf); + + memset(soundBuf, 0, _soundSliceSize); + _audioStream->queueBuffer(soundBuf, _soundSliceSize); + } + } + + // Set palette + if (cmd == 0xFFF4) { + _stream->seek(2, SEEK_CUR); + state.flags |= kStatePalette; + _stream->read(_palette, 768); + cmd = _stream->readUint16LE(); + } + + hasNextCmd = false; + + // Jump to frame + if (cmd == 0xFFFD) { + + frame = _stream->readUint16LE(); + if (_framesPos) { + _curFrame = frame; + _stream->seek(_framesPos[frame], SEEK_SET); + + hasNextCmd = true; + state.flags |= kStateJump; + } + + } else if (cmd == 0xFFFC) { + + state.flags |= 1; + cmd = _stream->readUint32LE(); + _stream->read(_frameData, cmd + 2); + + int16 left = _x; + int16 top = _y; + int16 right = _width + left; + int16 bottom = _height + top; + + if (!_vidMem) + setVideoMemory(); + + if (_vidMemWidth < right) { + left = 0; + right = _width; + } + if (_vidMemWidth < right) + right = _vidMemWidth; + if (_vidMemHeight < bottom) { + top = 0; + bottom = _height; + } + if (_vidMemHeight < bottom) + bottom = _vidMemHeight; + + _x = left; + _y = top; + _height = bottom - top; + _width = right - left; + + renderFrame(); + + state.flags |= _frameData[0]; + + // Frame video data + } else if (cmd != 0) { + + _stream->read(_frameData, cmd + 2); + + renderFrame(); + + state.flags |= _frameData[0]; + + } else + state.flags |= kStateNoData; + + } while (hasNextCmd); + + if (startSound && _soundEnabled) { + _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_audioHandle, _audioStream); + _soundStartTime = g_system->getMillis(); + _skipFrames = 0; + _soundStage = 2; + } + + _x = xBak; + _y = yBak; + _width = widthBak; + _height = heightBak; + + _curFrame++; + if ((_curFrame == _framesCount) && (_soundStage == 2)) { + _audioStream->finish(); + _mixer->stopHandle(_audioHandle); + _audioStream = 0; + _soundStage = 0; + } + + _lastFrameTime = g_system->getMillis(); + return state; +} + +CoktelVideo::State Imd::peekFrame(int16 frame) { + State state; + uint32 posBak; + uint32 tmp; + uint16 cmd; + int16 frameBak; + + if (!_stream) { + state.flags = kStateBreak; + return state; + } + + posBak = _stream->pos(); + frameBak = _curFrame; + + if (_curFrame != frame) { + state.flags |= kStateSeeked; + seekFrame(frame, SEEK_SET); + } + + do { + if (frame != 0) { + if (_stdX != -1) + state.flags |= kStateStdCoords; + if (_frameCoords && (_frameCoords[frame].left != -1)) + state.flags |= kStateFrameCoords; + } + + cmd = _stream->readUint16LE(); + + if ((cmd & 0xFFF8) == 0xFFF0) { + if (cmd == 0xFFF0) { + _stream->seek(2, SEEK_CUR); + cmd = _stream->readUint16LE(); + } + + if (cmd == 0xFFF1) { + state.flags = kStateBreak; + continue; + } else if (cmd == 0xFFF2) { // Skip (16 bit) + cmd = _stream->readUint16LE(); + _stream->seek(cmd, SEEK_CUR); + state.flags = kStateBreak; + continue; + } else if (cmd == 0xFFF3) { // Skip (32 bit) + tmp = _stream->readUint32LE(); + _stream->seek(cmd, SEEK_CUR); + state.flags = kStateBreak; + continue; + } + } + + // Jump to frame + if (cmd == 0xFFFD) { + frame = _stream->readUint16LE(); + if (_framesPos) { + _stream->seek(_framesPos[frame], SEEK_SET); + state.flags |= kStateJump; + continue; + } + break; + } + + // Next sound slice data + if (cmd == 0xFF00) { + _stream->seek(_soundSliceSize, SEEK_CUR); + cmd = _stream->readUint16LE(); + // Initial sound data (all slices) + } else if (cmd == 0xFF01) { + _stream->seek(_soundSliceSize * _soundSlicesCount, SEEK_CUR); + cmd = _stream->readUint16LE(); + } + + // Frame video data + if (cmd != 0) { + _stream->read(_frameData, 5); + state.flags |= _frameData[0]; + } else + state.flags |= kStateNoData; + + break; + + } while (true); + + _stream->seek(posBak, SEEK_SET); + _curFrame = frameBak; + return state; +} + +void Imd::renderFrame() { + if (!_frameData || (_width <= 0) || (_height <= 0)) + return; + + if (!_vidMem) + setVideoMemory(); + + byte *dataPtr = _frameData; + int16 imdX = _x; + int16 imdY = _y; + int16 imdW = _width; + int16 imdH = _height; + int16 sW = _vidMemWidth; + byte *imdVidMem = _vidMem + sW * imdY + imdX; + uint8 type = *dataPtr++; + byte *srcPtr = dataPtr; + + + if (type & 0x10) { // Palette data + type ^= 0x10; + dataPtr += 49; + } + + srcPtr = dataPtr; + if (type & 0x80) { // Frame data is compressed + srcPtr = _vidBuffer; + type &= 0x7F; + if ((type == 2) && (imdW == sW)) { + frameUncompressor(imdVidMem, dataPtr); + return; + } else + frameUncompressor(srcPtr, dataPtr); + } + + uint16 pixCount, pixWritten; + byte *imdVidMemBak; + + if (type == 2) { // Whole block + for (int i = 0; i < imdH; i++) { + memcpy(imdVidMem, srcPtr, imdW); + srcPtr += imdW; + imdVidMem += sW; + } + } else if (type == 1) { // Sparse block + imdVidMemBak = imdVidMem; + for (int i = 0; i < imdH; i++) { + pixWritten = 0; + while (pixWritten < imdW) { + pixCount = *srcPtr++; + if (pixCount & 0x80) { // data + pixCount = MIN((pixCount & 0x7F) + 1, imdW - pixWritten); + memcpy(imdVidMem, srcPtr, pixCount); + + pixWritten += pixCount; + imdVidMem += pixCount; + srcPtr += pixCount; + } else { // "hole" + pixCount = (pixCount + 1) % 256; + pixWritten += pixCount; + imdVidMem += pixCount; + } + } + imdVidMemBak += sW; + imdVidMem = imdVidMemBak; + } + } else if (type == 0x42) { // Whole quarter-wide block + for (int i = 0; i < imdH; i++) { + imdVidMemBak = imdVidMem; + + for (int j = 0; j < imdW; j += 4, imdVidMem += 4, srcPtr++) + memset(imdVidMem, *srcPtr, 4); + + imdVidMemBak += sW; + imdVidMem = imdVidMemBak; + } + } else if ((type & 0xF) == 2) { // Whole half-high block + for (; imdH > 1; imdH -= 2, imdVidMem += sW + sW, srcPtr += imdW) { + memcpy(imdVidMem, srcPtr, imdW); + memcpy(imdVidMem + sW, srcPtr, imdW); + } + if (imdH == -1) + memcpy(imdVidMem, srcPtr, imdW); + } else { // Sparse half-high block + imdVidMemBak = imdVidMem; + for (int i = 0; i < imdH; i += 2) { + pixWritten = 0; + while (pixWritten < imdW) { + pixCount = *srcPtr++; + if (pixCount & 0x80) { // data + pixCount = MIN((pixCount & 0x7F) + 1, imdW - pixWritten); + memcpy(imdVidMem, srcPtr, pixCount); + memcpy(imdVidMem + sW, srcPtr, pixCount); + + pixWritten += pixCount; + imdVidMem += pixCount; + srcPtr += pixCount; + } else { // "hole" + pixCount = (pixCount + 1) % 256; + pixWritten += pixCount; + imdVidMem += pixCount; + } + } + imdVidMemBak += sW + sW; + imdVidMem = imdVidMemBak; + } + } +} + +void Imd::frameUncompressor(byte *dest, byte *src) { + int i; + byte buf[4370]; + uint16 chunkLength; + uint16 frameLength; + uint16 bufPos1; + uint16 bufPos2; + uint16 tmp; + uint8 chunkBitField; + uint8 chunkCount; + bool mode; + + frameLength = READ_LE_UINT16(src); + src += 4; + + if ((READ_LE_UINT16(src) == 0x1234) && (READ_LE_UINT16(src + 2) == 0x5678)) { + src += 4; + bufPos1 = 273; + mode = 1; // 123Ch (cmp al, 12h) + } else { + bufPos1 = 4078; + mode = 0; // 275h (jnz +2) + } + + memset(buf, 32, bufPos1); + chunkCount = 1; + chunkBitField = 0; + + while (frameLength > 0) { + chunkCount--; + if (chunkCount == 0) { + tmp = *src++; + chunkCount = 8; + chunkBitField = tmp; + } + if (chunkBitField % 2) { + chunkBitField >>= 1; + buf[bufPos1] = *src; + *dest++ = *src++; + bufPos1 = (bufPos1 + 1) % 4096; + frameLength--; + continue; + } + chunkBitField >>= 1; + + tmp = READ_LE_UINT16(src); + src += 2; + chunkLength = ((tmp & 0xF00) >> 8) + 3; + + if ((mode && ((chunkLength & 0xFF) == 0x12)) || + (!mode && (chunkLength == 0))) + chunkLength = *src++ + 0x12; + + bufPos2 = (tmp & 0xFF) + ((tmp >> 4) & 0x0F00); + if (((tmp + chunkLength) >= 4096) || + ((chunkLength + bufPos1) >= 4096)) { + + for (i = 0; i < chunkLength; i++, dest++) { + *dest = buf[bufPos2]; + buf[bufPos1] = buf[bufPos2]; + bufPos1 = (bufPos1 + 1) % 4096; + bufPos2 = (bufPos2 + 1) % 4096; + } + + } else if (((tmp + chunkLength) < bufPos1) || + ((chunkLength + bufPos1) < bufPos2)) { + + memcpy(dest, buf + bufPos2, chunkLength); + memmove(buf + bufPos1, buf + bufPos2, chunkLength); + + dest += chunkLength; + bufPos1 += chunkLength; + bufPos2 += chunkLength; + + } else { + + for (i = 0; i < chunkLength; i++, dest++, bufPos1++, bufPos2++) { + *dest = buf[bufPos2]; + buf[bufPos1] = buf[bufPos2]; + } + + } + frameLength -= chunkLength; + + } +} + +} // End of namespace Gob diff --git a/engines/gob/coktelvideo.h b/engines/gob/coktelvideo.h new file mode 100644 index 0000000000..4e7512eb8b --- /dev/null +++ b/engines/gob/coktelvideo.h @@ -0,0 +1,248 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GOB_COKTELVIDEO_H +#define GOB_COKTELVIDEO_H + +#include "common/stream.h" +#include "sound/mixer.h" +#include "sound/audiostream.h" + +namespace Gob { + +/** Common interface for handling Coktel Vision videos and derivated formats. */ +class CoktelVideo { +public: + enum Features { + kFeaturesNone = 0, + /** Has an own palette. */ + kFeaturesPalette = 8, + /** Suggests a data size. */ + kFeaturesDataSize = 0x20, + /** Has sound. */ + kFeaturesSound = 0x40, + /** Has specific frame coordinates. */ + kFeaturesFrameCoords = 0x80, + /** Has general standard coordinates. */ + kFeaturesStdCoords = 0x100, + /** Has a frame positions table. */ + kFeaturesFramesPos = 0x200 + }; + + enum StateFlags { + kStateNone = 0, + /** Changed the palette. */ + kStatePalette = 0x10, + /** Performed a jump to another frame. */ + kStateJump = 0x200, + /** Updated according to the specific frame coordinates. */ + kStateFrameCoords = 0x400, + /** Got no frame data. */ + kStateNoData = 0x800, + /** Updated according to the general standard coordinates. */ + kStateStdCoords = 0x1000, + /** Had to explicitely seek to the frame. */ + kStateSeeked = 0x2000, + /** Reached a break-point. */ + kStateBreak = 0x8000 + }; + + struct State { + /** Left-most value of the updated rectangle. */ + int16 left; + /** Top-most value of the updated rectangle. */ + int16 top; + /** Right-most value of the updated rectangle. */ + int16 right; + /** Bottom-most value of the updated rectangle. */ + int16 bottom; + /** Set accordingly to what was done. */ + uint32 flags; + }; + + virtual ~CoktelVideo() { } + + /** Returns the features the loaded video possesses. */ + virtual uint16 getFeatures() const = 0; + /** Returns the x coordinate of the video. */ + virtual int16 getX() const = 0; + /** Returns the y coordinate of the video. */ + virtual int16 getY() const = 0; + /** Returns the width of the video. */ + virtual int16 getWidth() const = 0; + /** Returns the height of the video. */ + virtual int16 getHeight() const = 0; + /** Returns the number of frames the loaded video has. */ + virtual int16 getFramesCount() const = 0; + /** Returns the current frame number. */ + virtual int16 getCurrentFrame() const = 0; + /** Returns the frame rate. */ + virtual int16 getFrameRate() const = 0; + /** Returns the number of frames the video lags behind the audio. */ + virtual uint32 getSyncLag() const = 0; + /** Returns the current frame's palette. */ + virtual const byte *getPalette() const = 0; + + /** Load a video out of a stream. */ + virtual bool load(Common::SeekableReadStream &stream) = 0; + /** Unload the currently loaded video. */ + virtual void unload() = 0; + + /** Set the coordinations where to draw the video. */ + virtual void setXY(int16 x, int16 y) = 0; + /** Use a specific memory block as video memory. */ + virtual void setVideoMemory(byte *vidMem, uint16 width, uint16 height) = 0; + /** Use an own memory block as video memory. */ + virtual void setVideoMemory() = 0; + + /** Play sound (if the IMD has sound). */ + virtual void enableSound(Audio::Mixer &mixer) = 0; + /** Don't play sound or stop currently playing sound. */ + virtual void disableSound() = 0; + + /** Seek to a specific frame. + * + * @param frame The frame to which to seek. + * @param whence The offset from whence the frame is given. + * @param restart Restart the video to reach an otherwise inaccessible frame? + */ + virtual void seekFrame(int16 frame, int16 whence = SEEK_SET, bool restart = false) = 0; + + /** Render the next frame. */ + virtual State nextFrame() = 0; + /** Look at what a frame would do/have, without actually rendering the frame. */ + virtual State peekFrame(int16 frame) = 0; + /** Wait for the frame to end. */ + virtual void waitEndFrame() = 0; + + /** Copy the current frame. + * + * @param dest The memory to which to copy the current frame + * @param x The x position to where to copy. + * @param y The y position to where to copy. + * @param pitch The buffer's width. + * @param transp Which color should be seen as transparent? + */ + virtual void copyCurrentFrame(byte *dest, uint16 x, uint16 y, uint16 width, int16 transp = -1) = 0; +}; + +/** Coktel Vision's IMD files. + */ +class Imd : public CoktelVideo { +public: + Imd(); + ~Imd(); + + uint16 getFeatures() const { return _features; } + int16 getX() const { return _x; } + int16 getY() const { return _y; } + int16 getWidth() const { return _width; } + int16 getHeight() const { return _height; } + int16 getFramesCount() const { return _framesCount; } + int16 getCurrentFrame() const { return _curFrame; } + int16 getFrameRate() const { if (_hasSound) return 1000 / _soundSliceLength; return 12; } + uint32 getSyncLag() const { return _skipFrames; } + const byte *getPalette() const { return _palette; } + + bool load(Common::SeekableReadStream &stream); + void unload(); + + void setXY(int16 x, int16 y); + void setVideoMemory(byte *vidMem, uint16 width, uint16 height); + void setVideoMemory(); + + void enableSound(Audio::Mixer &mixer); + void disableSound(); + + void seekFrame(int16 frame, int16 whence = SEEK_SET, bool restart = false); + + State nextFrame(); + State peekFrame(int16 frame); + void waitEndFrame(); + + void copyCurrentFrame(byte *dest, uint16 x, uint16 y, uint16 width, int16 transp = -1); + +protected: + struct Coord { + int16 left; + int16 top; + int16 right; + int16 bottom; + } PACKED_STRUCT; + + Common::SeekableReadStream *_stream; + uint8 _version; + uint16 _features; + int16 _flags; + int16 _x, _y, _width, _height; + int16 _stdX, _stdY, _stdWidth, _stdHeight; + int16 _framesCount, _curFrame; + int32 *_framesPos; + int32 _firstFramePos; + Coord *_frameCoords; + + int32 _frameDataSize, _vidBufferSize; + byte *_frameData, *_vidBuffer; + + byte _palette[768]; + + bool _hasOwnVidMem; + byte *_vidMem; + uint16 _vidMemWidth, _vidMemHeight; + + bool _hasSound; + bool _soundEnabled; + uint8 _soundStage; // (0: no sound, 1: loaded, 2: playing) + uint32 _soundStartTime; + uint32 _skipFrames; + + int16 _soundFreq; + uint16 _soundSliceSize; + int16 _soundSlicesCount; + uint16 _soundSliceLength; + + Audio::AppendableAudioStream *_audioStream; + Audio::SoundHandle _audioHandle; + + uint32 _frameLength; + uint32 _lastFrameTime; + + Audio::Mixer *_mixer; + + void unsignedToSigned(byte *buffer, int length) { + while (length-- > 0) *buffer++ ^= 0x80; + } + + void deleteVidMem(bool del = true); + void clear(bool del = true); + + State processFrame(int16 frame); + void renderFrame(); + void frameUncompressor(byte *dest, byte *src); +}; + +} // End of namespace Gob + +#endif // GOB_COKTELVIDEO_H diff --git a/engines/gob/dataio.cpp b/engines/gob/dataio.cpp index 7ded953427..73318adc14 100644 --- a/engines/gob/dataio.cpp +++ b/engines/gob/dataio.cpp @@ -33,6 +33,83 @@ namespace Gob { +DataStream::DataStream(DataIO &io, int16 handle, uint32 dSize, bool dispose) { + _io = &io; + _handle = handle; + _size = dSize; + _dispose = dispose; + + _data = 0; + _stream = 0; +} + +DataStream::DataStream(byte *buf, uint32 dSize, bool dispose) { + _data = buf; + _size = dSize; + _stream = new Common::MemoryReadStream(_data, _size); + _dispose = dispose; + + _io = 0; + _handle = -1; +} + +DataStream::~DataStream() { + delete _stream; + + if (_dispose) { + delete[] _data; + if ((_handle >= 0) && _io) + _io->closeData(_handle); + } +} + +uint32 DataStream::pos() const { + if (_stream) + return _stream->pos(); + + uint32 resPos = _io->getChunkPos(_handle); + if (resPos != 0xFFFFFFFF) + return resPos; + + return _io->file_getHandle(_handle)->pos(); +} + +uint32 DataStream::size() const { + if (_stream) + return _stream->size(); + + return _size; +} + +void DataStream::seek(int32 offset, int whence) { + if (_stream) + _stream->seek(offset, whence); + + int32 resPos = _io->seekChunk(_handle, offset, whence); + if (resPos != -1) + return; + + _io->file_getHandle(_handle)->seek(offset, whence); +} + +bool DataStream::eos() const { + if (_stream) + return _stream->eos(); + + return pos() >= size(); +} + +uint32 DataStream::read(void *dataPtr, uint32 dataSize) { + if (_stream) + return _stream->read(dataPtr, dataSize); + + int32 res = _io->readChunk(_handle, (byte *) dataPtr, dataSize); + if (res >= 0) + return res; + + return _io->file_getHandle(_handle)->read((byte *) dataPtr, dataSize); +} + DataIO::DataIO(GobEngine *vm) : _vm(vm) { for (int i = 0; i < MAX_DATA_FILES; i++) { _dataFiles[i] = 0; @@ -115,6 +192,10 @@ Common::File *DataIO::file_getHandle(int16 handle) { return &_filesHandles[handle]; } +const Common::File *DataIO::file_getHandle(int16 handle) const { + return &_filesHandles[handle]; +} + int16 DataIO::file_open(const char *path, Common::File::AccessMode mode) { int16 i; @@ -226,7 +307,7 @@ int16 DataIO::seekChunk(int16 handle, int32 pos, int16 from) { return _chunkPos[file * MAX_SLOT_COUNT + slot]; } -uint32 DataIO::getChunkPos(int16 handle) { +uint32 DataIO::getChunkPos(int16 handle) const { int16 file; int16 slot; @@ -390,6 +471,15 @@ int16 DataIO::openData(const char *path, Common::File::AccessMode mode) { return file_open(path, mode); } +DataStream *DataIO::openAsStream(int16 handle, bool dispose) { + uint32 curPos = getPos(handle); + seekData(handle, 0, SEEK_END); + uint32 size = getPos(handle); + seekData(handle, curPos, SEEK_SET); + + return new DataStream(*this, handle, size, dispose); +} + int32 DataIO::readData(int16 handle, byte *buf, uint16 size) { int32 res; @@ -492,4 +582,11 @@ byte *DataIO::getData(const char *path) { return data; } +DataStream *DataIO::getDataStream(const char *path) { + uint32 size = getDataSize(path); + byte *data = getData(path); + + return new DataStream(data, size); +} + } // End of namespace Gob diff --git a/engines/gob/dataio.h b/engines/gob/dataio.h index 08498a4f7e..3560093d9e 100644 --- a/engines/gob/dataio.h +++ b/engines/gob/dataio.h @@ -37,6 +37,32 @@ namespace Gob { #define MAX_DATA_FILES 8 #define MAX_SLOT_COUNT 8 +class DataIO; + +class DataStream : public Common::SeekableReadStream { +public: + DataStream(DataIO &io, int16 handle, uint32 dSize, bool dispose = false); + DataStream(byte *buf, uint32 dSize, bool dispose = true); + virtual ~DataStream(); + + virtual uint32 pos() const; + virtual uint32 size() const; + + virtual void seek(int32 offset, int whence = SEEK_SET); + + virtual bool eos() const; + + virtual uint32 read(void *dataPtr, uint32 dataSize); + +private: + DataIO *_io; + int16 _handle; + uint32 _size; + byte *_data; + Common::MemoryReadStream *_stream; + bool _dispose; +}; + class DataIO { public: struct ChunkDesc { @@ -55,6 +81,8 @@ public: void closeData(int16 handle); int16 openData(const char *path, Common::File::AccessMode mode = Common::File::kFileReadMode); + DataStream *openAsStream(int16 handle, bool dispose = false); + int32 readData(int16 handle, byte *buf, uint16 size); byte readByte(int16 handle); uint16 readUint16(int16 handle); @@ -64,6 +92,7 @@ public: uint32 getPos(int16 handle); int32 getDataSize(const char *name); byte *getData(const char *path); + DataStream *getDataStream(const char *path); DataIO(class GobEngine *vm); ~DataIO(); @@ -85,13 +114,16 @@ protected: int16 file_open(const char *path, Common::File::AccessMode mode = Common::File::kFileReadMode); Common::File *file_getHandle(int16 handle); + const Common::File *file_getHandle(int16 handle) const; int16 getChunk(const char *chunkName); char freeChunk(int16 handle); int32 readChunk(int16 handle, byte *buf, uint16 size); int16 seekChunk(int16 handle, int32 pos, int16 from); - uint32 getChunkPos(int16 handle); + uint32 getChunkPos(int16 handle) const; int32 getChunkSize(const char *chunkName); + +friend class DataStream; }; } // End of namespace Gob diff --git a/engines/gob/game.cpp b/engines/gob/game.cpp index e47dc1809f..b625a35258 100644 --- a/engines/gob/game.cpp +++ b/engines/gob/game.cpp @@ -379,10 +379,12 @@ int16 Game::checkKeys(int16 *pMouseX, int16 *pMouseY, _vm->_inter->_soundEndTimeKey = 0; } - _vm->_util->getMouseState(pMouseX, pMouseY, pButtons); + if (pMouseX && pMouseY && pButtons) { + _vm->_util->getMouseState(pMouseX, pMouseY, pButtons); - if (*pButtons == 3) - *pButtons = 0; + if (*pButtons == 3) + *pButtons = 0; + } return _vm->_util->checkKey(); } diff --git a/engines/gob/game.h b/engines/gob/game.h index 2b684a179f..c83497eaeb 100644 --- a/engines/gob/game.h +++ b/engines/gob/game.h @@ -147,7 +147,8 @@ public: void evaluateScroll(int16 x, int16 y); - int16 checkKeys(int16 *pMousex, int16 *pMouseY, int16 *pButtons, char handleMouse); + int16 checkKeys(int16 *pMousex = 0, int16 *pMouseY = 0, + int16 *pButtons = 0, char handleMouse = 0); void start(void); void totSub(int8 flags, const char *newTotFile); void switchTotSub(int16 index, int16 skipPlay); diff --git a/engines/gob/game_v2.cpp b/engines/gob/game_v2.cpp index 4ccd6d718e..f7f7a10b92 100644 --- a/engines/gob/game_v2.cpp +++ b/engines/gob/game_v2.cpp @@ -1,27 +1,27 @@ -/* 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. - * - * $URL$ - * $Id$ - * - */ + /* 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. + * + * $URL$ + * $Id$ + * + */ #include "common/stdafx.h" #include "common/endian.h" @@ -34,13 +34,13 @@ #include "gob/dataio.h" #include "gob/draw.h" #include "gob/goblin.h" -#include "gob/imd.h" #include "gob/inter.h" #include "gob/mult.h" #include "gob/parse.h" #include "gob/scenery.h" #include "gob/sound.h" #include "gob/video.h" +#include "gob/videoplayer.h" namespace Gob { @@ -271,7 +271,7 @@ void Game_v2::playTot(int16 skipPlay) { _vm->_snd->freeSample(_soundSamples[i]); } - _vm->_imdPlayer->closeImd(); + _vm->_vidPlayer->closeVideo(); if (_totToLoad[0] == 0) break; diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp index 9a14194972..f1bec2b8d5 100644 --- a/engines/gob/gob.cpp +++ b/engines/gob/gob.cpp @@ -48,7 +48,7 @@ #include "gob/parse.h" #include "gob/scenery.h" #include "gob/music.h" -#include "gob/imd.h" +#include "gob/videoplayer.h" #include "gob/saveload.h" namespace Gob { @@ -72,7 +72,7 @@ GobEngine::GobEngine(OSystem *syst) : Engine(syst) { _snd = 0; _adlib = 0; _mult = 0; _game = 0; _global = 0; _cdrom = 0; - _dataIO = 0; _goblin = 0; _imdPlayer = 0; + _dataIO = 0; _goblin = 0; _vidPlayer = 0; _init = 0; _inter = 0; _map = 0; _palAnim = 0; _parse = 0; _scenery = 0; _draw = 0; _util = 0; _video = 0; @@ -236,7 +236,7 @@ bool GobEngine::initGameParts() { _util = new Util(this); _dataIO = new DataIO(this); _palAnim = new PalAnim(this); - _imdPlayer = new ImdPlayer(this); + _vidPlayer = new VideoPlayer(this); _cdrom = new CDROM(this); _snd = new Snd(this); @@ -364,7 +364,7 @@ void GobEngine::deinitGameParts() { delete _cdrom; _cdrom = 0; delete _dataIO; _dataIO = 0; delete _goblin; _goblin = 0; - delete _imdPlayer; _imdPlayer = 0; + delete _vidPlayer; _vidPlayer = 0; delete _init; _init = 0; delete _inter; _inter = 0; delete _map; _map = 0; diff --git a/engines/gob/gob.h b/engines/gob/gob.h index 8c9583c95d..9a88571c0e 100644 --- a/engines/gob/gob.h +++ b/engines/gob/gob.h @@ -42,7 +42,7 @@ class Draw; class CDROM; class DataIO; class Goblin; -class ImdPlayer; +class VideoPlayer; class Init; class Inter; class Map; @@ -216,7 +216,7 @@ public: Inter *_inter; SaveLoad *_saveLoad; Adlib *_adlib; - ImdPlayer *_imdPlayer; + VideoPlayer *_vidPlayer; void shutdown(); diff --git a/engines/gob/imd.cpp b/engines/gob/imd.cpp deleted file mode 100644 index 395fb01f9b..0000000000 --- a/engines/gob/imd.cpp +++ /dev/null @@ -1,1249 +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. - * - * $URL$ - * $Id$ - * - */ - -#include "common/stdafx.h" -#include "common/endian.h" - -#include "gob/gob.h" -#include "gob/imd.h" -#include "gob/global.h" -#include "gob/util.h" -#include "gob/dataio.h" -#include "gob/draw.h" -#include "gob/game.h" -#include "gob/inter.h" -#include "gob/palanim.h" -#include "gob/sound.h" -#include "gob/video.h" - -namespace Gob { - -ImdPlayer::ImdPlayer(GobEngine *vm) : _vm(vm) { - _curImd = 0; - _curFile[0] = 0; - - _curX = 0; - _curY = 0; - _left = 0; - _top = 0; - _right = 0; - _bottom = 0; - - _frameData = 0; - _vidBuffer = 0; - - _frontSurf = 21; - _backSurf = 21; - _frontMem = 0; - _frameDelay = 0; - - _noSound = true; - - _soundStartTime = 0; - _skipFrames = 0; - - _soundFreq = 0; - _soundSliceSize = 0; - _soundSlicesCount = 0; - - _soundSliceLength = 0; - _soundStage = 0; - - _audioStream = 0; -} - -ImdPlayer::~ImdPlayer() { - if (_curImd) { - delete[] _curImd->palette; - delete[] _curImd->framesPos; - delete[] _curImd->frameCoords; - delete[] _curImd->extraPalette; - } - delete[] _frameData; - delete[] _vidBuffer; - delete[] _frontMem; - delete _curImd; -} - -// flag bits: 0 = read and set palette -// 1 = read palette -ImdPlayer::Imd *ImdPlayer::loadImdFile(const char *path, SurfaceDesc *surfDesc, int8 flags) { - Imd *imdPtr; - int16 handle; - char buf[18]; - uint32 framesPosPos = 0; - uint32 framesCordsPos = 0; - - strncpy0(buf, path, 17); - if (!strchr(buf, '.')) { - buf[13] = 0; - strcat(buf, ".IMD"); - } - - handle = _vm->_dataIO->openData(buf); - - if (handle < 0) { - warning("Can't open IMD \"%s\"", buf); - return 0; - } - - imdPtr = new Imd; - assert(imdPtr); - memset(imdPtr, 0, sizeof(Imd)); - - imdPtr->handle = _vm->_dataIO->readUint16(handle); - imdPtr->verMin = _vm->_dataIO->readUint16(handle); - imdPtr->framesCount = _vm->_dataIO->readUint16(handle); - imdPtr->x = _vm->_dataIO->readUint16(handle); - imdPtr->y = _vm->_dataIO->readUint16(handle); - imdPtr->width = _vm->_dataIO->readUint16(handle); - imdPtr->height = _vm->_dataIO->readUint16(handle); - imdPtr->field_E = _vm->_dataIO->readUint16(handle); - imdPtr->curFrame = _vm->_dataIO->readUint16(handle); - - if ((imdPtr->handle != 0) || ((imdPtr->verMin & 0xFF) < 2)) { - warning("%s: Version incorrect (%d,%X)", buf, imdPtr->handle, imdPtr->verMin); - _vm->_dataIO->closeData(handle); - delete imdPtr; - return 0; - } - - imdPtr->handle = handle; - imdPtr->surfDesc = surfDesc; - imdPtr->firstFramePos = imdPtr->curFrame; - imdPtr->curFrame = 0; - - if ((imdPtr->verMin & 0x800) && ((flags & 3) != 3)) - imdPtr->extraPalette = new Video::Color[256]; - - if (flags & 3) { - imdPtr->palette = new Video::Color[256]; - assert(imdPtr->palette); - _vm->_dataIO->readData(handle, (byte *) imdPtr->palette, 768); - } else - _vm->_dataIO->seekData(handle, 768, SEEK_CUR); - - if ((flags & 3) == 1) - _vm->_video->setPalette(imdPtr->palette); - - if ((imdPtr->verMin & 0xFF) >= 3) { - imdPtr->stdX = _vm->_dataIO->readUint16(handle); - if (imdPtr->stdX > 1) { - warning("%s: More than one standard coordinate quad found (%d)", - buf, imdPtr->stdX); - finishImd(imdPtr); - return 0; - } - if (imdPtr->stdX != 0) { - imdPtr->stdX = _vm->_dataIO->readUint16(handle); - imdPtr->stdY = _vm->_dataIO->readUint16(handle); - imdPtr->stdWidth = _vm->_dataIO->readUint16(handle); - imdPtr->stdHeight = _vm->_dataIO->readUint16(handle); - } else - imdPtr->stdX = -1; - } else - imdPtr->stdX = -1; - - if ((imdPtr->verMin & 0xFF) >= 4) { - framesPosPos = _vm->_dataIO->readUint32(handle); - if (framesPosPos != 0) { - imdPtr->framesPos = new int32[imdPtr->framesCount]; - assert(imdPtr->framesPos); - } - } - - if (imdPtr->verMin & 0x8000) - framesCordsPos = _vm->_dataIO->readUint32(handle); - - _noSound = true; - _soundStage = 0; - if (imdPtr->verMin & 0x4000) { - _soundFreq = _vm->_dataIO->readUint16(handle); - _soundSliceSize = _vm->_dataIO->readUint16(handle); - _soundSlicesCount = _vm->_dataIO->readUint16(handle); - - if (_soundFreq < 0) - _soundFreq = -_soundFreq; - - if (_soundSlicesCount < 0) - _soundSlicesCount = -_soundSlicesCount - 1; - - if (_soundSlicesCount > 40) { - warning("%s: More than 40 sound slices found (%d)", - buf, _soundSlicesCount); - finishImd(imdPtr); - return 0; - } - - _soundSliceLength = 1000 / (_soundFreq / _soundSliceSize); - - _soundStage = 1; - _noSound = false; - - _audioStream = Audio::makeAppendableAudioStream(_soundFreq, 0); - } - - if (imdPtr->verMin & 0x2000) { - imdPtr->frameDataSize = _vm->_dataIO->readUint16(handle); - if (imdPtr->frameDataSize == 0) { - imdPtr->frameDataSize = _vm->_dataIO->readUint32(handle); - imdPtr->vidBufferSize = _vm->_dataIO->readUint32(handle); - } else - imdPtr->vidBufferSize = _vm->_dataIO->readUint16(handle); - } else { - imdPtr->frameDataSize = imdPtr->width * imdPtr->height + 500; - if (!(imdPtr->field_E & 0x100) || (imdPtr->field_E & 0x1000)) - imdPtr->vidBufferSize = imdPtr->frameDataSize; - } - - if (imdPtr->framesPos) { - _vm->_dataIO->seekData(handle, framesPosPos, SEEK_SET); - for (int i = 0; i < imdPtr->framesCount; i++) - imdPtr->framesPos[i] = _vm->_dataIO->readUint32(handle); - } - - if (imdPtr->verMin & 0x8000) { - _vm->_dataIO->seekData(handle, framesCordsPos, SEEK_SET); - imdPtr->frameCoords = new ImdCoord[imdPtr->framesCount]; - assert(imdPtr->frameCoords); - for (int i = 0; i < imdPtr->framesCount; i++) { - imdPtr->frameCoords[i].left = _vm->_dataIO->readUint16(handle); - imdPtr->frameCoords[i].top = _vm->_dataIO->readUint16(handle); - imdPtr->frameCoords[i].right = _vm->_dataIO->readUint16(handle); - imdPtr->frameCoords[i].bottom = _vm->_dataIO->readUint16(handle); - } - } - - _vm->_dataIO->seekData(handle, imdPtr->firstFramePos, SEEK_SET); - return imdPtr; -} - -void ImdPlayer::finishImd(ImdPlayer::Imd *&imdPtr) { - if (!imdPtr) - return; - - if (_soundStage == 2) - _vm->_snd->stopSound(0); - - _vm->_dataIO->closeData(imdPtr->handle); - - delete[] imdPtr->frameCoords; - delete[] imdPtr->palette; - delete[] imdPtr->framesPos; - delete[] imdPtr->extraPalette; - - delete imdPtr; - - if (_audioStream) { - _audioStream->finish(); - _vm->_mixer->stopHandle(_audioHandle); - _audioStream = 0; - } -} - -int8 ImdPlayer::openImd(const char *path, int16 x, int16 y, - int16 startFrame, int16 flags) { - const char *src; - byte *vidMem; - SurfaceDesc *surfDesc; - - if (!_curImd) - _curFile[0] = 0; - - src = strrchr(path, '\\'); - src = !src ? path : src + 1; - - if ((path[0] != 0) && scumm_stricmp(_curFile, src)) { - closeImd(); - - _curImd = loadImdFile(path, 0, 3); - if (!_curImd) - return 0; - - _curX = _curImd->x; - _curY = _curImd->y; - strncpy0(_curFile, src, 17); - - delete[] _frameData; - _frameData = new byte[_curImd->frameDataSize + 500]; - assert(_frameData); - memset(_frameData, 0, _curImd->frameDataSize + 500); - - delete[] _vidBuffer; - _vidBuffer = new byte[_curImd->vidBufferSize + 500]; - assert(_vidBuffer); - memset(_vidBuffer, 0, _curImd->vidBufferSize + 500); - - if (!(flags & 0x100)) { - - if (_vm->_global->_videoMode == 0x14) { - - _backSurf = (flags & 0x80) ? 20 : 21; - if (!(_curImd->field_E & 0x100) || (_curImd->field_E & 0x2000)) { - setXY(_curImd, 0, 0); - _curImd->surfDesc = - _vm->_video->initSurfDesc(0x13, - _curImd->width, _curImd->height, 0); - } else { - _curImd->surfDesc = _vm->_draw->_spritesArray[_frontSurf]; - if ((x != -1) || (y != -1)) { - _curX = x != -1 ? x : _curX; - _curY = y != -1 ? y : _curY; - setXY(_curImd, _curX, _curY); - } - } - - if (flags & 0x40) { - _curX = x != -1 ? x : _curX; - _curY = y != -1 ? y : _curY; - if (_curImd->surfDesc->_vidMode == 0x14) { - surfDesc = _vm->_video->initSurfDesc(0x13, - _curImd->width, _curImd->height, 0); - _vm->_video->drawSprite(_vm->_draw->_spritesArray[21], - surfDesc, _curX, _curY, - _curX + _curImd->width - 1, _curY + _curImd->height - 1, - 0, 0, 0); - - vidMem = _curImd->surfDesc->getVidMem(); - for (int i = 0; i < _curImd->height; i++) - for (int j = 0; j < _curImd->width; j++, vidMem++) { - *(vidMem) = *(surfDesc->getVidMem() + - (j / 4) + (surfDesc->getWidth() / 4 * i)); - } - surfDesc = 0; - } - } - - } else { - if ((x != -1) || (y != -1)) { - _curX = (x != -1) ? x : _curX; - _curY = (y != -1) ? y : _curY; - setXY(_curImd, _curX, _curY); - } - _backSurf = (flags & 0x80) ? 20 : 21; - _curImd->surfDesc = _vm->_draw->_spritesArray[_backSurf]; - } - - } - } - - if (!_curImd) - return 0; - - if (startFrame == -1) { - closeImd(); - return 0; - } - - _curX = (x != -1) ? x : _curX; - _curY = (y != -1) ? y : _curY; - - WRITE_VAR(7, _curImd->framesCount); - - return 1; -} - -void ImdPlayer::closeImd(void) { - finishImd(_curImd); - - delete[] _frameData; - delete[] _vidBuffer; - _frameData = 0; - _vidBuffer = 0; - - _curImd = 0; -} - -void ImdPlayer::setXY(ImdPlayer::Imd *imdPtr, int16 x, int16 y) { - int i; - - if (imdPtr->stdX != -1) { - imdPtr->stdX = imdPtr->stdX - imdPtr->x + x; - imdPtr->stdY = imdPtr->stdY - imdPtr->y + y; - } - - if (imdPtr->frameCoords) { - for (i = 0; i < imdPtr->framesCount; i++) { - if (imdPtr->frameCoords[i].left != -1) { - imdPtr->frameCoords[i].left = - imdPtr->frameCoords[i].left - imdPtr->x + x; - imdPtr->frameCoords[i].top = - imdPtr->frameCoords[i].top - imdPtr->y + y; - imdPtr->frameCoords[i].right = - imdPtr->frameCoords[i].right - imdPtr->x + x; - imdPtr->frameCoords[i].bottom = - imdPtr->frameCoords[i].bottom - imdPtr->y + y; - } - } - } - - imdPtr->x = x; - imdPtr->y = y; -} - -void ImdPlayer::drawFrame(Imd *imdPtr, int16 frame, int16 x, int16 y, - SurfaceDesc *dest) { - if (!dest) - dest = _vm->_draw->_frontSurface; - - if (frame == 0) - _vm->_video->drawSprite(imdPtr->surfDesc, dest, 0, 0, - imdPtr->width - 1, imdPtr->height - 1, x, y, 0); - else if (imdPtr->frameCoords && (imdPtr->frameCoords[frame].left != -1)) - _vm->_video->drawSprite(imdPtr->surfDesc, dest, - imdPtr->frameCoords[frame].left, imdPtr->frameCoords[frame].top, - imdPtr->frameCoords[frame].right, imdPtr->frameCoords[frame].bottom, - imdPtr->frameCoords[frame].left + x, - imdPtr->frameCoords[frame].top + y, 0); - else if (imdPtr->stdX != -1) - _vm->_video->drawSprite(imdPtr->surfDesc, dest, - imdPtr->stdX, imdPtr->stdY, imdPtr->stdX + imdPtr->stdWidth - 1, - imdPtr->stdY + imdPtr->stdHeight - 1, x + imdPtr->stdX, - y + imdPtr->stdY, 0); - else - _vm->_video->drawSprite(imdPtr->surfDesc, dest, 0, 0, - imdPtr->width - 1, imdPtr->height - 1, x, y, 0); -} - -void ImdPlayer::renderFrame(Imd *imdPtr) { - int16 imdX, imdY; - int16 imdW, imdH; - int16 sW; - uint16 pixCount, pixWritten; - uint8 type; - byte *imdVidMem; - byte *imdVidMemBak; - byte *dataPtr = 0; - byte *srcPtr = 0; - - dataPtr = _frameData; - imdX = imdPtr->x; - imdY = imdPtr->y; - imdW = imdPtr->width; - imdH = imdPtr->height; - sW = imdPtr->surfDesc->getWidth(); - imdVidMem = imdPtr->surfDesc->getVidMem() + sW * imdY + imdX; - - type = *dataPtr++; - srcPtr = dataPtr; - - if (type & 0x10) { // Palette data - type ^= 0x10; - dataPtr += 49; - } - - srcPtr = dataPtr; - if (type & 0x80) { // Frame data is compressed - srcPtr = _vidBuffer; - type &= 0x7F; - if ((type == 2) && (imdW == sW)) { - frameUncompressor(imdVidMem, dataPtr); - return; - } else - frameUncompressor(srcPtr, dataPtr); - } - - if (type == 2) { // Whole block - for (int i = 0; i < imdH; i++) { - memcpy(imdVidMem, srcPtr, imdW); - srcPtr += imdW; - imdVidMem += sW; - } - } else if (type == 1) { // Sparse block - imdVidMemBak = imdVidMem; - for (int i = 0; i < imdH; i++) { - pixWritten = 0; - while (pixWritten < imdW) { - pixCount = *srcPtr++; - if (pixCount & 0x80) { // data - pixCount = MIN((pixCount & 0x7F) + 1, imdW - pixWritten); - memcpy(imdVidMem, srcPtr, pixCount); - - pixWritten += pixCount; - imdVidMem += pixCount; - srcPtr += pixCount; - } else { // "hole" - pixCount = (pixCount + 1) % 256; - pixWritten += pixCount; - imdVidMem += pixCount; - } - } - imdVidMemBak += sW; - imdVidMem = imdVidMemBak; - } - } else if (type == 0x42) { // Whole quarter-wide block - for (int i = 0; i < imdH; i++) { - imdVidMemBak = imdVidMem; - - for (int j = 0; j < imdW; j += 4, imdVidMem += 4, srcPtr++) - memset(imdVidMem, *srcPtr, 4); - - imdVidMemBak += sW; - imdVidMem = imdVidMemBak; - } - } else if ((type & 0xF) == 2) { // Whole half-high block - for (; imdH > 1; imdH -= 2, imdVidMem += sW + sW, srcPtr += imdW) { - memcpy(imdVidMem, srcPtr, imdW); - memcpy(imdVidMem + sW, srcPtr, imdW); - } - if (imdH == -1) - memcpy(imdVidMem, srcPtr, imdW); - } else { // Sparse half-high block - imdVidMemBak = imdVidMem; - for (int i = 0; i < imdH; i += 2) { - pixWritten = 0; - while (pixWritten < imdW) { - pixCount = *srcPtr++; - if (pixCount & 0x80) { // data - pixCount = MIN((pixCount & 0x7F) + 1, imdW - pixWritten); - memcpy(imdVidMem, srcPtr, pixCount); - memcpy(imdVidMem + sW, srcPtr, pixCount); - - pixWritten += pixCount; - imdVidMem += pixCount; - srcPtr += pixCount; - } else { // "hole" - pixCount = (pixCount + 1) % 256; - pixWritten += pixCount; - imdVidMem += pixCount; - } - } - imdVidMemBak += sW + sW; - imdVidMem = imdVidMemBak; - } - } -} - -void ImdPlayer::frameUncompressor(byte *dest, byte *src) { - int i; - byte buf[4370]; - uint16 chunkLength; - uint16 frameLength; - uint16 bufPos1; - uint16 bufPos2; - uint16 tmp; - uint8 chunkBitField; - uint8 chunkCount; - bool mode; - - frameLength = READ_LE_UINT16(src); - src += 4; - - if ((READ_LE_UINT16(src) == 0x1234) && (READ_LE_UINT16(src + 2) == 0x5678)) { - src += 4; - bufPos1 = 273; - mode = 1; // 123Ch (cmp al, 12h) - } else { - bufPos1 = 4078; - mode = 0; // 275h (jnz +2) - } - - memset(buf, 32, bufPos1); - chunkCount = 1; - chunkBitField = 0; - - while (frameLength > 0) { - chunkCount--; - if (chunkCount == 0) { - tmp = *src++; - chunkCount = 8; - chunkBitField = tmp; - } - if (chunkBitField % 2) { - chunkBitField >>= 1; - buf[bufPos1] = *src; - *dest++ = *src++; - bufPos1 = (bufPos1 + 1) % 4096; - frameLength--; - continue; - } - chunkBitField >>= 1; - - tmp = READ_LE_UINT16(src); - src += 2; - chunkLength = ((tmp & 0xF00) >> 8) + 3; - - if ((mode && ((chunkLength & 0xFF) == 0x12)) || - (!mode && (chunkLength == 0))) - chunkLength = *src++ + 0x12; - - bufPos2 = (tmp & 0xFF) + ((tmp >> 4) & 0x0F00); - if (((tmp + chunkLength) >= 4096) || - ((chunkLength + bufPos1) >= 4096)) { - - for (i = 0; i < chunkLength; i++, dest++) { - *dest = buf[bufPos2]; - buf[bufPos1] = buf[bufPos2]; - bufPos1 = (bufPos1 + 1) % 4096; - bufPos2 = (bufPos2 + 1) % 4096; - } - - } else if (((tmp + chunkLength) < bufPos1) || - ((chunkLength + bufPos1) < bufPos2)) { - - memcpy(dest, buf + bufPos2, chunkLength); - memmove(buf + bufPos1, buf + bufPos2, chunkLength); - - dest += chunkLength; - bufPos1 += chunkLength; - bufPos2 += chunkLength; - - } else { - - for (i = 0; i < chunkLength; i++, dest++, bufPos1++, bufPos2++) { - *dest = buf[bufPos2]; - buf[bufPos1] = buf[bufPos2]; - } - - } - frameLength -= chunkLength; - - } -} - -void ImdPlayer::play(const char *path, int16 x, int16 y, bool interruptible) { - int16 mouseX; - int16 mouseY; - int16 buttons; - - _vm->_util->setFrameRate(12); - if (!openImd(path, x, y, 0, 2)) - return; - - _vm->_video->fillRect(_vm->_draw->_frontSurface, x, y, - x + _curImd->width - 1, y + _curImd->height - 1, 0); - - for (int i = 0; i < _curImd->framesCount; i++) { - play(i, 4, 0, 255, 0, _curImd->framesCount - 1); - - if (_vm->_quitRequested || (interruptible && - (_vm->_game->checkKeys(&mouseX, &mouseY, &buttons, 0) == 0x11B))) - break; - } - - closeImd(); -} - -void ImdPlayer::play(const char *path, int16 x, int16 y, int16 startFrame, - int16 frames, bool fade, bool interruptible) { - int16 mouseX; - int16 mouseY; - int16 buttons = 0; - int endFrame; - - _vm->_util->setFrameRate(12); - if (!openImd(path, x, y, 0, 0)) - return; - - _vm->_video->fillRect(_vm->_draw->_frontSurface, x, y, - x + _curImd->width - 1, y + _curImd->height - 1, 0); - - if (fade) - _vm->_palAnim->fade(0, -2, 0); - - endFrame = frames > 0 ? frames : _curImd->framesCount; - for (int i = startFrame; i < endFrame; i++) { - view(_curImd, i); - drawFrame(_curImd, i, x, y); - if (fade) { - _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); - fade = false; - } - _vm->_video->waitRetrace(); - - if (_vm->_quitRequested || (interruptible && - (_vm->_game->checkKeys(&mouseX, &mouseY, &buttons, 0) == 0x11B))) { - _vm->_palAnim->fade(0, -2, 0); - _vm->_video->clearSurf(_vm->_draw->_frontSurface); - memset((char *) _vm->_draw->_vgaPalette, 0, 768); - - WRITE_VAR(4, buttons); - WRITE_VAR(0, 0x11B); - WRITE_VAR(57, (uint32) -1); - break; - } - - _vm->_util->waitEndFrame(); - } - - if (frames < 0) { - endFrame = _curImd->framesCount + frames; - for (int i = _curImd->framesCount - 1; i >= endFrame; i--) { - seekFrame(_curImd, i, SEEK_SET, true); - drawFrame(_curImd, i, x, y); - _vm->_video->waitRetrace(); - - if (_vm->_quitRequested || (interruptible && - (_vm->_game->checkKeys(&mouseX, &mouseY, &buttons, 0) == 0x11B))) { - _vm->_palAnim->fade(0, -2, 0); - _vm->_video->clearSurf(_vm->_draw->_frontSurface); - memset((char *) _vm->_draw->_vgaPalette, 0, 768); - - WRITE_VAR(4, buttons); - WRITE_VAR(0, 0x11B); - WRITE_VAR(57, (uint32) -1); - break; - } - - _vm->_util->waitEndFrame(); - } - } - - closeImd(); -} - -void ImdPlayer::play(int16 frame, uint16 palCmd, - int16 palStart, int16 palEnd, int16 palFrame, int16 lastFrame) { - uint32 viewRet = 0; - SurfaceDesc *surfDescBak; - bool modifiedPal = false; - - _vm->_draw->_showCursor = 0; - - if ((frame < 0) || (frame > lastFrame)) - return; - - palCmd &= 0x3F; - if ((frame == palFrame) || ((frame == lastFrame) && (palCmd == 8))) { - modifiedPal = true; - _vm->_draw->_applyPal = true; - - if (palCmd >= 4) - copyPalette(palStart, palEnd); - } - - if (modifiedPal && (palCmd == 8) && (_backSurf == 20)) - _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); - - if (_curImd->surfDesc) { - if (_curImd->surfDesc->_vidMode == 0x14) { - - if ((_frontMem == _vm->_draw->_frontSurface->getVidMem()) && - (_frontSurf == 20)) { - _vm->_draw->_frontSurface->swap(_vm->_draw->_backSurface); - viewRet = view(_curImd, frame); - _vm->_draw->_frontSurface->swap(_vm->_draw->_backSurface); - } else - viewRet = view(_curImd, frame); - - if (_frontSurf == 21) - _vm->_draw->invalidateRect(_left, _top, _right, _bottom); - - } else { - if ((_curImd->field_E & 0x100) && - (_vm->_global->_videoMode == 0x14) && - (_frontSurf == 20) && - (checkFrameType(_curImd, frame) & 0x8000) && - (_backSurf == 21)) { - - surfDescBak = _curImd->surfDesc; - if (_frontMem == _vm->_draw->_spritesArray[20]->getVidMem()) - _curImd->surfDesc = _vm->_draw->_spritesArray[21]; - else - _curImd->surfDesc = _vm->_draw->_spritesArray[20]; - setXY(_curImd, _curX, _curY); - viewRet = view(_curImd, frame); - _curImd->surfDesc = surfDescBak; - setXY(_curImd, 0, 0); - - } else { - viewRet = view(_curImd, frame); - if (!(viewRet & 0x800)) - drawFrame(frame); - } - } - } else - viewRet = view(_curImd, frame); - - if (modifiedPal && (palCmd == 16)) { - if (_backSurf == 21) - _vm->_draw->forceBlit(); - _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); - _vm->_draw->_noInvalidated = true; - } - - if (viewRet & 0x10) { - copyPalette(palStart, palEnd); - - if (_backSurf == 20) - _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); - else - _vm->_draw->_applyPal = true; - } - - if (modifiedPal && (palCmd == 8) && (_backSurf == 21)) - _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); - - if (!(viewRet & 0x800)) { - if (_vm->_draw->_cursorIndex == -1) { - if (_frontSurf == 20) - flipFrontMem(); - else - _vm->_draw->blitInvalidated(); - } else - _vm->_draw->animateCursor(-1); - } - - if (modifiedPal && ((palCmd == 2) || (palCmd == 4))) - _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); - - // To allow quitting, etc. during IMDs - _vm->_util->processInput(); - if (_vm->_quitRequested) - return; - - if (_soundStage != 2) { - if (viewRet & 0x800) { - if (_frameDelay == 0) - _vm->_util->delay(30); - else { - _frameDelay -= 30; - if (_frameDelay < 0) - _frameDelay = 0; - } - } else - _vm->_util->waitEndFrame(); - } - - _vm->_inter->animPalette(); -} - -inline void ImdPlayer::drawFrame(int16 frame) { - if (_backSurf == 21) { - - if (_vm->_global->_videoMode == 0x14) { - if (_frontSurf == 21) { - _vm->_draw->_frontSurface->swap(_vm->_draw->_spritesArray[21]); - drawFrame(_curImd, frame, _curX, _curY); - _vm->_draw->_frontSurface->swap(_vm->_draw->_spritesArray[21]); - _vm->_draw->invalidateRect(_curX + _left, _curY + _top, - _curX + _right, _curY + _bottom); - } else { - if (_frontMem == _vm->_draw->_spritesArray[20]->getVidMem()) { - _vm->_draw->_frontSurface->swap(_vm->_draw->_spritesArray[21]); - drawFrame(_curImd, frame, _curX, _curY); - _vm->_draw->_frontSurface->swap(_vm->_draw->_spritesArray[21]); - } else - drawFrame(_curImd, frame, _curX, _curY); - } - } else - _vm->_draw->invalidateRect(_left, _top, _right, _bottom); - - } else if (_vm->_global->_videoMode == 0x14) - drawFrame(_curImd, frame, _curX, _curY); -} - -inline void ImdPlayer::copyPalette(int16 palStart, int16 palEnd) { - if ((palStart == -1) || (palEnd == -1)) - memcpy((char *) _vm->_global->_pPaletteDesc->vgaPal, - (char *) _curImd->palette, 768); - else - memcpy(((char *) (_vm->_global->_pPaletteDesc->vgaPal)) + - palStart * 3, ((char *) (_curImd->palette)) + palStart * 3, - (palEnd - palStart + 1) * 3); -} - -inline void ImdPlayer::flipFrontMem() { - if (_frontMem == _vm->_draw->_frontSurface->getVidMem()) - _frontMem = _vm->_draw->_backSurface->getVidMem(); - else - _frontMem = _vm->_draw->_frontSurface->getVidMem(); -} - -uint16 ImdPlayer::checkFrameType(Imd *imdPtr, int16 frame) { - uint16 retVal = 0; - uint32 posBak; - uint32 tmp; - uint16 cmd; - int16 frameBak; - - if (!imdPtr) - return 0x8000; - - posBak = _vm->_dataIO->getPos(imdPtr->handle); - frameBak = imdPtr->curFrame; - - if (imdPtr->curFrame != frame) { - retVal |= 0x2000; - seekFrame(imdPtr, frame, SEEK_SET); - } - - do { - if (frame != 0) { - if (imdPtr->stdX != -1) - retVal |= 0x1000; - if (imdPtr->frameCoords && (imdPtr->frameCoords[frame].left != -1)) - retVal |= 0x400; - } - - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - - if ((cmd & 0xFFF8) == 0xFFF0) { - if (cmd == 0xFFF0) { - _vm->_dataIO->seekData(imdPtr->handle, 2, SEEK_CUR); - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - } - - if (cmd == 0xFFF1) { - retVal = 0x8000; - continue; - } else if (cmd == 0xFFF2) { // Skip (16 bit) - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - _vm->_dataIO->seekData(imdPtr->handle, cmd, SEEK_CUR); - retVal = 0x8000; - continue; - } else if (cmd == 0xFFF3) { // Skip (32 bit) - tmp = _vm->_dataIO->readUint32(imdPtr->handle); - _vm->_dataIO->seekData(imdPtr->handle, cmd, SEEK_CUR); - retVal = 0x8000; - continue; - } - } - - // Jump to frame - if (cmd == 0xFFFD) { - frame = _vm->_dataIO->readUint16(imdPtr->handle); - if (imdPtr->framesPos) { - _vm->_dataIO->seekData(imdPtr->handle, - imdPtr->framesPos[frame], SEEK_SET); - retVal |= 0x200; - continue; - } - break; - } - - // Next sound slice data - if (cmd == 0xFF00) { - _vm->_dataIO->seekData(imdPtr->handle, - _soundSliceSize, SEEK_CUR); - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - // Initial sound data (all slices) - } else if (cmd == 0xFF01) { - _vm->_dataIO->seekData(imdPtr->handle, - _soundSliceSize * _soundSlicesCount, SEEK_CUR); - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - } - - // Frame video data - if (cmd != 0) { - _vm->_dataIO->readData(imdPtr->handle, _frameData, 5); - retVal |= _frameData[0]; - } else - retVal |= 0x800; - - break; - - } while (true); - - _vm->_dataIO->seekData(imdPtr->handle, posBak, SEEK_SET); - imdPtr->curFrame = frameBak; - return retVal; -} - -void ImdPlayer::seekFrame(Imd *imdPtr, int16 frame, int16 from, bool restart) { - uint32 framePos = 0; - - if (!imdPtr) - return; - - if (from == SEEK_CUR) - frame += imdPtr->curFrame; - else if (from == SEEK_END) - frame = imdPtr->framesCount - frame - 1; - - if (frame >= imdPtr->framesCount) - return; - - if (frame == 0) { - framePos = imdPtr->firstFramePos; - } else if (frame == 1) { - framePos = imdPtr->firstFramePos; - _vm->_dataIO->seekData(imdPtr->handle, framePos, SEEK_SET); - framePos += _vm->_dataIO->readUint16(imdPtr->handle) + 4; - } else if (imdPtr->framesPos) { - framePos = imdPtr->framesPos[frame]; - } else if (restart && (_soundStage == 0)) { - for (int i = 0; i <= frame; i++) - view(_curImd, i); - } else - error("%s: Frame %d is not directly accessible", _curFile, frame); - - _vm->_dataIO->seekData(imdPtr->handle, framePos, SEEK_SET); - imdPtr->curFrame = frame; -} - -uint32 ImdPlayer::view(Imd *imdPtr, int16 frame) { - uint32 retVal = 0; - uint32 cmd = 0; - int16 xBak, yBak, heightBak, widthBak; - bool hasNextCmd = false; - bool startSound = false; - - if (!imdPtr) - return 0x8000; - - if (frame != imdPtr->curFrame) { - retVal |= 0x2000; - seekFrame(imdPtr, frame, SEEK_SET); - } - - _left = xBak = imdPtr->x; - _top = yBak = imdPtr->y; - _bottom = heightBak= imdPtr->height; - _right = widthBak = imdPtr->width; - _right += _left - 1; - _bottom += _top - 1; - - if ((frame == 0) && (imdPtr->verMin & 0x800)) - _vm->_video->setPalette(imdPtr->palette); - - do { - if (frame != 0) { - if (imdPtr->stdX != -1) { - _left = imdPtr->x = imdPtr->stdX; - _top = imdPtr->y = imdPtr->stdY; - _right = imdPtr->width = imdPtr->stdWidth; - _bottom = imdPtr->height = imdPtr->stdHeight; - _right += _left - 1; - _bottom += _top - 1; - retVal |= 0x1000; - } - if (imdPtr->frameCoords && - (imdPtr->frameCoords[frame].left != -1)) { - _left = imdPtr->x = imdPtr->frameCoords[frame].left; - _top = imdPtr->y = imdPtr->frameCoords[frame].top; - _right = imdPtr->width = - imdPtr->frameCoords[frame].right - imdPtr->x + 1; - _bottom = imdPtr->height = - imdPtr->frameCoords[frame].bottom - imdPtr->y + 1; - _right += _left - 1; - _bottom += _top - 1; - retVal |= 0x400; - } - } - - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - - if ((cmd & 0xFFF8) == 0xFFF0) { - if (cmd == 0xFFF0) { - _vm->_dataIO->seekData(imdPtr->handle, 2, SEEK_CUR); - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - } - - if (cmd == 0xFFF1) { - retVal = 0x8000; - continue; - } else if (cmd == 0xFFF2) { // Skip (16 bit) - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - _vm->_dataIO->seekData(imdPtr->handle, cmd, SEEK_CUR); - retVal = 0x8000; - continue; - } else if (cmd == 0xFFF3) { // Skip (32 bit) - cmd = _vm->_dataIO->readUint32(imdPtr->handle); - _vm->_dataIO->seekData(imdPtr->handle, cmd, SEEK_CUR); - retVal = 0x8000; - continue; - } - } - - if (_soundStage != 0) { - byte *soundBuf; - - if (!hasNextCmd) - waitEndSoundSlice(); - - // Next sound slice data - if (cmd == 0xFF00) { - - if (!hasNextCmd && !_noSound) { - soundBuf = new byte[_soundSliceSize]; - assert(soundBuf); - - _vm->_dataIO->readData(imdPtr->handle, soundBuf, - _soundSliceSize); - _vm->_snd->convToSigned(soundBuf, _soundSliceSize); - _audioStream->queueBuffer(soundBuf, _soundSliceSize); - } else - _vm->_dataIO->seekData(imdPtr->handle, - _soundSliceSize, SEEK_CUR); - - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - - // Initial sound data (all slices) - } else if (cmd == 0xFF01) { - int dataLength = _soundSliceSize * _soundSlicesCount; - - if (!hasNextCmd && !_noSound) { - soundBuf = new byte[dataLength]; - assert(soundBuf); - - _vm->_dataIO->readData(imdPtr->handle, soundBuf, dataLength); - _vm->_snd->convToSigned(soundBuf, dataLength); - - _soundStage = 1; - startSound = true; - _audioStream->queueBuffer(soundBuf, dataLength); - } else - _vm->_dataIO->seekData(imdPtr->handle, dataLength, SEEK_CUR); - - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - - // Empty sound slice - } else if (!hasNextCmd && (!_noSound)) { - soundBuf = new byte[_soundSliceSize]; - assert(soundBuf); - - memset(soundBuf, 0, _soundSliceSize); - _audioStream->queueBuffer(soundBuf, _soundSliceSize); - } - } - - // Set palette - if (cmd == 0xFFF4) { - _vm->_dataIO->seekData(imdPtr->handle, 2, SEEK_CUR); - retVal |= 0x10; - if (imdPtr->extraPalette) { - _vm->_dataIO->readData(imdPtr->handle, - (byte *) imdPtr->extraPalette, 768); - _vm->_video->setPalette(imdPtr->extraPalette); - } else if (imdPtr->palette) - _vm->_dataIO->readData(imdPtr->handle, - (byte *) imdPtr->palette, 768); - else - _vm->_dataIO->readData(imdPtr->handle, _frameData, 768); - - cmd = _vm->_dataIO->readUint16(imdPtr->handle); - } - - hasNextCmd = false; - - // Jump to frame - if (cmd == 0xFFFD) { - - frame = _vm->_dataIO->readUint16(imdPtr->handle); - if (imdPtr->framesPos) { - imdPtr->curFrame = frame; - _vm->_dataIO->seekData(imdPtr->handle, - imdPtr->framesPos[frame], SEEK_SET); - - hasNextCmd = true; - retVal |= 0x200; - } - - } else if (cmd == 0xFFFC) { - - retVal |= 1; - cmd = _vm->_dataIO->readUint32(imdPtr->handle); - _vm->_dataIO->readData(imdPtr->handle, _frameData, cmd + 2); - - if (imdPtr->surfDesc) { - int16 left = imdPtr->x; - int16 top = imdPtr->y; - int16 right = imdPtr->width + left; - int16 bottom = imdPtr->height + top; - - if (imdPtr->surfDesc->getWidth() < right) { - left = 0; - right = imdPtr->width; - } - if (imdPtr->surfDesc->getWidth() < right) - right = imdPtr->surfDesc->getWidth(); - if (imdPtr->surfDesc->getHeight() < bottom) { - top = 0; - bottom = imdPtr->height; - } - if (imdPtr->surfDesc->getHeight() < bottom) - bottom = imdPtr->surfDesc->getHeight(); - - imdPtr->x = left; - imdPtr->y = top; - imdPtr->height = bottom - top; - imdPtr->width = right - left; - - renderFrame(imdPtr); - } - - retVal |= _frameData[0]; - - // Frame video data - } else if (cmd != 0) { - - _vm->_dataIO->readData(imdPtr->handle, _frameData, cmd + 2); - if (imdPtr->surfDesc) - renderFrame(imdPtr); - - retVal |= _frameData[0]; - - } else - retVal |= 0x800; - - } while (hasNextCmd); - - if (startSound) { - _vm->_snd->stopSound(0); - _vm->_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_audioHandle, _audioStream); - _soundStartTime = _vm->_util->getTimeKey(); - _skipFrames = 0; - _soundStage = 2; - } - - imdPtr->x = xBak; - imdPtr->y = yBak; - imdPtr->width = widthBak; - imdPtr->height = heightBak; - - imdPtr->curFrame++; - if ((imdPtr->curFrame == imdPtr->framesCount) && (_soundStage == 2)) { - waitEndSoundSlice(); - _audioStream->finish(); - _vm->_mixer->stopHandle(_audioHandle); - _audioStream = 0; - } - - return retVal; -} - -inline void ImdPlayer::waitEndSoundSlice() { - if (_soundStage != 2) - return; - - if (_skipFrames == 0) { - - _vm->_video->retrace(); - - int32 waitTime = (_curImd->curFrame * _soundSliceLength) - - (_vm->_util->getTimeKey() - _soundStartTime); - - if (waitTime < 0) { - _skipFrames = -waitTime / _soundSliceLength; - warning("IMD A/V sync broken, skipping %d frame(s)", _skipFrames + 1); - } else if (waitTime > 0) - _vm->_util->delay(waitTime); - - } else - _skipFrames--; -} - -} // End of namespace Gob diff --git a/engines/gob/imd.h b/engines/gob/imd.h deleted file mode 100644 index 27d95cd579..0000000000 --- a/engines/gob/imd.h +++ /dev/null @@ -1,143 +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. - * - * $URL$ - * $Id$ - * - */ - -#ifndef GOB_IMD_H -#define GOB_IMD_H - -#include "gob/video.h" -#include "gob/sound.h" - -namespace Gob { - -class ImdPlayer { -public: - -#include "common/pack-start.h" // START STRUCT PACKING - - struct ImdCoord { - int16 left; - int16 top; - int16 right; - int16 bottom; - } PACKED_STRUCT; - - struct Imd { - int16 handle; - int16 verMin; - int16 framesCount; - int16 x; - int16 y; - int16 width; - int16 height; - int16 field_E; - int16 curFrame; - Video::Color *palette; - SurfaceDesc *surfDesc; - int32 *framesPos; - int32 firstFramePos; - int16 stdX; - int16 stdY; - int16 stdWidth; - int16 stdHeight; - ImdCoord *frameCoords; - int32 frameDataSize; - int32 vidBufferSize; - Video::Color *extraPalette; - } PACKED_STRUCT; - -#include "common/pack-end.h" // END STRUCT PACKING - - Imd *_curImd; - byte _frontSurf; - int8 _backSurf; - byte *_frontMem; - int32 _frameDelay; - - uint8 _soundStage; // (0: no sound, 1: loaded, 2: playing) - - ImdPlayer(GobEngine *vm); - virtual ~ImdPlayer(); - - Imd *loadImdFile(const char *path, SurfaceDesc *surfDesc, int8 flags); - void finishImd(Imd *&imdPtr); - - int8 openImd(const char *path, int16 x, int16 y, - int16 startFrame, int16 flags); - void closeImd(void); - - void play(int16 frame, uint16 palCmd, int16 palStart, int16 palEnd, - int16 palFrame, int16 lastFrame); - void play(const char *path, int16 x, int16 y, bool interruptible); - void play(const char *path, int16 x, int16 y, int16 startFrame, - int16 frames, bool fade, bool interruptible); - -protected: - char _curFile[18]; - - int16 _curX; - int16 _curY; - int16 _left; - int16 _top; - int16 _right; - int16 _bottom; - - byte *_frameData; - byte *_vidBuffer; - - bool _noSound; - - uint32 _soundStartTime; - uint32 _skipFrames; - - int16 _soundFreq; - uint16 _soundSliceSize; - int16 _soundSlicesCount; - uint16 _soundSliceLength; - - Audio::AppendableAudioStream *_audioStream; - Audio::SoundHandle _audioHandle; - - GobEngine *_vm; - - void copyPalette(int16 palStart, int16 palEnd); - void flipFrontMem(); - void drawFrame(int16 frame); - void setXY(Imd *imdPtr, int16 x, int16 y); - - void seekFrame(Imd *imdPtr, int16 frame, int16 from, bool restart = false); - uint16 checkFrameType(Imd *imdPtr, int16 frame); - void drawFrame(Imd *imdPtr, int16 frame, int16 x, int16 y, - SurfaceDesc *dest = 0); - - uint32 view(ImdPlayer::Imd *imdPtr, int16 arg_4); - void renderFrame(Imd *imdPtr); - void frameUncompressor(byte *dest, byte *src); - - void waitEndSoundSlice(); -}; - -} // End of namespace Gob - -#endif // GOB_IMD_H diff --git a/engines/gob/init.cpp b/engines/gob/init.cpp index 2f1dbe5326..85f95fb261 100644 --- a/engines/gob/init.cpp +++ b/engines/gob/init.cpp @@ -37,7 +37,7 @@ #include "gob/palanim.h" #include "gob/sound.h" #include "gob/video.h" -#include "gob/imd.h" +#include "gob/videoplayer.h" namespace Gob { @@ -167,8 +167,14 @@ void Init::initGame(const char *totName) { _vm->_dataIO->closeData(imdHandle); _vm->_draw->initScreen(); _vm->_draw->_cursorIndex = -1; + _vm->_util->longDelay(200); // Letting everything settle - _vm->_imdPlayer->play("coktel", -1, -1, true); + + if (_vm->_vidPlayer->openVideo("coktel.imd")) { + _vm->_vidPlayer->play(); + _vm->_vidPlayer->closeVideo(); + } + _vm->_draw->closeScreen(); } else if ((imdHandle = _vm->_dataIO->openData("coktel.clt")) >= 0) { _vm->_draw->initScreen(); diff --git a/engines/gob/inter_bargon.cpp b/engines/gob/inter_bargon.cpp index ffbe9e45ea..492ea198a1 100644 --- a/engines/gob/inter_bargon.cpp +++ b/engines/gob/inter_bargon.cpp @@ -33,10 +33,10 @@ #include "gob/dataio.h" #include "gob/draw.h" #include "gob/game.h" -#include "gob/imd.h" #include "gob/palanim.h" #include "gob/sound.h" #include "gob/video.h" +#include "gob/videoplayer.h" namespace Gob { @@ -717,11 +717,17 @@ const char *Inter_Bargon::getOpcodeGoblinDesc(int i) { } void Inter_Bargon::oBargon_intro0(OpGobParams ¶ms) { - _vm->_imdPlayer->play("scaa", 0, 160, 0, 92, 0, 1); + if (_vm->_vidPlayer->openVideo("scaa", 0, 160)) { + _vm->_vidPlayer->play(0, 92, 27, 0, 0, 0); + _vm->_vidPlayer->closeVideo(); + } } void Inter_Bargon::oBargon_intro1(OpGobParams ¶ms) { - _vm->_imdPlayer->play("scaa", 0, 160, 0, -23, 1, 1); + if (_vm->_vidPlayer->openVideo("scaa", 0, 160)) { + _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0, 0, 0, true, 23); + _vm->_vidPlayer->closeVideo(); + } } void Inter_Bargon::oBargon_intro2(OpGobParams ¶ms) { @@ -813,27 +819,45 @@ void Inter_Bargon::oBargon_intro3(OpGobParams ¶ms) { } void Inter_Bargon::oBargon_intro4(OpGobParams ¶ms) { - _vm->_imdPlayer->play("scba", 191, 54, 0, 0, 1, 1); + if (_vm->_vidPlayer->openVideo("scba", 191, 54)) { + _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0, 0, 0, true); + _vm->_vidPlayer->closeVideo(); + } } void Inter_Bargon::oBargon_intro5(OpGobParams ¶ms) { - _vm->_imdPlayer->play("scbb", 191, 54, 0, 0, 0, 1); + if (_vm->_vidPlayer->openVideo("scbb", 191, 54)) { + _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0); + _vm->_vidPlayer->closeVideo(); + } } void Inter_Bargon::oBargon_intro6(OpGobParams ¶ms) { - _vm->_imdPlayer->play("scbc", 191, 54, 0, 0, 0, 1); + if (_vm->_vidPlayer->openVideo("scbc", 191, 54)) { + _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0); + _vm->_vidPlayer->closeVideo(); + } } void Inter_Bargon::oBargon_intro7(OpGobParams ¶ms) { - _vm->_imdPlayer->play("scbf", 191, 54, 0, 0, 0, 1); + if (_vm->_vidPlayer->openVideo("scbf", 191, 54)) { + _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0); + _vm->_vidPlayer->closeVideo(); + } } void Inter_Bargon::oBargon_intro8(OpGobParams ¶ms) { - _vm->_imdPlayer->play("scbc", 191, 54, 0, 0, 0, 1); + if (_vm->_vidPlayer->openVideo("scbc", 191, 54)) { + _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0); + _vm->_vidPlayer->closeVideo(); + } } void Inter_Bargon::oBargon_intro9(OpGobParams ¶ms) { - _vm->_imdPlayer->play("scbd", 191, 54, 0, 0, 0, 1); + if (_vm->_vidPlayer->openVideo("scbd", 191, 54)) { + _vm->_vidPlayer->play(0, -1, 27, 0, 0, 0); + _vm->_vidPlayer->closeVideo(); + } } } // End of namespace Gob diff --git a/engines/gob/inter_v2.cpp b/engines/gob/inter_v2.cpp index c78aa9e017..58970d9fcd 100644 --- a/engines/gob/inter_v2.cpp +++ b/engines/gob/inter_v2.cpp @@ -38,7 +38,6 @@ #include "gob/draw.h" #include "gob/game.h" #include "gob/goblin.h" -#include "gob/imd.h" #include "gob/map.h" #include "gob/mult.h" #include "gob/parse.h" @@ -46,6 +45,7 @@ #include "gob/sound.h" #include "gob/video.h" #include "gob/saveload.h" +#include "gob/videoplayer.h" namespace Gob { @@ -1493,48 +1493,28 @@ void Inter_v2::o2_playImd() { palEnd = _vm->_parse->parseValExpr(); palCmd = 1 << (flags & 0x3F); - if (!_vm->_imdPlayer->openImd(imd, x, y, startFrame, flags)) { + if ((imd[0] != 0) && !_vm->_vidPlayer->openVideo(imd, x, y, flags)) { WRITE_VAR(11, -1); return; } close = (lastFrame == -1); - if (lastFrame < 0) - lastFrame = _vm->_imdPlayer->_curImd->framesCount - 1; if (startFrame == -2) { startFrame = lastFrame = 0; close = false; } - _vm->_game->_preventScroll = true; - for (int i = startFrame; i <= lastFrame; i++) { - _vm->_imdPlayer->play(i, palCmd, palStart, palEnd, 0, lastFrame); - WRITE_VAR(11, i); - - if (_vm->_quitRequested) - break; - - if (breakKey != 0) { - _vm->_util->getMouseState(&_vm->_global->_inter_mouseX, - &_vm->_global->_inter_mouseY, &_vm->_game->_mouseButtons); - - storeKey(_vm->_util->checkKey()); - if (VAR(0) == (unsigned) breakKey) { - if (_vm->_imdPlayer->_soundStage == 2) - _vm->_snd->stopSound(0); - _vm->_game->_preventScroll = false; - return; - } - } + if (startFrame >= 0) { + _vm->_game->_preventScroll = true; + _vm->_vidPlayer->play(startFrame, lastFrame, breakKey, palCmd, palStart, palEnd, 0); + _vm->_game->_preventScroll = false; } - _vm->_game->_preventScroll = false; if (close) - _vm->_imdPlayer->closeImd(); + _vm->_vidPlayer->closeVideo(); } void Inter_v2::o2_getImdInfo() { - ImdPlayer::Imd *imd; int16 varX, varY; int16 varFrames; int16 varWidth, varHeight; @@ -1545,21 +1525,9 @@ void Inter_v2::o2_getImdInfo() { varFrames = _vm->_parse->parseVarIndex(); varWidth = _vm->_parse->parseVarIndex(); varHeight = _vm->_parse->parseVarIndex(); - imd = _vm->_imdPlayer->loadImdFile(_vm->_global->_inter_resStr, 0, 2); - if (!imd) { - WRITE_VAR_OFFSET(varX, -1); - WRITE_VAR_OFFSET(varY, -1); - WRITE_VAR_OFFSET(varFrames, -1); - WRITE_VAR_OFFSET(varWidth, -1); - WRITE_VAR_OFFSET(varHeight, -1); - } else { - WRITE_VAR_OFFSET(varX, imd->x); - WRITE_VAR_OFFSET(varY, imd->y); - WRITE_VAR_OFFSET(varFrames, imd->framesCount); - WRITE_VAR_OFFSET(varWidth, imd->width); - WRITE_VAR_OFFSET(varHeight, imd->height); - } - _vm->_imdPlayer->finishImd(imd); + + _vm->_vidPlayer->writeVideoInfo(_vm->_global->_inter_resStr, varX, varY, + varFrames, varWidth, varHeight); } void Inter_v2::o2_openItk() { @@ -1577,21 +1545,9 @@ void Inter_v2::o2_closeItk() { } void Inter_v2::o2_setImdFrontSurf() { - _vm->_imdPlayer->_frontSurf = 21; - if (_vm->_global->_videoMode == 0x14) { - _vm->_imdPlayer->_frontMem = _vm->_draw->_frontSurface->getVidMem(); - _vm->_draw->blitInvalidated(); - _vm->_imdPlayer->_frontSurf = 20; - } } void Inter_v2::o2_resetImdFrontSurf() { - _vm->_imdPlayer->_frontSurf = 21; - if (_vm->_imdPlayer->_frontMem) { - _vm->_imdPlayer->_frontMem = _vm->_draw->_frontSurface->getVidMem(); - _vm->_draw->forceBlit(); - } else - _vm->_draw->forceBlit(true); } bool Inter_v2::o2_evaluateStore(OpFuncParams ¶ms) { diff --git a/engines/gob/module.mk b/engines/gob/module.mk index 6c9a8d4b3e..7571853f27 100644 --- a/engines/gob/module.mk +++ b/engines/gob/module.mk @@ -18,7 +18,8 @@ MODULE_OBJS := \ goblin_v1.o \ goblin_v2.o \ goblin_v3.o \ - imd.o \ + coktelvideo.o \ + videoplayer.o \ init.o \ init_v1.o \ init_v2.o \ diff --git a/engines/gob/mult_v2.cpp b/engines/gob/mult_v2.cpp index 86a2a260de..cced4aac63 100644 --- a/engines/gob/mult_v2.cpp +++ b/engines/gob/mult_v2.cpp @@ -34,11 +34,11 @@ #include "gob/draw.h" #include "gob/game.h" #include "gob/goblin.h" -#include "gob/imd.h" #include "gob/inter.h" #include "gob/parse.h" #include "gob/scenery.h" #include "gob/video.h" +#include "gob/videoplayer.h" namespace Gob { @@ -1041,7 +1041,7 @@ void Mult_v2::playImd(const char *imdFile, Mult::Mult_ImdKey &key, int16 dir, x = y = -1; if (key.imdFile == -1) { - _vm->_imdPlayer->closeImd(); + _vm->_vidPlayer->closeVideo(); _vm->_game->_preventScroll = false; return; } @@ -1059,23 +1059,24 @@ void Mult_v2::playImd(const char *imdFile, Mult::Mult_ImdKey &key, int16 dir, if ((lastFrame - palFrame) < startFrame) if (!(key.flags & 0x4000)) { _vm->_game->_preventScroll = false; - _vm->_imdPlayer->closeImd(); + _vm->_vidPlayer->closeVideo(); return; } - if (!_vm->_imdPlayer->openImd(imdFile, x, y, 0, flags)) { + if (!_vm->_vidPlayer->openVideo(imdFile, x, y, flags)) { _vm->_game->_preventScroll = false; return; } if (palFrame == -1) palFrame = 0; + if (lastFrame == -1) - lastFrame = _vm->_imdPlayer->_curImd->framesCount - 1; + lastFrame = _vm->_vidPlayer->getFramesCount() - 1; baseFrame = startFrame % (lastFrame - palFrame + 1); - _vm->_imdPlayer->play(baseFrame + palFrame, flags & 0x7F, - palStart, palEnd, palFrame, lastFrame); + _vm->_vidPlayer->play(baseFrame + palFrame, baseFrame + palFrame, 0, + flags & 0x7F, palStart, palEnd, palFrame, lastFrame); } void Mult_v2::advanceObjects(int16 index) { diff --git a/engines/gob/util.cpp b/engines/gob/util.cpp index 1b20ca249e..ec8bb59f06 100644 --- a/engines/gob/util.cpp +++ b/engines/gob/util.cpp @@ -32,7 +32,6 @@ #include "gob/dataio.h" #include "gob/draw.h" #include "gob/game.h" -#include "gob/imd.h" #include "gob/sound.h" #include "gob/video.h" @@ -301,7 +300,6 @@ void Util::setFrameRate(int16 rate) { _vm->_global->_frameWaitTime = 1000 / rate; _vm->_global->_startFrameTime = getTimeKey(); - _vm->_imdPlayer->_frameDelay = 0; } void Util::waitEndFrame() { @@ -312,17 +310,13 @@ void Util::waitEndFrame() { time = getTimeKey() - _vm->_global->_startFrameTime; if ((time > 1000) || (time < 0)) { _vm->_global->_startFrameTime = getTimeKey(); - _vm->_imdPlayer->_frameDelay = 0; return; } - if (_vm->_global->_frameWaitTime - time > 0) { - _vm->_imdPlayer->_frameDelay = 0; - delay(_vm->_global->_frameWaitTime - _vm->_imdPlayer->_frameDelay - time); - } + if ((_vm->_global->_frameWaitTime - time) > 0) + delay(_vm->_global->_frameWaitTime - time); _vm->_global->_startFrameTime = getTimeKey(); - _vm->_imdPlayer->_frameDelay = time - _vm->_global->_frameWaitTime; } void Util::setScrollOffset(int16 x, int16 y) { diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp new file mode 100644 index 0000000000..dfb06e6c2d --- /dev/null +++ b/engines/gob/videoplayer.cpp @@ -0,0 +1,334 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "gob/videoplayer.h" +#include "gob/global.h" +#include "gob/util.h" +#include "gob/dataio.h" +#include "gob/video.h" +#include "gob/draw.h" +#include "gob/game.h" +#include "gob/palanim.h" +#include "gob/inter.h" + +namespace Gob { + +const char *VideoPlayer::_extensions[] = { "IMD", "VMD" }; + +VideoPlayer::VideoPlayer(GobEngine *vm) : _vm(vm) { + _curFile[0] = 0; + _stream = 0; + _video = 0; + _backSurf = false; +} + +VideoPlayer::~VideoPlayer() { + closeVideo(); +} + +bool VideoPlayer::openVideo(const char *video, int16 x, int16 y, int16 flags, Type which) { + char fileName[256]; + + strncpy0(fileName, video, 250); + + char *extStart = strchr(fileName, '.'); + if (extStart) { + // The requested file already has an extension. Verifying. + + int i; + for (i = 0; i < ARRAYSIZE(_extensions); i++) { + if (!scumm_stricmp(extStart + 1, _extensions[i])) { + if ((which != kVideoTypeTry) && (which == ((Type) i))) { + warning("Attempted to open video \"%s\", " + "but requested a different type", fileName); + return false; + } + which = (Type) i; + break; + } + } + if (i >= ARRAYSIZE(_extensions)) + extStart = 0; + + } + + if (!extStart) { + // No or unrecognized extension. Probing. + + int len = strlen(fileName); + + int i; + for (i = 0; i < ARRAYSIZE(_extensions); i++) { + if ((which == kVideoTypeTry) || (which == ((Type) i))) { + int16 handle; + + fileName[len] = '.'; + fileName[len + 1] = 0; + strcat(fileName, _extensions[i]); + + handle = _vm->_dataIO->openData(fileName); + if (handle >= 0) { + _vm->_dataIO->closeData(handle); + which = (Type) i; + break; + } + } + } + if ((i >= ARRAYSIZE(_extensions)) || (which == kVideoTypeTry)) { + fileName[len] = 0; + warning("Couldn't open video \"%s\"", fileName); + return false; + } + + } + + if (scumm_strnicmp(_curFile, fileName, strlen(fileName))) { + closeVideo(); + + int16 handle = _vm->_dataIO->openData(fileName); + + if (handle < 0) { + warning("Couldn't open video \"%s\": No such file", fileName); + return false; + } + + _stream = _vm->_dataIO->openAsStream(handle, true); + + if (which == kVideoTypeIMD) { + _video = new Imd(); + } else if (which == kVideoTypeVMD) { + warning("STUB: VMD"); + closeVideo(); + return false; + } else { + warning("Couldn't open video \"%s\": Invalid video Type", fileName); + closeVideo(); + return false; + } + + if (!_video->load(*_stream)) { + warning("While loading video \"%s\"", fileName); + closeVideo(); + return false; + } + + _video->setXY(x, y); + + if (!(flags & kFlagNoVideo)) { + _backSurf = ((flags & kFlagFrontSurface) == 0); + SurfaceDesc::Ptr surf = _vm->_draw->_spritesArray[_backSurf ? 21 : 20]; + _video->setVideoMemory(surf->getVidMem(), surf->getWidth(), surf->getHeight()); + } else + _video->setVideoMemory(); + + _video->enableSound(*_vm->_mixer); + } + + if (!_video) + return false; + + WRITE_VAR(7, _video->getFramesCount()); + + return true; +} + +void VideoPlayer::play(int16 startFrame, int16 lastFrame, int16 breakKey, + uint16 palCmd, int16 palStart, int16 palEnd, + int16 palFrame, int16 endFrame, bool fade, int16 reverseTo) { + + if (!_video) + return; + + if (startFrame < 0) + startFrame = _video->getCurrentFrame(); + if (lastFrame < 0) + lastFrame = _video->getFramesCount() - 1; + if (palFrame < 0) + palFrame = startFrame; + if (endFrame < 0) + endFrame = lastFrame; + palCmd &= 0x3F; + + if (_video->getCurrentFrame() != startFrame) + _video->seekFrame(startFrame); + + _vm->_draw->_showCursor = 0; + _vm->_util->setFrameRate(12); + + if (fade) + _vm->_palAnim->fade(0, -2, 0); + + while (startFrame <= lastFrame) { + if (doPlay(startFrame, breakKey, palCmd, palStart, palEnd, palFrame, endFrame)) + break; + + if (fade) { + _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); + fade = false; + } + + _video->waitEndFrame(); + startFrame++; + } + + if (reverseTo >= 0) { + int16 toFrame = _video->getFramesCount() - reverseTo; + for (int i = _video->getCurrentFrame(); i >= toFrame; i--) { + _video->seekFrame(i, SEEK_SET, true); + if (doPlay(i, breakKey, 0, 0, 0, 0, 0)) { + _vm->_palAnim->fade(0, -2, 0); + memset((char *) _vm->_draw->_vgaPalette, 0, 768); + } + _video->waitEndFrame(); + } + } +} + +int16 VideoPlayer::getFramesCount() const { + if (!_video) + return 0; + + return _video->getFramesCount(); +} + +int16 VideoPlayer::getCurrentFrame() const { + if (!_video) + return 0; + + return _video->getCurrentFrame(); +} + +bool VideoPlayer::doPlay(int16 frame, int16 breakKey, + uint16 palCmd, int16 palStart, int16 palEnd, + int16 palFrame, int16 endFrame) { + + bool modifiedPal = false; + + if ((frame == palFrame) || ((frame == endFrame) && (palCmd == 8))) { + modifiedPal = true; + _vm->_draw->_applyPal = true; + + if (palCmd >= 4) + copyPalette(palStart, palEnd); + } + + if (modifiedPal && (palCmd == 8) && !_backSurf) + _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); + + + CoktelVideo::State state = _video->nextFrame(); + WRITE_VAR(11, frame); + + + if (modifiedPal && (palCmd == 16)) { + if (_backSurf) + _vm->_draw->forceBlit(); + _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); + _vm->_draw->_noInvalidated = true; + } + + if (state.flags & CoktelVideo::kStatePalette) { + copyPalette(palStart, palEnd); + + if (!_backSurf) + _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); + else + _vm->_draw->_applyPal = true; + } + + if (modifiedPal && (palCmd == 8) && _backSurf) + _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); + + + if (_backSurf) { + _vm->_draw->invalidateRect(state.left, state.top, state.right, state.bottom); + _vm->_draw->blitInvalidated(); + } + _vm->_video->retrace(); + + + if (modifiedPal && ((palCmd == 2) || (palCmd == 4))) + _vm->_palAnim->fade(_vm->_global->_pPaletteDesc, -2, 0); + + + _vm->_util->processInput(); + + if (_vm->_quitRequested) { + _video->disableSound(); + return true; + } + + if (breakKey != 0) { + _vm->_util->getMouseState(&_vm->_global->_inter_mouseX, + &_vm->_global->_inter_mouseY, &_vm->_game->_mouseButtons); + + _vm->_inter->storeKey(_vm->_util->checkKey()); + if (VAR(0) == (unsigned) breakKey) { + _video->disableSound(); + return true; + } + } + + return false; +} + +void VideoPlayer::copyPalette(int16 palStart, int16 palEnd) { + if ((palStart == -1) || (palEnd == -1)) + memcpy((char *) _vm->_global->_pPaletteDesc->vgaPal, + _video->getPalette(), 768); + else + memcpy(((char *) (_vm->_global->_pPaletteDesc->vgaPal)) + + palStart * 3, _video->getPalette() + palStart * 3, + (palEnd - palStart + 1) * 3); +} + +void VideoPlayer::writeVideoInfo(const char *video, int16 varX, int16 varY, + int16 varFrames, int16 varWidth, int16 varHeight) { + + if (openVideo(video)) { + WRITE_VAR_OFFSET(varX, _video->getX()); + WRITE_VAR_OFFSET(varY, _video->getY()); + WRITE_VAR_OFFSET(varFrames, _video->getFramesCount()); + WRITE_VAR_OFFSET(varWidth, _video->getWidth()); + WRITE_VAR_OFFSET(varHeight, _video->getHeight()); + closeVideo(); + } else { + WRITE_VAR_OFFSET(varX, -1); + WRITE_VAR_OFFSET(varY, -1); + WRITE_VAR_OFFSET(varFrames, -1); + WRITE_VAR_OFFSET(varWidth, -1); + WRITE_VAR_OFFSET(varHeight, -1); + } +} + +void VideoPlayer::closeVideo() { + delete _video; + delete _stream; + + _video = 0; + _stream = 0; +} + +} // End of namespace Gob diff --git a/engines/gob/videoplayer.h b/engines/gob/videoplayer.h new file mode 100644 index 0000000000..c4c608dc99 --- /dev/null +++ b/engines/gob/videoplayer.h @@ -0,0 +1,86 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GOB_VIDEOPLAYER_H +#define GOB_VIDEOPLAYER_H + +#include "gob/coktelvideo.h" +#include "gob/dataio.h" + +namespace Gob { + +class GobEngine; + +class VideoPlayer { +public: + enum Flags { + kFlagNone = 0, + kFlagFrontSurface = 0x80, + kFlagNoVideo = 0x100 + }; + + enum Type { + kVideoTypeTry = -1, + kVideoTypeIMD = 0, + kVideoTypeVMD = 1 + }; + + VideoPlayer(GobEngine *vm); + ~VideoPlayer(); + + bool openVideo(const char *video, int16 x = -1, int16 y = -1, + int16 flags = kFlagFrontSurface, Type which = kVideoTypeTry); + + void play(int16 startFrame = -1, int16 lastFrame = -1, int16 breakKey = 27, + uint16 palCmd = 8, int16 palStart = 0, int16 palEnd = 255, + int16 palFrame = -1, int16 endFrame = -1, bool fade = false, + int16 reverseTo = -1); + + int16 getFramesCount() const; + int16 getCurrentFrame() const; + void writeVideoInfo(const char *video, int16 varX, int16 varY, + int16 varFrames, int16 varWidth, int16 varHeight); + + void closeVideo(); + +private: + static const char *_extensions[]; + + GobEngine *_vm; + + char _curFile[256]; + DataStream *_stream; + CoktelVideo *_video; + bool _backSurf; + + void copyPalette(int16 palStart = -1, int16 palEnd = -1); + bool doPlay(int16 frame, int16 breakKey, + uint16 palCmd, int16 palStart, int16 palEnd, + int16 palFrame, int16 endFrame); +}; + +} // End of namespace Gob + +#endif // GOB_VIDEOPLAYER_H -- cgit v1.2.3