2014-06-05 23:49:57 +02:00
|
|
|
/* 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"
|
2015-09-13 01:48:13 +02:00
|
|
|
#include "bladerunner/lights.h"
|
2017-09-10 20:19:02 +02:00
|
|
|
#include "bladerunner/screen_effects.h"
|
2016-09-10 18:16:17 +02:00
|
|
|
#include "bladerunner/set_effects.h"
|
|
|
|
#include "bladerunner/slice_animations.h"
|
2014-06-05 23:49:57 +02:00
|
|
|
|
|
|
|
#include "common/memstream.h"
|
|
|
|
#include "common/rect.h"
|
|
|
|
#include "common/util.h"
|
|
|
|
|
|
|
|
namespace BladeRunner {
|
|
|
|
|
2016-10-12 23:00:33 +02:00
|
|
|
SliceRenderer::SliceRenderer(BladeRunnerEngine *vm) {
|
2015-09-19 01:43:38 +02:00
|
|
|
_vm = vm;
|
2016-09-26 23:38:35 +02:00
|
|
|
_pixelFormat = createRGB555();
|
2016-09-10 18:16:17 +02:00
|
|
|
int i;
|
2015-09-19 01:43:38 +02:00
|
|
|
|
|
|
|
for (i = 0; i < 942; i++) { // yes, its going just to 942 and not 997
|
|
|
|
_animationsShadowEnabled[i] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-05 23:49:57 +02:00
|
|
|
SliceRenderer::~SliceRenderer() {
|
|
|
|
}
|
|
|
|
|
2017-09-10 20:19:02 +02:00
|
|
|
void SliceRenderer::setScreenEffects(ScreenEffects *screenEffects) {
|
|
|
|
_screenEffects = screenEffects;
|
2017-08-26 21:27:54 +02:00
|
|
|
}
|
|
|
|
|
2016-09-10 18:16:17 +02:00
|
|
|
void SliceRenderer::setView(const View &view) {
|
2014-06-05 23:49:57 +02:00
|
|
|
_view = view;
|
|
|
|
}
|
|
|
|
|
2016-10-12 23:00:33 +02:00
|
|
|
void SliceRenderer::setLights(Lights *lights) {
|
2016-09-10 18:16:17 +02:00
|
|
|
_lights = lights;
|
|
|
|
}
|
|
|
|
|
2016-10-12 23:00:33 +02:00
|
|
|
void SliceRenderer::setSetEffects(SetEffects *setEffects) {
|
2016-09-10 18:16:17 +02:00
|
|
|
_setEffects = setEffects;
|
|
|
|
}
|
|
|
|
|
2016-10-12 23:00:33 +02:00
|
|
|
void SliceRenderer::setupFrameInWorld(int animationId, int animationFrame, Vector3 position, float facing, float scale) {
|
2014-06-05 23:49:57 +02:00
|
|
|
_position = position;
|
|
|
|
_facing = facing;
|
|
|
|
_scale = scale;
|
|
|
|
|
2016-10-12 23:00:33 +02:00
|
|
|
loadFrame(animationId, animationFrame);
|
2014-06-05 23:49:57 +02:00
|
|
|
|
|
|
|
calculateBoundingRect();
|
|
|
|
}
|
|
|
|
|
2016-10-12 23:00:33 +02:00
|
|
|
void SliceRenderer::getScreenRectangle(Common::Rect *screenRectangle, int animationId, int animationFrame, Vector3 position, float facing, float scale) {
|
|
|
|
assert(screenRectangle);
|
|
|
|
setupFrameInWorld(animationId, animationFrame, position, facing, scale);
|
|
|
|
*screenRectangle = _screenRectangle;
|
|
|
|
}
|
|
|
|
|
2014-06-05 23:49:57 +02:00
|
|
|
Matrix3x2 SliceRenderer::calculateFacingRotationMatrix() {
|
|
|
|
assert(_sliceFramePtr);
|
|
|
|
|
2016-09-10 18:16:17 +02:00
|
|
|
Matrix4x3 viewMatrix = _view._sliceViewMatrix;
|
2014-06-05 23:49:57 +02:00
|
|
|
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);
|
|
|
|
|
2016-10-12 23:00:33 +02:00
|
|
|
_screenRectangle.left = 0;
|
|
|
|
_screenRectangle.right = 0;
|
|
|
|
_screenRectangle.top = 0;
|
|
|
|
_screenRectangle.bottom = 0;
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2016-09-10 18:16:17 +02:00
|
|
|
Matrix4x3 viewMatrix = _view._sliceViewMatrix;
|
2014-06-05 23:49:57 +02:00
|
|
|
|
|
|
|
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();
|
|
|
|
|
2016-10-12 23:00:33 +02:00
|
|
|
Matrix3x2 m_projection(_view._viewportDistance / bottom.z, 0.0f, 0.0f,
|
|
|
|
0.0f, 25.5f, 0.0f);
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2016-10-12 23:00:33 +02:00
|
|
|
Matrix3x2 m_frame(_frameScale.x, 0.0f, _framePos.x,
|
|
|
|
0.0f, _frameScale.y, _framePos.y);
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2016-10-12 23:00:33 +02:00
|
|
|
_modelMatrix = m_projection * (facingRotation * m_frame);
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
Vector4 startScreenVector(
|
|
|
|
_view._viewportHalfWidth + top.x / top.z * _view._viewportDistance,
|
2016-09-10 18:16:17 +02:00
|
|
|
_view._viewportHalfHeight + top.y / top.z * _view._viewportDistance,
|
2014-06-05 23:49:57 +02:00
|
|
|
1.0f / top.z,
|
|
|
|
_frameSliceCount * (1.0f / top.z));
|
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
Vector4 endScreenVector(
|
|
|
|
_view._viewportHalfWidth + bottom.x / bottom.z * _view._viewportDistance,
|
2016-09-10 18:16:17 +02:00
|
|
|
_view._viewportHalfHeight + bottom.y / bottom.z * _view._viewportDistance,
|
2014-06-05 23:49:57 +02:00
|
|
|
1.0f / bottom.z,
|
|
|
|
0.0f);
|
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
_startScreenVector.x = startScreenVector.x;
|
|
|
|
_startScreenVector.y = startScreenVector.y;
|
|
|
|
_startScreenVector.z = startScreenVector.z;
|
|
|
|
_endScreenVector.x = endScreenVector.x;
|
|
|
|
_endScreenVector.y = endScreenVector.y;
|
|
|
|
_endScreenVector.z = endScreenVector.z;
|
|
|
|
_startSlice = startScreenVector.w;
|
|
|
|
_endSlice = endScreenVector.w;
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
Vector4 delta = endScreenVector - startScreenVector;
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2016-10-12 23:00:33 +02:00
|
|
|
if (delta.y == 0.0f) {
|
2014-06-05 23:49:57 +02:00
|
|
|
return;
|
2016-10-12 23:00:33 +02:00
|
|
|
}
|
2014-06-05 23:49:57 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Calculate min and max Y
|
|
|
|
*/
|
|
|
|
|
|
|
|
float screenMinY = 0.0f;
|
|
|
|
float screenMaxY = 479.0f;
|
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
if (startScreenVector.y < screenMinY) {
|
|
|
|
if (endScreenVector.y < screenMinY)
|
2014-06-05 23:49:57 +02:00
|
|
|
return;
|
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
float f = (screenMinY - startScreenVector.y) / delta.y;
|
|
|
|
startScreenVector = startScreenVector + f * delta;
|
|
|
|
} else if (startScreenVector.y > screenMaxY) {
|
|
|
|
if (endScreenVector.y >= screenMaxY)
|
2014-06-05 23:49:57 +02:00
|
|
|
return;
|
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
float f = (screenMaxY - startScreenVector.y) / delta.y;
|
|
|
|
startScreenVector = startScreenVector + f * delta;
|
2014-06-05 23:49:57 +02:00
|
|
|
}
|
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
if (endScreenVector.y < screenMinY) {
|
|
|
|
float f = (screenMinY - endScreenVector.y) / delta.y;
|
|
|
|
endScreenVector = endScreenVector + f * delta;
|
|
|
|
} else if (endScreenVector.y > screenMaxY) {
|
|
|
|
float f = (screenMaxY - endScreenVector.y) / delta.y;
|
|
|
|
endScreenVector = endScreenVector + f * delta;
|
2014-06-05 23:49:57 +02:00
|
|
|
}
|
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
int bbox_min_y = (int)MIN(startScreenVector.y, endScreenVector.y);
|
|
|
|
int bbox_max_y = (int)MAX(startScreenVector.y, endScreenVector.y) + 1;
|
2014-06-05 23:49:57 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Calculate min and max X
|
|
|
|
*/
|
|
|
|
|
2016-10-12 23:00:33 +02:00
|
|
|
Matrix3x2 mB6 = _modelMatrix + Vector2(startScreenVector.x, 25.5f / startScreenVector.z);
|
|
|
|
Matrix3x2 mC2 = _modelMatrix + Vector2(endScreenVector.x, 25.5f / endScreenVector.z);
|
2014-06-05 23:49:57 +02:00
|
|
|
|
|
|
|
float min_x = 640.0f;
|
|
|
|
float max_x = 0.0f;
|
|
|
|
|
2016-10-03 12:38:43 +02:00
|
|
|
for (float i = 0.0f; i <= 256.0f; i += 255.0f) {
|
|
|
|
for (float j = 0.0f; j <= 256.0f; j += 255.0f) {
|
2014-06-05 23:49:57 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-12 23:00:33 +02:00
|
|
|
int bbox_min_x = CLIP((int)min_x, 0, 640);
|
|
|
|
int bbox_max_x = CLIP((int)max_x + 1, 0, 640);
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
_startScreenVector.x = startScreenVector.x;
|
|
|
|
_startScreenVector.y = startScreenVector.y;
|
|
|
|
_startScreenVector.z = startScreenVector.z;
|
|
|
|
_endScreenVector.x = endScreenVector.x;
|
|
|
|
_endScreenVector.y = endScreenVector.y;
|
|
|
|
_endScreenVector.z = endScreenVector.z;
|
|
|
|
_startSlice = startScreenVector.w;
|
|
|
|
_endSlice = endScreenVector.w;
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2016-10-12 23:00:33 +02:00
|
|
|
_screenRectangle.left = bbox_min_x;
|
|
|
|
_screenRectangle.right = bbox_max_x;
|
|
|
|
_screenRectangle.top = bbox_min_y;
|
|
|
|
_screenRectangle.bottom = bbox_max_y;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SliceRenderer::loadFrame(int animation, int frame) {
|
|
|
|
_animation = animation;
|
|
|
|
_frame = frame;
|
|
|
|
_sliceFramePtr = _vm->_sliceAnimations->getFramePtr(_animation, _frame);
|
|
|
|
|
2018-01-14 12:12:06 +01:00
|
|
|
Common::MemoryReadStream stream((byte *)_sliceFramePtr, _vm->_sliceAnimations->_animations[_animation].frameSize);
|
2016-10-12 23:00:33 +02:00
|
|
|
|
2018-02-01 20:40:49 +01:00
|
|
|
_frameScale.x = stream.readFloatLE();
|
|
|
|
_frameScale.y = stream.readFloatLE();
|
|
|
|
_frameSliceHeight = stream.readFloatLE();
|
|
|
|
_framePos.x = stream.readFloatLE();
|
|
|
|
_framePos.y = stream.readFloatLE();
|
|
|
|
_frameBottomZ = stream.readFloatLE();
|
2016-10-12 23:00:33 +02:00
|
|
|
_framePaletteIndex = stream.readUint32LE();
|
2018-02-01 20:40:49 +01:00
|
|
|
_frameSliceCount = stream.readUint32LE();
|
2014-06-05 23:49:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
struct SliceLineIterator {
|
2016-09-26 23:38:35 +02:00
|
|
|
int _sliceMatrix[2][3];
|
|
|
|
int _startY;
|
|
|
|
int _endY;
|
|
|
|
|
|
|
|
float _currentZ;
|
|
|
|
float _stepZ;
|
|
|
|
float _currentSlice;
|
|
|
|
float _stepSlice;
|
|
|
|
float _currentX;
|
|
|
|
float _stepX;
|
2014-06-05 23:49:57 +02:00
|
|
|
int _field_38;
|
2016-09-26 23:38:35 +02:00
|
|
|
int _currentY;
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
void setup(float endScreenX, float endScreenY, float endScreenZ,
|
|
|
|
float startScreenX, float startScreenY, float startScreenZ,
|
|
|
|
float endSlice, float startSlice,
|
|
|
|
Matrix3x2 m);
|
2014-06-05 23:49:57 +02:00
|
|
|
float line();
|
|
|
|
void advance();
|
|
|
|
};
|
|
|
|
|
|
|
|
void SliceLineIterator::setup(
|
2016-10-03 12:38:43 +02:00
|
|
|
float endScreenX, float endScreenY, float endScreenZ,
|
|
|
|
float startScreenX, float startScreenY, float startScreenZ,
|
|
|
|
float endSlice, float startSlice,
|
|
|
|
Matrix3x2 m) {
|
2016-09-26 23:38:35 +02:00
|
|
|
_startY = (int)startScreenY;
|
|
|
|
_endY = (int)endScreenY;
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
float size = endScreenY - startScreenY;
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
if (size <= 0.0f || startScreenZ <= 0.0f)
|
|
|
|
_currentY = _endY + 1;
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
_currentZ = startScreenZ;
|
|
|
|
_stepZ = (endScreenZ - startScreenZ) / size;
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
_stepSlice = (endSlice - startSlice) / size;
|
|
|
|
_currentSlice = startSlice - (startScreenY - floor(startScreenY) - 1.0f) * _stepSlice;
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
_currentX = startScreenX;
|
|
|
|
_stepX = (endScreenX - startScreenX) / size;
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
_field_38 = (int)((25.5f / size) * (1.0f / endScreenZ - 1.0f / startScreenZ) * 64.0);
|
|
|
|
_currentY = _startY;
|
|
|
|
|
|
|
|
float offsetX = _currentX;
|
|
|
|
float offsetZ = 25.5f / _currentZ;
|
|
|
|
|
|
|
|
Matrix3x2 translate_matrix = Matrix3x2(1.0f, 0.0f, offsetX,
|
|
|
|
0.0f, 1.0f, offsetZ);
|
2014-06-05 23:49:57 +02:00
|
|
|
|
|
|
|
Matrix3x2 scale_matrix = Matrix3x2(65536.0f, 0.0f, 0.0f,
|
|
|
|
0.0f, 64.0f, 0.0f);
|
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
m = scale_matrix * (translate_matrix * m);
|
2014-06-05 23:49:57 +02:00
|
|
|
|
|
|
|
for (int r = 0; r != 2; ++r)
|
|
|
|
for (int c = 0; c != 3; ++c)
|
2016-09-26 23:38:35 +02:00
|
|
|
_sliceMatrix[r][c] = m(r, c);
|
2014-06-05 23:49:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
float SliceLineIterator::line() {
|
|
|
|
float var_0 = 0.0f;
|
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
if (_currentZ != 0.0f)
|
|
|
|
var_0 = _currentSlice / _currentZ;
|
2014-06-05 23:49:57 +02:00
|
|
|
|
|
|
|
if (var_0 < 0.0)
|
|
|
|
var_0 = 0.0f;
|
|
|
|
|
|
|
|
return var_0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SliceLineIterator::advance() {
|
2016-09-26 23:38:35 +02:00
|
|
|
_currentZ += _stepZ;
|
|
|
|
_currentSlice += _stepSlice;
|
|
|
|
_currentX += _stepX;
|
|
|
|
_currentY += 1;
|
|
|
|
_sliceMatrix[0][2] += (int)(65536.0f * _stepX);
|
|
|
|
_sliceMatrix[1][2] += _field_38;
|
2014-06-05 23:49:57 +02:00
|
|
|
}
|
|
|
|
|
2016-10-03 12:38:43 +02:00
|
|
|
static void setupLookupTable(int t[256], int inc) {
|
2014-06-05 23:49:57 +02:00
|
|
|
int v = 0;
|
|
|
|
for (int i = 0; i != 256; ++i) {
|
|
|
|
t[i] = v;
|
|
|
|
v += inc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-08 21:06:22 +02:00
|
|
|
void SliceRenderer::drawInWorld(int animationId, int animationFrame, Vector3 position, float facing, float scale, Graphics::Surface &surface, uint16 *zbuffer) {
|
2016-09-10 18:33:04 +02:00
|
|
|
assert(_lights);
|
|
|
|
assert(_setEffects);
|
|
|
|
//assert(_view);
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2016-10-12 23:00:33 +02:00
|
|
|
_vm->_sliceRenderer->setupFrameInWorld(animationId, animationFrame, position, facing);
|
2016-10-22 18:30:46 +02:00
|
|
|
assert(_sliceFramePtr);
|
2016-09-26 23:38:35 +02:00
|
|
|
|
2014-06-05 23:49:57 +02:00
|
|
|
SliceLineIterator sliceLineIterator;
|
|
|
|
sliceLineIterator.setup(
|
2016-09-26 23:38:35 +02:00
|
|
|
_endScreenVector.x, _endScreenVector.y, _endScreenVector.z,
|
|
|
|
_startScreenVector.x, _startScreenVector.y, _startScreenVector.z,
|
|
|
|
_endSlice, _startSlice,
|
2016-10-12 23:00:33 +02:00
|
|
|
_modelMatrix
|
2016-09-26 23:38:35 +02:00
|
|
|
);
|
|
|
|
|
2017-08-26 21:27:54 +02:00
|
|
|
Vector3 cameraPosition(_view._cameraPosition.x, _view._cameraPosition.z, _view._cameraPosition.y); // not a bug
|
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
SliceRendererLights sliceRendererLights = SliceRendererLights(_lights);
|
2016-10-03 12:38:43 +02:00
|
|
|
|
2016-09-29 01:27:45 +02:00
|
|
|
_lights->setupFrame(_view._frame);
|
|
|
|
_setEffects->setupFrame(_view._frame);
|
2016-09-10 18:33:04 +02:00
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
float sliceLine = sliceLineIterator.line();
|
|
|
|
|
|
|
|
sliceRendererLights.calculateColorBase(
|
|
|
|
Vector3(_position.x, _position.y, _position.z + _frameBottomZ + sliceLine * _frameSliceHeight),
|
|
|
|
Vector3(_position.x, _position.y, _position.z + _frameBottomZ),
|
|
|
|
sliceLineIterator._endY - sliceLineIterator._startY);
|
2016-10-03 12:38:43 +02:00
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
float setEffectsColorCoeficient;
|
|
|
|
Color setEffectColor;
|
|
|
|
_setEffects->calculateColor(
|
2017-08-26 21:27:54 +02:00
|
|
|
cameraPosition,
|
2016-09-26 23:38:35 +02:00
|
|
|
Vector3(_position.x, _position.y, _position.z + _frameBottomZ + sliceLine * _frameSliceHeight),
|
|
|
|
&setEffectsColorCoeficient,
|
|
|
|
&setEffectColor);
|
|
|
|
|
|
|
|
_lightsColor.r = setEffectsColorCoeficient * sliceRendererLights._finalColor.r * 65536.0f;
|
|
|
|
_lightsColor.g = setEffectsColorCoeficient * sliceRendererLights._finalColor.g * 65536.0f;
|
|
|
|
_lightsColor.b = setEffectsColorCoeficient * sliceRendererLights._finalColor.b * 65536.0f;
|
|
|
|
|
|
|
|
_setEffectColor.r = setEffectColor.r * 31.0f * 65536.0f;
|
|
|
|
_setEffectColor.g = setEffectColor.g * 31.0f * 65536.0f;
|
|
|
|
_setEffectColor.b = setEffectColor.b * 31.0f * 65536.0f;
|
|
|
|
|
|
|
|
setupLookupTable(_m11lookup, sliceLineIterator._sliceMatrix[0][0]);
|
|
|
|
setupLookupTable(_m12lookup, sliceLineIterator._sliceMatrix[0][1]);
|
2016-10-12 23:00:33 +02:00
|
|
|
_m13 = sliceLineIterator._sliceMatrix[0][2];
|
2016-09-26 23:38:35 +02:00
|
|
|
setupLookupTable(_m21lookup, sliceLineIterator._sliceMatrix[1][0]);
|
|
|
|
setupLookupTable(_m22lookup, sliceLineIterator._sliceMatrix[1][1]);
|
2016-10-12 23:00:33 +02:00
|
|
|
_m23 = sliceLineIterator._sliceMatrix[1][2];
|
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
|
|
|
|
if(_animationsShadowEnabled[_animation]) {
|
|
|
|
//TODO: draw shadows
|
|
|
|
}
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
int frameY = sliceLineIterator._startY;
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2018-01-14 12:12:06 +01:00
|
|
|
uint16 *frameLinePtr = (uint16 *)surface.getPixels() + 640 * frameY;
|
2015-02-06 15:31:43 +01:00
|
|
|
uint16 *zBufferLinePtr = zbuffer + 640 * frameY;
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
while (sliceLineIterator._currentY <= sliceLineIterator._endY) {
|
|
|
|
sliceLine = sliceLineIterator.line();
|
|
|
|
|
|
|
|
sliceRendererLights.calculateColorSlice(Vector3(_position.x, _position.y, _position.z + _frameBottomZ + sliceLine * _frameSliceHeight));
|
|
|
|
|
|
|
|
if (sliceLineIterator._currentY & 1) {
|
|
|
|
_setEffects->calculateColor(
|
2017-08-26 21:27:54 +02:00
|
|
|
cameraPosition,
|
2016-09-26 23:38:35 +02:00
|
|
|
Vector3(_position.x, _position.y, _position.z + _frameBottomZ + sliceLine * _frameSliceHeight),
|
|
|
|
&setEffectsColorCoeficient,
|
|
|
|
&setEffectColor);
|
|
|
|
}
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2016-09-26 23:38:35 +02:00
|
|
|
_lightsColor.r = setEffectsColorCoeficient * sliceRendererLights._finalColor.r * 65536.0f;
|
|
|
|
_lightsColor.g = setEffectsColorCoeficient * sliceRendererLights._finalColor.g * 65536.0f;
|
|
|
|
_lightsColor.b = setEffectsColorCoeficient * sliceRendererLights._finalColor.b * 65536.0f;
|
|
|
|
|
|
|
|
_setEffectColor.r = setEffectColor.r * 31.0f * 65536.0f;
|
|
|
|
_setEffectColor.g = setEffectColor.g * 31.0f * 65536.0f;
|
|
|
|
_setEffectColor.b = setEffectColor.b * 31.0f * 65536.0f;
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2016-10-12 23:00:33 +02:00
|
|
|
if (frameY >= 0 && frameY < 480) {
|
2017-08-26 21:27:54 +02:00
|
|
|
drawSlice((int)sliceLine, true, frameLinePtr, zBufferLinePtr, frameY);
|
2016-10-12 23:00:33 +02:00
|
|
|
}
|
2014-06-05 23:49:57 +02:00
|
|
|
|
|
|
|
sliceLineIterator.advance();
|
|
|
|
frameY += 1;
|
|
|
|
frameLinePtr += 640;
|
2015-02-06 15:31:43 +01:00
|
|
|
zBufferLinePtr += 640;
|
2014-06-05 23:49:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-14 12:12:06 +01:00
|
|
|
void SliceRenderer::drawOnScreen(int animationId, int animationFrame, int screenX, int screenY, float facing, float scale, Graphics::Surface &surface) {
|
2016-10-08 21:06:22 +02:00
|
|
|
if (scale == 0.0f) {
|
|
|
|
return;
|
2016-10-15 13:47:06 +02:00
|
|
|
}
|
2016-10-08 21:06:22 +02:00
|
|
|
_position.x = 0;
|
|
|
|
_position.y = 0;
|
|
|
|
_position.z = 0;
|
|
|
|
_facing = facing;
|
2016-10-15 13:47:06 +02:00
|
|
|
|
2016-10-12 23:00:33 +02:00
|
|
|
loadFrame(animationId, animationFrame);
|
2016-10-08 21:06:22 +02:00
|
|
|
|
2016-10-09 12:03:19 +02:00
|
|
|
float frameHeight = _frameSliceHeight * _frameSliceCount;
|
|
|
|
float frameSize = sqrtf(_frameScale.x * 255.0f * _frameScale.x * 255.0f + _frameScale.y * 255.0f * _frameScale.y * 255.0f);
|
|
|
|
float size = scale / MAX(frameSize, frameHeight);
|
|
|
|
|
2016-10-08 21:06:22 +02:00
|
|
|
float s = sinf(_facing);
|
|
|
|
float c = cosf(_facing);
|
|
|
|
|
|
|
|
Matrix3x2 m_rotation(c, -s, 0.0f,
|
|
|
|
s, c, 0.0f);
|
|
|
|
|
|
|
|
Matrix3x2 m_frame(_frameScale.x, 0.0f, _framePos.x,
|
|
|
|
0.0f, _frameScale.y, _framePos.y);
|
|
|
|
|
2016-10-09 12:03:19 +02:00
|
|
|
Matrix3x2 m_scale_size_25_5(size, 0.0f, 0.0f,
|
|
|
|
0.0f, 25.5f, 0.0f);
|
2016-10-08 21:06:22 +02:00
|
|
|
|
|
|
|
Matrix3x2 m_translate_x_32k(1.0f, 0.0f, screenX,
|
|
|
|
0.0f, 1.0f, 32768.0f);
|
|
|
|
|
|
|
|
Matrix3x2 m_scale_64k_64(65536.0f, 0.0f, 0.0f,
|
|
|
|
0.0f, 64.0f, 0.0f);
|
|
|
|
|
2016-10-09 12:03:19 +02:00
|
|
|
Matrix3x2 m = m_scale_64k_64 * (m_translate_x_32k * (m_scale_size_25_5 * (m_rotation * m_frame)));
|
2016-10-08 21:06:22 +02:00
|
|
|
|
2016-10-09 12:03:19 +02:00
|
|
|
setupLookupTable(_m11lookup, m(0, 0));
|
|
|
|
setupLookupTable(_m12lookup, m(0, 1));
|
2016-10-08 21:06:22 +02:00
|
|
|
_m13 = m(0, 2);
|
2016-10-09 12:03:19 +02:00
|
|
|
setupLookupTable(_m21lookup, m(1, 0));
|
|
|
|
setupLookupTable(_m22lookup, m(1, 1));
|
2016-10-08 21:06:22 +02:00
|
|
|
_m23 = m(1, 2);
|
2016-10-09 12:03:19 +02:00
|
|
|
|
|
|
|
int frameY = screenY + (size / 2.0f * frameHeight);
|
2016-10-08 21:06:22 +02:00
|
|
|
int currentY = frameY;
|
2016-10-12 23:00:33 +02:00
|
|
|
|
2016-10-09 12:03:19 +02:00
|
|
|
float currentSlice = 0;
|
|
|
|
float sliceStep = 1.0f / size / _frameSliceHeight;
|
|
|
|
|
2018-01-14 12:12:06 +01:00
|
|
|
uint16 *frameLinePtr = (uint16 *)surface.getPixels() + 640 * frameY;
|
2016-10-08 21:06:22 +02:00
|
|
|
uint16 lineZbuffer[640];
|
2016-10-09 12:03:19 +02:00
|
|
|
|
|
|
|
while (currentSlice < _frameSliceCount) {
|
|
|
|
if (currentY >= 0 && currentY < 480) {
|
2016-10-08 21:06:22 +02:00
|
|
|
memset(lineZbuffer, 0xFF, 640 * 2);
|
2017-08-26 21:27:54 +02:00
|
|
|
drawSlice(currentSlice, false, frameLinePtr, lineZbuffer, currentY);
|
2016-10-09 12:03:19 +02:00
|
|
|
currentSlice += sliceStep;
|
2016-10-08 21:06:22 +02:00
|
|
|
currentY--;
|
|
|
|
frameLinePtr -= 640;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-26 21:27:54 +02:00
|
|
|
void SliceRenderer::drawSlice(int slice, bool advanced, uint16 *frameLinePtr, uint16 *zbufLinePtr, int y) {
|
2015-02-06 15:31:43 +01:00
|
|
|
if (slice < 0 || (uint32)slice >= _frameSliceCount)
|
2014-06-05 23:49:57 +02:00
|
|
|
return;
|
|
|
|
|
2018-01-14 12:12:06 +01:00
|
|
|
SliceAnimations::Palette &palette = _vm->_sliceAnimations->getPalette(_framePaletteIndex);
|
2014-06-05 23:49:57 +02:00
|
|
|
|
2018-01-14 12:12:06 +01:00
|
|
|
byte *p = (byte *)_sliceFramePtr + 0x20 + 4 * slice;
|
2014-06-05 23:49:57 +02:00
|
|
|
|
|
|
|
uint32 polyOffset = READ_LE_UINT32(p);
|
|
|
|
|
2018-01-14 12:12:06 +01:00
|
|
|
p = (byte *)_sliceFramePtr + polyOffset;
|
2014-06-05 23:49:57 +02:00
|
|
|
|
|
|
|
uint32 polyCount = READ_LE_UINT32(p);
|
|
|
|
p += 4;
|
|
|
|
while (polyCount--) {
|
|
|
|
uint32 vertexCount = READ_LE_UINT32(p);
|
|
|
|
p += 4;
|
|
|
|
|
|
|
|
if (vertexCount == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
uint32 lastVertex = vertexCount - 1;
|
2016-09-29 01:15:07 +02:00
|
|
|
int lastVertexX = MAX((_m11lookup[p[3 * lastVertex]] + _m12lookup[p[3 * lastVertex + 1]] + _m13) >> 16, 0);
|
2014-06-05 23:49:57 +02:00
|
|
|
|
|
|
|
int previousVertexX = lastVertexX;
|
|
|
|
|
|
|
|
while (vertexCount--) {
|
2016-09-26 23:38:35 +02:00
|
|
|
int vertexX = CLIP((_m11lookup[p[0]] + _m12lookup[p[1]] + _m13) >> 16, 0, 640);
|
2014-06-05 23:49:57 +02:00
|
|
|
|
|
|
|
if (vertexX > previousVertexX) {
|
2016-09-26 23:38:35 +02:00
|
|
|
int vertexZ = (_m21lookup[p[0]] + _m22lookup[p[1]] + _m23) >> 6;
|
2014-06-05 23:49:57 +02:00
|
|
|
|
|
|
|
if (vertexZ >= 0 && vertexZ < 65536) {
|
2016-10-08 21:06:22 +02:00
|
|
|
int color555 = palette.color555[p[2]];
|
|
|
|
if (advanced) {
|
2017-08-26 21:27:54 +02:00
|
|
|
Color256 aescColor = { 0, 0, 0 };
|
2017-09-10 20:19:02 +02:00
|
|
|
_screenEffects->getColor(&aescColor, vertexX, y, vertexZ);
|
2016-09-26 23:38:35 +02:00
|
|
|
|
2017-08-26 21:27:54 +02:00
|
|
|
Color256 color = palette.color[p[2]];
|
|
|
|
color.r = ((int)(_setEffectColor.r + _lightsColor.r * color.r) >> 16) + aescColor.r;
|
|
|
|
color.g = ((int)(_setEffectColor.g + _lightsColor.g * color.g) >> 16) + aescColor.g;
|
|
|
|
color.b = ((int)(_setEffectColor.b + _lightsColor.b * color.b) >> 16) + aescColor.b;
|
2016-09-26 23:38:35 +02:00
|
|
|
|
2016-10-08 21:06:22 +02:00
|
|
|
int bladeToScummVmConstant = 256 / 32;
|
|
|
|
color555 = _pixelFormat.RGBToColor(CLIP(color.r * bladeToScummVmConstant, 0, 255), CLIP(color.g * bladeToScummVmConstant, 0, 255), CLIP(color.b * bladeToScummVmConstant, 0, 255));
|
|
|
|
}
|
2014-06-05 23:49:57 +02:00
|
|
|
for (int x = previousVertexX; x != vertexX; ++x) {
|
|
|
|
if (vertexZ < zbufLinePtr[x]) {
|
2016-09-26 23:38:35 +02:00
|
|
|
frameLinePtr[x] = color555;
|
2015-02-06 15:31:43 +01:00
|
|
|
zbufLinePtr[x] = (uint16)vertexZ;
|
2014-06-05 23:49:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p += 3;
|
|
|
|
previousVertexX = vertexX;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-09-15 20:26:46 +02:00
|
|
|
void SliceRenderer::preload(int animationId) {
|
|
|
|
int i;
|
2016-09-10 18:16:17 +02:00
|
|
|
int frameCount = _vm->_sliceAnimations->getFrameCount(animationId);
|
|
|
|
for (i = 0; i < frameCount; i++)
|
2015-09-15 20:26:46 +02:00
|
|
|
_vm->_sliceAnimations->getFramePtr(animationId, i);
|
|
|
|
}
|
2015-09-19 01:43:38 +02:00
|
|
|
|
2016-09-10 18:33:04 +02:00
|
|
|
void SliceRenderer::disableShadows(int animationsIdsList[], int listSize) {
|
2015-09-19 01:43:38 +02:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < listSize; i++) {
|
|
|
|
_animationsShadowEnabled[animationsIdsList[i]] = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-15 13:47:06 +02:00
|
|
|
SliceRendererLights::SliceRendererLights(Lights *lights) {
|
2016-09-26 23:38:35 +02:00
|
|
|
_finalColor.r = 0.0f;
|
|
|
|
_finalColor.g = 0.0f;
|
|
|
|
_finalColor.b = 0.0f;
|
|
|
|
|
|
|
|
_lights = lights;
|
|
|
|
|
2016-10-12 23:00:33 +02:00
|
|
|
for (int i = 0; i < 20; i++) {
|
2017-04-02 18:17:43 +02:00
|
|
|
_cacheColor[i].r = 0.0f;
|
|
|
|
_cacheColor[i].g = 0.0f;
|
|
|
|
_cacheColor[i].b = 0.0f;
|
2016-09-26 23:38:35 +02:00
|
|
|
}
|
2018-02-01 20:40:49 +01:00
|
|
|
|
|
|
|
_cacheRecalculation = 0.0f;
|
2016-09-26 23:38:35 +02:00
|
|
|
}
|
|
|
|
|
2016-10-15 13:47:06 +02:00
|
|
|
void SliceRendererLights::calculateColorBase(Vector3 position1, Vector3 position2, float height) {
|
2016-09-26 23:38:35 +02:00
|
|
|
_finalColor.r = 0.0f;
|
|
|
|
_finalColor.g = 0.0f;
|
|
|
|
_finalColor.b = 0.0f;
|
2017-04-02 18:17:43 +02:00
|
|
|
_cacheRecalculation = 0;
|
2016-09-26 23:38:35 +02:00
|
|
|
if (_lights) {
|
2016-10-12 23:00:33 +02:00
|
|
|
for (uint i = 0; i < _lights->_lights.size(); i++) {
|
2016-09-29 01:15:07 +02:00
|
|
|
Light *light = _lights->_lights[i];
|
|
|
|
if (i < 20) {
|
2017-04-02 18:17:43 +02:00
|
|
|
float cacheCoeficient = light->calculate(position1, position2/*, height*/);
|
|
|
|
_cacheStart[i] = cacheCoeficient;
|
|
|
|
_cacheCounter[i] = cacheCoeficient;
|
2016-09-29 01:15:07 +02:00
|
|
|
|
2017-04-02 18:17:43 +02:00
|
|
|
Color color;
|
|
|
|
light->calculateColor(&color, position1);
|
|
|
|
_cacheColor[i] = color;
|
|
|
|
_finalColor.r += color.r;
|
|
|
|
_finalColor.g += color.g;
|
|
|
|
_finalColor.b += color.b;
|
2016-09-29 01:15:07 +02:00
|
|
|
} else {
|
2017-04-02 18:17:43 +02:00
|
|
|
Color color;
|
|
|
|
light->calculateColor(&color, position1);
|
|
|
|
_finalColor.r += color.r;
|
|
|
|
_finalColor.g += color.g;
|
|
|
|
_finalColor.b += color.b;
|
2016-09-29 01:15:07 +02:00
|
|
|
}
|
2016-09-26 23:38:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
_finalColor.r += _lights->_ambientLightColor.r;
|
|
|
|
_finalColor.g += _lights->_ambientLightColor.g;
|
|
|
|
_finalColor.b += _lights->_ambientLightColor.b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-15 13:47:06 +02:00
|
|
|
void SliceRendererLights::calculateColorSlice(Vector3 position) {
|
2016-09-26 23:38:35 +02:00
|
|
|
_finalColor.r = 0.0f;
|
|
|
|
_finalColor.g = 0.0f;
|
|
|
|
_finalColor.b = 0.0f;
|
|
|
|
|
|
|
|
if (_lights) {
|
2016-09-29 01:15:07 +02:00
|
|
|
for (uint i = 0; i < _lights->_lights.size(); i++) {
|
|
|
|
Light *light = _lights->_lights[i];
|
|
|
|
if (i < 20) {
|
2017-04-02 18:17:43 +02:00
|
|
|
_cacheCounter[i] -= 1.0f;
|
|
|
|
if (_cacheCounter[i] <= 0.0f) {
|
2016-09-29 01:15:07 +02:00
|
|
|
do {
|
2017-04-02 18:17:43 +02:00
|
|
|
_cacheCounter[i] = _cacheCounter[i] + _cacheStart[i];
|
|
|
|
} while (_cacheCounter[i] <= 0.0f);
|
|
|
|
light->calculateColor(&_cacheColor[i], position);
|
|
|
|
_cacheRecalculation++;
|
2016-09-26 23:38:35 +02:00
|
|
|
}
|
2017-04-02 18:17:43 +02:00
|
|
|
_finalColor.r += _cacheColor[i].r;
|
|
|
|
_finalColor.g += _cacheColor[i].g;
|
|
|
|
_finalColor.b += _cacheColor[i].b;
|
2016-09-29 01:15:07 +02:00
|
|
|
} else {
|
|
|
|
Color color;
|
|
|
|
light->calculateColor(&color, position);
|
2017-04-02 18:17:43 +02:00
|
|
|
_cacheRecalculation++;
|
2016-09-29 01:15:07 +02:00
|
|
|
_finalColor.r += color.r;
|
|
|
|
_finalColor.g += color.g;
|
|
|
|
_finalColor.b += color.b;
|
|
|
|
}
|
2016-09-26 23:38:35 +02:00
|
|
|
}
|
|
|
|
_finalColor.r += _lights->_ambientLightColor.r;
|
|
|
|
_finalColor.g += _lights->_ambientLightColor.g;
|
|
|
|
_finalColor.b += _lights->_ambientLightColor.b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-05 23:49:57 +02:00
|
|
|
} // End of namespace BladeRunner
|