1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "bladerunner/slice_renderer.h"
24
25 #include "bladerunner/bladerunner.h"
26 #include "bladerunner/lights.h"
27 #include "bladerunner/screen_effects.h"
28 #include "bladerunner/set_effects.h"
29 #include "bladerunner/slice_animations.h"
30
31 #include "common/memstream.h"
32 #include "common/rect.h"
33 #include "common/util.h"
34
35 namespace BladeRunner {
36
SliceRenderer(BladeRunnerEngine * vm)37 SliceRenderer::SliceRenderer(BladeRunnerEngine *vm) {
38 _vm = vm;
39 _pixelFormat = screenPixelFormat();
40
41 // original game is going just up to 942 and not 997
42 for (int i = 0; i < ARRAYSIZE(_animationsShadowEnabled); ++i) {
43 _animationsShadowEnabled[i] = true;
44 }
45 _animation = -1;
46 _frame = -1;
47 _facing = 0.0f;
48 _scale = 0.0f;
49
50 _screenEffects = nullptr;
51 _view = nullptr;
52 _lights = nullptr;
53 _setEffects = nullptr;
54 _sliceFramePtr = nullptr;
55
56 _frameBottomZ = 0.0f;
57 _frameSliceHeight = 0.0f;
58 _framePaletteIndex = 0;
59 _frameSliceCount = 0;
60 _startSlice = 0.0f;
61 _endSlice = 0.0f;
62 _m13 = 0;
63 _m23 = 0;
64
65 _shadowPolygonDefault[ 0] = Vector3( 16.0f, 96.0f, 0.0f);
66 _shadowPolygonDefault[ 1] = Vector3( 16.0f, 160.0f, 0.0f);
67 _shadowPolygonDefault[ 2] = Vector3( 64.0f, 192.0f, 0.0f);
68 _shadowPolygonDefault[ 3] = Vector3( 80.0f, 240.0f, 0.0f);
69 _shadowPolygonDefault[ 4] = Vector3(160.0f, 240.0f, 0.0f);
70 _shadowPolygonDefault[ 5] = Vector3(192.0f, 192.0f, 0.0f);
71 _shadowPolygonDefault[ 6] = Vector3(240.0f, 160.0f, 0.0f);
72 _shadowPolygonDefault[ 7] = Vector3(240.0f, 96.0f, 0.0f);
73 _shadowPolygonDefault[ 8] = Vector3(192.0f, 64.0f, 0.0f);
74 _shadowPolygonDefault[ 9] = Vector3(160.0f, 16.0f, 0.0f);
75 _shadowPolygonDefault[10] = Vector3( 96.0f, 16.0f, 0.0f);
76 _shadowPolygonDefault[11] = Vector3( 64.0f, 64.0f, 0.0f);
77
78 for (int i = 0; i < 12; ++i) {
79 _shadowPolygonCurrent[i] = Vector3(0.0f, 0.0f, 0.0f);
80 }
81 }
82
~SliceRenderer()83 SliceRenderer::~SliceRenderer() {
84 }
85
setScreenEffects(ScreenEffects * screenEffects)86 void SliceRenderer::setScreenEffects(ScreenEffects *screenEffects) {
87 _screenEffects = screenEffects;
88 }
89
setView(View * view)90 void SliceRenderer::setView(View *view) {
91 _view = view;
92 }
93
setLights(Lights * lights)94 void SliceRenderer::setLights(Lights *lights) {
95 _lights = lights;
96 }
97
setSetEffects(SetEffects * setEffects)98 void SliceRenderer::setSetEffects(SetEffects *setEffects) {
99 _setEffects = setEffects;
100 }
101
setupFrameInWorld(int animationId,int animationFrame,Vector3 position,float facing,float scale)102 void SliceRenderer::setupFrameInWorld(int animationId, int animationFrame, Vector3 position, float facing, float scale) {
103 _position = position;
104 _facing = facing;
105 _scale = scale;
106
107 loadFrame(animationId, animationFrame);
108
109 calculateBoundingRect();
110 }
111
getScreenRectangle(Common::Rect * screenRectangle,int animationId,int animationFrame,Vector3 position,float facing,float scale)112 void SliceRenderer::getScreenRectangle(Common::Rect *screenRectangle, int animationId, int animationFrame, Vector3 position, float facing, float scale) {
113 assert(screenRectangle);
114 setupFrameInWorld(animationId, animationFrame, position, facing, scale);
115 *screenRectangle = _screenRectangle;
116 }
117
calculateFacingRotationMatrix()118 Matrix3x2 SliceRenderer::calculateFacingRotationMatrix() {
119 assert(_sliceFramePtr);
120
121 Vector3 viewPos = _view->_sliceViewMatrix * _position;
122 float dir = atan2(viewPos.x, viewPos.z) + _facing;
123 float s = sin(dir);
124 float c = cos(dir);
125
126 Matrix3x2 mRotation(c, -s, 0.0f,
127 s, c, 0.0f);
128
129 Matrix3x2 mView(_view->_sliceViewMatrix(0,0), _view->_sliceViewMatrix(0,1), 0.0f,
130 _view->_sliceViewMatrix(2,0), _view->_sliceViewMatrix(2,1), 0.0f);
131
132 return mView * mRotation;
133 }
134
calculateBoundingRect()135 void SliceRenderer::calculateBoundingRect() {
136 assert(_sliceFramePtr);
137
138 _screenRectangle.left = 0;
139 _screenRectangle.right = 0;
140 _screenRectangle.top = 0;
141 _screenRectangle.bottom = 0;
142
143 Matrix4x3 viewMatrix = _view->_sliceViewMatrix;
144
145 Vector3 frameBottom = Vector3(0.0f, 0.0f, _frameBottomZ);
146 Vector3 frameTop = Vector3(0.0f, 0.0f, _frameBottomZ + _frameSliceCount * _frameSliceHeight);
147
148 Vector3 bottom = viewMatrix * (_position + frameBottom);
149 Vector3 top = viewMatrix * (_position + frameTop);
150
151 top = bottom + _scale * (top - bottom);
152
153 if (bottom.z <= 0.0f || top.z <= 0.0f) {
154 return;
155 }
156
157 Vector4 startScreenVector(
158 _view->_viewportPosition.x + (top.x / top.z) * _view->_viewportPosition.z,
159 _view->_viewportPosition.y + (top.y / top.z) * _view->_viewportPosition.z,
160 1.0f / top.z,
161 _frameSliceCount * (1.0f / top.z));
162
163 Vector4 endScreenVector(
164 _view->_viewportPosition.x + (bottom.x / bottom.z) * _view->_viewportPosition.z,
165 _view->_viewportPosition.y + (bottom.y / bottom.z) * _view->_viewportPosition.z,
166 1.0f / bottom.z,
167 0.0f);
168
169 Vector4 delta = endScreenVector - startScreenVector;
170
171 if (delta.y == 0.0f) {
172 return;
173 }
174
175 /*
176 * Calculate min and max Y
177 */
178
179 float screenTop = 0.0f;
180 float screenBottom = 479.0f;
181
182 if (startScreenVector.y < screenTop) {
183 if (endScreenVector.y < screenTop) {
184 return;
185 }
186 float f = (screenTop - startScreenVector.y) / delta.y;
187 startScreenVector = startScreenVector + f * delta;
188 } else if (startScreenVector.y > screenBottom) {
189 if (endScreenVector.y >= screenBottom) {
190 return;
191 }
192 float f = (screenBottom - startScreenVector.y) / delta.y;
193 startScreenVector = startScreenVector + f * delta;
194 }
195
196 if (endScreenVector.y < screenTop) {
197 float f = (screenTop - endScreenVector.y) / delta.y;
198 endScreenVector = endScreenVector + f * delta;
199 } else if (endScreenVector.y > screenBottom) {
200 float f = (screenBottom - endScreenVector.y) / delta.y;
201 endScreenVector = endScreenVector + f * delta;
202 }
203
204 _screenRectangle.top = (int)MIN(startScreenVector.y, endScreenVector.y);
205 _screenRectangle.bottom = (int)MAX(startScreenVector.y, endScreenVector.y) + 1;
206
207 /*
208 * Calculate min and max X
209 */
210
211 Matrix3x2 facingRotation = calculateFacingRotationMatrix();
212
213 Matrix3x2 mProjection(_view->_viewportPosition.z / bottom.z, 0.0f, 0.0f,
214 0.0f, 25.5f, 0.0f);
215
216 Matrix3x2 mOffset(1.0f, 0.0f, _framePos.x,
217 0.0f, 1.0f, _framePos.y);
218
219 Matrix3x2 mScale(_frameScale.x, 0.0f, 0.0f,
220 0.0f, _frameScale.y, 0.0f);
221
222 _mvpMatrix = mProjection * (facingRotation * (mOffset * mScale));
223
224 Matrix3x2 mStart(
225 1.0f, 0.0f, startScreenVector.x,
226 0.0f, 1.0f, 25.5f / startScreenVector.z
227 );
228
229 Matrix3x2 mEnd(
230 1.0f, 0.0f, endScreenVector.x,
231 0.0f, 1.0f, 25.5f / endScreenVector.z
232 );
233
234 Matrix3x2 mStartMVP = mStart * _mvpMatrix;
235 Matrix3x2 mEndMVP = mEnd * _mvpMatrix;
236
237 float minX = 640.0f;
238 float maxX = 0.0f;
239
240 for (float i = 0.0f; i <= 255.0f; i += 255.0f) {
241 for (float j = 0.0f; j <= 255.0f; j += 255.0f) {
242 Vector2 v1 = mStartMVP * Vector2(i, j);
243 minX = MIN(minX, v1.x);
244 maxX = MAX(maxX, v1.x);
245
246 Vector2 v2 = mEndMVP * Vector2(i, j);
247 minX = MIN(minX, v2.x);
248 maxX = MAX(maxX, v2.x);
249 }
250 }
251
252 _screenRectangle.left = CLIP((int)minX, 0, 640);
253 _screenRectangle.right = CLIP((int)maxX + 1, 0, 640);
254
255 _startScreenVector.x = startScreenVector.x;
256 _startScreenVector.y = startScreenVector.y;
257 _startScreenVector.z = startScreenVector.z;
258 _endScreenVector.x = endScreenVector.x;
259 _endScreenVector.y = endScreenVector.y;
260 _endScreenVector.z = endScreenVector.z;
261 _startSlice = startScreenVector.w;
262 _endSlice = endScreenVector.w;
263 }
264
loadFrame(int animation,int frame)265 void SliceRenderer::loadFrame(int animation, int frame) {
266 _animation = animation;
267 _frame = frame;
268 _sliceFramePtr = _vm->_sliceAnimations->getFramePtr(_animation, _frame);
269
270 Common::MemoryReadStream stream((byte *)_sliceFramePtr, _vm->_sliceAnimations->_animations[_animation].frameSize);
271
272 _frameScale.x = stream.readFloatLE();
273 _frameScale.y = stream.readFloatLE();
274 _frameSliceHeight = stream.readFloatLE();
275 _framePos.x = stream.readFloatLE();
276 _framePos.y = stream.readFloatLE();
277 _frameBottomZ = stream.readFloatLE();
278 _framePaletteIndex = stream.readUint32LE();
279 _frameSliceCount = stream.readUint32LE();
280 }
281
282 struct SliceLineIterator {
283 Matrix3x2 _sliceMatrix;
284 int _startY;
285 int _endY;
286 int _currentY;
287
288 float _currentZ;
289 float _stepZ;
290 float _currentSlice;
291 float _stepSlice;
292
293 float _currentX;
294 float _stepX;
295
296 float _field_38;
297
298 void setup(float endScreenX, float endScreenY, float endScreenZ,
299 float startScreenX, float startScreenY, float startScreenZ,
300 float endSlice, float startSlice,
301 Matrix3x2 m);
302 float line() const;
303 void advance();
304 };
305
setup(float endScreenX,float endScreenY,float endScreenZ,float startScreenX,float startScreenY,float startScreenZ,float endSlice,float startSlice,Matrix3x2 m)306 void SliceLineIterator::setup(
307 float endScreenX, float endScreenY, float endScreenZ,
308 float startScreenX, float startScreenY, float startScreenZ,
309 float endSlice, float startSlice,
310 Matrix3x2 m) {
311 _startY = (int)startScreenY;
312 _endY = (int)endScreenY;
313 _currentY = _startY;
314
315 float size = endScreenY - startScreenY;
316
317 if (size <= 0.0f || startScreenZ <= 0.0f) {
318 _currentY = _endY + 1;
319 }
320
321 _currentZ = startScreenZ;
322 _stepZ = (endScreenZ - startScreenZ) / size;
323
324 _stepSlice = (endSlice - startSlice) / size;
325 _currentSlice = startSlice - (startScreenY - floor(startScreenY) - 1.0f) * _stepSlice;
326
327 _currentX = startScreenX;
328 _stepX = (endScreenX - startScreenX) / size;
329
330 _field_38 = (25.5f / size) * (1.0f / endScreenZ - 1.0f / startScreenZ);
331
332 float offsetX = _currentX;
333 float offsetZ = 25.5f / _currentZ;
334
335 Matrix3x2 mTranslate = Matrix3x2(1.0f, 0.0f, offsetX,
336 0.0f, 1.0f, offsetZ);
337
338 Matrix3x2 mScale = Matrix3x2(65536.0f, 0.0f, 0.0f, // x position is using fixed-point precisson with 16 bits
339 0.0f, 64.0f, 0.0f); // z position is using fixed-point precisson with 6 bits
340
341 _sliceMatrix = mScale * (mTranslate * m);
342 }
343
line() const344 float SliceLineIterator::line() const {
345 float var_0 = 0.0f;
346
347 if (_currentZ != 0.0f)
348 var_0 = _currentSlice / _currentZ;
349
350 if (var_0 < 0.0)
351 var_0 = 0.0f;
352
353 return var_0;
354 }
355
advance()356 void SliceLineIterator::advance() {
357 _currentZ += _stepZ;
358 _currentSlice += _stepSlice;
359 _currentX += _stepX;
360 ++_currentY;
361
362 _sliceMatrix._m[0][2] += _stepX * 65536.0f;
363 _sliceMatrix._m[1][2] += _field_38 * 64.0f;
364 }
365
setupLookupTable(int t[256],int inc)366 static void setupLookupTable(int t[256], int inc) {
367 int v = 0;
368 for (int i = 0; i != 256; ++i) {
369 t[i] = v;
370 v += inc;
371 }
372 }
373
drawInWorld(int animationId,int animationFrame,Vector3 position,float facing,float scale,Graphics::Surface & surface,uint16 * zbuffer)374 void SliceRenderer::drawInWorld(int animationId, int animationFrame, Vector3 position, float facing, float scale, Graphics::Surface &surface, uint16 *zbuffer) {
375 assert(_lights);
376 assert(_setEffects);
377 //assert(_view);
378
379 setupFrameInWorld(animationId, animationFrame, position, facing, scale);
380
381 assert(_sliceFramePtr);
382
383 if (_screenRectangle.isEmpty()) {
384 return;
385 }
386
387 SliceLineIterator sliceLineIterator;
388 sliceLineIterator.setup(
389 _endScreenVector.x, _endScreenVector.y, _endScreenVector.z,
390 _startScreenVector.x, _startScreenVector.y, _startScreenVector.z,
391 _endSlice, _startSlice,
392 _mvpMatrix
393 );
394
395 SliceRendererLights sliceRendererLights = SliceRendererLights(_lights);
396
397 _lights->setupFrame(_view->_frame);
398 _setEffects->setupFrame(_view->_frame);
399
400 float sliceLine = sliceLineIterator.line();
401
402 sliceRendererLights.calculateColorBase(
403 Vector3(_position.x, _position.y, _position.z + _frameBottomZ + sliceLine * _frameSliceHeight),
404 Vector3(_position.x, _position.y, _position.z + _frameBottomZ),
405 sliceLineIterator._endY - sliceLineIterator._startY);
406
407 float setEffectsColorCoeficient;
408 Color setEffectColor;
409 _setEffects->calculateColor(
410 _view->_cameraPosition,
411 Vector3(_position.x, _position.y, _position.z + _frameBottomZ + sliceLine * _frameSliceHeight),
412 &setEffectsColorCoeficient,
413 &setEffectColor);
414
415 _lightsColor.r = setEffectsColorCoeficient * sliceRendererLights._finalColor.r * 65536.0f;
416 _lightsColor.g = setEffectsColorCoeficient * sliceRendererLights._finalColor.g * 65536.0f;
417 _lightsColor.b = setEffectsColorCoeficient * sliceRendererLights._finalColor.b * 65536.0f;
418
419 _setEffectColor.r = setEffectColor.r * 31.0f * 65536.0f;
420 _setEffectColor.g = setEffectColor.g * 31.0f * 65536.0f;
421 _setEffectColor.b = setEffectColor.b * 31.0f * 65536.0f;
422
423 setupLookupTable(_m12lookup, sliceLineIterator._sliceMatrix(0, 1));
424 setupLookupTable(_m11lookup, sliceLineIterator._sliceMatrix(0, 0));
425 _m13 = sliceLineIterator._sliceMatrix(0, 2);
426 setupLookupTable(_m21lookup, sliceLineIterator._sliceMatrix(1, 0));
427 setupLookupTable(_m22lookup, sliceLineIterator._sliceMatrix(1, 1));
428 _m23 = sliceLineIterator._sliceMatrix(1, 2);
429
430 if (_animationsShadowEnabled[_animation]) {
431 float coeficientShadow;
432 Color colorShadow;
433 _setEffects->calculateColor(
434 _view->_cameraPosition,
435 _position,
436 &coeficientShadow,
437 &colorShadow);
438
439 int transparency = 32.0f * sqrt(setEffectColor.r * setEffectColor.r + setEffectColor.g * setEffectColor.g + setEffectColor.b * setEffectColor.b);
440
441 drawShadowInWorld(transparency, surface, zbuffer);
442 }
443
444 int frameY = sliceLineIterator._startY;
445
446 uint16 *zBufferLinePtr = zbuffer + 640 * frameY;
447
448 while (sliceLineIterator._currentY <= sliceLineIterator._endY) {
449 _m13 = sliceLineIterator._sliceMatrix(0, 2);
450 _m23 = sliceLineIterator._sliceMatrix(1, 2);
451 sliceLine = sliceLineIterator.line();
452
453 sliceRendererLights.calculateColorSlice(Vector3(_position.x, _position.y, _position.z + _frameBottomZ + sliceLine * _frameSliceHeight));
454
455 if (sliceLineIterator._currentY & 1) {
456 _setEffects->calculateColor(
457 _view->_cameraPosition,
458 Vector3(_position.x, _position.y, _position.z + _frameBottomZ + sliceLine * _frameSliceHeight),
459 &setEffectsColorCoeficient,
460 &setEffectColor);
461 }
462
463 _lightsColor.r = setEffectsColorCoeficient * sliceRendererLights._finalColor.r * 65536.0f;
464 _lightsColor.g = setEffectsColorCoeficient * sliceRendererLights._finalColor.g * 65536.0f;
465 _lightsColor.b = setEffectsColorCoeficient * sliceRendererLights._finalColor.b * 65536.0f;
466
467 _setEffectColor.r = setEffectColor.r * 31.0f * 65536.0f;
468 _setEffectColor.g = setEffectColor.g * 31.0f * 65536.0f;
469 _setEffectColor.b = setEffectColor.b * 31.0f * 65536.0f;
470
471 if (frameY >= 0 && frameY < surface.h) {
472 drawSlice((int)sliceLine, true, frameY, surface, zBufferLinePtr);
473 }
474
475 sliceLineIterator.advance();
476 ++frameY;
477 zBufferLinePtr += 640;
478 }
479 }
480
drawOnScreen(int animationId,int animationFrame,int screenX,int screenY,float facing,float scale,Graphics::Surface & surface)481 void SliceRenderer::drawOnScreen(int animationId, int animationFrame, int screenX, int screenY, float facing, float scale, Graphics::Surface &surface) {
482 if (scale == 0.0f) {
483 return;
484 }
485 _position.x = 0;
486 _position.y = 0;
487 _position.z = 0;
488 _facing = facing;
489
490 loadFrame(animationId, animationFrame);
491
492 float frameHeight = _frameSliceHeight * _frameSliceCount;
493 float frameSize = sqrt(_frameScale.x * 255.0f * _frameScale.x * 255.0f + _frameScale.y * 255.0f * _frameScale.y * 255.0f);
494 float size = scale / MAX(frameSize, frameHeight);
495
496 float s = sin(_facing);
497 float c = cos(_facing);
498
499 Matrix3x2 mRotation(c, -s, 0.0f,
500 s, c, 0.0f);
501
502 Matrix3x2 mFrame(_frameScale.x, 0.0f, _framePos.x,
503 0.0f, _frameScale.y, _framePos.y);
504
505 Matrix3x2 mScale(size, 0.0f, 0.0f,
506 0.0f, 25.5f, 0.0f);
507
508 Matrix3x2 mTranslate(1.0f, 0.0f, screenX,
509 0.0f, 1.0f, 32768.0f);
510
511 Matrix3x2 mScaleFixed(65536.0f, 0.0f, 0.0f, // x position is using fixed-point precisson with 16 bits
512 0.0f, 64.0f, 0.0f); // z position is using fixed-point precisson with 6 bits
513
514 Matrix3x2 m = mScaleFixed * (mTranslate * (mScale * (mRotation * mFrame)));
515
516 setupLookupTable(_m11lookup, m(0, 0));
517 setupLookupTable(_m12lookup, m(0, 1));
518 _m13 = m(0, 2);
519 setupLookupTable(_m21lookup, m(1, 0));
520 setupLookupTable(_m22lookup, m(1, 1));
521 _m23 = m(1, 2);
522
523 int frameY = screenY + (size / 2.0f * frameHeight);
524 int currentY = frameY;
525
526 float currentSlice = 0;
527 float sliceStep = 1.0f / size / _frameSliceHeight;
528
529 uint16 lineZbuffer[640];
530
531 while (currentSlice < _frameSliceCount) {
532 if (currentY >= 0 && currentY < surface.h) {
533 memset(lineZbuffer, 0xFF, 640 * 2);
534 drawSlice(currentSlice, false, currentY, surface, lineZbuffer);
535 currentSlice += sliceStep;
536 --currentY;
537 }
538 }
539 }
540
drawSlice(int slice,bool advanced,int y,Graphics::Surface & surface,uint16 * zbufferLine)541 void SliceRenderer::drawSlice(int slice, bool advanced, int y, Graphics::Surface &surface, uint16 *zbufferLine) {
542 if (slice < 0 || (uint32)slice >= _frameSliceCount) {
543 return;
544 }
545
546 SliceAnimations::Palette &palette = _vm->_sliceAnimations->getPalette(_framePaletteIndex);
547
548 byte *p = (byte *)_sliceFramePtr + 0x20 + 4 * slice;
549
550 uint32 polyOffset = READ_LE_UINT32(p);
551
552 p = (byte *)_sliceFramePtr + polyOffset;
553
554 uint32 polyCount = READ_LE_UINT32(p);
555 p += 4;
556
557 while (polyCount--) {
558 uint32 vertexCount = READ_LE_UINT32(p);
559 p += 4;
560
561 if (vertexCount == 0)
562 continue;
563
564 uint32 lastVertex = vertexCount - 1;
565 int lastVertexX = MAX((_m11lookup[p[3 * lastVertex]] + _m12lookup[p[3 * lastVertex + 1]] + _m13) / 65536, 0);
566
567 int previousVertexX = lastVertexX;
568
569 while (vertexCount--) {
570 int vertexX = CLIP((_m11lookup[p[0]] + _m12lookup[p[1]] + _m13) / 65536, 0, 640);
571
572 if (vertexX > previousVertexX) {
573 int vertexZ = (_m21lookup[p[0]] + _m22lookup[p[1]] + _m23) / 64;
574
575 if (vertexZ >= 0 && vertexZ < 65536) {
576 uint32 outColor = palette.value[p[2]];
577 if (advanced) {
578 Color256 aescColor = { 0, 0, 0 };
579 _screenEffects->getColor(&aescColor, vertexX, y, vertexZ);
580
581 Color256 color = palette.color[p[2]];
582 color.r = ((int)(_setEffectColor.r + _lightsColor.r * color.r) / 65536) + aescColor.r;
583 color.g = ((int)(_setEffectColor.g + _lightsColor.g * color.g) / 65536) + aescColor.g;
584 color.b = ((int)(_setEffectColor.b + _lightsColor.b * color.b) / 65536) + aescColor.b;
585 // We need to convert from 5 bits per channel (r,g,b) to 8 bits
586 outColor = _pixelFormat.RGBToColor(Color::get8BitColorFrom5Bit(color.r), Color::get8BitColorFrom5Bit(color.g), Color::get8BitColorFrom5Bit(color.b));
587 }
588
589 for (int x = previousVertexX; x != vertexX; ++x) {
590 if (vertexZ < zbufferLine[x]) {
591 zbufferLine[x] = (uint16)vertexZ;
592
593 void *dstPtr = surface.getBasePtr(CLIP(x, 0, surface.w - 1), CLIP(y, 0, surface.h - 1));
594 drawPixel(surface, dstPtr, outColor);
595 }
596 }
597 }
598 }
599 p += 3;
600 previousVertexX = vertexX;
601 }
602 }
603 }
604
drawShadowInWorld(int transparency,Graphics::Surface & surface,uint16 * zbuffer)605 void SliceRenderer::drawShadowInWorld(int transparency, Graphics::Surface &surface, uint16 *zbuffer) {
606 Matrix4x3 mOffset(
607 1.0f, 0.0f, 0.0f, _framePos.x,
608 0.0f, 1.0f, 0.0f, _framePos.y,
609 0.0f, 0.0f, 1.0f, 0.0f);
610
611 Matrix4x3 mTransition(
612 1.0f, 0.0f, 0.0f, _position.x,
613 0.0f, 1.0f, 0.0f, _position.y,
614 0.0f, 0.0f, 1.0f, _position.z);
615
616 Matrix4x3 mRotation(
617 cos(_facing), -sin(_facing), 0.0f, 0.0f,
618 sin(_facing), cos(_facing), 0.0f, 0.0f,
619 0.0f, 0.0f, 1.0f, 0.0f);
620
621 Matrix4x3 mScale(
622 _frameScale.x, 0.0f, 0.0f, 0.0f,
623 0.0f, _frameScale.y, 0.0f, 0.0f,
624 0.0f, 0.0f, _frameSliceHeight, 0.0f);
625
626 Matrix4x3 m = _view->_sliceViewMatrix * (mTransition * (mRotation * (mOffset * mScale)));
627
628 for (int i = 0; i < 12; ++i) {
629 Vector3 t = m * _shadowPolygonDefault[i];
630 if (t.z > 0.0f) {
631 _shadowPolygonCurrent[i] = Vector3(
632 _view->_viewportPosition.x + t.x / t.z * _view->_viewportPosition.z,
633 _view->_viewportPosition.y + t.y / t.z * _view->_viewportPosition.z,
634 t.z * 25.5f
635 );
636 } else {
637 _shadowPolygonCurrent[i] = Vector3(0.0f, 0.0f, 0.0f);
638 }
639 }
640
641 drawShadowPolygon(transparency, surface, zbuffer);
642 }
643
drawShadowPolygon(int transparency,Graphics::Surface & surface,uint16 * zbuffer)644 void SliceRenderer::drawShadowPolygon(int transparency, Graphics::Surface &surface, uint16 *zbuffer) {
645 // this simplified polygon drawing algo is in the game
646
647 int yMax = 0;
648 int yMin = 480;
649 uint16 zMin = 65535;
650
651 int polygonLeft[480] = {};
652 int polygonRight[480] = {};
653
654 int iNext = 11;
655 for (int i = 0; i < 12; ++i) {
656 int xCurrent = _shadowPolygonCurrent[i].x;
657 int yCurrent = _shadowPolygonCurrent[i].y;
658 int xNext = _shadowPolygonCurrent[iNext].x;
659 int yNext = _shadowPolygonCurrent[iNext].y;
660
661 if (yCurrent < yMin) {
662 yMin = yCurrent;
663 }
664 if (yCurrent > yMax) {
665 yMax = yCurrent;
666 }
667 if (_shadowPolygonCurrent[i].z < zMin) {
668 zMin = _shadowPolygonCurrent[i].z;
669 }
670
671 int xDelta = abs(xNext - xCurrent);
672 int yDelta = abs(yNext - yCurrent);
673
674 int xDirection = -1;
675 if (xCurrent < xNext) {
676 xDirection = 1;
677 }
678
679 int xCounter = 0;
680
681 int x = xCurrent;
682 int y = yCurrent;
683
684 if (yCurrent > yNext) {
685 while (y >= yNext) {
686 if (y >= 0 && y < 480) {
687 polygonLeft[y] = x;
688 }
689 xCounter += xDelta;
690 while (xCounter >= yDelta) {
691 x += xDirection;
692 xCounter -= yDelta;
693 }
694 --y;
695 }
696 } else if (yCurrent < yNext) {
697 while (y <= yNext) {
698 if (y >= 0 && y < 480) {
699 polygonRight[y] = x;
700 }
701 xCounter += xDelta;
702 while (xCounter >= yDelta) {
703 x += xDirection;
704 xCounter -= yDelta;
705 }
706 ++y;
707 }
708 }
709 iNext = (iNext + 1) % 12;
710 }
711
712 yMax = CLIP(yMax, 0, 480);
713 yMin = CLIP(yMin, 0, 480);
714
715 static const int ditheringFactor[] = {
716 0, 8, 2, 10,
717 12, 4, 14, 6,
718 3, 11, 1, 9,
719 15, 7, 13, 5
720 };
721
722 for (int y = yMin; y < yMax; ++y) {
723 int xMin = CLIP(polygonLeft[y], 0, 640);
724 int xMax = CLIP(polygonRight[y], 0, 640);
725
726 for (int x = MIN(xMin, xMax); x < MAX(xMin, xMax); ++x) {
727 uint16 z = zbuffer[x + y * 640];
728 void *pixel = surface.getBasePtr(CLIP(x, 0, surface.w - 1), CLIP(y, 0, surface.h - 1));
729
730 if (z >= zMin) {
731 int index = (x & 3) + ((y & 3) << 2);
732 if (transparency - ditheringFactor[index] <= 0) {
733 uint8 r, g, b;
734 surface.format.colorToRGB(READ_UINT32(pixel), r, g, b);
735 r *= 0.75f;
736 g *= 0.75f;
737 b *= 0.75f;
738
739 drawPixel(surface, pixel, surface.format.RGBToColor(r, g, b));
740 }
741 }
742 }
743 }
744 }
745
preload(int animationId)746 void SliceRenderer::preload(int animationId) {
747 int frameCount = _vm->_sliceAnimations->getFrameCount(animationId);
748 for (int i = 0; i < frameCount; ++i) {
749 _vm->_sliceAnimations->getFramePtr(animationId, i);
750 }
751 }
752
disableShadows(int animationsIdsList[],int listSize)753 void SliceRenderer::disableShadows(int animationsIdsList[], int listSize) {
754 for (int i = 0; i < listSize; ++i) {
755 _animationsShadowEnabled[animationsIdsList[i]] = false;
756 }
757 }
758
SliceRendererLights(Lights * lights)759 SliceRendererLights::SliceRendererLights(Lights *lights) {
760 _finalColor.r = 0.0f;
761 _finalColor.g = 0.0f;
762 _finalColor.b = 0.0f;
763
764 _lights = lights;
765
766 for (int i = 0; i < 20; ++i) {
767 _cacheColor[i].r = 0.0f;
768 _cacheColor[i].g = 0.0f;
769 _cacheColor[i].b = 0.0f;
770 }
771
772 _cacheRecalculation = 0.0f;
773 }
774
calculateColorBase(Vector3 position1,Vector3 position2,float height)775 void SliceRendererLights::calculateColorBase(Vector3 position1, Vector3 position2, float height) {
776 _finalColor.r = 0.0f;
777 _finalColor.g = 0.0f;
778 _finalColor.b = 0.0f;
779 _cacheRecalculation = 0;
780 if (_lights) {
781 for (uint i = 0; i < _lights->_lights.size(); ++i) {
782 Light *light = _lights->_lights[i];
783 if (i < 20) {
784 float cacheCoeficient = light->calculate(position1, position2/*, height*/);
785 _cacheStart[i] = cacheCoeficient;
786 _cacheCounter[i] = cacheCoeficient;
787
788 Color color;
789 light->calculateColor(&color, position1);
790 _cacheColor[i] = color;
791 _finalColor.r += color.r;
792 _finalColor.g += color.g;
793 _finalColor.b += color.b;
794 } else {
795 Color color;
796 light->calculateColor(&color, position1);
797 _finalColor.r += color.r;
798 _finalColor.g += color.g;
799 _finalColor.b += color.b;
800 }
801 }
802
803 _finalColor.r += _lights->_ambientLightColor.r;
804 _finalColor.g += _lights->_ambientLightColor.g;
805 _finalColor.b += _lights->_ambientLightColor.b;
806 }
807 }
808
calculateColorSlice(Vector3 position)809 void SliceRendererLights::calculateColorSlice(Vector3 position) {
810 _finalColor.r = 0.0f;
811 _finalColor.g = 0.0f;
812 _finalColor.b = 0.0f;
813
814 if (_lights) {
815 for (uint i = 0; i < _lights->_lights.size(); ++i) {
816 Light *light = _lights->_lights[i];
817 if (i < 20) {
818 _cacheCounter[i] -= 1.0f;
819 if (_cacheCounter[i] <= 0.0f) {
820 do {
821 _cacheCounter[i] = _cacheCounter[i] + _cacheStart[i];
822 } while (_cacheCounter[i] <= 0.0f);
823 light->calculateColor(&_cacheColor[i], position);
824 ++_cacheRecalculation;
825 }
826 _finalColor.r += _cacheColor[i].r;
827 _finalColor.g += _cacheColor[i].g;
828 _finalColor.b += _cacheColor[i].b;
829 } else {
830 Color color;
831 light->calculateColor(&color, position);
832 ++_cacheRecalculation;
833 _finalColor.r += color.r;
834 _finalColor.g += color.g;
835 _finalColor.b += color.b;
836 }
837 }
838 _finalColor.r += _lights->_ambientLightColor.r;
839 _finalColor.g += _lights->_ambientLightColor.g;
840 _finalColor.b += _lights->_ambientLightColor.b;
841 }
842 }
843
844 } // End of namespace BladeRunner
845