mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-01 06:58:34 +00:00
218e132e37
svn-id: r27024
1250 lines
31 KiB
C++
1250 lines
31 KiB
C++
/* 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
|