Initial commit
This commit is contained in:
354
engines/lab/anim.cpp
Normal file
354
engines/lab/anim.cpp
Normal file
@@ -0,0 +1,354 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is based on Labyrinth of Time code with assistance of
|
||||
*
|
||||
* Copyright (c) 1993 Terra Nova Development
|
||||
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/file.h"
|
||||
|
||||
#include "lab/lab.h"
|
||||
|
||||
#include "lab/anim.h"
|
||||
#include "lab/dispman.h"
|
||||
#include "lab/eventman.h"
|
||||
#include "lab/music.h"
|
||||
#include "lab/utils.h"
|
||||
|
||||
namespace Lab {
|
||||
|
||||
Anim::Anim(LabEngine *vm) : _vm(vm) {
|
||||
_lastBlockHeader = 0;
|
||||
_numChunks = 1;
|
||||
_headerdata._width = 0;
|
||||
_headerdata._height = 0;
|
||||
_headerdata._fps = 0;
|
||||
_headerdata._flags = 0;
|
||||
_delayMicros = 0;
|
||||
_continuous = false;
|
||||
_isPlaying = false;
|
||||
_isAnim = false;
|
||||
_isPal = false;
|
||||
_noPalChange = false;
|
||||
_donePal = false;
|
||||
_frameNum = 0;
|
||||
_playOnce = false;
|
||||
_diffFile = nullptr;
|
||||
_diffFileStart = 0;
|
||||
_size = 0;
|
||||
_scrollScreenBuffer = nullptr;
|
||||
_waitForEffect = false;
|
||||
_stopPlayingEnd = false;
|
||||
_sampleSpeed = 0;
|
||||
_doBlack = false;
|
||||
|
||||
for (int i = 0; i < 3 * 256; i++)
|
||||
_diffPalette[i] = 0;
|
||||
|
||||
_outputBuffer = nullptr; // output to screen
|
||||
}
|
||||
|
||||
Anim::~Anim() {
|
||||
delete[] _vm->_anim->_scrollScreenBuffer;
|
||||
_vm->_anim->_scrollScreenBuffer = nullptr;
|
||||
}
|
||||
|
||||
void Anim::setOutputBuffer(byte *memoryBuffer) {
|
||||
_outputBuffer = memoryBuffer;
|
||||
}
|
||||
|
||||
uint16 Anim::getDIFFHeight() {
|
||||
return _headerdata._height;
|
||||
}
|
||||
|
||||
void Anim::diffNextFrame(bool onlyDiffData) {
|
||||
if (_lastBlockHeader == 65535)
|
||||
// Already done.
|
||||
return;
|
||||
|
||||
bool drawOnScreen = false;
|
||||
byte *startOfBuf = _outputBuffer;
|
||||
int bufPitch = _vm->_graphics->_screenWidth;
|
||||
|
||||
if (!startOfBuf) {
|
||||
startOfBuf = _vm->_graphics->getCurrentDrawingBuffer();
|
||||
drawOnScreen = true;
|
||||
}
|
||||
byte *endOfBuf = startOfBuf + (int)_headerdata._width * _headerdata._height;
|
||||
|
||||
int curBit = 0;
|
||||
|
||||
while (1) {
|
||||
byte *buf = startOfBuf + 0x10000 * curBit;
|
||||
|
||||
if (buf >= endOfBuf) {
|
||||
if (!onlyDiffData) {
|
||||
if (_headerdata._fps) {
|
||||
uint32 targetMillis = _vm->_system->getMillis() + _delayMicros;
|
||||
while (_vm->_system->getMillis() < targetMillis)
|
||||
_vm->_system->delayMillis(10);
|
||||
}
|
||||
|
||||
if (_isPal && !_noPalChange) {
|
||||
_vm->_graphics->setPalette(_diffPalette, 256);
|
||||
_isPal = false;
|
||||
}
|
||||
|
||||
_donePal = true;
|
||||
}
|
||||
|
||||
if (_isPal && !_noPalChange && !onlyDiffData && !_donePal) {
|
||||
_vm->_graphics->setPalette(_diffPalette, 256);
|
||||
_isPal = false;
|
||||
}
|
||||
|
||||
_donePal = false;
|
||||
|
||||
_frameNum++;
|
||||
|
||||
if ((_frameNum == 1) && (_continuous || !_playOnce))
|
||||
_diffFileStart = _diffFile->pos();
|
||||
|
||||
_isAnim = (_frameNum >= 3) && (!_playOnce);
|
||||
|
||||
if (drawOnScreen)
|
||||
_vm->_graphics->screenUpdate();
|
||||
|
||||
// done with the next frame.
|
||||
return;
|
||||
}
|
||||
|
||||
_vm->updateEvents();
|
||||
_lastBlockHeader = _diffFile->readUint32LE();
|
||||
_size = _diffFile->readUint32LE();
|
||||
|
||||
uint32 curPos = 0;
|
||||
|
||||
switch (_lastBlockHeader) {
|
||||
case 8:
|
||||
_diffFile->read(_diffPalette, _size);
|
||||
_isPal = true;
|
||||
break;
|
||||
|
||||
case 10:
|
||||
if (onlyDiffData) {
|
||||
if (curBit > 0)
|
||||
error("diffNextFrame: attempt to read screen to non-zero plane (%d)", curBit);
|
||||
delete[] _scrollScreenBuffer;
|
||||
_scrollScreenBuffer = new byte[_headerdata._width * _headerdata._height];
|
||||
_diffFile->read(_scrollScreenBuffer, _size);
|
||||
} else {
|
||||
_diffFile->read(buf, _size);
|
||||
}
|
||||
curBit++;
|
||||
break;
|
||||
|
||||
case 11:
|
||||
curPos = _diffFile->pos();
|
||||
_diffFile->skip(4);
|
||||
_vm->_utils->runLengthDecode(buf, _diffFile);
|
||||
curBit++;
|
||||
_diffFile->seek(curPos + _size, SEEK_SET);
|
||||
break;
|
||||
|
||||
case 12:
|
||||
curPos = _diffFile->pos();
|
||||
_diffFile->skip(4);
|
||||
_vm->_utils->verticalRunLengthDecode(buf, _diffFile, bufPitch);
|
||||
curBit++;
|
||||
_diffFile->seek(curPos + _size, SEEK_SET);
|
||||
break;
|
||||
|
||||
case 20:
|
||||
curPos = _diffFile->pos();
|
||||
_vm->_utils->unDiff(buf, buf, _diffFile, bufPitch, false);
|
||||
curBit++;
|
||||
_diffFile->seek(curPos + _size, SEEK_SET);
|
||||
break;
|
||||
|
||||
case 21:
|
||||
curPos = _diffFile->pos();
|
||||
_vm->_utils->unDiff(buf, buf, _diffFile, bufPitch, true);
|
||||
curBit++;
|
||||
_diffFile->seek(curPos + _size, SEEK_SET);
|
||||
break;
|
||||
|
||||
case 25:
|
||||
case 26:
|
||||
curBit++;
|
||||
break;
|
||||
|
||||
case 30:
|
||||
case 31:
|
||||
if (_waitForEffect) {
|
||||
while (_vm->_music->isSoundEffectActive()) {
|
||||
_vm->updateEvents();
|
||||
_vm->waitTOF();
|
||||
}
|
||||
|
||||
_waitForEffect = false;
|
||||
}
|
||||
|
||||
_size -= 8;
|
||||
|
||||
_diffFile->skip(4);
|
||||
_sampleSpeed = _diffFile->readUint16LE();
|
||||
_diffFile->skip(2);
|
||||
|
||||
// Sound effects embedded in animations are started here. These are
|
||||
// usually animation-specific, like door opening sounds, and are not looped.
|
||||
// The engine should wait for all such sounds to end.
|
||||
_waitForEffect = true;
|
||||
_vm->_music->playSoundEffect(_sampleSpeed, _size, false, _diffFile);
|
||||
break;
|
||||
|
||||
case 65535:
|
||||
if ((_frameNum == 1) || _playOnce || _stopPlayingEnd) {
|
||||
bool didTOF = false;
|
||||
|
||||
if (_waitForEffect) {
|
||||
while (_vm->_music->isSoundEffectActive()) {
|
||||
_vm->updateEvents();
|
||||
_vm->waitTOF();
|
||||
|
||||
if (drawOnScreen)
|
||||
didTOF = true;
|
||||
}
|
||||
|
||||
_waitForEffect = false;
|
||||
}
|
||||
|
||||
_isPlaying = false;
|
||||
|
||||
if (!didTOF)
|
||||
_vm->_graphics->screenUpdate();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Random frame number so it never gets back to 2
|
||||
_frameNum = 4;
|
||||
_diffFile->seek(_diffFileStart, SEEK_SET);
|
||||
break;
|
||||
|
||||
default:
|
||||
_diffFile->skip(_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Anim::stopDiff() {
|
||||
if (_isPlaying && _isAnim)
|
||||
_vm->_graphics->blackScreen();
|
||||
}
|
||||
|
||||
void Anim::stopDiffEnd() {
|
||||
if (!_isPlaying)
|
||||
return;
|
||||
|
||||
_stopPlayingEnd = true;
|
||||
while (_isPlaying) {
|
||||
_vm->updateEvents();
|
||||
diffNextFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void Anim::readDiff(Common::File *diffFile, bool playOnce, bool onlyDiffData) {
|
||||
_playOnce = playOnce;
|
||||
_delayMicros = 0;
|
||||
_frameNum = 0;
|
||||
_numChunks = 1;
|
||||
_donePal = false;
|
||||
_stopPlayingEnd = false;
|
||||
_isPlaying = true;
|
||||
|
||||
if (_doBlack) {
|
||||
_doBlack = false;
|
||||
_vm->_graphics->blackScreen();
|
||||
}
|
||||
|
||||
_diffFile = diffFile;
|
||||
|
||||
_continuous = false;
|
||||
|
||||
if (!_diffFile)
|
||||
return;
|
||||
|
||||
uint32 magicBytes = _diffFile->readUint32LE();
|
||||
if (magicBytes != 1219009121) {
|
||||
_isPlaying = false;
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 signature3 = _diffFile->readUint32LE();
|
||||
_size = _diffFile->readUint32LE();
|
||||
|
||||
if (signature3 != 0)
|
||||
return;
|
||||
|
||||
// sizeof(headerdata) != 18, but the padding might be at the end
|
||||
// 2 bytes, version, unused.
|
||||
_diffFile->skip(2);
|
||||
_headerdata._width = _diffFile->readUint16LE();
|
||||
_headerdata._height = _diffFile->readUint16LE();
|
||||
// 1 byte, depth, unused
|
||||
_diffFile->skip(1);
|
||||
_headerdata._fps = _diffFile->readByte();
|
||||
|
||||
// HACK: The original game defines a 1 second delay when changing screens, which is
|
||||
// very annoying. We first removed the delay, but it looked wrong when changing screens
|
||||
// as it was possible to see that something was displayed, without being able to tell
|
||||
// what it was. A shorter delay (150ms) makes it acceptable during gameplay and
|
||||
// readable. The big question is: do we need that message?
|
||||
_vm->_system->delayMillis(150);
|
||||
|
||||
if (_headerdata._fps == 1)
|
||||
_headerdata._fps = 0;
|
||||
|
||||
// 4 + 2 bytes, buffer size and machine, unused
|
||||
_diffFile->skip(6);
|
||||
_headerdata._flags = _diffFile->readUint32LE();
|
||||
|
||||
_diffFile->skip(_size - 18);
|
||||
|
||||
_continuous = CONTINUOUS & _headerdata._flags;
|
||||
_vm->_utils->setBytesPerRow(_headerdata._width);
|
||||
|
||||
delete[] _scrollScreenBuffer;
|
||||
_scrollScreenBuffer = nullptr;
|
||||
|
||||
if (_headerdata._fps)
|
||||
_delayMicros = 1000 / _headerdata._fps;
|
||||
|
||||
_lastBlockHeader = signature3;
|
||||
if (_playOnce) {
|
||||
while (_lastBlockHeader != 65535)
|
||||
diffNextFrame(onlyDiffData);
|
||||
} else
|
||||
diffNextFrame(onlyDiffData);
|
||||
}
|
||||
|
||||
} // End of namespace Lab
|
||||
Reference in New Issue
Block a user