From 5f552c9446ddf3f02ec99ff6902822d66d2cc955 Mon Sep 17 00:00:00 2001 From: Thomas Fach-Pedersen Date: Tue, 28 Mar 2017 17:50:04 +0200 Subject: BLADERUNNER: Implement ZBuffer class --- engines/bladerunner/actor.cpp | 23 +++- engines/bladerunner/actor.h | 4 +- engines/bladerunner/bladerunner.cpp | 30 ++-- engines/bladerunner/bladerunner.h | 8 +- engines/bladerunner/item.cpp | 67 +++++---- engines/bladerunner/item.h | 2 +- engines/bladerunner/item_pickup.cpp | 7 +- engines/bladerunner/items.cpp | 6 +- engines/bladerunner/module.mk | 3 +- engines/bladerunner/mouse.cpp | 3 +- engines/bladerunner/scene.cpp | 6 +- engines/bladerunner/scene.h | 2 +- engines/bladerunner/script/scene/rc01.cpp | 6 +- engines/bladerunner/vqa_decoder.cpp | 79 ++--------- engines/bladerunner/vqa_decoder.h | 8 +- engines/bladerunner/vqa_player.cpp | 6 +- engines/bladerunner/vqa_player.h | 3 +- engines/bladerunner/zbuffer.cpp | 221 ++++++++++++++++++++++++++++++ engines/bladerunner/zbuffer.h | 87 ++++++++++++ 19 files changed, 422 insertions(+), 149 deletions(-) create mode 100644 engines/bladerunner/zbuffer.cpp create mode 100644 engines/bladerunner/zbuffer.h diff --git a/engines/bladerunner/actor.cpp b/engines/bladerunner/actor.cpp index 330ed58ddf..f783791ba1 100644 --- a/engines/bladerunner/actor.cpp +++ b/engines/bladerunner/actor.cpp @@ -40,6 +40,7 @@ #include "bladerunner/slice_animations.h" #include "bladerunner/slice_renderer.h" #include "bladerunner/waypoints.h" +#include "bladerunner/zbuffer.h" namespace BladeRunner { @@ -534,7 +535,7 @@ bool Actor::loopWalkToWaypoint(int waypointId, int destinationOffset, int a3, bo return loopWalk(waypointPosition, destinationOffset, a3, run, _position, 0.0f, 24.0f, a5, isRunning, false); } -bool Actor::tick(bool forceDraw) { +bool Actor::tick(bool forceDraw, Common::Rect *screenRect) { int remain = 0; bool needsUpdate = false; if (_fps > 0) { @@ -639,7 +640,13 @@ bool Actor::tick(bool forceDraw) { } } - draw(); + bool isVisible = false; + if (!_isInvisible) { + isVisible = draw(screenRect); + if (isVisible) { + _screenRectangle = *screenRect; + } + } if (needsUpdate) { int nextFrameTime = remain + _frame_ms; @@ -654,18 +661,20 @@ bool Actor::tick(bool forceDraw) { this->setFacing(this->_targetFacing, false); } } - return false; + return isVisible; } -void Actor::draw() { +bool Actor::draw(Common::Rect *screenRect) { Vector3 drawPosition(_position.x, -_position.z, _position.y + 2.0); float drawAngle = M_PI - _facing * (M_PI / 512.0f); float drawScale = _scale; // TODO: Handle SHORTY mode - _vm->_sliceRenderer->drawInWorld(_animationId, _animationFrame, drawPosition, drawAngle, drawScale, _vm->_surface2, _vm->_zBuffer2); - _vm->_sliceRenderer->getScreenRectangle(&_screenRectangle, _animationId, _animationFrame, drawPosition, drawAngle, drawScale); + _vm->_sliceRenderer->drawInWorld(_animationId, _animationFrame, drawPosition, drawAngle, drawScale, _vm->_surface2, _vm->_zbuffer->getData()); + _vm->_sliceRenderer->getScreenRectangle(screenRect, _animationId, _animationFrame, drawPosition, drawAngle, drawScale); + + return !screenRect->isEmpty(); } int Actor::getSetId() { @@ -1011,7 +1020,7 @@ void Actor::setGoal(int goalNumber) { _goalNumber = goalNumber; if (goalNumber == oldGoalNumber) { return; - } + } _vm->_aiScripts->GoalChanged(_id, oldGoalNumber, goalNumber); _vm->_sceneScript->ActorChangedGoal(_id, goalNumber, oldGoalNumber, _vm->_scene->getSetId() == _setId); diff --git a/engines/bladerunner/actor.h b/engines/bladerunner/actor.h index d924730b4b..40bcae5b70 100644 --- a/engines/bladerunner/actor.h +++ b/engines/bladerunner/actor.h @@ -149,8 +149,8 @@ public: bool loopWalkToWaypoint(int waypointId, int destinationOffset, int a3, bool run, bool a5, bool *isRunning); bool loopWalkToXYZ(const Vector3 &destination, int destinationOffset, bool a3, bool run, bool a5, bool *isRunning); - bool tick(bool forceUpdate); - void draw(); + bool tick(bool forceUpdate, Common::Rect *screenRect); + bool draw(Common::Rect *screenRect); int getSetId(); void setSetId(int setId); diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp index 78239adbbb..ec54a7c76a 100644 --- a/engines/bladerunner/bladerunner.cpp +++ b/engines/bladerunner/bladerunner.cpp @@ -52,6 +52,7 @@ #include "bladerunner/text_resource.h" #include "bladerunner/vqa_decoder.h" #include "bladerunner/waypoints.h" +#include "bladerunner/zbuffer.h" #include "common/array.h" #include "common/error.h" @@ -61,7 +62,7 @@ #include "engines/util.h" #include "graphics/pixelformat.h" -#include "suspects_database.h" +#include "suspects_database.h" namespace BladeRunner { @@ -112,8 +113,7 @@ BladeRunnerEngine::~BladeRunnerEngine() { // _surface1.free(); // _surface2.free(); - // delete[] _zBuffer1; - // delete[] _zBuffer2; + delete _zbuffer; delete _itemPickup; delete _obstacles; @@ -232,9 +232,8 @@ bool BladeRunnerEngine::startup(bool hasSavegames) { // TODO: Video overlays - // TODO: Proper ZBuf class - _zBuffer1 = new uint16[640 * 480]; - _zBuffer2 = new uint16[640 * 480]; + _zbuffer = new ZBuffer(); + _zbuffer->init(640, 480); int actorCount = (int)_gameInfo->getActorCount(); assert(actorCount < ACTORS_COUNT); @@ -500,12 +499,8 @@ void BladeRunnerEngine::shutdown() { _playerActor = nullptr; - // TODO: Delete proper ZBuf class - delete[] _zBuffer1; - _zBuffer1 = nullptr; - - delete[] _zBuffer2; - _zBuffer2 = nullptr; + delete _zbuffer; + _zbuffer = nullptr; delete _gameInfo; _gameInfo = nullptr; @@ -597,19 +592,19 @@ void BladeRunnerEngine::gameTick() { _sceneScript->PlayerWalkedIn(); } // TODO: Gun range announcements - // TODO: ZBUF repair dirty rects + + _zbuffer->clean(); _ambientSounds->tick(); bool backgroundChanged = false; - int frame = _scene->advanceFrame(_surface1, _zBuffer1); + int frame = _scene->advanceFrame(_surface1); if (frame >= 0) { _sceneScript->SceneFrameAdvanced(frame); backgroundChanged = true; } (void)backgroundChanged; _surface2.copyFrom(_surface1); - memcpy(_zBuffer2, _zBuffer1, 640 * 480 * 2); #if 0 { @@ -641,7 +636,10 @@ void BladeRunnerEngine::gameTick() { for (int i = 0, end = _gameInfo->getActorCount(); i != end; ++i) { if (_actors[i]->getSetId() == setId) { if (i == 0 || i == 15 || i == 23) { // Currently limited to McCoy, Runciter and Officer Leroy - _actors[i]->tick(backgroundChanged); + Common::Rect screenRect; + if (_actors[i]->tick(backgroundChanged, &screenRect)) { + _zbuffer->mark(screenRect); + } } } } diff --git a/engines/bladerunner/bladerunner.h b/engines/bladerunner/bladerunner.h index 87bb7dbeca..fd62f35bed 100644 --- a/engines/bladerunner/bladerunner.h +++ b/engines/bladerunner/bladerunner.h @@ -63,6 +63,7 @@ class SliceRenderer; class TextResource; class View; class Waypoints; +class ZBuffer; #define ACTORS_COUNT 100 #define VOICEOVER_ACTOR (ACTORS_COUNT - 1) @@ -72,7 +73,7 @@ public: bool _gameIsRunning; bool _windowIsActive; int _playerLosesControlCounter; - + ADQ *_adq; AIScripts *_aiScripts; AmbientSounds *_ambientSounds; @@ -99,7 +100,7 @@ public: View *_view; Waypoints *_waypoints; int *_gameVars; - + TextResource *_textActorNames; TextResource *_textCrimes; TextResource *_textCluetype; @@ -117,8 +118,7 @@ public: Graphics::Surface _surface1; Graphics::Surface _surface2; - uint16 *_zBuffer1; - uint16 *_zBuffer2; + ZBuffer *_zbuffer; Common::RandomSource _rnd; diff --git a/engines/bladerunner/item.cpp b/engines/bladerunner/item.cpp index b8d4cd2c1f..3ad2868c51 100644 --- a/engines/bladerunner/item.cpp +++ b/engines/bladerunner/item.cpp @@ -25,6 +25,7 @@ #include "bladerunner/bladerunner.h" #include "bladerunner/slice_renderer.h" +#include "bladerunner/zbuffer.h" namespace BladeRunner { @@ -75,40 +76,54 @@ bool Item::isTargetable() { return _isTargetable; } -void Item::tick(bool special) { - if (_isVisible) { - Vector3 postition(_position.x, -_position.z, _position.y); - int animationId = _animationId + (special ? 1 : 0); - _vm->_sliceRenderer->drawInWorld(animationId, 0, postition, M_PI - _angle, 1.0f, _vm->_surface2, _vm->_zBuffer2); - _vm->_sliceRenderer->getScreenRectangle(&_screenRectangle, animationId, 0, postition, M_PI - _angle, 1.0f); +bool Item::tick(Common::Rect *screenRect, bool special) { + if (!_isVisible) { + *screenRect = Common::Rect(); + return false; + } - if (_isSpinning) { - _facing += _facingChange; + bool isVisible = false; - if (_facing >= 1024) { - _facing -= 1024; - } else if (_facing < 0) { - _facing += 1024; - } - _angle = _facing * (M_PI / 512.0f); + Vector3 position(_position.x, -_position.z, _position.y); + int animationId = _animationId + (special ? 1 : 0); + _vm->_sliceRenderer->drawInWorld(animationId, 0, position, M_PI - _angle, 1.0f, _vm->_surface2, _vm->_zbuffer->getData()); + _vm->_sliceRenderer->getScreenRectangle(&_screenRectangle, animationId, 0, position, M_PI - _angle, 1.0f); + + if (!_screenRectangle.isEmpty()) { + *screenRect = _screenRectangle; + isVisible = true; + } else { + *screenRect = Common::Rect(); + } + + if (_isSpinning) { + _facing += _facingChange; + if (_facing >= 1024) { + _facing -= 1024; + } else if (_facing < 0) { + _facing += 1024; + } + _angle = _facing * (M_PI / 512.0f); + + if (_facingChange > 0) { + _facingChange = _facingChange - 20; + if (_facingChange < 0) { + _facingChange = 0; + _isSpinning = false; + } + } else if (_facingChange < 0) { + _facingChange = _facingChange + 20; if (_facingChange > 0) { - _facingChange = _facingChange - 20; - if (_facingChange < 0) { - _facingChange = 0; - _isSpinning = false; - } - } else if (_facingChange < 0) { - _facingChange = _facingChange + 20; - if (_facingChange > 0) { - _facingChange = 0; - _isSpinning = false; - } - } else { + _facingChange = 0; _isSpinning = false; } + } else { + _isSpinning = false; } } + + return isVisible; } void Item::setXYZ(Vector3 position) { diff --git a/engines/bladerunner/item.h b/engines/bladerunner/item.h index 0c74bf3be3..76d49ac614 100644 --- a/engines/bladerunner/item.h +++ b/engines/bladerunner/item.h @@ -68,7 +68,7 @@ public: void getWidthHeight(int *width, int *height); bool isTargetable(); - void tick(bool special); + bool tick(Common::Rect *screenRect, bool special); void setup(int itemId, int setId, int animationId, Vector3 position, int facing, int height, int width, bool isTargetableFlag, bool isVisibleFlag, bool isPoliceMazeEnemyFlag); }; diff --git a/engines/bladerunner/item_pickup.cpp b/engines/bladerunner/item_pickup.cpp index aa293c2b9b..7549c8db01 100644 --- a/engines/bladerunner/item_pickup.cpp +++ b/engines/bladerunner/item_pickup.cpp @@ -26,8 +26,9 @@ #include "bladerunner/audio_player.h" #include "bladerunner/gameinfo.h" -#include "slice_animations.h" -#include "slice_renderer.h" +#include "bladerunner/slice_animations.h" +#include "bladerunner/slice_renderer.h" +#include "bladerunner/zbuffer.h" namespace BladeRunner { @@ -103,6 +104,6 @@ void ItemPickup::draw() { return; } - _vm->_sliceRenderer->drawOnScreen(_animationId, _animationFrame, _screenX, _screenY, _facing, _scale, _vm->_surface2, _vm->_zBuffer2); + _vm->_sliceRenderer->drawOnScreen(_animationId, _animationFrame, _screenX, _screenY, _facing, _scale, _vm->_surface2, _vm->_zbuffer->getData()); } } // End of namespace BladeRunner diff --git a/engines/bladerunner/items.cpp b/engines/bladerunner/items.cpp index 6fa17dffd5..dda284f67d 100644 --- a/engines/bladerunner/items.cpp +++ b/engines/bladerunner/items.cpp @@ -24,6 +24,7 @@ #include "bladerunner/scene.h" #include "bladerunner/scene_objects.h" +#include "bladerunner/zbuffer.h" namespace BladeRunner { @@ -58,7 +59,10 @@ void Items::tick() { continue; } bool set14NotTarget = setId == 14 && !_items[i]->isTargetable(); - _items[i]->tick(set14NotTarget); + Common::Rect screenRect; + if (_items[i]->tick(&screenRect, set14NotTarget)) { + _vm->_zbuffer->mark(screenRect); + } } } diff --git a/engines/bladerunner/module.mk b/engines/bladerunner/module.mk index 5ef5735a74..408d5ae207 100644 --- a/engines/bladerunner/module.mk +++ b/engines/bladerunner/module.mk @@ -170,7 +170,8 @@ MODULE_OBJS = \ view.o \ vqa_decoder.o \ vqa_player.o \ - waypoints.o + waypoints.o \ + zbuffer.o # This module can be built as a plugin ifeq ($(ENABLE_BLADERUNNER), DYNAMIC_PLUGIN) diff --git a/engines/bladerunner/mouse.cpp b/engines/bladerunner/mouse.cpp index 675e20c0fd..be114dc1bb 100644 --- a/engines/bladerunner/mouse.cpp +++ b/engines/bladerunner/mouse.cpp @@ -26,6 +26,7 @@ #include "bladerunner/scene.h" #include "bladerunner/scene_objects.h" #include "bladerunner/shape.h" +#include "bladerunner/zbuffer.h" #include "graphics/surface.h" @@ -308,7 +309,7 @@ Vector3 Mouse::getXYZ(int x, int y) { float x3d = (2.0f / 640.0f * screenRight - 1.0f); float y3d = (2.0f / 480.0f * screenDown - 1.0f) * 0.75f; - uint16 zbufval = _vm->_zBuffer1[x + y * 640]; + uint16 zbufval = _vm->_zbuffer->getZValue(x, y); Vector3 pos; pos.z = zbufval / 25.5f; diff --git a/engines/bladerunner/scene.cpp b/engines/bladerunner/scene.cpp index 05abfbe16e..be5be7cc67 100644 --- a/engines/bladerunner/scene.cpp +++ b/engines/bladerunner/scene.cpp @@ -105,7 +105,7 @@ bool Scene::open(int setId, int sceneId, bool isLoadingGame) { _defaultLoopSet = true; _specialLoopAtEnd = false; } - _vm->_scene->advanceFrame(_vm->_surface1, _vm->_zBuffer1); + _vm->_scene->advanceFrame(_vm->_surface1); _vm->_playerActor->setAtXYZ(_actorStartPosition, _actorStartFacing); _vm->_playerActor->setSetId(setId); @@ -168,11 +168,11 @@ bool Scene::close(bool isLoadingGame) { return result; } -int Scene::advanceFrame(Graphics::Surface &surface, uint16 *&zBuffer) { +int Scene::advanceFrame(Graphics::Surface &surface) { int frame = _vqaPlayer->update(); if (frame >= 0) { surface.copyFrom(*_vqaPlayer->getSurface()); - memcpy(zBuffer, _vqaPlayer->getZBuffer(), 640 * 480 * 2); + _vqaPlayer->updateZBuffer(_vm->_zbuffer); _vqaPlayer->updateView(_vm->_view); _vqaPlayer->updateLights(_vm->_lights); } diff --git a/engines/bladerunner/scene.h b/engines/bladerunner/scene.h index 5bc25fc6fc..fac67ff5f4 100644 --- a/engines/bladerunner/scene.h +++ b/engines/bladerunner/scene.h @@ -88,7 +88,7 @@ public: bool open(int setId, int sceneId, bool isLoadingGame); bool close(bool isLoadingGame); - int advanceFrame(Graphics::Surface &surface, uint16 *&zBuffer); + int advanceFrame(Graphics::Surface &surface); void setActorStart(Vector3 position, int facing); void loopSetDefault(int a); diff --git a/engines/bladerunner/script/scene/rc01.cpp b/engines/bladerunner/script/scene/rc01.cpp index 1a5367b0fc..3a26cd2fdd 100644 --- a/engines/bladerunner/script/scene/rc01.cpp +++ b/engines/bladerunner/script/scene/rc01.cpp @@ -291,8 +291,8 @@ bool SceneScriptRC01::ClickedOnActor(int actorId) { Game_Flag_Reset(392); } } else { - I_Sez("MG: Hey, leave that officer alone.Can't you see he's busy?"); - I_Sez("JM: (...mmm, donuts..."); + I_Sez("MG: Hey, leave that officer alone. Can't you see he's busy?"); + I_Sez("JM: (...mmm, donuts...)"); Game_Flag_Set(3); Actor_Clue_Acquire(0, 0, 1, 23); Actor_Says(0, 4515, 13); @@ -301,7 +301,7 @@ bool SceneScriptRC01::ClickedOnActor(int actorId) { if (!Game_Flag_Query(1)) { Actor_Says(23, 50, 14); Actor_Says(23, 60, 15); - I_Sez("MG: It's all fun and games until someone loses a tiger cub"); + I_Sez("MG: It's all fun and games until someone loses a tiger cub."); Actor_Says(0, 4520, 18); Actor_Says(23, 70, 16); Actor_Says(0, 4525, 14); diff --git a/engines/bladerunner/vqa_decoder.cpp b/engines/bladerunner/vqa_decoder.cpp index 15bf49306a..1e22257843 100644 --- a/engines/bladerunner/vqa_decoder.cpp +++ b/engines/bladerunner/vqa_decoder.cpp @@ -27,6 +27,7 @@ #include "bladerunner/decompress_lzo.h" #include "bladerunner/lights.h" #include "bladerunner/view.h" +#include "bladerunner/zbuffer.h" #include "audio/decoders/raw.h" @@ -191,8 +192,8 @@ const Graphics::Surface *VQADecoder::decodeVideoFrame() { return _videoTrack->decodeVideoFrame(); } -const uint16 *VQADecoder::decodeZBuffer() { - return _videoTrack->decodeZBuffer(); +void VQADecoder::decodeZBuffer(ZBuffer *zbuffer) { + _videoTrack->decodeZBuffer(zbuffer); } Audio::SeekableAudioStream *VQADecoder::decodeAudioFrame() { @@ -552,7 +553,6 @@ VQADecoder::VQAVideoTrack::VQAVideoTrack(VQADecoder *vqaDecoder) { _maxVPTRSize = header->maxVPTRSize; _maxCBFZSize = header->maxCBFZSize; _maxZBUFChunkSize = vqaDecoder->_maxZBUFChunkSize; - _zbuffer = nullptr; _codebookSize = 0; _codebook = nullptr; @@ -564,7 +564,6 @@ VQADecoder::VQAVideoTrack::VQAVideoTrack(VQADecoder *vqaDecoder) { _curFrame = -1; - _zbufChunk = new uint8[roundup(_maxZBUFChunkSize)]; _surface = new Graphics::Surface(); @@ -583,7 +582,6 @@ VQADecoder::VQAVideoTrack::~VQAVideoTrack() { if (_surface) _surface->free(); delete _surface; - delete[] _zbuffer; if (_viewData) delete[] _viewData; @@ -668,42 +666,6 @@ bool VQADecoder::VQAVideoTrack::readCBFZ(Common::SeekableReadStream *s, uint32 s return true; } -static int decodeZBUF_partial(uint8 *src, uint16 *curZBUF, uint32 srcLen) { - uint32 dstSize = 640 * 480; // This is taken from global variables? - uint32 dstRemain = dstSize; - - uint16 *curzp = curZBUF; - uint16 *inp = (uint16*)src; - - while (dstRemain && (inp - (uint16*)src) < (std::ptrdiff_t)srcLen) { - uint32 count = FROM_LE_16(*inp++); - - if (count & 0x8000) { - count = MIN(count & 0x7fff, dstRemain); - dstRemain -= count; - - while (count--) { - uint16 value = FROM_LE_16(*inp++); - if (value) - *curzp = value; - ++curzp; - } - } else { - count = MIN(count, dstRemain); - dstRemain -= count; - uint16 value = FROM_LE_16(*inp++); - - if (!value) { - curzp += count; - } else { - while (count--) - *curzp++ = value; - } - } - } - return dstSize - dstRemain; -} - bool VQADecoder::VQAVideoTrack::readZBUF(Common::SeekableReadStream *s, uint32 size) { if (size > _maxZBUFChunkSize) { debug("VQA ERROR: ZBUF chunk size: %08x > %08x", size, _maxZBUFChunkSize); @@ -711,42 +673,17 @@ bool VQADecoder::VQAVideoTrack::readZBUF(Common::SeekableReadStream *s, uint32 s return false; } - uint32 width, height, complete, unk0; - width = s->readUint32LE(); - height = s->readUint32LE(); - complete = s->readUint32LE(); - unk0 = s->readUint32LE(); - - uint32 remain = size - 16; - - if (_width != width || _height != height) { - debug("%d, %d, %d, %d", width, height, complete, unk0); - s->skip(roundup(remain)); - return false; - } - - _zbufChunkComplete = complete; - _zbufChunkSize = remain; - s->read(_zbufChunk, roundup(remain)); + _zbufChunkSize = size; + s->read(_zbufChunk, roundup(size)); return true; } -const uint16 *VQADecoder::VQAVideoTrack::decodeZBuffer() { +void VQADecoder::VQAVideoTrack::decodeZBuffer(ZBuffer *zbuffer) { if (_maxZBUFChunkSize == 0) - return nullptr; - - if (!_zbuffer) - _zbuffer = new uint16[_width * _height]; - - if (_zbufChunkComplete) { - size_t zbufOutSize; - decompress_lzo1x(_zbufChunk, _zbufChunkSize, (uint8*)_zbuffer, &zbufOutSize); - } else { - decodeZBUF_partial(_zbufChunk, _zbuffer, _zbufChunkSize); - } + return; - return _zbuffer; + zbuffer->decodeData(_zbufChunk, _zbufChunkSize); } bool VQADecoder::VQAVideoTrack::readVIEW(Common::SeekableReadStream *s, uint32 size) { diff --git a/engines/bladerunner/vqa_decoder.h b/engines/bladerunner/vqa_decoder.h index 7863afaff0..fb81ef1dc3 100644 --- a/engines/bladerunner/vqa_decoder.h +++ b/engines/bladerunner/vqa_decoder.h @@ -40,6 +40,7 @@ namespace BladeRunner { class Lights; class View; +class ZBuffer; class VQADecoder { public: @@ -52,7 +53,7 @@ public: void readPacket(int frame); const Graphics::Surface *decodeVideoFrame(); - const uint16 *decodeZBuffer(); + void decodeZBuffer(ZBuffer *zbuffer); Audio::SeekableAudioStream *decodeAudioFrame(); void decodeView(View *view); void decodeLights(Lights *lights); @@ -160,7 +161,7 @@ private: int getCurFrame() const; int getFrameCount() const; const Graphics::Surface *decodeVideoFrame(); - const uint16 *decodeZBuffer(); + void decodeZBuffer(ZBuffer *zbuffer); void decodeView(View *view); void decodeLights(Lights *lights); @@ -180,8 +181,7 @@ private: private: Graphics::Surface *_surface; - uint16 *_zbuffer; - bool _hasNewFrame; + bool _hasNewFrame; uint16 _numFrames; uint16 _width, _height; diff --git a/engines/bladerunner/vqa_player.cpp b/engines/bladerunner/vqa_player.cpp index c15ebc6d7a..6018f40bab 100644 --- a/engines/bladerunner/vqa_player.cpp +++ b/engines/bladerunner/vqa_player.cpp @@ -72,7 +72,6 @@ int VQAPlayer::update() { if (_hasAudio) queueAudioFrame(_decoder.decodeAudioFrame()); _surface = _decoder.decodeVideoFrame(); - _zBuffer = _decoder.decodeZBuffer(); } _frameDecoded = calcNextFrame(_frameCurrent); @@ -95,7 +94,6 @@ int VQAPlayer::update() { _frameCurrent = _frameDecoded; if (_frameCurrent >= 0) { _surface = _decoder.decodeVideoFrame(); - _zBuffer = _decoder.decodeZBuffer(); } _frameDecoded = calcNextFrame(_frameCurrent); @@ -117,8 +115,8 @@ const Graphics::Surface *VQAPlayer::getSurface() const { return _surface; } -const uint16 *VQAPlayer::getZBuffer() const { - return _zBuffer; +void VQAPlayer::updateZBuffer(ZBuffer *zbuffer) { + _decoder.decodeZBuffer(zbuffer); } void VQAPlayer::updateView(View *view) { diff --git a/engines/bladerunner/vqa_player.h b/engines/bladerunner/vqa_player.h index 941b3638ed..d0eb069969 100644 --- a/engines/bladerunner/vqa_player.h +++ b/engines/bladerunner/vqa_player.h @@ -35,6 +35,7 @@ namespace BladeRunner { class BladeRunnerEngine; class View; class Lights; +class ZBuffer; //TODO: split this into two components as it is in original game: universal vqa player, blade runner player functionality @@ -99,7 +100,7 @@ public: int update(); const Graphics::Surface *getSurface() const; - const uint16 *getZBuffer() const; + void updateZBuffer(ZBuffer *zbuffer); void updateView(View *view); void updateLights(Lights *lights); diff --git a/engines/bladerunner/zbuffer.cpp b/engines/bladerunner/zbuffer.cpp new file mode 100644 index 0000000000..76391f009f --- /dev/null +++ b/engines/bladerunner/zbuffer.cpp @@ -0,0 +1,221 @@ +/* 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 "bladerunner/zbuffer.h" + +#include "bladerunner/decompress_lzo.h" + +namespace BladeRunner { + +void ZBufferDirtyRects::reset() { + _count = 0; +} + +bool ZBufferDirtyRects::add(Common::Rect rect) { + if (_count == MAX_DIRTY_RECTS) + return false; + + _rects[_count++] = rect; + if (_count > 1) { + extendExisting(); + } + return true; +} + +void ZBufferDirtyRects::extendExisting() { + if (_count < 2) + return; + + Common::Rect last = _rects[_count - 1]; + + int i; + for (i = 0; i != _count - 1; ++i) { + if (last.intersects(_rects[i])) { + _rects[i].extend(last); + _count--; + break; + } + } +} + +int ZBufferDirtyRects::getCount() { + return _count; +} + +bool ZBufferDirtyRects::popRect(Common::Rect *rect) { + if (_count == 0) + return false; + + *rect = _rects[--_count]; + return true; +} + +ZBuffer::ZBuffer() { + reset(); +} + +ZBuffer::~ZBuffer() { + delete[] _zbuf1; + delete[] _zbuf2; +} + +void ZBuffer::init(int width, int height) { + _width = width; + _height = height; + + _zbuf1 = new uint16[width * height]; + _zbuf2 = new uint16[width * height]; + + _dirtyRects = new ZBufferDirtyRects(); +} + +static int decodePartialZBuffer(const uint8 *src, uint16 *curZBUF, uint32 srcLen) { + uint32 dstSize = 640 * 480; // This is taken from global variables? + uint32 dstRemain = dstSize; + + uint16 *curzp = curZBUF; + uint16 *inp = (uint16*)src; + + while (dstRemain && (inp - (uint16*)src) < (std::ptrdiff_t)srcLen) { + uint32 count = FROM_LE_16(*inp++); + + if (count & 0x8000) { + count = MIN(count & 0x7fff, dstRemain); + dstRemain -= count; + + while (count--) { + uint16 value = FROM_LE_16(*inp++); + if (value) + *curzp = value; + ++curzp; + } + } else { + count = MIN(count, dstRemain); + dstRemain -= count; + uint16 value = FROM_LE_16(*inp++); + + if (!value) { + curzp += count; + } else { + while (count--) + *curzp++ = value; + } + } + } + return dstSize - dstRemain; +} + +bool ZBuffer::decodeData(const uint8 *data, int size) { + if (_disabled) { + return false; + } + + uint32 width, height, complete, unk0; + + width = READ_LE_UINT32(data + 0); + height = READ_LE_UINT32(data + 4); + complete = READ_LE_UINT32(data + 8); + unk0 = READ_LE_UINT32(data + 12); + + if (width != (uint32)_width || height != (uint32)_height) { + warning("zbuffer size mismatch (%d, %d) != (%d, %d)", _width, _height, width, height); + return false; + } + + data += 16; + size -= 16; + + if (complete) { + resetUpdates(); + size_t zbufOutSize; + decompress_lzo1x(data, size, (uint8*)_zbuf1, &zbufOutSize); + memcpy(_zbuf2, _zbuf1, 2 * _width * _height); + } else { + clean(); + decodePartialZBuffer(data, _zbuf1, size); + decodePartialZBuffer(data, _zbuf2, size); + } + + return true; +} + +uint16 *ZBuffer::getData() { + return _zbuf2; +} + +uint16 ZBuffer::getZValue(int x, int y) { + assert(x >= 0 && x < _width); + assert(y >= 0 && y < _height); + + if (!_zbuf2) + return 0; + + return _zbuf2[y * _width + x]; +} + +void ZBuffer::reset() { + _zbuf1 = nullptr; + _zbuf2 = nullptr; + _dirtyRects = nullptr; + _width = 0; + _height = 0; + enable(); +} + +void ZBuffer::blit(Common::Rect rect) { + int line_width = rect.width(); + + for (int y = rect.top; y != rect.bottom; ++y) { + int offset = y * _width + rect.left; + memcpy(_zbuf2 + offset, _zbuf1 + offset, 2 * line_width); + } +} + +void ZBuffer::mark(Common::Rect rect) { + assert(rect.isValidRect()); + + // debug("mark %d, %d, %d, %d", rect.top, rect.right, rect.bottom, rect.left); + rect.clip(_width, _height); + _dirtyRects->add(rect); +} + +void ZBuffer::clean() { + Common::Rect rect; + while (_dirtyRects->popRect(&rect)) { + // debug("blit %d, %d, %d, %d", rect.top, rect.right, rect.bottom, rect.left); + blit(rect); + } +} + +void ZBuffer::resetUpdates() { + _dirtyRects->reset(); +} + +void ZBuffer::disable() { + _disabled = true; +} + +void ZBuffer::enable() { + _disabled = false; +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/zbuffer.h b/engines/bladerunner/zbuffer.h new file mode 100644 index 0000000000..5c771b1381 --- /dev/null +++ b/engines/bladerunner/zbuffer.h @@ -0,0 +1,87 @@ +/* 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. + * + */ + +#ifndef BLADERUNNER_ZBUFFER_H +#define BLADERUNNER_ZBUFFER_H + +#include "bladerunner/bladerunner.h" + +#include "common/rect.h" + +namespace BladeRunner { + +#define MAX_DIRTY_RECTS 20 + +class ZBufferDirtyRects { + int _count; + Common::Rect _rects[MAX_DIRTY_RECTS]; + +public: + ZBufferDirtyRects() : + _count(0) + {} + + void reset(); + bool add(Common::Rect rect); + void extendExisting(); + int getCount(); + bool popRect(Common::Rect *rect); +}; + +class ZBuffer { + int _width; + int _height; + + uint16 *_zbuf1; + uint16 *_zbuf2; + + ZBufferDirtyRects *_dirtyRects;; + + bool _disabled; + +public: + ZBuffer(); + ~ZBuffer(); + + void init(int width, int height); + bool decodeData(const uint8 *data, int size); + + uint16 *getData(); + uint16 getZValue(int x, int y); + +private: + void reset(); + void blit(Common::Rect rect); + +public: + void mark(Common::Rect rect); + void clean(); + void resetUpdates(); + + // Only called from Scene::resume which is not yet implemented + void disable(); + void enable(); +}; + +} // End of namespace BladeRunner + +#endif -- cgit v1.2.3