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/light.h"
24 
25 #include "common/util.h"
26 
27 namespace BladeRunner {
28 
Light()29 Light::Light() {
30 	_frameCount         = 0;
31 	_animated           = 0;
32 	_animationData      = nullptr;
33 	_animatedParameters = 0;
34 	_falloffStart       = 0.0f;
35 	_falloffEnd         = 0.0f;
36 	_angleStart         = 0.0f;
37 	_angleEnd           = 0.0f;
38 	_m11ptr             = nullptr;
39 	_m12ptr             = nullptr;
40 	_m13ptr             = nullptr;
41 	_m14ptr             = nullptr;
42 	_m21ptr             = nullptr;
43 	_m22ptr             = nullptr;
44 	_m23ptr             = nullptr;
45 	_m24ptr             = nullptr;
46 	_m31ptr             = nullptr;
47 	_m32ptr             = nullptr;
48 	_m33ptr             = nullptr;
49 	_m34ptr             = nullptr;
50 	_colorRPtr          = nullptr;
51 	_colorGPtr          = nullptr;
52 	_colorBPtr          = nullptr;
53 	_falloffStartPtr    = nullptr;
54 	_falloffEndPtr      = nullptr;
55 	_angleStartPtr      = nullptr;
56 	_angleEndPtr        = nullptr;
57 }
58 
~Light()59 Light::~Light() {
60 	if (_animationData != nullptr) {
61 		delete[] _animationData;
62 	}
63 }
64 
read(Common::ReadStream * stream,int frameCount,int frame,int animated)65 void Light::read(Common::ReadStream *stream, int frameCount, int frame, int animated) {
66 	_frameCount = frameCount;
67 	_animated = animated;
68 
69 	int size = stream->readUint32LE();
70 	size = size - 32;
71 
72 	char buf[20];
73 	stream->read(buf, sizeof(buf));
74 	_name = buf;
75 
76 	_animatedParameters = stream->readUint32LE();
77 
78 	if (_animationData != nullptr) {
79 		delete[] _animationData;
80 	}
81 	int floatCount = size / 4;
82 	_animationData = new float[floatCount];
83 	for (int i = 0; i < floatCount; ++i) {
84 		_animationData[i] = stream->readFloatLE();
85 	}
86 
87 	_m11ptr          = _animationData;
88 	_m12ptr          = _m11ptr          + ((_animatedParameters &     0x1) ? frameCount : 1);
89 	_m13ptr          = _m12ptr          + ((_animatedParameters &     0x2) ? frameCount : 1);
90 	_m14ptr          = _m13ptr          + ((_animatedParameters &     0x4) ? frameCount : 1);
91 	_m21ptr          = _m14ptr          + ((_animatedParameters &     0x8) ? frameCount : 1);
92 	_m22ptr          = _m21ptr          + ((_animatedParameters &    0x10) ? frameCount : 1);
93 	_m23ptr          = _m22ptr          + ((_animatedParameters &    0x20) ? frameCount : 1);
94 	_m24ptr          = _m23ptr          + ((_animatedParameters &    0x40) ? frameCount : 1);
95 	_m31ptr          = _m24ptr          + ((_animatedParameters &    0x80) ? frameCount : 1);
96 	_m32ptr          = _m31ptr          + ((_animatedParameters &   0x100) ? frameCount : 1);
97 	_m33ptr          = _m32ptr          + ((_animatedParameters &   0x200) ? frameCount : 1);
98 	_m34ptr          = _m33ptr          + ((_animatedParameters &   0x400) ? frameCount : 1);
99 	_colorRPtr       = _m34ptr          + ((_animatedParameters &   0x800) ? frameCount : 1);
100 	_colorGPtr       = _colorRPtr       + ((_animatedParameters &  0x1000) ? frameCount : 1);
101 	_colorBPtr       = _colorGPtr       + ((_animatedParameters &  0x2000) ? frameCount : 1);
102 	_falloffStartPtr = _colorBPtr       + ((_animatedParameters &  0x4000) ? frameCount : 1);
103 	_falloffEndPtr   = _falloffStartPtr + ((_animatedParameters &  0x8000) ? frameCount : 1);
104 	_angleStartPtr   = _falloffEndPtr   + ((_animatedParameters & 0x10000) ? frameCount : 1);
105 	_angleEndPtr     = _angleStartPtr   + ((_animatedParameters & 0x20000) ? frameCount : 1);
106 
107 	setupFrame(frame);
108 }
109 
readVqa(Common::ReadStream * stream,int frameCount,int frame,int animated)110 void Light::readVqa(Common::ReadStream *stream, int frameCount, int frame, int animated) {
111 	_frameCount = frameCount;
112 	_animated = animated;
113 
114 	_animatedParameters = stream->readUint32LE();
115 
116 	int size = stream->readUint32LE();
117 
118 	if (_animationData != nullptr) {
119 		delete[] _animationData;
120 	}
121 
122 	int floatCount = size / 4;
123 	_animationData = new float[floatCount];
124 	for (int i = 0; i < floatCount; ++i) {
125 		_animationData[i] = stream->readFloatLE();
126 	}
127 
128 	_m11ptr          = _animationData;
129 	_m12ptr          = _m11ptr          + ((_animatedParameters &     0x1) ? frameCount : 1);
130 	_m13ptr          = _m12ptr          + ((_animatedParameters &     0x2) ? frameCount : 1);
131 	_m14ptr          = _m13ptr          + ((_animatedParameters &     0x4) ? frameCount : 1);
132 	_m21ptr          = _m14ptr          + ((_animatedParameters &     0x8) ? frameCount : 1);
133 	_m22ptr          = _m21ptr          + ((_animatedParameters &    0x10) ? frameCount : 1);
134 	_m23ptr          = _m22ptr          + ((_animatedParameters &    0x20) ? frameCount : 1);
135 	_m24ptr          = _m23ptr          + ((_animatedParameters &    0x40) ? frameCount : 1);
136 	_m31ptr          = _m24ptr          + ((_animatedParameters &    0x80) ? frameCount : 1);
137 	_m32ptr          = _m31ptr          + ((_animatedParameters &   0x100) ? frameCount : 1);
138 	_m33ptr          = _m32ptr          + ((_animatedParameters &   0x200) ? frameCount : 1);
139 	_m34ptr          = _m33ptr          + ((_animatedParameters &   0x400) ? frameCount : 1);
140 	_colorRPtr       = _m34ptr          + ((_animatedParameters &   0x800) ? frameCount : 1);
141 	_colorGPtr       = _colorRPtr       + ((_animatedParameters &  0x1000) ? frameCount : 1);
142 	_colorBPtr       = _colorGPtr       + ((_animatedParameters &  0x2000) ? frameCount : 1);
143 	_falloffStartPtr = _colorBPtr       + ((_animatedParameters &  0x4000) ? frameCount : 1);
144 	_falloffEndPtr   = _falloffStartPtr + ((_animatedParameters &  0x8000) ? frameCount : 1);
145 	_angleStartPtr   = _falloffEndPtr   + ((_animatedParameters & 0x10000) ? frameCount : 1);
146 	_angleEndPtr     = _angleStartPtr   + ((_animatedParameters & 0x20000) ? frameCount : 1);
147 
148 	setupFrame(frame);
149 }
150 
setupFrame(int frame)151 void Light::setupFrame(int frame) {
152 	int offset = frame % _frameCount;
153 	_matrix._m[0][0] = ((_animatedParameters &     0x1) ? _m11ptr[offset]          : *_m11ptr);
154 	_matrix._m[0][1] = ((_animatedParameters &     0x2) ? _m12ptr[offset]          : *_m12ptr);
155 	_matrix._m[0][2] = ((_animatedParameters &     0x4) ? _m13ptr[offset]          : *_m13ptr);
156 	_matrix._m[0][3] = ((_animatedParameters &     0x8) ? _m14ptr[offset]          : *_m14ptr);
157 	_matrix._m[1][0] = ((_animatedParameters &    0x10) ? _m21ptr[offset]          : *_m21ptr);
158 	_matrix._m[1][1] = ((_animatedParameters &    0x20) ? _m22ptr[offset]          : *_m22ptr);
159 	_matrix._m[1][2] = ((_animatedParameters &    0x40) ? _m23ptr[offset]          : *_m23ptr);
160 	_matrix._m[1][3] = ((_animatedParameters &    0x80) ? _m24ptr[offset]          : *_m24ptr);
161 	_matrix._m[2][0] = ((_animatedParameters &   0x100) ? _m31ptr[offset]          : *_m31ptr);
162 	_matrix._m[2][1] = ((_animatedParameters &   0x200) ? _m32ptr[offset]          : *_m32ptr);
163 	_matrix._m[2][2] = ((_animatedParameters &   0x400) ? _m33ptr[offset]          : *_m33ptr);
164 	_matrix._m[2][3] = ((_animatedParameters &   0x800) ? _m34ptr[offset]          : *_m34ptr);
165 	_color.r         = ((_animatedParameters &  0x1000) ? _colorRPtr[offset]       : *_colorRPtr);
166 	_color.g         = ((_animatedParameters &  0x2000) ? _colorGPtr[offset]       : *_colorGPtr);
167 	_color.b         = ((_animatedParameters &  0x4000) ? _colorBPtr[offset]       : *_colorBPtr);
168 	_falloffStart    = ((_animatedParameters &  0x8000) ? _falloffStartPtr[offset] : *_falloffStartPtr);
169 	_falloffEnd      = ((_animatedParameters & 0x10000) ? _falloffEndPtr[offset]   : *_falloffEndPtr);
170 	_angleStart      = ((_animatedParameters & 0x20000) ? _angleStartPtr[offset]   : *_angleStartPtr);
171 	_angleEnd        = ((_animatedParameters & 0x40000) ? _angleEndPtr[offset]     : *_angleEndPtr);
172 }
173 
calculate(Vector3 start,Vector3 end) const174 float Light::calculate(Vector3 start, Vector3 end) const {
175 	return calculateFalloutCoefficient(_matrix * start, _matrix * end, _falloffStart, _falloffEnd);
176 }
177 
calculateColor(Color * outColor,Vector3 position) const178 void Light::calculateColor(Color *outColor, Vector3 position) const {
179 	Vector3 positionT = _matrix * position;
180 	float att = attenuation(_falloffStart, _falloffEnd, positionT.length());
181 	outColor->r = _color.r * att;
182 	outColor->g = _color.g * att;
183 	outColor->b = _color.b * att;
184 }
185 
calculateFalloutCoefficient(Vector3 start,Vector3 end,float falloffStart,float falloffEnd) const186 float Light::calculateFalloutCoefficient(Vector3 start, Vector3 end, float falloffStart, float falloffEnd) const {
187 	if (falloffEnd == 0.0f) {
188 		return 1.0e30f;
189 	}
190 
191 	if (falloffStart * falloffStart >= start.length() && falloffStart * falloffStart >= end.length()) {
192 		return 1.0e30f;
193 	}
194 
195 	float diff = (end - start).length();
196 	float v31 = 0.0f;
197 	if (diff != 0.0f) {
198 		Vector3 v27 = Vector3::cross(start, (end - start));
199 		v31 = v27.length() / diff;
200 	}
201 
202 	if (v31 < falloffEnd) {
203 		return 1.0f / (1.0f - (v31 / falloffEnd));
204 	}
205 	return 1.0e30f;
206 }
207 
attenuation(float min,float max,float distance) const208 float Light::attenuation(float min, float max, float distance) const {
209 	if (max == 0.0f) {
210 		return 1.0f;
211 	}
212 	if (min < max) {
213 		distance = CLIP(distance, min, max);
214 		float x = (max - distance) / (max - min);
215 		return x * x * (3.0f - 2.0f * x);
216 	}
217 	if (distance < min) {
218 		return 1.0f;
219 	}
220 	return 0.0f;
221 }
222 
calculate(Vector3 start,Vector3 end) const223 float Light1::calculate(Vector3 start, Vector3 end) const {
224 	start = _matrix * start;
225 	end = _matrix * end;
226 
227 	float v40 = 0.0f;
228 	if (_falloffEnd != 0.0f) {
229 		v40 = calculateFalloutCoefficient(start, end, _falloffStart, _falloffEnd);
230 	}
231 
232 	float v41 = atan2(sqrt(start.x * start.x + start.y * start.y), -start.z);
233 	float v42 = atan2(sqrt(end.x * end.x + end.y * end.y), -end.z);
234 
235 	float v43;
236 	if ((_angleStart >= v41 && _angleStart >= v42) || (_angleEnd <= v41 && _angleEnd <= v42)) {
237 		v43 = 1.0e30f;
238 	} else {
239 		v43 = 2.0;
240 	}
241 	if (v43 < v40) {
242 		return v40;
243 	} else {
244 		return v43;
245 	}
246 }
247 
calculateColor(Color * outColor,Vector3 position) const248 void Light1::calculateColor(Color *outColor, Vector3 position) const {
249 	Vector3 positionT = _matrix * position;
250 
251 	outColor->r = 0.0f;
252 	outColor->g = 0.0f;
253 	outColor->b = 0.0f;
254 
255 	if (positionT.z < 0.0f) {
256 		float v12 = attenuation(_angleStart, _angleEnd, atan2(sqrt(positionT.x * positionT.x + positionT.y * positionT.y), -positionT.z));
257 		float v13 = attenuation(_falloffStart, _falloffEnd, positionT.length());
258 
259 		outColor->r = v12 * v13 * _color.r;
260 		outColor->g = v12 * v13 * _color.g;
261 		outColor->b = v12 * v13 * _color.b;
262 	}
263 }
264 
calculate(Vector3 start,Vector3 end) const265 float Light2::calculate(Vector3 start, Vector3 end) const {
266 	start = _matrix * start;
267 	end = _matrix * end;
268 
269 	float v54 = 0.0f;
270 	if (_falloffEnd != 0.0f) {
271 		v54 = calculateFalloutCoefficient(start, end, _falloffStart, _falloffEnd);
272 	}
273 
274 	float v55 = atan2(fabs(start.x), -start.z);
275 	float v58 = atan2(fabs(start.y), -start.z);
276 	float v57 = atan2(fabs(end.x), -end.z);
277 	float v56 = atan2(fabs(end.y), -end.z);
278 
279 	float v59;
280 	if ((_angleStart >= v55 && _angleStart >= v57 && _angleStart >= v58 && _angleStart >= v56) || (_angleEnd <= v55 && _angleEnd <= v57 && _angleEnd <= v58 && _angleEnd <= v56)) {
281 		v59 = 1.0e30f;
282 	} else {
283 		v59 = 2.0f;
284 	}
285 	if (v59 < v54) {
286 		return v54;
287 	} else {
288 		return v59;
289 	}
290 }
291 
calculateColor(Color * outColor,Vector3 position) const292 void Light2::calculateColor(Color *outColor, Vector3 position) const {
293 	Vector3 positionT = _matrix * position;
294 
295 	outColor->r = 0.0f;
296 	outColor->g = 0.0f;
297 	outColor->b = 0.0f;
298 
299 	if (positionT.z < 0.0f) {
300 		float v11 = attenuation(_angleStart, _angleEnd, atan2(fabs(positionT.y), -positionT.z));
301 		float v12 = attenuation(_angleStart, _angleEnd, atan2(fabs(positionT.x), -positionT.z));
302 		float v13 = attenuation(_falloffStart, _falloffEnd, positionT.length());
303 
304 		outColor->r = v11 * v12 * v13 * _color.r;
305 		outColor->g = v11 * v12 * v13 * _color.g;
306 		outColor->b = v11 * v12 * v13 * _color.b;
307 	}
308 }
309 
calculateColor(Color * outColor,Vector3 position) const310 void Light3::calculateColor(Color *outColor, Vector3 position) const {
311 	Vector3 positionT = _matrix * position;
312 
313 	outColor->r = 0.0f;
314 	outColor->g = 0.0f;
315 	outColor->b = 0.0f;
316 
317 	if (positionT.z < 0.0f) {
318 		float v12 = attenuation(_angleStart, _angleEnd, sqrt(positionT.x * positionT.x + positionT.y * positionT.y));
319 		float v13 = attenuation(_falloffStart, _falloffEnd, positionT.length());
320 
321 		outColor->r = v12 * v13 * _color.r;
322 		outColor->g = v12 * v13 * _color.g;
323 		outColor->b = v12 * v13 * _color.b;
324 	}
325 }
326 
calculateColor(Color * outColor,Vector3 position) const327 void Light4::calculateColor(Color *outColor, Vector3 position) const {
328 	Vector3 positionT = _matrix * position;
329 
330 	outColor->r = 0.0f;
331 	outColor->g = 0.0f;
332 	outColor->b = 0.0f;
333 
334 	if (positionT.z < 0.0f) {
335 		float v11 = attenuation(_angleStart, _angleEnd, fabs(positionT.y));
336 		float v12 = attenuation(_angleStart, _angleEnd, fabs(positionT.x));
337 		float v13 = attenuation(_falloffStart, _falloffEnd, positionT.length());
338 
339 		outColor->r = v11 * v12 * v13 * _color.r;
340 		outColor->g = v11 * v12 * v13 * _color.g;
341 		outColor->b = v11 * v12 * v13 * _color.b;
342 	}
343 }
344 
calculate(Vector3 start,Vector3 end) const345 float LightAmbient::calculate(Vector3 start, Vector3 end) const {
346 	return 1.0e30f;
347 }
348 
calculateColor(Color * outColor,Vector3 position) const349 void LightAmbient::calculateColor(Color *outColor, Vector3 position) const {
350 	outColor->r = _color.r;
351 	outColor->g = _color.g;
352 	outColor->b = _color.b;
353 }
354 
355 } // End of namespace BladeRunner
356