scummvm/engines/toltecs/movie.cpp
Tarek Soliman a4798602d7 JANITORIAL: Fix missing whitespace in pointer cast
find -name '*.h' -or -name '*.cpp' | xargs sed -r -i 's@\(([A-Za-z0-9]+)\*\)@(\1 *)@g'

This seems to have caught some params as well which is not undesirable IMO.
It also caught some strings containing this which is undesirable so I
excluded them manually. (engines/sci/engine/kernel_tables.h)
2012-02-15 10:07:10 -06:00

290 lines
7.7 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.
*
*
*/
#include "audio/mixer.h"
#include "audio/decoders/raw.h"
#include "toltecs/toltecs.h"
#include "toltecs/movie.h"
#include "toltecs/palette.h"
#include "toltecs/resource.h"
#include "toltecs/screen.h"
#include "toltecs/script.h"
namespace Toltecs {
enum ChunkTypes {
kChunkFirstImage = 0,
kChunkSubsequentImages = 1,
kChunkPalette = 2,
kChunkUnused = 3,
kChunkAudio = 4,
kChunkShowSubtitle = 5,
kChunkShakeScreen = 6,
kChunkSetupSubtitles = 7,
kChunkStopSubtitles = 8
};
MoviePlayer::MoviePlayer(ToltecsEngine *vm) : _vm(vm) {
}
MoviePlayer::~MoviePlayer() {
}
void MoviePlayer::playMovie(uint resIndex) {
const uint32 subtitleSlot = kMaxScriptSlots - 1;
int16 savedSceneWidth = _vm->_sceneWidth;
int16 savedSceneHeight = _vm->_sceneHeight;
int16 savedCameraHeight = _vm->_cameraHeight;
int16 savedCameraX = _vm->_cameraX;
int16 savedCameraY = _vm->_cameraY;
int16 savedGuiHeight = _vm->_guiHeight;
byte moviePalette[768];
_vm->_isSaveAllowed = false;
memset(moviePalette, 0, sizeof(moviePalette));
_vm->_screen->finishTalkTextItems();
_vm->_screen->clearSprites();
_vm->_arc->openResource(resIndex);
_frameCount = _vm->_arc->readUint32LE();
_chunkCount = _vm->_arc->readUint32LE();
// TODO: Figure out rest of the header
_vm->_arc->readUint32LE();
_vm->_arc->readUint32LE();
_framesPerSoundChunk = _vm->_arc->readUint32LE();
_vm->_arc->readUint32LE();
_vm->_sceneWidth = 640;
_vm->_sceneHeight = 400;
_vm->_cameraHeight = 400;
_vm->_cameraX = 0;
_vm->_cameraY = 0;
_vm->_guiHeight = 0;
_audioStream = Audio::makeQueuingAudioStream(22050, false);
_vm->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_audioStreamHandle, _audioStream);
_soundChunkFramesLeft = 0;
_lastPrefetchOfs = 0;
fetchAudioChunks();
uint32 lastTime = _vm->_mixer->getSoundElapsedTime(_audioStreamHandle);
while (_chunkCount--) {
byte chunkType = _vm->_arc->readByte();
uint32 chunkSize = _vm->_arc->readUint32LE();
byte *chunkBuffer = NULL;
uint32 movieOffset;
debug(0, "chunkType = %d; chunkSize = %d", chunkType, chunkSize);
// Skip audio chunks - we've already queued them in
// fetchAudioChunks() above
if (chunkType == kChunkAudio) {
_vm->_arc->skip(chunkSize);
} else {
chunkBuffer = new byte[chunkSize];
_vm->_arc->read(chunkBuffer, chunkSize);
}
movieOffset = _vm->_arc->pos();
switch (chunkType) {
case kChunkFirstImage:
case kChunkSubsequentImages:
unpackRle(chunkBuffer, _vm->_screen->_backScreen);
// TODO: Rework this
_vm->_screen->updateShakeScreen();
_vm->_screen->_fullRefresh = true;
_vm->updateInput();
_vm->drawScreen();
_soundChunkFramesLeft--;
if (_soundChunkFramesLeft <= _framesPerSoundChunk) {
fetchAudioChunks();
}
while (_vm->_mixer->getSoundElapsedTime(_audioStreamHandle) < lastTime + 111) {
g_system->delayMillis(10);
}
lastTime = _vm->_mixer->getSoundElapsedTime(_audioStreamHandle);
break;
case kChunkPalette:
unpackPalette(chunkBuffer, moviePalette, 256, 3);
_vm->_palette->setFullPalette(moviePalette);
break;
case kChunkUnused:
error("Chunk considered to be unused has been encountered");
case kChunkAudio:
// Already processed
break;
case kChunkShowSubtitle:
// TODO: Check if the text is a subtitle (last character == 0xFE).
// If so, don't show it if text display is disabled.
memcpy(_vm->_script->getSlotData(subtitleSlot), chunkBuffer, chunkSize);
_vm->_screen->updateTalkText(subtitleSlot, 0);
break;
case kChunkShakeScreen: // start/stop shakescreen effect
if (chunkBuffer[0] == 0xFF)
_vm->_screen->stopShakeScreen();
else
_vm->_screen->startShakeScreen(chunkBuffer[0]);
break;
case kChunkSetupSubtitles: // setup subtitle parameters
_vm->_screen->_talkTextY = READ_LE_UINT16(chunkBuffer + 0);
_vm->_screen->_talkTextX = READ_LE_UINT16(chunkBuffer + 2);
_vm->_screen->_talkTextFontColor = ((chunkBuffer[4] << 4) & 0xF0) | ((chunkBuffer[4] >> 4) & 0x0F);
debug(0, "_talkTextX = %d; _talkTextY = %d; _talkTextFontColor = %d",
_vm->_screen->_talkTextX, _vm->_screen->_talkTextY, _vm->_screen->_talkTextFontColor);
break;
case kChunkStopSubtitles:
_vm->_script->getSlotData(subtitleSlot)[0] = 0xFF;
_vm->_screen->finishTalkTextItems();
break;
default:
error("MoviePlayer::playMovie(%04X) Unknown chunk type %d at %08X", resIndex, chunkType, _vm->_arc->pos() - 5 - chunkSize);
}
delete[] chunkBuffer;
_vm->_arc->seek(movieOffset, SEEK_SET);
if (!handleInput())
break;
}
_audioStream->finish();
_vm->_mixer->stopHandle(_audioStreamHandle);
_vm->_arc->closeResource();
debug(0, "playMovie() done");
_vm->_sceneWidth = savedSceneWidth;
_vm->_sceneHeight = savedSceneHeight;
_vm->_cameraHeight = savedCameraHeight;
_vm->_cameraX = savedCameraX;
_vm->_cameraY = savedCameraY;
_vm->_guiHeight = savedGuiHeight;
_vm->_isSaveAllowed = true;
}
void MoviePlayer::fetchAudioChunks() {
uint32 startOfs = _vm->_arc->pos();
uint32 chunkCount = _chunkCount;
uint prefetchChunkCount = 0;
if (_lastPrefetchOfs != 0)
_vm->_arc->seek(_lastPrefetchOfs, SEEK_SET);
while (chunkCount-- && prefetchChunkCount < _framesPerSoundChunk / 2) {
byte chunkType = _vm->_arc->readByte();
uint32 chunkSize = _vm->_arc->readUint32LE();
if (chunkType == 4) {
byte *chunkBuffer = (byte *)malloc(chunkSize);
_vm->_arc->read(chunkBuffer, chunkSize);
_audioStream->queueBuffer(chunkBuffer, chunkSize, DisposeAfterUse::YES, Audio::FLAG_UNSIGNED);
chunkBuffer = NULL;
prefetchChunkCount++;
_soundChunkFramesLeft += _framesPerSoundChunk;
} else {
_vm->_arc->seek(chunkSize, SEEK_CUR);
}
}
_lastPrefetchOfs = _vm->_arc->pos();
_vm->_arc->seek(startOfs, SEEK_SET);
}
void MoviePlayer::unpackPalette(byte *source, byte *dest, int elemCount, int elemSize) {
int ofs = 0, size = elemCount * elemSize;
while (ofs < size) {
byte len;
len = *source++;
if (len == 0) {
len = *source++;
} else {
byte value = *source++;
memset(dest, value, len);
}
ofs += len;
dest += len;
}
}
void MoviePlayer::unpackRle(byte *source, byte *dest) {
int size = 256000;
while (size > 0) {
byte a = *source++;
byte b = *source++;
if (a == 0) {
dest += b;
size -= b;
} else {
memset(dest, b, a);
dest += a;
size -= a;
}
}
}
bool MoviePlayer::handleInput() {
Common::Event event;
Common::EventManager *eventMan = g_system->getEventManager();
while (eventMan->pollEvent(event)) {
switch (event.type) {
case Common::EVENT_KEYDOWN:
if (event.kbd.keycode == Common::KEYCODE_ESCAPE)
return false;
break;
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_RBUTTONDOWN:
return false;
case Common::EVENT_QUIT:
_vm->quitGame();
return false;
default:
break;
}
}
return !_vm->shouldQuit();
}
} // End of namespace Toltecs