From 4b181e4bed3af7b7e32a8d4c9209d81ece366554 Mon Sep 17 00:00:00 2001 From: Thomas Fach-Pedersen Date: Thu, 5 Jun 2014 23:49:57 +0200 Subject: BLADERUNNER: First pass at slice animation renderer Z-buffers are not being read from the VQA background yet, so z-buffer handling is faked for now. --- engines/bladerunner/bladerunner.cpp | 32 ++- engines/bladerunner/bladerunner.h | 17 +- engines/bladerunner/module.mk | 2 + engines/bladerunner/slice_animations.cpp | 173 +++++++++++++ engines/bladerunner/slice_animations.h | 111 +++++++++ engines/bladerunner/slice_renderer.cpp | 412 +++++++++++++++++++++++++++++++ engines/bladerunner/slice_renderer.h | 96 +++++++ 7 files changed, 836 insertions(+), 7 deletions(-) create mode 100644 engines/bladerunner/slice_animations.cpp create mode 100644 engines/bladerunner/slice_animations.h create mode 100644 engines/bladerunner/slice_renderer.cpp create mode 100644 engines/bladerunner/slice_renderer.h (limited to 'engines') diff --git a/engines/bladerunner/bladerunner.cpp b/engines/bladerunner/bladerunner.cpp index 4791be9aca..7da46f1f0e 100644 --- a/engines/bladerunner/bladerunner.cpp +++ b/engines/bladerunner/bladerunner.cpp @@ -29,6 +29,8 @@ #include "bladerunner/scene.h" #include "bladerunner/script/script.h" #include "bladerunner/settings.h" +#include "bladerunner/slice_animations.h" +#include "bladerunner/slice_renderer.h" #include "bladerunner/vqa_decoder.h" #include "common/error.h" @@ -50,9 +52,13 @@ BladeRunnerEngine::BladeRunnerEngine(OSystem *syst) : Engine(syst) { _scene = new Scene(this); _script = new Script(this); _settings = new Settings(this); + _sliceAnimations = new SliceAnimations(this); + _sliceRenderer = new SliceRenderer(this); } BladeRunnerEngine::~BladeRunnerEngine() { + delete _sliceRenderer; + delete _sliceAnimations; delete _settings; delete _script; delete _scene; @@ -60,6 +66,7 @@ BladeRunnerEngine::~BladeRunnerEngine() { delete _chapters; _surface1.free(); + _surface2.free(); } bool BladeRunnerEngine::hasFeature(EngineFeature f) const { @@ -120,6 +127,18 @@ bool BladeRunnerEngine::startup() { if (!r) return false; + r = _sliceAnimations->open("INDEX.DAT"); + if (!r) + return false; + + r = _sliceAnimations->openCoreAnim(); + if (!r) + return false; + + r = _sliceAnimations->openHDFrames(); + if (!r) + return false; + initChapterAndScene(); return true; @@ -201,6 +220,7 @@ void BladeRunnerEngine::gameTick() { _script->SceneFrameAdvanced(frame); backgroundChanged = true; } + _surface2.copyFrom(_surface1); // TODO: Render overlays (mostly in Replicant) // TODO: Tick Actor AI and Timers (timers in Replicant) @@ -208,6 +228,16 @@ void BladeRunnerEngine::gameTick() { if (_settings->getNewScene() == -1 || _script->_inScriptCounter /* || in_ai */) { // TODO: Tick and draw all actors in current set (drawing works in Replicant) + + // Hardcode McCoy in place to test the slice renderer + Vector3 pos(-151.98f, -0.30f, 318.15f); + Vector3 draw_pos(pos.x, -pos.z, pos.y + 2); + float facing = -1.570796f; + + _sliceRenderer->setView(_scene->_view); + _sliceRenderer->setupFrame(19, 1, draw_pos, facing); + _sliceRenderer->drawFrame(_surface2); + // TODO: Draw items (drawing works in Replicant) // TODO: Draw item pickup (understood, drawing works in Replicant) // TODO: Draw dialogue menu @@ -215,7 +245,7 @@ void BladeRunnerEngine::gameTick() { // TODO: Process AUD (audio in Replicant) // TODO: Footstep sound - _system->copyRectToScreen((const byte *) _surface1.getBasePtr(0, 0), _surface1.pitch, 0, 0, 640, 480); + _system->copyRectToScreen((const byte *)_surface2.getBasePtr(0, 0), _surface2.pitch, 0, 0, 640, 480); _system->updateScreen(); _system->delayMillis(10); } diff --git a/engines/bladerunner/bladerunner.h b/engines/bladerunner/bladerunner.h index 60d87efe00..c3f7eac4d7 100644 --- a/engines/bladerunner/bladerunner.h +++ b/engines/bladerunner/bladerunner.h @@ -36,25 +36,30 @@ namespace BladeRunner { class Chapters; +class GameInfo; class Scene; class Script; class Settings; -class GameInfo; +class SliceAnimations; +class SliceRenderer; class BladeRunnerEngine : public Engine { public: bool _gameIsRunning; bool _windowIsActive; - Chapters *_chapters; - GameInfo *_gameInfo; - Scene *_scene; - Script *_script; - Settings *_settings; + Chapters *_chapters; + GameInfo *_gameInfo; + Scene *_scene; + Script *_script; + Settings *_settings; + SliceAnimations *_sliceAnimations; + SliceRenderer *_sliceRenderer; int in_script_counter; Graphics::Surface _surface1; + Graphics::Surface _surface2; private: static const int kArchiveCount = 10; diff --git a/engines/bladerunner/module.mk b/engines/bladerunner/module.mk index eae0d950c7..37ba70bd51 100644 --- a/engines/bladerunner/module.mk +++ b/engines/bladerunner/module.mk @@ -17,6 +17,8 @@ MODULE_OBJS = \ script/script.o \ set.o \ settings.o \ + slice_animations.o \ + slice_renderer.o \ view.o \ vqa_decoder.o \ vqa_player.o diff --git a/engines/bladerunner/slice_animations.cpp b/engines/bladerunner/slice_animations.cpp new file mode 100644 index 0000000000..b17e5173ae --- /dev/null +++ b/engines/bladerunner/slice_animations.cpp @@ -0,0 +1,173 @@ +/* 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/slice_animations.h" + +#include "bladerunner/bladerunner.h" + +#include "common/debug.h" +#include "common/file.h" +#include "common/system.h" + +namespace BladeRunner { + +bool SliceAnimations::open(const Common::String &name) { + Common::File file; + if (!file.open(_vm->getResourceStream(name), name)) + return false; + + _timestamp = file.readUint32LE(); + _pageSize = file.readUint32LE(); + _pageCount = file.readUint32LE(); + _paletteCount = file.readUint32LE(); + + if (_timestamp != 0x3457b6f6) // Timestamp: Wed, 29 Oct 1997 22:21:42 GMT + return false; + + _palettes.resize(_paletteCount); + + for (uint32 i = 0; i != _paletteCount; ++i) { + for (uint32 j = 0; j != 256; ++j) { + uint8 color_r = file.readByte(); + uint8 color_g = file.readByte(); + uint8 color_b = file.readByte(); + + uint16 rgb555 = ((uint16)color_r << 10) | + ((uint16)color_g << 5) | + (uint16)color_b; + + _palettes[i][j] = rgb555; + } + } + + uint32 animationCount = file.readUint32LE(); + _animations.resize(animationCount); + + for (uint32 i = 0; i != animationCount; ++i) { + _animations[i].frameCount = file.readUint32LE(); + _animations[i].frameSize = file.readUint32LE(); + _animations[i].fps = file.readFloatLE(); + _animations[i].unk0 = file.readFloatLE(); + _animations[i].unk1 = file.readFloatLE(); + _animations[i].unk2 = file.readFloatLE(); + _animations[i].unk3 = file.readFloatLE(); + _animations[i].offset = file.readUint32LE(); + +#if 0 + debug("%4d %6d %6x %7.2g %7.2g %7.2g %7.2g %7.2g %8x", + i, + _animations[i].frameCount, + _animations[i].frameSize, + _animations[i].fps, + _animations[i].unk0, + _animations[i].unk1, + _animations[i].unk2, + _animations[i].unk3, + _animations[i].offset); +#endif + } + + _pages.resize(_pageCount); + for (uint32 i = 0; i != _pageCount; ++i) + _pages[i]._data = nullptr; + + return true; +} + +SliceAnimations::~SliceAnimations() { + for (uint32 i = 0; i != _pageCount; ++i) + free(_pages[i]._data); +} + +bool SliceAnimations::openCoreAnim() { + return _coreAnimPageFile.open("COREANIM.DAT"); +} + +bool SliceAnimations::openHDFrames() { + return _framesPageFile.open("HDFRAMES.DAT"); +} + +bool SliceAnimations::PageFile::open(const Common::String &name) { + if (!_file.open(name)) + return false; + + uint32 timestamp = _file.readUint32LE(); + if (timestamp != _sliceAnimations->_timestamp) + return false; + + _pageOffsets.resize(_sliceAnimations->_pageCount); + for (uint32 i = 0; i != _sliceAnimations->_pageCount; ++i) + _pageOffsets[i] = -1; + + uint32 pageCount = _file.readUint32LE(); + uint32 dataOffset = 8 + 4 * pageCount; + + for (uint32 i = 0; i != pageCount; ++i) { + uint32 pageNumber = _file.readUint32LE(); + if (pageNumber == 0xffffffff) + continue; + _pageOffsets[pageNumber] = dataOffset + i * _sliceAnimations->_pageSize; + } + + debug("PageFile::Open: page file \"%s\" opened with %d pages", name.c_str(), pageCount); + + return true; +} + +void *SliceAnimations::PageFile::loadPage(uint32 pageNumber) { + if (_pageOffsets[pageNumber] == -1) + return nullptr; + + uint32 pageSize = _sliceAnimations->_pageSize; + + // TODO: Retire oldest pages if we exceed some memory limit + + void *data = malloc(pageSize); + _file.seek(_pageOffsets[pageNumber], SEEK_SET); + uint32 r = _file.read(data, pageSize); + assert(r == pageSize); + + return data; +} + +void *SliceAnimations::getFramePtr(uint32 animation, uint32 frame) { + assert(frame < _animations[animation].frameCount); + + uint32 frameOffset = _animations[animation].offset + frame * _animations[animation].frameSize; + uint32 page = frameOffset / _pageSize; + uint32 pageOffset = frameOffset % _pageSize; + + if (!_pages[page]._data) + _pages[page]._data = _coreAnimPageFile.loadPage(page); + + if (!_pages[page]._data) + _pages[page]._data = _framesPageFile.loadPage(page); + + if (!_pages[page]._data) + error("Unable to locate page %d for animation %d frame %d", page, animation, frame); + + _pages[page]._lastAccess = _vm->_system->getMillis(); + + return (byte*)_pages[page]._data + pageOffset; +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/slice_animations.h b/engines/bladerunner/slice_animations.h new file mode 100644 index 0000000000..cc07b570b6 --- /dev/null +++ b/engines/bladerunner/slice_animations.h @@ -0,0 +1,111 @@ +/* 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_SLICE_ANIMATIONS_H +#define BLADERUNNER_SLICE_ANIMATIONS_H + +#include "common/array.h" +#include "common/file.h" +#include "common/str.h" +#include "common/types.h" + +namespace BladeRunner { + +class BladeRunnerEngine; + +struct SlicePalette { + uint16 color[256]; + + uint16 &operator[](size_t i) { return color[i]; } +}; + +class SliceAnimations { + friend class SliceRenderer; + + struct Animation + { + uint32 frameCount; + uint32 frameSize; + float fps; + float unk0; + float unk1; + float unk2; + float unk3; + uint32 offset; + }; + + struct Page { + void *_data; + uint32 _lastAccess; + + Page() + : _data(nullptr) + {} + }; + + struct PageFile { + SliceAnimations *_sliceAnimations; + Common::File _file; + Common::Array _pageOffsets; + + PageFile(SliceAnimations *sliceAnimations) + : _sliceAnimations(sliceAnimations) + {} + + bool open(const Common::String &name); + void *loadPage(uint32 page); + }; + + BladeRunnerEngine *_vm; + + uint32 _timestamp; + uint32 _pageSize; + uint32 _pageCount; + uint32 _paletteCount; + + Common::Array _palettes; + Common::Array _animations; + Common::Array _pages; + + PageFile _coreAnimPageFile; + PageFile _framesPageFile; + +public: + SliceAnimations(BladeRunnerEngine *vm) + : _vm(vm), + _coreAnimPageFile(this), + _framesPageFile(this) + {} + ~SliceAnimations(); + + bool open(const Common::String &name); + + bool openCoreAnim(); + bool openHDFrames(); + + SlicePalette &getPalette(int i) { return _palettes[i]; }; + void *getFramePtr(uint32 animation, uint32 frame); +}; + +} // End of namespace BladeRunner + +#endif diff --git a/engines/bladerunner/slice_renderer.cpp b/engines/bladerunner/slice_renderer.cpp new file mode 100644 index 0000000000..e8e3ecf894 --- /dev/null +++ b/engines/bladerunner/slice_renderer.cpp @@ -0,0 +1,412 @@ +/* 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/slice_renderer.h" + +#include "bladerunner/bladerunner.h" +#include "bladerunner/slice_animations.h" + +#include "common/debug.h" +#include "common/memstream.h" +#include "common/rect.h" +#include "common/util.h" + +namespace BladeRunner { + +#if 0 +void dump(const char *str, Vector3 v) { + debug("%s %g %g %g", str, v.x, v.y, v.z); +} + +void dump(const char *str, Matrix3x2 m) { + debug("%s", str); + debug("%11.6g %11.6g %11.6g", m(0, 0), m(0, 1), m(0, 2)); + debug("%11.6g %11.6g %11.6g", m(1, 0), m(1, 1), m(1, 2)); +} + +void dump(const char *str, Matrix4x3 m) { + debug("%s", str); + debug("%11.6g %11.6g %11.6g %11.6g", m(0, 0), m(0, 1), m(0, 2), m(0, 3)); + debug("%11.6g %11.6g %11.6g %11.6g", m(1, 0), m(1, 1), m(1, 2), m(1, 3)); + debug("%11.6g %11.6g %11.6g %11.6g", m(2, 0), m(2, 1), m(2, 2), m(2, 3)); +} +#endif + +SliceRenderer::~SliceRenderer() { +} + +void SliceRenderer::setView(const View &view) { + _view = view; +} + +void SliceRenderer::setupFrame(int animation, int frame, Vector3 position, float facing, float scale) { + _animation = animation; + _frame = frame; + _position = position; + _facing = facing; + _scale = scale; + + _sliceFramePtr = _vm->_sliceAnimations->getFramePtr(_animation, _frame); + + Common::MemoryReadStream stream((byte*)_sliceFramePtr, _vm->_sliceAnimations->_animations[_animation].frameSize); + + _frameFront.x = stream.readFloatLE(); + _frameFront.y = stream.readFloatLE(); + _frameSliceHeight = stream.readFloatLE(); + _framePos.x = stream.readFloatLE(); + _framePos.y = stream.readFloatLE(); + _frameBottomZ = stream.readFloatLE(); + _framePaletteIndex = stream.readUint32LE(); + _frameSliceCount = stream.readUint32LE(); + + calculateBoundingRect(); +} + +Matrix3x2 SliceRenderer::calculateFacingRotationMatrix() { + assert(_sliceFramePtr); + + Matrix4x3 viewMatrix = _view._sliceViewMatrix; + Vector3 viewPos = viewMatrix * _position; + float dir = atan2f(viewPos.x, viewPos.z) + _facing; + float s = sinf(dir); + float c = cosf(dir); + + Matrix3x2 rotation( c, -s, 0.0f, + s, c, 0.0f); + + Matrix3x2 viewRotation(viewMatrix(0,0), viewMatrix(0,1), 0.0f, + viewMatrix(2,0), viewMatrix(2,1), 0.0f); + + return viewRotation * rotation; +} + +void SliceRenderer::calculateBoundingRect() { + assert(_sliceFramePtr); + + _minX = 0.0f; + _maxX = 0.0f; + _minY = 0.0f; + _maxY = 0.0f; + + Matrix4x3 viewMatrix = _view._sliceViewMatrix; + + Vector3 frameBottom = Vector3(0.0f, 0.0f, _frameBottomZ); + Vector3 frameTop = Vector3(0.0f, 0.0f, _frameBottomZ + _frameSliceCount * _frameSliceHeight); + + Vector3 bottom = viewMatrix * (_position + frameBottom); + Vector3 top = viewMatrix * (_position + frameTop); + + top = bottom + _scale * (top - bottom); + + if (bottom.z < 0.0f || top.z < 0.0f) + return; + + Matrix3x2 facingRotation = calculateFacingRotationMatrix(); + + Matrix3x2 m4(_view._viewportDistance / bottom.z, 0.0f, 0.0f, + 0.0f, 25.5f, 0.0f); + + Matrix3x2 m2(_frameFront.x, 0.0f, _framePos.x, + 0.0f, _frameFront.y, _framePos.y); + + _field_109E = m4 * (facingRotation * m2); + + Vector4 B6(_view._viewportHalfWidth + top.x / top.z * _view._viewportDistance, + _view._viewportHalfHeight + top.y / top.z * _view._viewportDistance, + 1.0f / top.z, + _frameSliceCount * (1.0f / top.z)); + + Vector4 C2(_view._viewportHalfWidth + bottom.x / bottom.z * _view._viewportDistance, + _view._viewportHalfHeight + bottom.y / bottom.z * _view._viewportDistance, + 1.0f / bottom.z, + 0.0f); + + _field_10B6.x = B6.x; + _field_10B6.y = B6.y; + _field_10B6.z = B6.z; + _field_10C2.x = C2.x; + _field_10C2.y = C2.y; + _field_10C2.z = C2.z; + _field_10CE = B6.w; + _field_10D2 = C2.w; + + Vector4 delta = C2 - B6; + + if (delta.y == 0.0f) + return; + + /* + * Calculate min and max Y + */ + + float screenMinY = 0.0f; + float screenMaxY = 479.0f; + + if (B6.y < screenMinY) { + if (C2.y < screenMinY) + return; + + float f = (screenMinY - B6.y) / delta.y; + B6 = B6 + f * delta; + } else if (B6.y > screenMaxY) { + if (C2.y >= screenMaxY) + return; + + float f = (screenMaxY - B6.y) / delta.y; + B6 = B6 + f * delta; + } + + if (C2.y < screenMinY) { + float f = (screenMinY - C2.y) / delta.y; + C2 = C2 + f * delta; + } else if (C2.y > screenMaxY) { + float f = (screenMaxY - C2.y) / delta.y; + C2 = C2 + f * delta; + } + + int bbox_min_y = (int)MIN(B6.y, C2.y); + int bbox_max_y = (int)MAX(B6.y, C2.y) + 1; + + /* + * Calculate min and max X + */ + + Matrix3x2 mB6 = _field_109E + Vector2(B6.x, 25.5f / B6.z); + Matrix3x2 mC2 = _field_109E + Vector2(C2.x, 25.5f / C2.z); + + float min_x = 640.0f; + float max_x = 0.0f; + + for (float i = 0.0f; i <= 256.0f; i += 255.0f) + { + for (float j = 0.0f; j <= 256.0f; j += 255.0f) + { + Vector2 v1 = mB6 * Vector2(i, j); + + min_x = MIN(min_x, v1.x); + max_x = MAX(max_x, v1.x); + + Vector2 v2 = mC2 * Vector2(i, j); + + min_x = MIN(min_x, v2.x); + max_x = MAX(max_x, v2.x); + } + } + + int bbox_min_x = MIN(MAX((int)min_x, 0), 640); + int bbox_max_x = MIN(MAX((int)max_x + 1, 0), 640); + + _field_10B6.x = B6.x; + _field_10B6.y = B6.y; + _field_10B6.z = B6.z; + _field_10C2.x = C2.x; + _field_10C2.y = C2.y; + _field_10C2.z = C2.z; + _field_10CE = B6.w; + _field_10D2 = C2.w; + + _minX = bbox_min_x; + _minY = bbox_min_y; + _maxX = bbox_max_x; + _maxY = bbox_max_y; +} + +struct SliceLineIterator { + int _field_00[2][3]; + int _field_18; + int _field_1C; + + float _field_20; + float _field_24; + float _field_28; + float _field_2C; + float _field_30; + float _field_34; + int _field_38; + int _field_3C; + + void setup(float arg_1, float arg_2, float arg_3, + float arg_4, float arg_5, float arg_6, + float arg_7, float arg_8, + Matrix3x2 arg_9); + float line(); + void advance(); +}; + +void SliceLineIterator::setup( + float arg_1, float arg_2, float arg_3, + float arg_4, float arg_5, float arg_6, + float arg_7, float arg_8, + Matrix3x2 arg_9) +{ + _field_18 = (int)arg_5; + _field_1C = (int)arg_2; + + float var_3 = arg_2 - arg_5; + + if (var_3 <= 0.0f || arg_6 <= 0.0f) + _field_3C = _field_1C + 1; + + _field_20 = arg_6; + _field_24 = (arg_3 - arg_6) / var_3; + _field_2C = (arg_7 - arg_8) / var_3; + _field_28 = arg_8 - (arg_5 - floor(arg_5) - 1.0f) * _field_2C; + + _field_30 = arg_4; + _field_34 = (arg_1 - arg_4) / var_3; + _field_38 = (int)((25.5f / var_3) * (1.0f / arg_3 - 1.0f / arg_6) * 64.0); + _field_3C = _field_18; + + float var_54 = _field_30; + float var_55 = 25.5f / _field_20; + + Matrix3x2 translate_matrix = Matrix3x2(1.0f, 0.0f, var_54, + 0.0f, 1.0f, var_55); + + Matrix3x2 scale_matrix = Matrix3x2(65536.0f, 0.0f, 0.0f, + 0.0f, 64.0f, 0.0f); + + arg_9 = scale_matrix * (translate_matrix * arg_9); + + for (int r = 0; r != 2; ++r) + for (int c = 0; c != 3; ++c) + _field_00[r][c] = arg_9(r, c); +} + +float SliceLineIterator::line() { + float var_0 = 0.0f; + + if (_field_20 != 0.0f) + var_0 = _field_28 / _field_20; + + if (var_0 < 0.0) + var_0 = 0.0f; + + return var_0; +} + +void SliceLineIterator::advance() { + _field_20 += _field_24; + _field_28 += _field_2C; + _field_30 += _field_34; + _field_3C += 1; + _field_00[0][2] += (int)(65536.0f * _field_34); + _field_00[1][2] += _field_38; +} + +static +void setupLookupTable(int t[256], int inc) { + int v = 0; + for (int i = 0; i != 256; ++i) { + t[i] = v; + v += inc; + } +} + +void SliceRenderer::drawFrame(Graphics::Surface &surface) { + assert(_sliceFramePtr); + + SliceLineIterator sliceLineIterator; + sliceLineIterator.setup( + _field_10C2.x, _field_10C2.y, _field_10C2.z, + _field_10B6.x, _field_10B6.y, _field_10B6.z, + _field_10D2, _field_10CE, // 2 floats + _field_109E // 3x2 matrix + ); + + setupLookupTable(_t1, sliceLineIterator._field_00[0][0]); + setupLookupTable(_t2, sliceLineIterator._field_00[0][1]); + setupLookupTable(_t4, sliceLineIterator._field_00[1][0]); + setupLookupTable(_t5, sliceLineIterator._field_00[1][1]); + + int frameY = sliceLineIterator._field_18; + + uint16 *frameLinePtr = (uint16*)surface.getPixels() + 640 * frameY; + + while (sliceLineIterator._field_3C <= sliceLineIterator._field_1C) { + _c3 = sliceLineIterator._field_00[0][2]; + _c6 = sliceLineIterator._field_00[1][2]; + + float sliceLine = sliceLineIterator.line(); + + if (frameY >= 0 && frameY < 480) + drawSlice((int)sliceLine, frameLinePtr); + + sliceLineIterator.advance(); + frameY += 1; + frameLinePtr += 640; + } +} + +void SliceRenderer::drawSlice(int slice, uint16 *frameLinePtr) { + if (slice < 0 || slice >= _frameSliceCount) + return; + + SlicePalette &palette = _vm->_sliceAnimations->getPalette(_framePaletteIndex); + + byte *p = (byte*)_sliceFramePtr + 0x20 + 4 * slice; + + uint32 polyOffset = READ_LE_UINT32(p); + + p = (byte*)_sliceFramePtr + polyOffset; + + uint32 polyCount = READ_LE_UINT32(p); + p += 4; + + int zbufLinePtr[640]; + for (int i = 0; i != 640; ++i) + zbufLinePtr[i] = 65535; + + while (polyCount--) { + uint32 vertexCount = READ_LE_UINT32(p); + p += 4; + + if (vertexCount == 0) + continue; + + uint32 lastVertex = vertexCount - 1; + int lastVertexX = MAX((_t1[p[3*lastVertex]] + _t2[p[3*lastVertex+1]] + _c3) >> 16, 0); + + int previousVertexX = lastVertexX; + + while (vertexCount--) { + int vertexX = CLIP((_t1[p[0]] + _t2[p[1]] + _c3) >> 16, 0, 640); + + if (vertexX > previousVertexX) { + int vertexZ = (_t4[p[0]] + _t5[p[1]] + _c6) >> 6; + + if (vertexZ >= 0 && vertexZ < 65536) { + for (int x = previousVertexX; x != vertexX; ++x) { + if (vertexZ < zbufLinePtr[x]) { + frameLinePtr[x] = palette[p[2]]; + zbufLinePtr[x] = (int16)vertexZ; + } + } + } + } + p += 3; + previousVertexX = vertexX; + } + } +} + +} // End of namespace BladeRunner diff --git a/engines/bladerunner/slice_renderer.h b/engines/bladerunner/slice_renderer.h new file mode 100644 index 0000000000..2e0fe93d77 --- /dev/null +++ b/engines/bladerunner/slice_renderer.h @@ -0,0 +1,96 @@ +/* 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_SLICE_RENDERER_H +#define BLADERUNNER_SLICE_RENDERER_H + +#include "bladerunner/vector.h" +#include "bladerunner/view.h" +#include "bladerunner/matrix.h" + +#include "graphics/surface.h" + +namespace Common { + class MemoryReadStream; +} + +namespace BladeRunner { + +class BladeRunnerEngine; + +class SliceRenderer { + BladeRunnerEngine *_vm; + + int _animation; + int _frame; + Vector3 _position; + float _facing; + float _scale; + + View _view; + + void *_sliceFramePtr; + + // Animation frame data + Vector2 _frameFront; + float _frameBottomZ; + Vector2 _framePos; + float _frameSliceHeight; + uint32 _framePaletteIndex; + uint32 _frameSliceCount; + + Matrix3x2 _field_109E; + Vector3 _field_10B6; + Vector3 _field_10C2; + float _field_10CE; + float _field_10D2; + int _minX; + int _maxX; + int _minY; + int _maxY; + + int _t1[256]; + int _t2[256]; + int _c3; + int _t4[256]; + int _t5[256]; + int _c6; + + Matrix3x2 calculateFacingRotationMatrix(); + void drawSlice(int slice, uint16 *frameLinePtr); + +public: + SliceRenderer(BladeRunnerEngine *vm) + : _vm(vm) + {} + ~SliceRenderer(); + + void setView(const View &view); + void setupFrame(int animation, int frame, Vector3 position, float facing, float scale = 1.0f); + void calculateBoundingRect(); + + void drawFrame(Graphics::Surface &surface); +}; + +} // End of namespace BladeRunner + +#endif -- cgit v1.2.3