diff options
Diffstat (limited to 'engines/toon')
33 files changed, 627 insertions, 415 deletions
diff --git a/engines/toon/anim.cpp b/engines/toon/anim.cpp index 2e63d89f37..856acbd986 100644 --- a/engines/toon/anim.cpp +++ b/engines/toon/anim.cpp @@ -23,6 +23,9 @@ * */ +#include "common/debug.h" +#include "common/rect.h" + #include "toon/anim.h" #include "toon/toon.h" #include "toon/tools.h" @@ -99,7 +102,7 @@ bool Animation::loadAnimation(Common::String file) { _frames[e]._data = new uint8[decompressedSize]; if (compressedSize < decompressedSize) { decompressLZSS(imageData, _frames[e]._data, decompressedSize); - } else { + } else { memcpy(_frames[e]._data, imageData, compressedSize); } } @@ -151,6 +154,8 @@ void Animation::drawFrame(Graphics::Surface &surface, int32 frame, int32 xx, int int32 offsX = 0; int32 offsY = 0; + _vm->addDirtyRect(xx + _x1 + _frames[frame]._x1, yy + _y1 + _frames[frame]._y1, xx + rectX + _x1 + _frames[frame]._x1 , yy + rectY + _y1 + _frames[frame]._y1); + if (xx + _x1 + _frames[frame]._x1 < 0) { offsX = -(xx + _x1 + _frames[frame]._x1); } @@ -212,14 +217,14 @@ void Animation::drawFrameWithMaskAndScale(Graphics::Surface &surface, int32 fram int32 finalWidth = rectX * scale / 1024; int32 finalHeight = rectY * scale / 1024; - // compute final x1,y1,x2,y2 + // compute final x1, y1, x2, y2 int32 xx1 = xx + _x1 + _frames[frame]._x1 * scale / 1024; int32 yy1 = yy + _y1 + _frames[frame]._y1 * scale / 1024; int32 xx2 = xx1 + finalWidth; int32 yy2 = yy1 + finalHeight; int32 w = _frames[frame]._x2 - _frames[frame]._x1; -// Strangerke - Commented (not used) -// int32 h = _frames[frame]._y2 - _frames[frame]._y1; + + _vm->addDirtyRect(xx1, yy1, xx2, yy2); int32 destPitch = surface.pitch; int32 destPitchMask = mask->getWidth(); @@ -442,7 +447,6 @@ AnimationInstance::AnimationInstance(ToonEngine *vm, AnimationInstanceType type) _layerZ = 0; } - void AnimationInstance::render() { debugC(5, kDebugAnim, "render()"); if (_visible && _animation) { @@ -574,7 +578,7 @@ void AnimationInstance::getRect(int32 *x1, int32 *y1, int32 *x2, int32 *y2) cons int32 finalWidth = rectX * _scale / 1024; int32 finalHeight = rectY * _scale / 1024; - // compute final x1,y1,x2,y2 + // compute final x1, y1, x2, y2 *x1 = _x + _animation->_x1 + _animation->_frames[_currentFrame]._x1 * _scale / 1024; *y1 = _y + _animation->_y1 + _animation->_frames[_currentFrame]._y1 * _scale / 1024; *x2 = *x1 + finalWidth; @@ -604,7 +608,7 @@ void AnimationInstance::setZ(int32 z, bool relative) { void AnimationInstance::setLayerZ(int32 z) { _layerZ = z; - if (_vm->getAnimationManager()->hasInstance(this)) + if (_vm->getAnimationManager()->hasInstance(this)) _vm->getAnimationManager()->updateInstance(this); } @@ -665,8 +669,6 @@ void AnimationInstance::load(Common::ReadStream *stream) { _useMask = stream->readSint32LE(); } - - void AnimationInstance::setLooping(bool enable) { debugC(6, kDebugAnim, "setLooping(%d)", (enable) ? 1 : 0); _looping = enable; @@ -682,7 +684,7 @@ AnimationManager::AnimationManager(ToonEngine *vm) : _vm(vm) { bool AnimationManager::hasInstance(AnimationInstance* instance) { for (uint32 i = 0; i < _instances.size(); i++) { - if(_instances[i] == instance) + if(_instances[i] == instance) return true; } return false; @@ -698,12 +700,12 @@ void AnimationManager::addInstance(AnimationInstance *instance) { // if the instance already exists, we skip the add for (uint32 i = 0; i < _instances.size(); i++) { - if(_instances[i] == instance) + if(_instances[i] == instance) return; } - + int found = -1; - + // here we now do an ordered insert (closer to the original game) for (uint32 i = 0; i < _instances.size(); i++) { if (_instances[i]->getLayerZ() >= instance->getLayerZ()) { @@ -717,7 +719,6 @@ void AnimationManager::addInstance(AnimationInstance *instance) { } else { _instances.insert_at(found, instance); } - } void AnimationManager::removeInstance(AnimationInstance *instance) { diff --git a/engines/toon/anim.h b/engines/toon/anim.h index d7f64ab687..dfb6842b0e 100644 --- a/engines/toon/anim.h +++ b/engines/toon/anim.h @@ -161,7 +161,7 @@ public: AnimationInstance *createNewInstance(AnimationInstanceType type); void addInstance(AnimationInstance *instance); void removeInstance(AnimationInstance *instance); - void updateInstance(AnimationInstance* instance); + void updateInstance(AnimationInstance* instance); void removeAllInstances(AnimationInstanceType type); void render(); void update(int32 timeIncrement); diff --git a/engines/toon/audio.cpp b/engines/toon/audio.cpp index e5e5b85832..026450d3c9 100644 --- a/engines/toon/audio.cpp +++ b/engines/toon/audio.cpp @@ -23,32 +23,20 @@ * */ +#include "common/debug.h" + #include "toon/audio.h" #include "common/memstream.h" #include "common/substream.h" +#include "audio/decoders/adpcm_intern.h" namespace Toon { -static int ADPCM_index[8] = { - -1, -1, -1, -1, 2 , 4 , 6 , 8 -}; -static int ADPCM_table[89] = { - 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, - 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, - 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, - 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, - 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, - 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, - 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, - 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, - 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 -}; - AudioManager::AudioManager(ToonEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) { for (int32 i = 0; i < 16; i++) _channels[i] = NULL; - for (int32 i = 0; i < 4; i++) + for (int32 i = 0; i < 4; i++) _audioPacks[i] = NULL; for (int32 i = 0; i < 4; i++) { @@ -63,6 +51,8 @@ AudioManager::AudioManager(ToonEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixe _voiceMuted = false; _musicMuted = false; _sfxMuted = false; + + _currentMusicChannel = 0; } AudioManager::~AudioManager(void) { @@ -113,24 +103,23 @@ void AudioManager::playMusic(Common::String dir, Common::String music) { return; // see what channel to take - if (_channels[0] && _channels[0]->isPlaying() && _channels[1] && _channels[1]->isPlaying()) { - // take the one that is fading - if (_channels[0]->isFading()) { - _channels[0]->stop(false); - _channels[1]->stop(true); - _currentMusicChannel = 0; - } else { - _channels[1]->stop(false); - _channels[0]->stop(true); - _currentMusicChannel = 1; + // if the current channel didn't really start. reuse this one + if (_channels[_currentMusicChannel] && _channels[_currentMusicChannel]->isPlaying()) { + if (_channels[_currentMusicChannel]->getPlayedSampleCount() < 500) { + _channels[_currentMusicChannel]->stop(false); + _currentMusicChannel = 1 - _currentMusicChannel; + } + else + { + _channels[_currentMusicChannel]->stop(true); } - } else if (_channels[0] && _channels[0]->isPlaying()) { - _channels[0]->stop(true); - _currentMusicChannel = 1; - } else { - if (_channels[1] && _channels[1]->isPlaying()) - _channels[1]->stop(true); - _currentMusicChannel = 0; + } + // go to the next channel + _currentMusicChannel = 1 - _currentMusicChannel; + + // if it's already playing.. stop it quickly (no fade) + if (_channels[_currentMusicChannel] && _channels[_currentMusicChannel]->isPlaying()) { + _channels[_currentMusicChannel]->stop(false); } // no need to delete instance here it will automatically deleted by the mixer is done with it @@ -208,7 +197,6 @@ void AudioManager::stopCurrentVoice() { _channels[2]->stop(false); } - void AudioManager::closeAudioPack(int32 id) { delete _audioPacks[id]; _audioPacks[id] = NULL; @@ -261,6 +249,7 @@ AudioStreamInstance::AudioStreamInstance(AudioManager *man, Audio::Mixer *mixer, _looping = looping; _musicAttenuation = 1000; _deleteFileStream = deleteFileStreamAtEnd; + _playedSamples = 0; // preload one packet if (_totalSize > 0) { @@ -286,7 +275,7 @@ AudioStreamInstance::~AudioStreamInstance() { int AudioStreamInstance::readBuffer(int16 *buffer, const int numSamples) { debugC(5, kDebugAudio, "readBuffer(buffer, %d)", numSamples); - if(_stopped) + if(_stopped) return 0; handleFade(numSamples); @@ -309,6 +298,8 @@ int AudioStreamInstance::readBuffer(int16 *buffer, const int numSamples) { _bufferOffset += leftSamples; } + _playedSamples += numSamples; + return numSamples; } @@ -369,7 +360,7 @@ void AudioStreamInstance::decodeADPCM(uint8 *comp, int16 *dest, int32 packetSize int32 v31 = v30 & 0x8; int32 v32 = v30 & 0x7; - int32 v33 = ADPCM_table[v19]; + int32 v33 = Audio::Ima_ADPCMStream::_imaTable[v19]; int32 v34 = v33 >> 3; if (v32 & 4) v34 += v33; @@ -380,12 +371,8 @@ void AudioStreamInstance::decodeADPCM(uint8 *comp, int16 *dest, int32 packetSize if (v32 & 1) v34 += v33 >> 2; - v19 += ADPCM_index[v32]; - if (v19 < 0) - v19 = 0; - - if (v19 > 88) - v19 = 88; + v19 += Audio::ADPCMStream::_stepAdjustTable[v32]; + v19 = CLIP<int32>(v19, 0, ARRAYSIZE(Audio::Ima_ADPCMStream::_imaTable) - 1); if (v31) v18 -= v34; @@ -423,7 +410,7 @@ void AudioStreamInstance::handleFade(int32 numSamples) { debugC(5, kDebugAudio, "handleFade(%d)", numSamples); // Fading enabled only for music - if (_soundType != Audio::Mixer::kMusicSoundType) + if (_soundType != Audio::Mixer::kMusicSoundType) return; int32 finalVolume = _volume; @@ -457,7 +444,7 @@ void AudioStreamInstance::handleFade(int32 numSamples) { _musicAttenuation = 250; } else { _musicAttenuation += numSamples >> 5; - if (_musicAttenuation > 1000) + if (_musicAttenuation > 1000) _musicAttenuation = 1000; } @@ -468,9 +455,11 @@ void AudioStreamInstance::stop(bool fade /*= false*/) { debugC(1, kDebugAudio, "stop(%d)", (fade) ? 1 : 0); if (fade) { - _fadingIn = false; - _fadingOut = true; - _fadeTime = 0; + if (!_fadingOut) { + _fadingIn = false; + _fadingOut = true; + _fadeTime = 0; + } } else { stopNow(); } @@ -551,7 +540,7 @@ void AudioManager::startAmbientSFX(int32 id, int32 delay, int32 mode, int32 volu } } - if (found < 0) + if (found < 0) return; _ambientSFXs[found]._lastTimer = _vm->getOldMilli() - 1; @@ -610,13 +599,14 @@ void AudioManager::killAllAmbientSFX() void AudioManager::updateAmbientSFX() { - if (_vm->getMoviePlayer()->isPlaying()) return; + if (_vm->getMoviePlayer()->isPlaying()) + return; for (int32 i = 0; i < 4; i++) { AudioAmbientSFX* ambient = &_ambientSFXs[i]; if (ambient->_enabled && (ambient->_channel < 0 || !(_channels[ambient->_channel] && _channels[ambient->_channel]->isPlaying()))) { if(ambient->_mode == 1) { - if (_vm->randRange(0, 32767) < ambient->_delay) { + if (_vm->randRange(0, 32767) < ambient->_delay) { ambient->_channel = playSFX(ambient->_id, ambient->_volume, false); } } else { @@ -629,6 +619,5 @@ void AudioManager::updateAmbientSFX() } } - } // End of namespace Toon diff --git a/engines/toon/audio.h b/engines/toon/audio.h index 7c1eedfee9..5feae9c5a1 100644 --- a/engines/toon/audio.h +++ b/engines/toon/audio.h @@ -52,6 +52,10 @@ public: return _fadingIn || _fadingOut; } + int32 getPlayedSampleCount() { + return _playedSamples; + } + void setVolume(int32 volume); protected: int readBuffer(int16 *buffer, const int numSamples); @@ -93,6 +97,7 @@ protected: int32 _volume; int32 _musicAttenuation; bool _deleteFileStream; + int32 _playedSamples; }; class AudioStreamPackage { @@ -133,14 +138,14 @@ public: void playVoice(int32 id, bool genericVoice); int32 playSFX(int32 id, int volume, bool genericSFX); void stopCurrentVoice(); - void stopAllSfxs(); + void stopAllSfxs(); void setMusicVolume(int32 volume); void stopMusic(); void muteVoice(bool mute); void muteMusic(bool mute); void muteSfx(bool mute); bool isVoiceMuted() { return _voiceMuted; } - bool isMusicMuted() { return _musicMuted; } + bool isMusicMuted() { return _musicMuted; } bool isSfxMuted() { return _sfxMuted; } void startAmbientSFX(int32 id, int32 delay, int32 mode, int32 volume); diff --git a/engines/toon/character.cpp b/engines/toon/character.cpp index f1f246e549..29a61ffd78 100644 --- a/engines/toon/character.cpp +++ b/engines/toon/character.cpp @@ -23,6 +23,9 @@ * */ +#include "common/debug.h" +#include "common/system.h" + #include "toon/character.h" #include "toon/drew.h" #include "toon/flux.h" @@ -64,6 +67,7 @@ Character::Character(ToonEngine *vm) : _vm(vm) { _lastWalkTime = 0; _numPixelToWalk = 0; _nextIdleTime = _vm->getSystem()->getMillis() + (_vm->randRange(0, 600) + 300) * _vm->getTickLength(); + _lineToSayId = 0; } Character::~Character(void) { @@ -104,7 +108,7 @@ void Character::setFacing(int32 facing) { _lastWalkTime = _vm->getSystem()->getMillis(); if ((_facing - facing + 8) % 8 > (facing - _facing + 8) % 8) dir = 1; - else + else dir = -1; while (_facing != facing) { @@ -125,14 +129,13 @@ void Character::setFacing(int32 facing) { if (_currentPathNode == 0) playStandingAnim(); else - playWalkAnim(0,0); + playWalkAnim(0, 0); _vm->doFrame(); }; _flags &= ~2; } - _facing = facing; } @@ -140,7 +143,7 @@ void Character::forcePosition(int32 x, int32 y) { debugC(5, kDebugCharacter, "forcePosition(%d, %d)", x, y); - setPosition(x,y); + setPosition(x, y); _finalX = x; _finalY = y; } @@ -166,8 +169,9 @@ bool Character::walkTo(int32 newPosX, int32 newPosY) { _vm->getPathFinding()->resetBlockingRects(); - if (_id == 1) { - int32 sizeX = MAX<int32>(5, 40 * _vm->getDrew()->getScale() / 1024); + // don't allow flux to go at the same position as drew + if (_id == 1 ) { + int32 sizeX = MAX<int32>(5, 30 * _vm->getDrew()->getScale() / 1024); int32 sizeY = MAX<int32>(2, 20 * _vm->getDrew()->getScale() / 1024); _vm->getPathFinding()->addBlockingEllipse(_vm->getDrew()->getFinalX(), _vm->getDrew()->getFinalY(), sizeX, sizeY); } @@ -176,7 +180,6 @@ bool Character::walkTo(int32 newPosX, int32 newPosY) { if (_x == _finalX && _y == _finalY) return true; - if (_vm->getPathFinding()->findPath(_x, _y, _finalX, _finalY)) { int32 localFinalX = _finalX; @@ -191,7 +194,7 @@ bool Character::walkTo(int32 newPosX, int32 newPosY) { _currentPathNodeCount = _vm->getPathFinding()->getPathNodeCount(); _currentPathNode = 0; stopSpecialAnim(); - + _lastWalkTime = _vm->getSystem()->getMillis(); _numPixelToWalk = 0; @@ -327,11 +330,6 @@ void Character::updateTimers(int32 relativeAdd) { void Character::stopSpecialAnim() { debugC(4, kDebugCharacter, "stopSpecialAnim()"); -// Strangerke - Commented (not used) -#if 0 - if (_animSpecialId != _animSpecialDefaultId) - delete anim; -#endif if (_animScriptId != -1) _vm->getSceneAnimationScript(_animScriptId)->_frozenForConversation = false; @@ -388,7 +386,6 @@ void Character::update(int32 timeIncrement) { if ((_flags & 4) == 0) return; - if (_animScriptId != -1) { _animationInstance = _vm->getSceneAnimation(this->) #endif @@ -423,19 +420,9 @@ void Character::update(int32 timeIncrement) { return; } -// Strangerke - Commented (not used) -#if 0 - if (_animFlags & 8) { - if (anim->_flags7 == 0xff && anim->_flags9 == 0xff) { - // start voice - } - } -#endif - if (_animScriptId != -1) _vm->getSceneAnimationScript(_animScriptId)->_frozenForConversation = true; - - + // TODO setup backup // _animFlags |= 0x10; @@ -494,17 +481,6 @@ void Character::update(int32 timeIncrement) { } } else { nextFrame = currentFrame + 1; -// Strangerke - Commented (not used) -#if 0 - if (!_vm->getAudioManager()->voiceStillPlaying()) { - if (_animFlags & 8) { - if ((anim->_flags9 == 0xff && nextFrame == anim->_flags6) || - (anim->_flags9 != 0xff && nextFrame >= anim->_flags9)) { - // start really talking - } - } - } -#endif if (nextFrame == anim->_flags7 + 1 && (_animFlags & 0x40) == 0) { if (anim->_flags8 != 1 && (_vm->randRange(0, 1) || anim->_flags8 == 2)) { _animFlags |= 0x20; @@ -525,7 +501,6 @@ void Character::update(int32 timeIncrement) { //label78 - #if 0 if (_id == 0) debug(" drew animation name %s / flag %d / frame %d", _specialAnim->_name, _animFlags, nextFrame); @@ -611,7 +586,6 @@ int32 Character::getScale() { } void Character::playWalkAnim(int32 startFrame, int32 endFrame) { - } void Character::setId(int32 id) { @@ -677,7 +651,6 @@ int32 Character::getAnimScript() { } void Character::playTalkAnim() { - } void Character::stopWalk() { @@ -1046,7 +1019,6 @@ void Character::playAnim(int32 animId, int32 unused, int32 flags) { *strchr(animName, '?') = '0' + facing; strcat(animName, ".CAF"); - if (_animScriptId != -1 && (flags & 8) == 0) _vm->getSceneAnimationScript(_animScriptId)->_frozenForConversation = true; @@ -1068,11 +1040,9 @@ void Character::playAnim(int32 animId, int32 unused, int32 flags) { } } - if (_sceneAnimationId > -1) setAnimationInstance(_vm->getSceneAnimation(_sceneAnimationId)->_animInstance); - _animFlags |= flags; delete _specialAnim; diff --git a/engines/toon/character.h b/engines/toon/character.h index d4079d82ef..e870d81813 100644 --- a/engines/toon/character.h +++ b/engines/toon/character.h @@ -49,7 +49,6 @@ struct SpecialCharacterAnimation { byte _flags9; // 25 }; - class Character { public: Character(ToonEngine *vm); @@ -106,7 +105,6 @@ public: int32 getFacingFromDirection(int32 dx, int32 dy); static const SpecialCharacterAnimation *getSpecialAnimation(int32 characterId, int32 animationId); - protected: ToonEngine *_vm; diff --git a/engines/toon/conversation.cpp b/engines/toon/conversation.cpp index 4678ccc1c8..fc846288ef 100644 --- a/engines/toon/conversation.cpp +++ b/engines/toon/conversation.cpp @@ -45,5 +45,4 @@ void Conversation::load(Common::ReadStream *stream, int16 *conversationDataBase) } } - } diff --git a/engines/toon/conversation.h b/engines/toon/conversation.h index 784c681055..0380210e02 100644 --- a/engines/toon/conversation.h +++ b/engines/toon/conversation.h @@ -33,10 +33,10 @@ namespace Toon { class Conversation { public: - int32 _enable; // 00 + int32 _enable; // 00 struct ConvState { - int32 _data2; // 04 + int32 _data2; // 04 int16 _data3; // 08 void *_data4; // 10 } state[10]; diff --git a/engines/toon/detection.cpp b/engines/toon/detection.cpp index f8c4c08ce6..ef023564bc 100644 --- a/engines/toon/detection.cpp +++ b/engines/toon/detection.cpp @@ -91,6 +91,15 @@ static const ADGameDescription gameDescriptions[] = { }, Common::DE_DEU, Common::kPlatformPC, ADGF_DEMO, GUIO_NONE }, + { + "toon", "", + { + {"local.pak", 0, "8ef3368078b9ea70b305c04db826feea", 2680573}, + {"generic.svl", 0, "5c42724bb93b360dca7044d6b7ef26e5", 7739319}, + AD_LISTEND + }, + Common::EN_ANY, Common::kPlatformPC, ADGF_DEMO, GUIO_NONE + }, AD_TABLE_END_MARKER }; diff --git a/engines/toon/drew.cpp b/engines/toon/drew.cpp index eefb4b8efa..77333c4a9f 100644 --- a/engines/toon/drew.cpp +++ b/engines/toon/drew.cpp @@ -23,6 +23,8 @@ * */ +#include "common/debug.h" + #include "toon/drew.h" namespace Toon { @@ -111,11 +113,10 @@ void CharacterDrew::update(int32 timeIncrement) { _scale = _currentScale; } else if (_currentScale < _scale) { _scale -= timeIncrement * 2; - if (_scale < _currentScale) + if (_scale < _currentScale) _scale = _currentScale; } setPosition(_x, _y); - } int32 CharacterDrew::getRandomIdleAnim() { diff --git a/engines/toon/drew.h b/engines/toon/drew.h index d8091f2225..f248e4aa51 100644 --- a/engines/toon/drew.h +++ b/engines/toon/drew.h @@ -28,7 +28,6 @@ #include "toon/character.h" - namespace Toon { class ToonEngine; @@ -46,7 +45,6 @@ public: int32 getRandomIdleAnim(); protected: int32 _currentScale; - }; } // End of namespace Toon diff --git a/engines/toon/flux.cpp b/engines/toon/flux.cpp index 2b5551732b..833fdbf5ce 100644 --- a/engines/toon/flux.cpp +++ b/engines/toon/flux.cpp @@ -23,6 +23,8 @@ * */ +#include "common/debug.h" + #include "toon/flux.h" namespace Toon { @@ -96,7 +98,7 @@ int32 CharacterFlux::fixFacingForAnimation(int32 originalFacing, int32 animation if (!facingMask) break; } - + return finalFacing; } diff --git a/engines/toon/flux.h b/engines/toon/flux.h index a90853cb02..136dedd415 100644 --- a/engines/toon/flux.h +++ b/engines/toon/flux.h @@ -26,7 +26,6 @@ #ifndef TOON_FLUX_H #define TOON_FLUX_H - #include "toon/character.h" class ToonEngine; diff --git a/engines/toon/font.cpp b/engines/toon/font.cpp index 8455ca7b61..9367d79036 100644 --- a/engines/toon/font.cpp +++ b/engines/toon/font.cpp @@ -23,6 +23,8 @@ * */ +#include "common/debug.h" + #include "toon/font.h" namespace Toon { @@ -81,6 +83,8 @@ void FontRenderer::renderText(int32 x, int32 y, Common::String origText, int32 m x -= xx / 2; } + _vm->addDirtyRect(x, y, x + xx + 2, y + yy); + int32 curX = x; int32 curY = y; int32 height = 0; @@ -212,7 +216,7 @@ void FontRenderer::renderMultiLineText(int32 x, int32 y, Common::String origText curChar = textToFont(curChar); int width = _currentFont->getFrameWidth(curChar); - curWidth += width - 2; + curWidth += MAX<int32>(width - 2, 0); it++; curLetterNr++; } @@ -263,8 +267,8 @@ void FontRenderer::renderMultiLineText(int32 x, int32 y, Common::String origText if (x - 30 - maxWidth / 2 < 0) x = maxWidth / 2 + 30; - if (x + 30 + (maxWidth / 2) > 640) - x = 640 - (maxWidth / 2) - 30; + if (x + 30 + (maxWidth / 2) > TOON_SCREEN_WIDTH) + x = TOON_SCREEN_WIDTH - (maxWidth / 2) - 30; // we have good coordinates now, we can render the multi line int32 curX = x; @@ -273,10 +277,12 @@ void FontRenderer::renderMultiLineText(int32 x, int32 y, Common::String origText for (int32 i = 0; i < numLines; i++) { const byte *line = lines[i]; curX = x - lineSize[i] / 2; + _vm->addDirtyRect(curX + _vm->state()->_currentScrollValue, curY, curX + lineSize[i] + _vm->state()->_currentScrollValue + 2, curY + height); + while (*line) { byte curChar = textToFont(*line); if (curChar != 32) _currentFont->drawFontFrame(_vm->getMainSurface(), curChar, curX + _vm->state()->_currentScrollValue, curY, _currentFontColor); - curX = curX + _currentFont->getFrameWidth(curChar) - 2; + curX = curX + MAX<int32>(_currentFont->getFrameWidth(curChar) - 2, 0); //height = MAX(height, _currentFont->getFrameHeight(curChar)); line++; } diff --git a/engines/toon/hotspot.cpp b/engines/toon/hotspot.cpp index 687ea6ee83..1c1e23e39e 100644 --- a/engines/toon/hotspot.cpp +++ b/engines/toon/hotspot.cpp @@ -23,6 +23,8 @@ * */ +#include "common/debug.h" + #include "toon/hotspot.h" #include "toon/tools.h" @@ -78,8 +80,6 @@ int32 Hotspots::Find(int32 x, int32 y) { debugC(6, kDebugHotspot, "Find(%d, %d)", x, y); int32 priority = -1; -// Strangerke - Commented (not used) -// bool found = false; int32 foundId = -1; int32 testId = -1; @@ -91,8 +91,6 @@ int32 Hotspots::Find(int32 x, int32 y) { testId = i; if (_items[testId].getPriority() > priority) { -// Strangerke - Commented (not used) -// found = true; foundId = testId; priority = _items[testId].getPriority(); } @@ -128,10 +126,10 @@ bool Hotspots::LoadRif(Common::String rifName, Common::String additionalRifName) // RIFs are compressed in RNC1 RncDecoder decoder; - decoder.unpackM1(rifData, _items); + decoder.unpackM1(rifData, size, _items); if (rifsize2) { RncDecoder decoder2; - decoder2.unpackM1(rifData2 , _items + (rifsize >> 9)); + decoder2.unpackM1(rifData2 , size2, _items + (rifsize >> 9)); for (int32 i = 0; i < (rifsize2 >> 9); i++) { HotspotData *hot = _items + (rifsize >> 9) + i; hot->setData(0, hot->getX1() + 1280); diff --git a/engines/toon/movie.cpp b/engines/toon/movie.cpp index c6b57d96e2..64b80c29b3 100644 --- a/engines/toon/movie.cpp +++ b/engines/toon/movie.cpp @@ -23,7 +23,16 @@ * */ +#include "common/debug.h" +#include "common/events.h" +#include "common/keyboard.h" +#include "common/stream.h" +#include "common/system.h" +#include "graphics/surface.h" + +#include "toon/audio.h" #include "toon/movie.h" +#include "toon/toon.h" namespace Toon { @@ -38,8 +47,8 @@ void ToonstruckSmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, ui Video::SmackerDecoder::handleAudioTrack(track, chunkSize, unpackedSize); } -bool ToonstruckSmackerDecoder::loadFile(const Common::String &filename, int forcedflags) { - debugC(1, kDebugMovie, "loadFile(%s, %d)", filename.c_str(), forcedflags); +bool ToonstruckSmackerDecoder::loadFile(const Common::String &filename) { + debugC(1, kDebugMovie, "loadFile(%s)", filename.c_str()); _lowRes = false; @@ -50,14 +59,12 @@ bool ToonstruckSmackerDecoder::loadFile(const Common::String &filename, int forc delete _surface; } _surface = new Graphics::Surface(); - _surface->create(640, 400, 1); + _surface->create(640, 400, Graphics::PixelFormat::createFormatCLUT8()); _header.flags = 4; } return true; } - - return false; } @@ -88,7 +95,7 @@ void Movie::play(Common::String video, int32 flags) { _playing = true; if (flags & 1) _vm->getAudioManager()->setMusicVolume(0); - _decoder->loadFile(video.c_str(), flags); + _decoder->loadFile(video.c_str()); playVideo(isFirstIntroVideo); _vm->flushPalette(false); if (flags & 1) @@ -107,9 +114,9 @@ bool Movie::playVideo(bool isFirstIntroVideo) { if (_decoder->isLowRes()) { // handle manually 2x scaling here Graphics::Surface* surf = _vm->getSystem()->lockScreen(); - for (int y = 0; y < frame->h/2; y++) { - memcpy(surf->getBasePtr(0, y*2+0), frame->getBasePtr(0, y), frame->pitch); - memcpy(surf->getBasePtr(0, y*2+1), frame->getBasePtr(0, y), frame->pitch); + for (int y = 0; y < frame->h / 2; y++) { + memcpy(surf->getBasePtr(0, y * 2 + 0), frame->getBasePtr(0, y), frame->pitch); + memcpy(surf->getBasePtr(0, y * 2 + 1), frame->getBasePtr(0, y), frame->pitch); } _vm->getSystem()->unlockScreen(); } else { @@ -135,11 +142,13 @@ bool Movie::playVideo(bool isFirstIntroVideo) { Common::Event event; while (_vm->getSystem()->getEventManager()->pollEvent(event)) if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE)) { + _vm->dirtyAllScreen(); return false; } _vm->getSystem()->delayMillis(10); } + _vm->dirtyAllScreen(); return !_vm->shouldQuit(); } diff --git a/engines/toon/movie.h b/engines/toon/movie.h index 2a9173850f..bed2ceceae 100644 --- a/engines/toon/movie.h +++ b/engines/toon/movie.h @@ -36,7 +36,7 @@ public: ToonstruckSmackerDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType); virtual ~ToonstruckSmackerDecoder() {} void handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize); - bool loadFile(const Common::String &filename, int forcedflags); + bool loadFile(const Common::String &filename); bool isLowRes() { return _lowRes; } protected: bool _lowRes; diff --git a/engines/toon/path.cpp b/engines/toon/path.cpp index 3f948679f4..26355863f6 100644 --- a/engines/toon/path.cpp +++ b/engines/toon/path.cpp @@ -23,6 +23,8 @@ * */ +#include "common/debug.h" + #include "toon/path.h" namespace Toon { @@ -186,7 +188,7 @@ int32 PathFinding::findClosestWalkingPoint(int32 xx, int32 yy, int32 *fxx, int32 for (int y = 0; y < _height; y++) { for (int x = 0; x < _width; x++) { - if (isWalkable(x, y) && isLikelyWalkable(x,y)) { + if (isWalkable(x, y) && isLikelyWalkable(x, y)) { int32 ndist = (x - xx) * (x - xx) + (y - yy) * (y - yy); int32 ndist2 = (x - origX) * (x - origX) + (y - origY) * (y - origY); if (currentFound < 0 || ndist < dist || (ndist == dist && ndist2 < dist2)) { @@ -283,8 +285,8 @@ int32 PathFinding::findPath(int32 x, int32 y, int32 destx, int32 desty) { } // first test direct line - if (lineIsWalkable(x,y,destx,desty)) { - walkLine(x,y,destx,desty); + if (lineIsWalkable(x, y, destx, desty)) { + walkLine(x, y, destx, desty); return true; } @@ -317,7 +319,7 @@ int32 PathFinding::findPath(int32 x, int32 y, int32 destx, int32 desty) { int32 curPNode = px + py * _width; if (isWalkable(px, py)) { // walkable ? - int sum = sq[curNode] + wei * (1 + (isLikelyWalkable(px,py) ? 5 : 0)); + int sum = sq[curNode] + wei * (1 + (isLikelyWalkable(px, py) ? 5 : 0)); if (sq[curPNode] > sum || !sq[curPNode]) { int newWeight = abs(destx - px) + abs(desty - py); sq[curPNode] = sum; @@ -407,7 +409,11 @@ void PathFinding::init(Picture *mask) { _height = mask->getHeight(); _currentMask = mask; _heap->unload(); - _heap->init(_width * _height); + // In order to reduce memory fragmentation on small devices, we use the maximum + // possible size here which is TOON_BACKBUFFER_WIDTH. Even though this is + // 1280 as opposed to the possible 640, it actually helps memory allocation on + // those devices. + _heap->init(TOON_BACKBUFFER_WIDTH * _height); // should really be _width delete[] _gridTemp; _gridTemp = new int32[_width*_height]; } @@ -438,7 +444,6 @@ void PathFinding::addBlockingEllipse(int32 x1, int32 y1, int32 w, int32 h) { _numBlockingRects++; } - int32 PathFinding::getPathNodeCount() const { return _gridPathCount; } diff --git a/engines/toon/path.h b/engines/toon/path.h index a2b1b7bf92..03d2b188e5 100644 --- a/engines/toon/path.h +++ b/engines/toon/path.h @@ -91,7 +91,6 @@ protected: int32 _gridPathCount; ToonEngine *_vm; - }; } // End of namespace Toon diff --git a/engines/toon/picture.cpp b/engines/toon/picture.cpp index 18e6a8cf7f..ce28f9c68b 100644 --- a/engines/toon/picture.cpp +++ b/engines/toon/picture.cpp @@ -23,16 +23,18 @@ * */ - #include "toon/picture.h" #include "toon/tools.h" + +#include "common/debug.h" +#include "common/rect.h" #include "common/stack.h" namespace Toon { bool Picture::loadPicture(Common::String file, bool totalPalette /*= false*/) { debugC(1, kDebugPicture, "loadPicture(%s, %d)", file.c_str(), (totalPalette) ? 1 : 0); - + uint32 size = 0; uint8 *fileData = _vm->resources()->getFileData(file, &size); if (!fileData) @@ -49,12 +51,12 @@ bool Picture::loadPicture(Common::String file, bool totalPalette /*= false*/) { decompressLZSS(fileData + 8, _data, dstsize); // size can only be 640x400 or 1280x400 - if (dstsize > 640 * 400 + 768) - _width = 1280; + if (dstsize > TOON_SCREEN_WIDTH * TOON_SCREEN_HEIGHT + 768) + _width = TOON_BACKBUFFER_WIDTH; else - _width = 640; + _width = TOON_SCREEN_WIDTH; - _height = 400; + _height = TOON_SCREEN_HEIGHT; // do we have a palette ? _paletteEntries = (dstsize & 0x7ff) / 3; @@ -69,7 +71,7 @@ bool Picture::loadPicture(Common::String file, bool totalPalette /*= false*/) { } case kCompSPCN: { uint32 decSize = READ_LE_UINT32(fileData + 10); - _data = new uint8[decSize+100]; + _data = new uint8[decSize + 100]; _paletteEntries = READ_LE_UINT16(fileData + 14) / 3; if (_paletteEntries) { @@ -79,12 +81,12 @@ bool Picture::loadPicture(Common::String file, bool totalPalette /*= false*/) { } // size can only be 640x400 or 1280x400 - if (decSize > 640 * 400 + 768) - _width = 1280; + if (decSize > TOON_SCREEN_WIDTH * TOON_SCREEN_HEIGHT + 768) + _width = TOON_BACKBUFFER_WIDTH; else - _width = 640; + _width = TOON_SCREEN_WIDTH; - _height = 400; + _height = TOON_SCREEN_HEIGHT; // decompress the picture into our buffer decompressSPCN(fileData + 16 + _paletteEntries * 3, _data, decSize); @@ -98,15 +100,15 @@ bool Picture::loadPicture(Common::String file, bool totalPalette /*= false*/) { _data = new uint8[decSize]; - rnc.unpackM1(fileData, _data); + rnc.unpackM1(fileData, size, _data); // size can only be 640x400 or 1280x400 - if (decSize > 640 * 400 + 768) - _width = 1280; + if (decSize > TOON_SCREEN_WIDTH * TOON_SCREEN_HEIGHT + 768) + _width = TOON_BACKBUFFER_WIDTH; else - _width = 640; + _width = TOON_SCREEN_WIDTH; - _height = 400; + _height = TOON_SCREEN_HEIGHT; return true; } case kCompRNC2: { @@ -119,12 +121,12 @@ bool Picture::loadPicture(Common::String file, bool totalPalette /*= false*/) { decSize = rnc.unpackM2(fileData, _data); - if (decSize > 640 * 400 + 768) - _width = 1280; + if (decSize > TOON_SCREEN_WIDTH * TOON_SCREEN_HEIGHT + 768) + _width = TOON_BACKBUFFER_WIDTH; else - _width = 640; + _width = TOON_SCREEN_WIDTH; - _height = 400; + _height = TOON_SCREEN_HEIGHT; return true; } } @@ -187,6 +189,41 @@ void Picture::drawMask(Graphics::Surface &surface, int32 x, int32 y, int32 dx, i } } +void Picture::drawWithRectList(Graphics::Surface& surface, int32 x, int32 y, int32 dx, int32 dy, Common::Array<Common::Rect>& rectArray) { + + int32 rx = MIN(_width, surface.w - x); + int32 ry = MIN(_height, surface.h - y); + + if (rx < 0 || ry < 0) + return; + + int32 destPitch = surface.pitch; + int32 srcPitch = _width; + + for (uint32 i = 0; i < rectArray.size(); i++) { + + Common::Rect rect = rectArray[i]; + + int32 fillRx = MIN<int32>(rx, rect.right - rect.left); + int32 fillRy = MIN<int32>(ry, rect.bottom - rect.top); + + uint8 *c = _data + _width * (dy + rect.top) + (dx + rect.left); + uint8 *curRow = (uint8 *)surface.pixels + (y + rect.top) * destPitch + (x + rect.left); + + for (int32 yy = 0; yy < fillRy; yy++) { + uint8 *curSrc = c; + uint8 *cur = curRow; + for (int32 xx = 0; xx < fillRx; xx++) { + *cur = *curSrc; + curSrc++; + cur++; + } + curRow += destPitch; + c += srcPitch; + } + } +} + void Picture::draw(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 dy) { debugC(6, kDebugPicture, "draw(surface, %d, %d, %d, %d)", x, y, dx, dy); @@ -279,7 +316,6 @@ void Picture::drawLineOnMask(int32 x, int32 y, int32 x2, int32 y2, bool walkable else t = adx; - int32 cdx = (dx << 16) / t; int32 cdy = (dy << 16) / t; @@ -289,15 +325,15 @@ void Picture::drawLineOnMask(int32 x, int32 y, int32 x2, int32 y2, bool walkable int32 rx = bx >> 16; int32 ry = by >> 16; - if( rx >= 0 && rx < _width-1 && ry >= 0 && ry < _height) { // sanity check: some lines in the game + if( rx >= 0 && rx < _width-1 && ry >= 0 && ry < _height) { // sanity check: some lines in the game // were drawing outside the screen causing corruption if (!walkable) { _data[_width * ry + rx] &= 0xe0; - _data[_width * ry + rx+1] &= 0xe0; + _data[_width * ry + rx + 1] &= 0xe0; } else { int32 v = _data[_width * (by >> 16) + rx - 1]; _data[_width * ry + rx] = v; - _data[_width * ry + rx+1] = v; + _data[_width * ry + rx + 1] = v; } } diff --git a/engines/toon/picture.h b/engines/toon/picture.h index 1b0fd7f550..6aca408364 100644 --- a/engines/toon/picture.h +++ b/engines/toon/picture.h @@ -44,6 +44,7 @@ public: bool loadPicture(Common::String file, bool totalPalette = false); void setupPalette(); void draw(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 dy); + void drawWithRectList(Graphics::Surface& surface, int32 x, int32 y, int32 dx, int32 dy, Common::Array<Common::Rect>& rectArray); void drawMask(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 dy); void drawLineOnMask(int32 x, int32 y, int32 x2, int32 y2, bool walkable); void floodFillNotWalkableOnMask(int32 x, int32 y); diff --git a/engines/toon/resource.cpp b/engines/toon/resource.cpp index 61e3ffb111..f9f65b423b 100644 --- a/engines/toon/resource.cpp +++ b/engines/toon/resource.cpp @@ -24,18 +24,26 @@ */ #include "toon/resource.h" +#include "common/debug.h" #include "common/file.h" #include "common/memstream.h" #include "common/substream.h" #include "toon/toon.h" - namespace Toon { -Resources::Resources(ToonEngine *vm) : _vm(vm) { +Resources::Resources(ToonEngine *vm) : _vm(vm), _cacheSize(0) { + _resourceCache.clear(); } Resources::~Resources() { + + while (!_resourceCache.empty()) { + CacheEntry *temp = _resourceCache.back(); + _resourceCache.pop_back(); + delete temp; + } + while(!_pakFiles.empty()) { PakFile *temp = _pakFiles.back(); _pakFiles.pop_back(); @@ -45,8 +53,73 @@ Resources::~Resources() { purgeFileData(); } -void Resources::openPackage(Common::String fileName, bool preloadEntirePackage) { - debugC(1, kDebugResource, "openPackage(%s, %d)", fileName.c_str(), (preloadEntirePackage) ? 1 : 0); +void Resources::removePackageFromCache(Common::String packName) { + // I'm not sure what's a good strategy here. It seems unnecessary to + // actually remove the cached resources, because the player may be + // wandering back and forth between rooms. So for now, do nothing. +} + +bool Resources::getFromCache(Common::String fileName, uint32 *fileSize, uint8 **fileData) { + for (Common::Array<CacheEntry *>::iterator entry = _resourceCache.begin(); entry != _resourceCache.end(); ++entry) { + if ((*entry)->_data && (*entry)->_fileName.compareToIgnoreCase(fileName) == 0) { + debugC(5, kDebugResource, "getFromCache(%s) - Got %d bytes from %s", fileName.c_str(), (*entry)->_size, (*entry)->_packName.c_str()); + (*entry)->_age = 0; + *fileSize = (*entry)->_size; + *fileData = (*entry)->_data; + return true; + } + } + return false; +} + +void Resources::addToCache(Common::String packName, Common::String fileName, uint32 fileSize, uint8 *fileData) { + debugC(5, kDebugResource, "addToCache(%s, %s, %d) - Total Size: %d", packName.c_str(), fileName.c_str(), fileSize, _cacheSize + fileSize); + for (Common::Array<CacheEntry *>::iterator entry = _resourceCache.begin(); entry != _resourceCache.end(); ++entry) { + if ((*entry)->_data) { + (*entry)->_age++; + } + } + _cacheSize += fileSize; + + while (_cacheSize > MAX_CACHE_SIZE) { + CacheEntry *bestEntry = 0; + for (Common::Array<CacheEntry *>::iterator entry = _resourceCache.begin(); entry != _resourceCache.end(); ++entry) { + if ((*entry)->_data) { + if (!bestEntry || ((*entry)->_age >= bestEntry->_age && (*entry)->_size >= bestEntry->_size)) { + bestEntry = *entry; + } + } + } + if (!bestEntry) + break; + + free(bestEntry->_data); + bestEntry->_data = 0; + _cacheSize -= bestEntry->_size; + debugC(5, kDebugResource, "Freed %s (%s) to reclaim %d bytes", bestEntry->_fileName.c_str(), bestEntry->_packName.c_str(), bestEntry->_size); + } + + for (Common::Array<CacheEntry *>::iterator entry = _resourceCache.begin(); entry != _resourceCache.end(); ++entry) { + if (!(*entry)->_data) { + (*entry)->_packName = packName; + (*entry)->_fileName = fileName; + (*entry)->_age = 0; + (*entry)->_size = fileSize; + (*entry)->_data = fileData; + return; + } + } + + CacheEntry *entry = new CacheEntry(); + entry->_packName = packName; + entry->_fileName = fileName; + entry->_size = fileSize; + entry->_data = fileData; + _resourceCache.push_back(entry); +} + +void Resources::openPackage(Common::String fileName) { + debugC(1, kDebugResource, "openPackage(%s)", fileName.c_str()); Common::File file; bool opened = file.open(fileName); @@ -55,15 +128,16 @@ void Resources::openPackage(Common::String fileName, bool preloadEntirePackage) return; PakFile *pakFile = new PakFile(); - pakFile->open(&file, fileName, preloadEntirePackage); + pakFile->open(&file, fileName); - if (preloadEntirePackage) - file.close(); + file.close(); _pakFiles.push_back(pakFile); } void Resources::closePackage(Common::String fileName) { + + removePackageFromCache(fileName); for (uint32 i = 0; i < _pakFiles.size(); i++) { if (_pakFiles[i]->getPackName() == fileName) { delete _pakFiles[i]; @@ -91,13 +165,21 @@ uint8 *Resources::getFileData(Common::String fileName, uint32 *fileSize) { _allocatedFileData.push_back(memory); return memory; } else { + + uint32 locFileSize = 0; + uint8 *locFileData = 0; + + if (getFromCache(fileName, &locFileSize, &locFileData)) { + *fileSize = locFileSize; + return locFileData; + } + for (uint32 i = 0; i < _pakFiles.size(); i++) { - uint32 locFileSize = 0; - uint8 *locFileData = 0; locFileData = _pakFiles[i]->getFileData(fileName, &locFileSize); if (locFileData) { *fileSize = locFileSize; + addToCache(_pakFiles[i]->getPackName(), fileName, locFileSize, locFileData); return locFileData; } } @@ -136,25 +218,16 @@ void Resources::purgeFileData() { } _allocatedFileData.clear(); } + Common::SeekableReadStream *PakFile::createReadStream(Common::String fileName) { debugC(1, kDebugResource, "createReadStream(%s)", fileName.c_str()); - int32 offset = 0; - int32 size = 0; - for (uint32 i = 0; i < _numFiles; i++) { - if (fileName.compareToIgnoreCase(_files[i]._name) == 0) { - size = _files[i]._size; - offset = _files[i]._offset; - break; - } - } - if (!size) - return 0; - - if (_fileHandle) - return new Common::SeekableSubReadStream(_fileHandle, offset, offset + size); + uint32 fileSize = 0; + uint8 *buffer = getFileData(fileName, &fileSize); + if (buffer) + return new Common::MemoryReadStream(buffer, fileSize, DisposeAfterUse::YES); else - return new Common::MemoryReadStream(_buffer + offset, size); + return 0; } uint8 *PakFile::getFileData(Common::String fileName, uint32 *fileSize) { @@ -162,16 +235,26 @@ uint8 *PakFile::getFileData(Common::String fileName, uint32 *fileSize) { for (uint32 i = 0; i < _numFiles; i++) { if (fileName.compareToIgnoreCase(_files[i]._name) == 0) { - *fileSize = _files[i]._size; - return _buffer + _files[i]._offset; + Common::File file; + if (file.open(_packName)) { + *fileSize = _files[i]._size; + file.seek(_files[i]._offset); + + // Use malloc() because that's what MemoryReadStream + // uses to dispose of the memory when it's done. + uint8 *buffer = (uint8 *)malloc(*fileSize); + file.read(buffer, *fileSize); + file.close(); + return buffer; + } } } return 0; } -void PakFile::open(Common::SeekableReadStream *rs, Common::String packName, bool preloadEntirePackage) { - debugC(1, kDebugResource, "open(rs, %d)", (preloadEntirePackage) ? 1 : 0); +void PakFile::open(Common::SeekableReadStream *rs, Common::String packName) { + debugC(1, kDebugResource, "open(rs)"); char buffer[64]; int32 currentPos = 0; @@ -199,30 +282,12 @@ void PakFile::open(Common::SeekableReadStream *rs, Common::String packName, bool _numFiles++; _files.push_back(newFile); } - - if (preloadEntirePackage) { - _bufferSize = rs->size(); - delete[] _buffer; - _buffer = new uint8[_bufferSize]; - rs->seek(0); - rs->read(_buffer, _bufferSize); - } } void PakFile::close() { - delete[] _buffer; - - if (_fileHandle) { - _fileHandle->close(); - delete _fileHandle; - } } PakFile::PakFile() { - _bufferSize = 0; - _buffer = NULL; - - _fileHandle = NULL; } PakFile::~PakFile() { diff --git a/engines/toon/resource.h b/engines/toon/resource.h index e117c8e259..d6ed29b81b 100644 --- a/engines/toon/resource.h +++ b/engines/toon/resource.h @@ -31,6 +31,8 @@ #include "common/file.h" #include "common/stream.h" +#define MAX_CACHE_SIZE (4 * 1024 * 1024) + namespace Toon { class PakFile { @@ -38,7 +40,7 @@ public: PakFile(); ~PakFile(); - void open(Common::SeekableReadStream *rs, Common::String packName, bool preloadEntirePackage); + void open(Common::SeekableReadStream *rs, Common::String packName); uint8 *getFileData(Common::String fileName, uint32 *fileSize); Common::String getPackName() { return _packName; } Common::SeekableReadStream *createReadStream(Common::String fileName); @@ -52,9 +54,6 @@ protected: }; Common::String _packName; - uint8 *_buffer; - int32 _bufferSize; - uint32 _numFiles; Common::Array<File> _files; Common::File *_fileHandle; @@ -62,11 +61,25 @@ protected: class ToonEngine; +class CacheEntry { +public: + CacheEntry() : _age(0), _size(0), _data(0) {} + ~CacheEntry() { + free(_data); + } + + Common::String _packName; + Common::String _fileName; + uint32 _age; + uint32 _size; + uint8 *_data; +}; + class Resources { public: Resources(ToonEngine *vm); ~Resources(); - void openPackage(Common::String file, bool preloadEntirePackage); + void openPackage(Common::String file); void closePackage(Common::String fileName); Common::SeekableReadStream *openFile(Common::String file); uint8 *getFileData(Common::String fileName, uint32 *fileSize); // this memory must be copied to your own structures! @@ -76,6 +89,12 @@ protected: ToonEngine *_vm; Common::Array<uint8 *> _allocatedFileData; Common::Array<PakFile *> _pakFiles; + uint32 _cacheSize; + Common::Array<CacheEntry *> _resourceCache; + + void removePackageFromCache(Common::String packName); + bool getFromCache(Common::String fileName, uint32 *fileSize, uint8 **fileData); + void addToCache(Common::String packName, Common::String fileName, uint32 fileSize, uint8 *fileData); }; } // End of namespace Toon diff --git a/engines/toon/script.cpp b/engines/toon/script.cpp index 3cd56761f6..8703666781 100644 --- a/engines/toon/script.cpp +++ b/engines/toon/script.cpp @@ -23,11 +23,9 @@ * */ - +#include "common/debug.h" #include "common/endian.h" #include "common/stream.h" -#include "common/util.h" -#include "common/system.h" #include "toon/toon.h" #include "toon/script.h" @@ -71,7 +69,7 @@ EMCInterpreter::~EMCInterpreter() { bool EMCInterpreter::callback(Common::IFFChunk &chunk) { switch (chunk._type) { - case MKID_BE('TEXT'): + case MKTAG('T','E','X','T'): delete[] _scriptData->text; _scriptData->text = new byte[chunk._size]; assert(_scriptData->text); @@ -79,7 +77,7 @@ bool EMCInterpreter::callback(Common::IFFChunk &chunk) { error("Couldn't read TEXT chunk from file '%s'", _filename); break; - case MKID_BE('ORDR'): + case MKTAG('O','R','D','R'): delete[] _scriptData->ordr; _scriptData->ordr = new uint16[chunk._size >> 1]; assert(_scriptData->ordr); @@ -90,7 +88,7 @@ bool EMCInterpreter::callback(Common::IFFChunk &chunk) { _scriptData->ordr[i] = READ_BE_UINT16(&_scriptData->ordr[i]); break; - case MKID_BE('DATA'): + case MKTAG('D','A','T','A'): delete[] _scriptData->data; _scriptData->data = new uint16[chunk._size >> 1]; assert(_scriptData->data); @@ -177,7 +175,7 @@ bool EMCInterpreter::start(EMCState *script, int function) { if (functionOffset == 0xFFFF) return false; - script->ip = &script->dataPtr->data[functionOffset+1]; + script->ip = &script->dataPtr->data[functionOffset + 1]; return true; } diff --git a/engines/toon/script.h b/engines/toon/script.h index 6c46238238..b6d28e1171 100644 --- a/engines/toon/script.h +++ b/engines/toon/script.h @@ -31,7 +31,6 @@ #include "common/func.h" #include "common/iff_container.h" - // Based on Kyra script interpretor namespace Toon { @@ -88,9 +87,9 @@ public: // Both lead to some problems in our IFF parser, either reading after the end // of file or producing a "Chunk overread" error message. To work around this // we need to adjust the size field properly. - if (_formType == MKID_BE('EMC2')) + if (_formType == MKTAG('E','M','C','2')) _formChunk.size -= 8; - else if (_formType == MKID_BE('AVFS')) + else if (_formType == MKTAG('A','V','F','S')) _formChunk.size += 4; } }; diff --git a/engines/toon/script_func.cpp b/engines/toon/script_func.cpp index adf3a1c9cc..8f75097bd4 100644 --- a/engines/toon/script_func.cpp +++ b/engines/toon/script_func.cpp @@ -23,6 +23,9 @@ * */ +#include "common/debug.h" +#include "common/system.h" + #include "toon/script_func.h" #include "toon/script.h" #include "toon/state.h" @@ -265,7 +268,6 @@ int32 ScriptFunc::sys_Cmd_Draw_Actor_Standing(EMCState *state) { arg1 = 1; } - if (arg2 > -1) _vm->getDrew()->forceFacing(arg2); @@ -461,7 +463,7 @@ int32 ScriptFunc::sys_Cmd_Actor_Talks(EMCState *state) { } int32 ScriptFunc::sys_Cmd_Say_Lines(EMCState *state) { - + // WORKAROUND: In the scene 4 (Castle), if you click twice on the closed door, Drew disappears // the script makes him disappear for the custom animation and not reappear. if (_vm->state()->_currentScene == 4 && stackPos(1) == 562) { @@ -491,11 +493,11 @@ int32 ScriptFunc::sys_Cmd_Empty_Inventory(EMCState *state) { int32 ScriptFunc::sys_Cmd_Set_Anim_Scale_Size(EMCState *state) { int32 animID = stackPos(0); int32 scale = stackPos(1); - + SceneAnimation *sceneAnim = _vm->getSceneAnimation(animID); if (sceneAnim) { sceneAnim->_animInstance->setUseMask(true); - sceneAnim->_animInstance->setScale(scale,true); + sceneAnim->_animInstance->setScale(scale, true); } return 0; } @@ -939,8 +941,6 @@ int32 ScriptFunc::sys_Cmd_Init_Scene_Anim(EMCState *state) { sceneAnim->_animInstance->setAnimationRange(stackPos(11), stackPos(11)); sceneAnim->_animInstance->setFrame(stackPos(11)); - - debugC(0, 0xfff, "Init Anim %s %d %d %d %d %d %d %d %d %d %d %d %d %d\n", GetText(12, state), stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7), stackPos(8), stackPos(9), stackPos(10), stackPos(11), stackPos(12)); @@ -950,7 +950,7 @@ int32 ScriptFunc::sys_Cmd_Init_Scene_Anim(EMCState *state) { int32 layerZ = stackPos(3); if (dx == -2) - sceneAnim->_animInstance->moveRelative(640, 0, 0); + sceneAnim->_animInstance->moveRelative(TOON_SCREEN_WIDTH, 0, 0); else if (dx < 0) { dx = sceneAnim->_animation->_x1; } @@ -1028,7 +1028,7 @@ int32 ScriptFunc::sys_Cmd_Draw_Scene_Anim_WSA_Frame(EMCState *state) { else if (animId == 20 || animId == 15 || animId == 21 || animId == 16 || animId == 17 || animId == 18) _vm->pauseSceneAnimationScript(_vm->getCurrentUpdatingSceneAnimation(), 1); else if (animId == 9) { - _vm->pauseSceneAnimationScript(_vm->getCurrentUpdatingSceneAnimation(), 6); + _vm->pauseSceneAnimationScript(_vm->getCurrentUpdatingSceneAnimation(), 3); } } @@ -1091,13 +1091,13 @@ int32 ScriptFunc::sys_Cmd_Proceed_To_Next_Chapter(EMCState *state) { } int32 ScriptFunc::sys_Cmd_Play_Sfx_Plus(EMCState *state) { - //debugC(0,0xfff, "playSfx ( %d , %d, %d, %d, %d )", stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4)); + //debugC(0, 0xfff, "playSfx ( %d , %d, %d, %d, %d )", stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4)); _vm->playSFX(stackPos(0), stackPos(1)); return 0; } int32 ScriptFunc::sys_Cmd_Play_Sfx(EMCState *state) { - //debugC(0,0xfff, "playSfx ( %d , %d)", stackPos(0), stackPos(1)); + //debugC(0, 0xfff, "playSfx ( %d , %d)", stackPos(0), stackPos(1)); _vm->playSFX(stackPos(0), stackPos(1)); return 0; } diff --git a/engines/toon/state.cpp b/engines/toon/state.cpp index f676a65025..af37ea9e68 100644 --- a/engines/toon/state.cpp +++ b/engines/toon/state.cpp @@ -23,6 +23,8 @@ * */ +#include "common/debug.h" + #include "toon/state.h" #include "toon/toon.h" @@ -119,7 +121,6 @@ State::State(void) { } State::~State(void) { - } int32 State::getGameFlag(int32 flagId) { diff --git a/engines/toon/state.h b/engines/toon/state.h index d31ff4f3c2..63505fd5fb 100644 --- a/engines/toon/state.h +++ b/engines/toon/state.h @@ -81,7 +81,6 @@ public: int32 _nextSpecialEnterX; int32 _nextSpecialEnterY; - bool _timerEnabled[2]; int32 _timerTimeout[2]; int32 _timerDelay[2]; @@ -94,7 +93,6 @@ public: void loadConversations(Common::ReadStream *stream); void saveConversations(Common::WriteStream *stream); - }; } // End of namespace Toon diff --git a/engines/toon/text.cpp b/engines/toon/text.cpp index f0d17dd34e..94a3ea5aa7 100644 --- a/engines/toon/text.cpp +++ b/engines/toon/text.cpp @@ -23,6 +23,8 @@ * */ +#include "common/debug.h" + #include "toon/text.h" namespace Toon { diff --git a/engines/toon/tools.cpp b/engines/toon/tools.cpp index a03a2d57ce..ff72e69543 100644 --- a/engines/toon/tools.cpp +++ b/engines/toon/tools.cpp @@ -23,6 +23,8 @@ * */ +#include "common/debug.h" + #include "toon/tools.h" #include "toon/toon.h" @@ -125,7 +127,6 @@ uint32 decompressSPCN(byte *src, byte *dst, uint32 dstsize) { return (dstp - dst); } - //return codes #define NOT_PACKED 0 #define PACKED_CRC -1 @@ -201,7 +202,16 @@ uint16 RncDecoder::inputBits(uint8 amount) { newBitBuffl >>= newBitCount; newBitBuffl |= remBits; _srcPtr += 2; - newBitBuffh = READ_LE_UINT16(_srcPtr); + + // added some more check here to prevent reading in the buffer + // if there are no bytes anymore. + _inputByteLeft -= 2; + if (_inputByteLeft <= 0) + newBitBuffh = 0; + else if (_inputByteLeft == 1) + newBitBuffh = *_srcPtr; + else + newBitBuffh = READ_LE_UINT16(_srcPtr); amount -= newBitCount; newBitCount = 16 - amount; } @@ -284,7 +294,7 @@ int RncDecoder::getbit() { return temp; } -int32 RncDecoder::unpackM1(const void *input, void *output) { +int32 RncDecoder::unpackM1(const void *input, uint16 inputSize, void *output) { debugC(1, kDebugTools, "unpackM1(input, output)"); uint8 *outputLow, *outputHigh; @@ -297,6 +307,7 @@ int32 RncDecoder::unpackM1(const void *input, void *output) { uint16 crcPacked = 0; + _inputByteLeft = inputSize; _bitBuffl = 0; _bitBuffh = 0; _bitCount = 0; @@ -339,9 +350,12 @@ int32 RncDecoder::unpackM1(const void *input, void *output) { _srcPtr = (_dstPtr - packLen); } + _inputByteLeft -= HEADER_LEN; + _dstPtr = (uint8 *)output; _bitCount = 0; + _bitBuffl = READ_LE_UINT16(_srcPtr); inputBits(2); @@ -360,8 +374,22 @@ int32 RncDecoder::unpackM1(const void *input, void *output) { memcpy(_dstPtr, _srcPtr, inputLength); //memcpy is allowed here _dstPtr += inputLength; _srcPtr += inputLength; - uint16 a = READ_LE_UINT16(_srcPtr); - uint16 b = READ_LE_UINT16(_srcPtr + 2); + _inputByteLeft -= inputLength; + uint16 a; + if (_inputByteLeft <= 0) + a = 0; + else if (_inputByteLeft == 1) + a = *_srcPtr; + else + a = READ_LE_UINT16(_srcPtr); + + uint16 b; + if (_inputByteLeft <= 2) + b = 0; + else if(_inputByteLeft == 3) + b = *(_srcPtr + 2); + else + b = READ_LE_UINT16(_srcPtr + 2); _bitBuffl &= ((1 << _bitCount) - 1); _bitBuffl |= (a << _bitCount); @@ -397,9 +425,6 @@ int32 RncDecoder::unpackM2(const void *input, void *output) { uint16 crcUnpacked = 0; uint16 crcPacked = 0; -// Strangerke - Commented (not used) -// uint16 counts = 0; - _bitBuffl = 0; _bitCount = 0; @@ -429,7 +454,6 @@ int32 RncDecoder::unpackM2(const void *input, void *output) { _srcPtr = inputptr; _dstPtr = (uint8 *)output; - uint16 ofs, len; byte ofs_hi, ofs_lo; diff --git a/engines/toon/tools.h b/engines/toon/tools.h index 05fc5c9cda..1434ca26c7 100644 --- a/engines/toon/tools.h +++ b/engines/toon/tools.h @@ -42,8 +42,8 @@ const uint32 kCompRNC2 = 0x524E4302; #define READ_LE_INT16(x) (int16) READ_LE_UINT16(x) #define READ_LE_INT32(x) (int32) READ_LE_UINT32(x) -#define WRITE_LE_INT16(x,y) WRITE_LE_UINT16(x,(int16)y) -#define WRITE_LE_INT32(x,y) WRITE_LE_UINT32(x,(int32)y) +#define WRITE_LE_INT16(x, y) WRITE_LE_UINT16(x, (int16)y) +#define WRITE_LE_INT32(x, y) WRITE_LE_UINT32(x, (int32)y) uint32 decompressSPCN(byte *src, byte *dst, uint32 dstsize); uint32 decompressLZSS(byte *src, byte *dst, int dstsize); @@ -63,10 +63,12 @@ protected: const uint8 *_srcPtr; uint8 *_dstPtr; + int16 _inputByteLeft; + public: RncDecoder(); ~RncDecoder(); - int32 unpackM1(const void *input, void *output); + int32 unpackM1(const void *input, uint16 inputSize, void *output); int32 unpackM2(const void *input, void *output); protected: diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp index d65230df85..81c4d313e4 100644 --- a/engines/toon/toon.cpp +++ b/engines/toon/toon.cpp @@ -33,6 +33,7 @@ #include "common/memstream.h" #include "engines/util.h" +#include "graphics/palette.h" #include "graphics/surface.h" #include "graphics/thumbnail.h" #include "gui/saveload.h" @@ -49,7 +50,6 @@ namespace Toon { - void ToonEngine::init() { _currentScriptRegion = 0; _resources = new Resources(this); @@ -58,7 +58,7 @@ void ToonEngine::init() { _hotspots = new Hotspots(this); _mainSurface = new Graphics::Surface(); - _mainSurface->create(1280, 400, 1); + _mainSurface->create(TOON_BACKBUFFER_WIDTH, TOON_BACKBUFFER_HEIGHT, Graphics::PixelFormat::createFormatCLUT8()); _finalPalette = new uint8[768]; _backupPalette = new uint8[768]; @@ -101,14 +101,13 @@ void ToonEngine::init() { SearchMan.addSubDirectoryMatching(gameDataDir, "ACT1"); SearchMan.addSubDirectoryMatching(gameDataDir, "ACT2"); - syncSoundSettings(); _pathFinding = new PathFinding(this); - resources()->openPackage("LOCAL.PAK", true); - resources()->openPackage("ONETIME.PAK", true); - resources()->openPackage("DREW.PAK", true); + resources()->openPackage("LOCAL.PAK"); + resources()->openPackage("ONETIME.PAK"); + resources()->openPackage("DREW.PAK"); for (int32 i = 0; i < 32; i++) _characters[i] = NULL; @@ -118,6 +117,8 @@ void ToonEngine::init() { _drew = _characters[0]; _flux = _characters[1]; + + // preload walk anim for flux and drew _drew->loadWalkAnimation("STNDWALK.CAF"); _drew->setupPalette(); @@ -137,6 +138,9 @@ void ToonEngine::init() { memset(_sceneAnimations, 0, sizeof(_sceneAnimations)); memset(_sceneAnimationScripts, 0, sizeof(_sceneAnimationScripts)); + _drew->setVisible(false); + _flux->setVisible(false); + _gameState->_currentChapter = 1; initChapter(); loadCursor(); @@ -262,7 +266,6 @@ void ToonEngine::parseInput() { selectHotspot(); clickEvent(); } - } void ToonEngine::enableTimer(int32 timerId) { @@ -325,8 +328,8 @@ void ToonEngine::updateScrolling(bool force, int32 timeIncrement) { if ((_gameState->_locations[_gameState->_currentScene]._flags & 0x80) == 0) { if (desiredScrollValue < 0) desiredScrollValue = 0; - if (desiredScrollValue >= _currentPicture->getWidth() - 640) - desiredScrollValue = _currentPicture->getWidth() - 640; + if (desiredScrollValue >= _currentPicture->getWidth() - TOON_SCREEN_WIDTH) + desiredScrollValue = _currentPicture->getWidth() - TOON_SCREEN_WIDTH; if (force) { _gameState->_currentScrollValue = desiredScrollValue; @@ -378,12 +381,23 @@ void ToonEngine::updateTimer(int32 timeIncrement) { } void ToonEngine::render() { - if (_gameState->_inCutaway) - _currentCutaway->draw(*_mainSurface, 0, 0, 0, 0); - else - _currentPicture->draw(*_mainSurface, 0, 0, 0, 0); - //_currentMask->drawMask(*_mainSurface,0,0,0,0); + if (_dirtyAll) { + if (_gameState->_inCutaway) + _currentCutaway->draw(*_mainSurface, 0, 0, 0, 0); + else + _currentPicture->draw(*_mainSurface, 0, 0, 0, 0); + _dirtyRects.push_back(Common::Rect(0, 0, TOON_BACKBUFFER_WIDTH, TOON_BACKBUFFER_HEIGHT)); + } else { + if (_gameState->_inCutaway) + _currentCutaway->drawWithRectList(*_mainSurface, 0, 0, 0, 0, _dirtyRects); + else + _currentPicture->drawWithRectList(*_mainSurface, 0, 0, 0, 0, _dirtyRects); + } + + clearDirtyRects(); + + //_currentMask->drawMask(*_mainSurface, 0, 0, 0, 0); _animationManager->render(); drawInfoLine(); @@ -399,7 +413,7 @@ void ToonEngine::render() { sprintf(test, "%d %d / mask %d layer %d z %d", _mouseX, _mouseY, getMask()->getData(_mouseX, _mouseY), getLayerAtPoint(_mouseX, _mouseY), getZAtPoint(_mouseX, _mouseY)); int32 c = *(uint8 *)_mainSurface->getBasePtr(_mouseX, _mouseY); - sprintf(test, "%d %d / color id %d %d,%d,%d", _mouseX, _mouseY, c, _finalPalette[c*3+0], _finalPalette[c*3+1], _finalPalette[c*3+2]); + sprintf(test, "%d %d / color id %d %d,%d,%d", _mouseX, _mouseY, c, _finalPalette[c * 3 + 0], _finalPalette[c * 3 + 1], _finalPalette[c * 3 + 2]); _fontRenderer->setFont(_fontToon); _fontRenderer->renderText(40, 150, Common::String(test), 0); @@ -422,8 +436,8 @@ void ToonEngine::render() { // add a little sleep here int32 newMillis = (int32)_system->getMillis(); int32 sleepMs = 1; // Minimum delay to allow thread scheduling - if ((newMillis - _lastRenderTime) < _tickLength) - sleepMs = _tickLength - (newMillis - _lastRenderTime); + if ((newMillis - _lastRenderTime) < _tickLength * 2) + sleepMs = _tickLength * 2 - (newMillis - _lastRenderTime); assert(sleepMs >= 0); _system->delayMillis(sleepMs); _lastRenderTime = _system->getMillis(); @@ -454,24 +468,24 @@ void ToonEngine::doMagnifierEffect() { 11, 11, 11, 11, 12 }; - byte tempBuffer[25*25]; + byte tempBuffer[25 * 25]; for (int32 y = -12; y <= 12; y++) { for (int32 x = -12; x <= 12; x++) { int32 destPitch = surface.pitch; uint8 *curRow = (uint8 *)surface.pixels + (posY + y) * destPitch + (posX + x); - tempBuffer[(y+12) * 25 + x + 12] = *curRow; + tempBuffer[(y + 12) * 25 + x + 12] = *curRow; } } for (int32 y = -12; y <= 12; y++) { for (int32 x = -12; x <= 12; x++) { int32 dist = y * y + x * x; - if (dist > 144) + if (dist > 144) continue; int32 destPitch = surface.pitch; uint8 *curRow = (uint8 *)surface.pixels + (posY + y) * destPitch + (posX + x); int32 lerp = (512 + intSqrt[dist] * 256 / 12); - *curRow = tempBuffer[(y*lerp/1024+12) * 25 + x*lerp/1024 + 12]; + *curRow = tempBuffer[(y * lerp / 1024 + 12) * 25 + x * lerp / 1024 + 12]; } } } @@ -484,7 +498,50 @@ void ToonEngine::copyToVirtualScreen(bool updateScreen) { _cursorAnimationInstance->setPosition(_mouseX - 40 + state()->_currentScrollValue - _cursorOffsetX, _mouseY - 40 - _cursorOffsetY, 0, false); _cursorAnimationInstance->render(); } - _system->copyRectToScreen((byte *)_mainSurface->pixels + state()->_currentScrollValue, 1280, 0, 0, 640, 400); + + // Handle dirty rects here + static int32 lastScroll = 0; + + if (_dirtyAll || _gameState->_currentScrollValue != lastScroll) { + // we have to refresh everything in case of scrolling. + _system->copyRectToScreen((byte *)_mainSurface->pixels + state()->_currentScrollValue, TOON_BACKBUFFER_WIDTH, 0, 0, TOON_SCREEN_WIDTH, TOON_SCREEN_HEIGHT); + } else { + + int32 offX = 0; + for (uint i = 0; i < _oldDirtyRects.size(); i++) { + Common::Rect rect = _oldDirtyRects[i]; + rect.translate(-state()->_currentScrollValue, 0); + offX = 0; + if(rect.right <= 0) + continue; + if (rect.left < 0) { + offX = -rect.left; + rect.left = 0; + } + rect.clip(TOON_SCREEN_WIDTH, TOON_SCREEN_HEIGHT); + if (rect.left >= 0 && rect.top >= 0 && rect.right - rect.left > 0 && rect.bottom - rect.top > 0) { + _system->copyRectToScreen((byte *)_mainSurface->pixels + _oldDirtyRects[i].left + offX + _oldDirtyRects[i].top * TOON_BACKBUFFER_WIDTH, TOON_BACKBUFFER_WIDTH, rect.left , rect.top, rect.right - rect.left, rect.bottom - rect.top); + } + } + + for (uint i = 0; i < _dirtyRects.size(); i++) { + Common::Rect rect = _dirtyRects[i]; + rect.translate(-state()->_currentScrollValue, 0); + offX = 0; + if (rect.right <= 0) + continue; + if (rect.left < 0) { + offX = -rect.left; + rect.left = 0; + } + rect.clip(TOON_SCREEN_WIDTH, TOON_SCREEN_HEIGHT); + if (rect.left >= 0 && rect.top >= 0 && rect.right - rect.left > 0 && rect.bottom - rect.top > 0) { + _system->copyRectToScreen((byte *)_mainSurface->pixels + _dirtyRects[i].left + offX + _dirtyRects[i].top * TOON_BACKBUFFER_WIDTH, TOON_BACKBUFFER_WIDTH, rect.left , rect.top, rect.right - rect.left, rect.bottom - rect.top); + } + } + } + lastScroll = _gameState->_currentScrollValue; + if (updateScreen) { _system->updateScreen(); _shouldQuit = shouldQuit(); // update game quit flag - this shouldn't be called all the time, as it's a virtual function @@ -589,6 +646,7 @@ bool ToonEngine::showMainmenu(bool &loadedGame) { bool musicPlaying = false; _gameState->_inMenu = true; + dirtyAllScreen(); while (!doExit) { clickingOn = MAINMENUHOTSPOT_NONE; @@ -607,7 +665,15 @@ bool ToonEngine::showMainmenu(bool &loadedGame) { } while (!clickRelease) { - mainmenuPicture->draw(*_mainSurface, 0, 0, 0, 0); + + if(_dirtyAll) { + mainmenuPicture->draw(*_mainSurface, 0, 0, 0, 0); + addDirtyRect(0, 0, TOON_SCREEN_WIDTH, TOON_SCREEN_HEIGHT); + } else { + mainmenuPicture->drawWithRectList(*_mainSurface, 0, 0, 0, 0, _dirtyRects); + } + + clearDirtyRects(); for (int entryNr = 0; entryNr < MAINMENU_ENTRYCOUNT; entryNr++) { if (entries[entryNr].menuMask & menuMask) { @@ -719,7 +785,7 @@ Common::Error ToonEngine::run() { g_eventRec.registerRandomSource(_rnd, "toon"); - initGraphics(640, 400, true); + initGraphics(TOON_SCREEN_WIDTH, TOON_SCREEN_HEIGHT, true); init(); // do we need to load directly a game? @@ -783,6 +849,7 @@ ToonEngine::ToonEngine(OSystem *syst, const ADGameDescription *gameDescription) _backupPalette = NULL; _additionalPalette1 = NULL; _additionalPalette2 = NULL; + _additionalPalette2Present = false; _cutawayPalette = NULL; _universalPalette = NULL; _fluxPalette = NULL; @@ -817,7 +884,20 @@ ToonEngine::ToonEngine(OSystem *syst, const ADGameDescription *gameDescription) _inventoryIcons = NULL; _inventoryIconSlots = NULL; _genericTexts = NULL; - _audioManager = NULL; + _audioManager = NULL; + _gameState = NULL; + + _locationDirNotVisited = NULL; + _locationDirVisited = NULL; + _specialInfoLine = NULL; + + for (int i = 0; i < 64; i++) { + _sceneAnimations[i]._active = false; + } + + for (int i = 0; i < 32; i++) { + _characters[i] = NULL; + } memset(&_scriptData, 0, sizeof(EMCData)); @@ -859,7 +939,7 @@ ToonEngine::~ToonEngine() { _mainSurface->free(); delete _mainSurface; } - + delete[] _finalPalette; delete[] _backupPalette; delete[] _additionalPalette1; @@ -888,7 +968,6 @@ ToonEngine::~ToonEngine() { delete _pathFinding; - for (int32 i = 0; i < 64; i++) { if (_sceneAnimations[i]._active) { // see if one character shares this instance @@ -950,8 +1029,6 @@ void ToonEngine::simpleUpdate(bool waitCharacterToTalk) { _animationManager->update(elapsedTime); _audioManager->updateAmbientSFX(); render(); - - } void ToonEngine::fixPaletteEntries(uint8 *palette, int num) { @@ -967,13 +1044,8 @@ void ToonEngine::fixPaletteEntries(uint8 *palette, int num) { // adapted from KyraEngine void ToonEngine::updateAnimationSceneScripts(int32 timeElapsed) { - - static int32 numReentrant = 0; numReentrant++; - -// Strangerke - Commented (not used) -// uint32 nextTime = _system->getMillis() + _tickLength; const int startScript = _lastProcessedSceneScript; _updatingSceneScriptRunFlag = true; @@ -1006,10 +1078,8 @@ void ToonEngine::updateAnimationSceneScripts(int32 timeElapsed) { } while (_lastProcessedSceneScript != startScript && !_shouldQuit); - _updatingSceneScriptRunFlag = false; numReentrant--; - } void ToonEngine::loadScene(int32 SceneId, bool forGameLoad) { @@ -1077,15 +1147,15 @@ void ToonEngine::loadScene(int32 SceneId, bool forGameLoad) { _mouseButton = 0; _lastMouseButton = 0x3; - // load package strcpy(temp, createRoomFilename(Common::String::format("%s.PAK", _gameState->_locations[_gameState->_currentScene]._name).c_str()).c_str()); - resources()->openPackage(temp, true); + resources()->openPackage(temp); strcpy(temp, state()->_locations[SceneId]._name); strcat(temp, ".NPP"); loadAdditionalPalette(temp, 0); + _additionalPalette2Present = false; strcpy(temp, state()->_locations[SceneId]._name); strcat(temp, ".NP2"); loadAdditionalPalette(temp, 1); @@ -1198,6 +1268,9 @@ void ToonEngine::loadScene(int32 SceneId, bool forGameLoad) { state()->_mouseHidden = false; + clearDirtyRects(); + dirtyAllScreen(); + if (!forGameLoad) { _script->start(&_scriptState[0], 0); @@ -1215,7 +1288,7 @@ void ToonEngine::loadScene(int32 SceneId, bool forGameLoad) { _gameState->_nextSpecialEnterX = -1; _gameState->_nextSpecialEnterY = -1; } - + _script->start(&_scriptState[0], 3); while (_script->run(&_scriptState[0])) @@ -1253,10 +1326,11 @@ void ToonEngine::loadAdditionalPalette(Common::String fileName, int32 mode) { case 1: memcpy(_additionalPalette2, palette, 69); fixPaletteEntries(_additionalPalette2, 23); + _additionalPalette2Present = true; break; case 2: - memcpy(_cutawayPalette, palette, 768); - fixPaletteEntries(_cutawayPalette, 256); + memcpy(_cutawayPalette, palette, size); + fixPaletteEntries(_cutawayPalette, size/3); break; case 3: memcpy(_universalPalette, palette, 96); @@ -1290,7 +1364,6 @@ void ToonEngine::initChapter() { _script->unload(&data); setupGeneralPalette(); - } void ToonEngine::loadCursor() { @@ -1412,10 +1485,9 @@ void ToonEngine::clickEvent() { return; } - int32 mouseX = _mouseX; if (_gameState->_inCutaway) { - mouseX += 1280; + mouseX += TOON_BACKBUFFER_WIDTH; } // find hotspot @@ -1443,7 +1515,6 @@ void ToonEngine::clickEvent() { } } - if (!currentHot) { int32 xx, yy; @@ -1471,9 +1542,6 @@ void ToonEngine::clickEvent() { int16 command = currentHot->getData(commandId); int16 argument = currentHot->getData(commandId + 1); int16 priority = currentHot->getPriority(); -// Strangerke - Commented (not used) -// int16 ref = currentHot->getRef(); -// int16 pad1 = currentHot->getData(6); if (!_gameState->_inCutaway && !_gameState->_inCloseUp) { if (leftButton && (currentHot->getData(4) != 2 || _gameState->_mouseState >= 0) && currentHot->getData(5) != -1) { @@ -1515,8 +1583,6 @@ void ToonEngine::clickEvent() { break; case 7: // switch to CloseUp -// Strangerke - Commented (not used) -// int closeup = 1; break; case 8: // face flux @@ -1524,11 +1590,6 @@ void ToonEngine::clickEvent() { break; case 9: case 10: -// Strangerke - Commented (not used) -// if (rand() % 1 == 1) { -// } else { -// } - // setFluxFacingPoint(x,y) sayLines(2, argument); break; case 11: @@ -1552,7 +1613,6 @@ void ToonEngine::clickEvent() { int32 val = _scriptState[_currentScriptRegion].regs[4]; currentHot->setData(4, currentHot->getData(4) & val); } - } void ToonEngine::selectHotspot() { @@ -1564,7 +1624,7 @@ void ToonEngine::selectHotspot() { int32 mouseX = _mouseX; if (_gameState->_inCutaway) - mouseX += 1280; + mouseX += TOON_BACKBUFFER_WIDTH; if (_gameState->_sackVisible) { if (_mouseX > 0 && _mouseX < 40 && _mouseY > 356 && _mouseY < 396) { @@ -1722,7 +1782,6 @@ void ToonEngine::exitScene() { strcpy(temp, createRoomFilename(Common::String::format("%s.PAK", _gameState->_locations[_gameState->_currentScene]._name).c_str()).c_str()); resources()->closePackage(temp); - _drew->stopWalk(); _flux->stopWalk(); @@ -1734,9 +1793,10 @@ void ToonEngine::flipScreens() { _gameState->_inCloseUp = !_gameState->_inCloseUp; if (_gameState->_inCloseUp) { - _gameState->_currentScrollValue = 640; + _gameState->_currentScrollValue = TOON_SCREEN_WIDTH; setPaletteEntries(_cutawayPalette, 1, 128); - setPaletteEntries(_additionalPalette2, 232, 23); + if (_additionalPalette2Present) + setPaletteEntries(_additionalPalette2, 232, 23); } else { _gameState->_currentScrollValue = 0; _currentPicture->setupPalette(); @@ -1750,9 +1810,9 @@ void ToonEngine::fadeIn(int32 numFrames) { uint8 vmpalette[3 * 256]; for (int32 i = 0; i < 256; i++) { - vmpalette[i*3+0] = f * _finalPalette[i*3+0] / (numFrames - 1); - vmpalette[i*3+1] = f * _finalPalette[i*3+1] / (numFrames - 1); - vmpalette[i*3+2] = f * _finalPalette[i*3+2] / (numFrames - 1); + vmpalette[i * 3 + 0] = f * _finalPalette[i * 3 + 0] / (numFrames - 1); + vmpalette[i * 3 + 1] = f * _finalPalette[i * 3 + 1] / (numFrames - 1); + vmpalette[i * 3 + 2] = f * _finalPalette[i * 3 + 2] / (numFrames - 1); } _system->getPaletteManager()->setPalette(vmpalette, 0, 256); _system->updateScreen(); @@ -1768,9 +1828,9 @@ void ToonEngine::fadeOut(int32 numFrames) { for (int32 f = 0; f < numFrames; f++) { uint8 vmpalette[3 * 256]; for (int32 i = 0; i < 256; i++) { - vmpalette[i*3+0] = (numFrames - f - 1) * oldpalette[i*3+0] / (numFrames - 1); - vmpalette[i*3+1] = (numFrames - f - 1) * oldpalette[i*3+1] / (numFrames - 1); - vmpalette[i*3+2] = (numFrames - f - 1) * oldpalette[i*3+2] / (numFrames - 1); + vmpalette[i * 3 + 0] = (numFrames - f - 1) * oldpalette[i * 3 + 0] / (numFrames - 1); + vmpalette[i * 3 + 1] = (numFrames - f - 1) * oldpalette[i * 3 + 1] / (numFrames - 1); + vmpalette[i * 3 + 2] = (numFrames - f - 1) * oldpalette[i * 3 + 2] / (numFrames - 1); } _system->getPaletteManager()->setPalette(vmpalette, 0, 256); _system->updateScreen(); @@ -1824,11 +1884,11 @@ int32 ToonEngine::getScaleAtPoint(int32 x, int32 y) { return 1024; // clamp values - x = MIN<int32>(1279, MAX<int32>(0, x)); - y = MIN<int32>(399, MAX<int32>(0, y)); + x = MIN<int32>(TOON_BACKBUFFER_WIDTH - 1, MAX<int32>(0, x)); + y = MIN<int32>(TOON_BACKBUFFER_HEIGHT - 1, MAX<int32>(0, y)); int32 maskData = _currentMask->getData(x, y) & 0x1f; - return _roomScaleData[maskData+2] * 1024 / 100; + return _roomScaleData[maskData + 2] * 1024 / 100; } int32 ToonEngine::getLayerAtPoint(int32 x, int32 y) { @@ -1836,11 +1896,11 @@ int32 ToonEngine::getLayerAtPoint(int32 x, int32 y) { return 0; // clamp values - x = MIN<int32>(1279, MAX<int32>(0, x)); - y = MIN<int32>(399, MAX<int32>(0, y)); + x = MIN<int32>(TOON_BACKBUFFER_WIDTH - 1, MAX<int32>(0, x)); + y = MIN<int32>(TOON_BACKBUFFER_HEIGHT - 1, MAX<int32>(0, y)); int32 maskData = _currentMask->getData(x, y) & 0x1f; - return _roomScaleData[maskData+130] << 5; + return _roomScaleData[maskData + 130] << 5; } int32 ToonEngine::getZAtPoint(int32 x, int32 y) { @@ -1917,25 +1977,11 @@ void ToonEngine::sayLines(int numLines, int dialogId) { if (oldShowMouse) Game.MouseHiddenCount = 0; #endif - } int32 ToonEngine::simpleCharacterTalk(int32 dialogid) { int32 myId = 0; -// Strangerke - Commented (not used) -#if 0 - char *myLine; - if (dialogid < 1000) { - myLine = _roomTexts->getText(dialogid); - myId = dialogid; - } else { - myLine = _genericTexts->getText(dialogid - 1000); - myId = dialogid - 1000; - } - debugC(0, 0xfff, "Talker = %d will say '%s' \n", READ_LE_UINT16(c - 2), myLine); -#endif - if (_audioManager->voiceStillPlaying()) _audioManager->stopCurrentVoice(); @@ -1952,14 +1998,6 @@ int32 ToonEngine::simpleCharacterTalk(int32 dialogid) { void ToonEngine::playTalkAnimOnCharacter(int32 animID, int32 characterId, bool talker) { if (animID || talker) { -// Strangerke - Commented (not used) -#if 0 - if (_gameState->_inCutaway || _gameState->_inInventory) { - if (talker) { - // character talks - } - } else -#endif if (characterId == 0) { _drew->playAnim(animID, 0, (talker ? 8 : 0) + 2); } else if (characterId == 1) { @@ -2009,7 +2047,6 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) { _gameState->_mouseHidden = true; } - // get what is before the string int a = READ_LE_UINT16(myLine - 2); char *b = myLine - 2 - 4 * a; @@ -2020,14 +2057,6 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) { char *e = c - 2 - 4 * numParticipants; READ_LE_UINT16(e); -// Strangerke - Commented (not used) -// char *g = e - 2 * f; - - // flag as talking -// Strangerke - Commented (not used) -// char *h = c; - - // if one voice is still playing, wait ! if (blocking) { while (_audioManager->voiceStillPlaying() && !_shouldQuit) @@ -2085,8 +2114,6 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) { _currentTextLine = myLine; _currentTextLineCharacterId = talkerId; _currentTextLineId = dialogid; - - } else { Character *character = getCharacterById(talkerId); if (character) @@ -2095,7 +2122,6 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) { debugC(0, 0xfff, "Talker = %d (num participants : %d) will say '%s'", (int)talkerId , (int)numParticipants, myLine); - getTextPosition(talkerId, &_currentTextLineX, &_currentTextLineY); if (dialogid < 1000) { @@ -2115,8 +2141,6 @@ int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) { if (character) character->setTalking(false); } - - return 1; } @@ -2131,7 +2155,7 @@ void ToonEngine::haveAConversation(int32 convId) { _gameState->_currentConversationId = convId; // change the music to the "conversation" music if needed. - playRoomMusic(); + playRoomMusic(); if (conv->_enable) { // fix dialog script based on new flags @@ -2149,7 +2173,6 @@ void ToonEngine::haveAConversation(int32 convId) { doFrame(); } - _mouseButton = 0; _gameState->_firstConverstationLine = true; @@ -2178,11 +2201,13 @@ void ToonEngine::haveAConversation(int32 convId) { a++; } } - if (_shouldQuit) return; + + if (_shouldQuit) + return; + _gameState->_showConversationIcons = false; _gameState->_mouseHidden = 1; - if (selected < 0 || selected == 1 || selected == 3) { if (_gameState->_firstConverstationLine) processConversationClick(conv, 3); @@ -2194,9 +2219,6 @@ void ToonEngine::haveAConversation(int32 convId) { } } -// Strangerke - Commented (not used) -// int cur = 0; - for (int i = 0; i < 10; i++) { if (conv->state[i]._data2 == 2) { if (i != 3) @@ -2211,8 +2233,7 @@ void ToonEngine::haveAConversation(int32 convId) { _gameState->_sackVisible = true; // switch back to original music - playRoomMusic(); - + playRoomMusic(); } void ToonEngine::drawConversationIcons() { @@ -2334,7 +2355,6 @@ retry: break; } } - } // hardcoded conversation flag to know if one dialogue icon must be displayed or not @@ -2495,7 +2515,7 @@ int32 ToonEngine::runConversationCommand(int16 **command) { int16 *v5 = *command; int v2 = READ_LE_INT16(v5); - int v4 = READ_LE_INT16(v5+1); + int v4 = READ_LE_INT16(v5 + 1); int result = v2 - 100; switch (v2) { case 100: @@ -2528,9 +2548,6 @@ int32 ToonEngine::runConversationCommand(int16 **command) { } int32 ToonEngine::waitTicks(int32 numTicks, bool breakOnMouseClick) { -// Strangerke - Commented (not used) -// Common::EventManager *_event = _system->getEventManager(); - uint32 nextTime = _system->getMillis() + numTicks * _tickLength; while (_system->getMillis() < nextTime || numTicks == -1) { //if (!_animationSceneScriptRunFlag) @@ -2549,7 +2566,13 @@ void ToonEngine::renderInventory() { if (!_gameState->_inInventory) return; - _inventoryPicture->draw(*_mainSurface, 0, 0, 0, 0); + if (!_dirtyAll) { + _inventoryPicture->drawWithRectList(*_mainSurface, 0, 0, 0, 0, _dirtyRects); + } else { + _inventoryPicture->draw(*_mainSurface, 0, 0, 0, 0); + _dirtyRects.push_back(Common::Rect(0, 0, TOON_SCREEN_WIDTH, TOON_SCREEN_HEIGHT)); + } + clearDirtyRects(); // draw items on screen for (int32 i = 0; i < _gameState->_numInventoryItems; i++) { @@ -2577,13 +2600,13 @@ void ToonEngine::renderInventory() { int32 ToonEngine::showInventory() { int32 oldScrollValue = _gameState->_currentScrollValue; -// Strangerke - Commented (not used) -// Common::EventManager *_event = _system->getEventManager(); + delete _inventoryPicture; _inventoryPicture = new Picture(this); fadeOut(5); _inventoryPicture->loadPicture("SACK128.CPS", true); _inventoryPicture->setupPalette(); + dirtyAllScreen(); if (_gameState->_mouseState >= 0) { setCursor(_gameState->_mouseState, true, -18, -14); @@ -2632,7 +2655,6 @@ int32 ToonEngine::showInventory() { int32 modItem = getSpecialInventoryItem(item); if (modItem) { - if (modItem == -1) { _gameState->_mouseState = item; _gameState->_inventory[foundObj] = 0; @@ -2681,7 +2703,7 @@ int32 ToonEngine::showInventory() { } _gameState->_currentScrollValue = oldScrollValue; - _gameState->_inInventory = false; + _gameState->_inInventory = false; _mouseButton = 0; _lastMouseButton = 0x3; @@ -2697,6 +2719,7 @@ int32 ToonEngine::showInventory() { setupGeneralPalette(); } flushPalette(); + dirtyAllScreen(); _firstFrame = true; return 0; @@ -2771,6 +2794,7 @@ void ToonEngine::showCutaway(Common::String cutawayPicture) { _currentCutaway->setupPalette(); _oldScrollValue = _gameState->_currentScrollValue; _gameState->_currentScrollValue = 0; + dirtyAllScreen(); flushPalette(); } @@ -2781,6 +2805,7 @@ void ToonEngine::hideCutaway() { _gameState->_currentScrollValue = _oldScrollValue; _currentCutaway = 0; _currentPicture->setupPalette(); + dirtyAllScreen(); flushPalette(); } @@ -2805,7 +2830,7 @@ void ToonEngine::rearrangeInventory() { if (_gameState->_inventory[i] == 0) { // move all the following items from one for (int32 j = i + 1; j < _gameState->_numInventoryItems; j++) { - _gameState->_inventory[j-1] = _gameState->_inventory[j]; + _gameState->_inventory[j - 1] = _gameState->_inventory[j]; } _gameState->_numInventoryItems--; } @@ -2819,14 +2844,14 @@ void ToonEngine::newGame() { addItemToInventory(67); addItemToInventory(11); addItemToInventory(19); - loadScene(_gameState->_currentScene); + loadScene(22); + //loadScene(_gameState->_currentScene); } else { //loadScene(4); loadScene(_gameState->_currentScene); } } - void ToonEngine::playSFX(int32 id, int32 volume) { if (id < 0) _audioManager->playSFX(-id + 1, volume, true); @@ -2852,7 +2877,7 @@ void ToonEngine::getTextPosition(int32 characterId, int32 *retX, int32 *retY) { // drew int32 x = _drew->getX(); int32 y = _drew->getY(); - if (x >= _gameState->_currentScrollValue && x <= _gameState->_currentScrollValue + 640) { + if (x >= _gameState->_currentScrollValue && x <= _gameState->_currentScrollValue + TOON_SCREEN_WIDTH) { if (!_gameState->_inCutaway && !_gameState->_inInventory) { *retX = x; *retY = y - ((_drew->getScale() * 256 / 1024) >> 1) - 45; @@ -2862,7 +2887,7 @@ void ToonEngine::getTextPosition(int32 characterId, int32 *retX, int32 *retY) { // flux int32 x = _flux->getX(); int32 y = _flux->getY(); - if (x >= _gameState->_currentScrollValue && x <= _gameState->_currentScrollValue + 640) { + if (x >= _gameState->_currentScrollValue && x <= _gameState->_currentScrollValue + TOON_SCREEN_WIDTH) { if (!_gameState->_inCutaway) { *retX = x; *retY = y - ((_drew->getScale() * 100 / 1024) >> 1) - 30; @@ -2892,7 +2917,7 @@ void ToonEngine::getTextPosition(int32 characterId, int32 *retX, int32 *retY) { Character *character = getCharacterById(characterId); if (character && !_gameState->_inCutaway) { if (character->getAnimationInstance()) { - if (character->getX() >= _gameState->_currentScrollValue && character->getX() <= _gameState->_currentScrollValue + 640) { + if (character->getX() >= _gameState->_currentScrollValue && character->getX() <= _gameState->_currentScrollValue + TOON_SCREEN_WIDTH) { int32 x1, y1, x2, y2; character->getAnimationInstance()->getRect(&x1, &y1, &x2, &y2); *retX = (x1 + x2) / 2; @@ -2921,7 +2946,7 @@ void ToonEngine::drawConversationLine() { } void ToonEngine::pauseEngineIntern(bool pause) { - + Engine::pauseEngineIntern(pause); static int32 pauseStart = 0; @@ -3013,7 +3038,6 @@ bool ToonEngine::saveGame(int32 slot, Common::String saveGameDesc) { saveFile->writeUint32BE(saveDate); saveFile->writeUint16BE(saveTime); - // save global state _gameState->save(saveFile); _gameState->saveConversations(saveFile); @@ -3040,7 +3064,6 @@ bool ToonEngine::saveGame(int32 slot, Common::String saveGameDesc) { _sceneAnimations[i].save(this, saveFile); } - for (int32 i = 0; i < 8; i++) { if (_characters[i]) { saveFile->writeSByte(i); @@ -3120,7 +3143,7 @@ bool ToonEngine::loadGame(int32 slot) { _sceneAnimationScripts[i]._frozen = loadFile->readByte(); _sceneAnimationScripts[i]._frozenForConversation = false; int32 oldTimer = loadFile->readSint32BE(); - _sceneAnimationScripts[i]._lastTimer = MAX<int32>(0,oldTimer + timerDiff); + _sceneAnimationScripts[i]._lastTimer = MAX<int32>(0, oldTimer + timerDiff); _script->loadState(&_sceneAnimationScripts[i]._state, loadFile); } @@ -3159,7 +3182,7 @@ bool ToonEngine::loadGame(int32 slot) { // load "command buffer" int32 size = loadFile->readSint16BE(); if (size) { - uint8 *buf = new uint8[size+2]; + uint8 *buf = new uint8[size + 2]; loadFile->read(buf, size + 2); Common::MemoryReadStream rStr(buf, size + 2); @@ -3278,10 +3301,6 @@ void ToonEngine::initCharacter(int32 characterId, int32 animScriptId, int32 scen return; } -// Strangerke - Commented (not used) -// if (_characters[characterIndex]) -// delete current char - _characters[characterIndex] = new Character(this); _characters[characterIndex]->setId(characterId); _characters[characterIndex]->setAnimScript(animScriptId); @@ -3405,6 +3424,7 @@ void ToonEngine::viewInventoryItem(Common::String str, int32 lineId, int32 itemD Picture *pic = new Picture(this); pic->loadPicture(str, false); pic->setupPalette(); + dirtyAllScreen(); flushPalette(); if (lineId) { @@ -3428,7 +3448,13 @@ void ToonEngine::viewInventoryItem(Common::String str, int32 lineId, int32 itemD break; } - pic->draw(*_mainSurface, 0, 0, 0, 0); + if (!_dirtyAll) { + pic->drawWithRectList(*_mainSurface, 0, 0, 0, 0, _dirtyRects); + } else { + pic->draw(*_mainSurface, 0, 0, 0, 0); + _dirtyRects.push_back(Common::Rect(0, 0, TOON_SCREEN_WIDTH, TOON_SCREEN_HEIGHT)); + } + clearDirtyRects(); drawConversationLine(); if (!_audioManager->voiceStillPlaying()) { @@ -3447,11 +3473,11 @@ void ToonEngine::viewInventoryItem(Common::String str, int32 lineId, int32 itemD } fadeOut(5); + dirtyAllScreen(); restorePalette(); _firstFrame = true; _gameState->_currentScrollValue = oldScrollValue; delete pic; - } int32 ToonEngine::handleInventoryOnInventory(int32 itemDest, int32 itemSrc) { @@ -3493,7 +3519,7 @@ int32 ToonEngine::handleInventoryOnInventory(int32 itemDest, int32 itemSrc) { case 11: if (itemSrc == 0xb) { _gameState->_mouseState = -1; - replaceItemFromInventory(11,12); + replaceItemFromInventory(11, 12); setCursor(0, false, 0, 0); rearrangeInventory(); return 1; @@ -4506,9 +4532,9 @@ void ToonEngine::createShadowLUT() { for (int32 i = 0; i < 255; i++) { // goal color - uint32 destR = _finalPalette[i*3+0] * scaleNum / scaleDenom; - uint32 destG = _finalPalette[i*3+1] * scaleNum / scaleDenom; - uint32 destB = _finalPalette[i*3+2] * scaleNum / scaleDenom; + uint32 destR = _finalPalette[i * 3 + 0] * scaleNum / scaleDenom; + uint32 destG = _finalPalette[i * 3 + 1] * scaleNum / scaleDenom; + uint32 destB = _finalPalette[i * 3 + 2] * scaleNum / scaleDenom; // search only in the "picture palette" which is in colors 1-128 and 200-255 int32 colorDist = 0xffffff; @@ -4516,9 +4542,9 @@ void ToonEngine::createShadowLUT() { for (int32 c = 1; c < 129; c++) { - int32 diffR = _finalPalette[c*3+0] - destR; - int32 diffG = _finalPalette[c*3+1] - destG; - int32 diffB = _finalPalette[c*3+2] - destB; + int32 diffR = _finalPalette[c * 3 + 0] - destR; + int32 diffG = _finalPalette[c * 3 + 1] - destG; + int32 diffB = _finalPalette[c * 3 + 2] - destB; if (colorDist > diffR * diffR + diffG * diffG + diffB * diffB) { colorDist = diffR * diffR + diffG * diffG + diffB * diffB; @@ -4528,9 +4554,9 @@ void ToonEngine::createShadowLUT() { for (int32 c = 200; c < 256; c++) { - int32 diffR = _finalPalette[c*3+0] - destR; - int32 diffG = _finalPalette[c*3+1] - destG; - int32 diffB = _finalPalette[c*3+2] - destB; + int32 diffR = _finalPalette[c * 3 + 0] - destR; + int32 diffG = _finalPalette[c * 3 + 1] - destG; + int32 diffB = _finalPalette[c * 3 + 2] - destB; if (colorDist > diffR * diffR + diffG * diffG + diffB * diffB) { colorDist = diffR * diffR + diffG * diffG + diffB * diffB; @@ -4660,6 +4686,47 @@ void ToonEngine::playRoomMusic() { _audioManager->playMusic(_gameState->_locations[_gameState->_currentScene]._name, _gameState->_locations[_gameState->_currentScene]._music); } +void ToonEngine::dirtyAllScreen() +{ + _dirtyRects.clear(); + _dirtyAll = true; +} + +void ToonEngine::addDirtyRect( int32 left, int32 top, int32 right, int32 bottom ) { + left = MIN<int32>(MAX<int32>(left, 0), TOON_BACKBUFFER_WIDTH); + right = MIN<int32>(MAX<int32>(right, 0), TOON_BACKBUFFER_WIDTH); + top = MIN<int32>(MAX<int32>(top, 0), TOON_BACKBUFFER_HEIGHT); + bottom = MIN<int32>(MAX<int32>(bottom, 0), TOON_BACKBUFFER_HEIGHT); + + Common::Rect rect(left, top, right, bottom); + + if (bottom - top <= 0 || right - left <= 0) + return; + + for (uint32 i = 0; i < _dirtyRects.size(); i++) { + if (_dirtyRects[i].contains(rect)) + return; + if (rect.contains(_dirtyRects[i])) { + _dirtyRects.remove_at(i); + i--; + } + } + + // check also in the old rect (of the old frame) + for (int32 i = _oldDirtyRects.size() - 1 ; i >= 0; i--) { + if (rect.contains(_oldDirtyRects[i])) { + _oldDirtyRects.remove_at(i); + } + } + + _dirtyRects.push_back(rect); +} + +void ToonEngine::clearDirtyRects() { + _oldDirtyRects = _dirtyRects; + _dirtyRects.clear(); + _dirtyAll = false; +} void SceneAnimation::save(ToonEngine *vm, Common::WriteStream *stream) { stream->writeByte(_active); stream->writeSint32BE(_id); @@ -4686,7 +4753,6 @@ void SceneAnimation::load(ToonEngine *vm, Common::ReadStream *stream) { _active = stream->readByte(); _id = stream->readSint32BE(); - if (!_active) return; diff --git a/engines/toon/toon.h b/engines/toon/toon.h index f3370aed5e..373437d658 100644 --- a/engines/toon/toon.h +++ b/engines/toon/toon.h @@ -52,6 +52,11 @@ class MemoryWriteStreamDynamic; #define TOON_SAVEGAME_VERSION 4 #define DATAALIGNMENT 4 +#define TOON_SCREEN_WIDTH 640 +#define TOON_SCREEN_HEIGHT 400 +#define TOON_BACKBUFFER_WIDTH 1280 +#define TOON_BACKBUFFER_HEIGHT 400 + /** * This is the namespace of the Toon engine. * @@ -206,8 +211,6 @@ public: void waitForScriptStep(); void doMagnifierEffect(); - - bool canSaveGameStateCurrently(); bool canLoadGameStateCurrently(); void pauseEngineIntern(bool pause); @@ -334,6 +337,10 @@ public: (f == kSupportsSavingDuringRuntime); } + void dirtyAllScreen(); + void addDirtyRect(int32 left, int32 top, int32 right, int32 bottom); + void clearDirtyRects(); + protected: OSystem *_system; int32 _tickLength; @@ -345,6 +352,7 @@ protected: uint8 *_backupPalette; uint8 *_additionalPalette1; uint8 *_additionalPalette2; + bool _additionalPalette2Present; uint8 *_cutawayPalette; uint8 *_universalPalette; uint8 *_fluxPalette; @@ -371,6 +379,11 @@ protected: bool _updatingSceneScriptRunFlag; Graphics::Surface *_mainSurface; + Common::Array<Common::Rect> _dirtyRects; + Common::Array<Common::Rect> _oldDirtyRects; + + bool _dirtyAll; + AnimationInstance *_cursorAnimationInstance; Animation *_cursorAnimation; |