diff options
| -rw-r--r-- | engines/bladerunner/bladerunner.cpp | 32 | ||||
| -rw-r--r-- | engines/bladerunner/bladerunner.h | 17 | ||||
| -rw-r--r-- | engines/bladerunner/module.mk | 2 | ||||
| -rw-r--r-- | engines/bladerunner/slice_animations.cpp | 173 | ||||
| -rw-r--r-- | engines/bladerunner/slice_animations.h | 111 | ||||
| -rw-r--r-- | engines/bladerunner/slice_renderer.cpp | 412 | ||||
| -rw-r--r-- | engines/bladerunner/slice_renderer.h | 96 | 
7 files changed, 836 insertions, 7 deletions
| 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<int32> _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<SlicePalette> _palettes; +	Common::Array<Animation>    _animations; +	Common::Array<Page>         _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 | 
