1 /*
2  * Copyright 2011-2012 Arx Libertatis Team (see the AUTHORS file)
3  *
4  * This file is part of Arx Libertatis.
5  *
6  * Arx Libertatis is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Arx Libertatis is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Arx Libertatis.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 /* Based on:
20 ===========================================================================
21 ARX FATALIS GPL Source Code
22 Copyright (C) 1999-2010 Arkane Studios SA, a ZeniMax Media company.
23 
24 This file is part of the Arx Fatalis GPL Source Code ('Arx Fatalis Source Code').
25 
26 Arx Fatalis Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
27 License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
28 
29 Arx Fatalis Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
30 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
31 
32 You should have received a copy of the GNU General Public License along with Arx Fatalis Source Code.  If not, see
33 <http://www.gnu.org/licenses/>.
34 
35 In addition, the Arx Fatalis Source Code is also subject to certain additional terms. You should have received a copy of these
36 additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Arx
37 Fatalis Source Code. If not, please request a copy in writing from Arkane Studios at the address below.
38 
39 If you have questions concerning this license or the applicable additional terms, you may contact in writing Arkane Studios, c/o
40 ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
41 ===========================================================================
42 */
43 // Copyright (c) 1999-2000 ARKANE Studios SA. All rights reserved
44 
45 #include "scene/Light.h"
46 
47 #include "core/Application.h"
48 #include "core/GameTime.h"
49 #include "core/Core.h"
50 #include "game/Entity.h"
51 #include "game/EntityManager.h"
52 #include "game/Inventory.h"
53 #include "graphics/Math.h"
54 #include "graphics/Draw.h"
55 #include "scene/Object.h"
56 #include "scene/GameSound.h"
57 #include "scene/Interactive.h"
58 
59 extern float GLOBAL_LIGHT_FACTOR;
60 EERIE_LIGHT * GLight[MAX_LIGHTS];
61 EERIE_LIGHT DynLight[MAX_DYNLIGHTS];
62 
63 EERIE_LIGHT * PDL[MAX_DYNLIGHTS];
64 long TOTPDL = 0;
65 
66 EERIE_LIGHT * IO_PDL[MAX_DYNLIGHTS];
67 long TOTIOPDL = 0;
68 
69 static void ARX_EERIE_LIGHT_Make(EERIEPOLY * ep, float * epr, float * epg, float * epb, EERIE_LIGHT * light);
70 
ValidDynLight(long num)71 bool ValidDynLight(long num)
72 {
73 	if (	(num >= 0)
74         &&	((size_t)num < MAX_DYNLIGHTS)
75         &&	DynLight[num].exist)
76 		return true;
77 
78 	return false;
79 }
80 
PrecalcIOLighting(const Vec3f * pos,float radius,long flags)81 void PrecalcIOLighting(const Vec3f * pos, float radius, long flags) {
82 
83 	static Vec3f lastpos;
84 	if(flags & 1) {
85 		lastpos = Vec3f::repeat(99999.f) + lastpos;
86 		return;
87 	}
88 
89 	// Lastpos optim
90 	if(closerThan(*pos, lastpos, 100.f)) {
91 		return;
92 	}
93 
94 	lastpos = *pos;
95 
96 	TOTIOPDL = 0;
97 
98 	for(size_t i = 0; i < MAX_LIGHTS; i++) {
99 
100 		EERIE_LIGHT * el = GLight[i];
101 
102 		if ((el)  && (el->exist) && (el->status)
103 		        && !(el->extras & EXTRAS_SEMIDYNAMIC))
104 		{
105 			if ((el->pos.x >= pos->x - radius) && (el->pos.x <= pos->x + radius)
106 			        && (el->pos.z >= pos->z - radius) && (el->pos.z <= pos->z + radius))
107 			{
108 
109 				el->rgb255 = el->rgb * 255.f;
110 				el->falldiff = el->fallend - el->fallstart;
111 				el->falldiffmul = 1.f / el->falldiff;
112 				el->precalc = el->intensity * GLOBAL_LIGHT_FACTOR;
113 				IO_PDL[TOTIOPDL] = el;
114 
115 				TOTIOPDL++;
116 
117 				if ((size_t)TOTIOPDL >= MAX_DYNLIGHTS) TOTIOPDL--;
118 			}
119 		}
120 	}
121 }
122 
EERIE_LIGHT_Apply(EERIEPOLY * ep)123 void EERIE_LIGHT_Apply(EERIEPOLY * ep) {
124 
125 	if (ep->type & POLY_IGNORE)  return;
126 
127 	float epr[4];
128 	float epg[4];
129 	float epb[4];
130 
131 	epr[3] = epr[2] = epr[1] = epr[0] = 0;
132 	epg[3] = epg[2] = epg[1] = epg[0] = 0;
133 	epb[3] = epb[2] = epb[1] = epb[0] = 0;
134 
135 	for(size_t i = 0; i < MAX_LIGHTS; i++) {
136 
137 		EERIE_LIGHT * el = GLight[i];
138 
139 		if ((el) && (el->treat) && (el->exist) && (el->status)
140 		        && !(el->extras & EXTRAS_SEMIDYNAMIC))
141 		{
142 			if(closerThan(el->pos, ep->center, el->fallend + 100.f)) {
143 				ARX_EERIE_LIGHT_Make(ep, epr, epg, epb, el);
144 			}
145 		}
146 	}
147 
148 	for (size_t i = 0; i < MAX_ACTIONS; i++)
149 	{
150 		if ((actions[i].exist) && ((actions[i].type == ACT_FIRE2) || (actions[i].type == ACT_FIRE)))
151 		{
152 			if(closerThan(actions[i].light.pos, ep->center, actions[i].light.fallend + 100.f)) {
153 				ARX_EERIE_LIGHT_Make(ep, epr, epg, epb, &actions[i].light);
154 			}
155 		}
156 	}
157 
158 	long nbvert;
159 
160 	if (ep->type & POLY_QUAD) nbvert = 4;
161 	else nbvert = 3;
162 
163 	for(long i = 0; i < nbvert; i++) {
164 		epr[i] = clamp(epr[i], ACTIVEBKG->ambient.r, 1.f);
165 		epg[i] = clamp(epg[i], ACTIVEBKG->ambient.g, 1.f);
166 		epb[i] = clamp(epb[i], ACTIVEBKG->ambient.b, 1.f);
167 		ep->v[i].color = Color3f(epr[i], epg[i], epb[i]).toBGR();
168 	}
169 }
170 
EERIE_LIGHT_TranslateSelected(const Vec3f * trans)171 void EERIE_LIGHT_TranslateSelected(const Vec3f * trans) {
172 	for(size_t i = 0; i < MAX_LIGHTS; i++) {
173 		if(GLight[i] && GLight[i]->selected) {
174 			if(GLight[i]->tl > 0) {
175 				DynLight[GLight[i]->tl].exist = 0;
176 			}
177 			GLight[i]->tl = -1;
178 			GLight[i]->pos += *trans;
179 		}
180 	}
181 }
182 
EERIE_LIGHT_UnselectAll()183 void EERIE_LIGHT_UnselectAll() {
184 	for(size_t i = 0; i < MAX_LIGHTS; i++) {
185 		if(GLight[i] && GLight[i]->exist && GLight[i]->treat) {
186 			GLight[i]->selected = 0;
187 		}
188 	}
189 }
190 
EERIE_LIGHT_ClearByIndex(long num)191 void EERIE_LIGHT_ClearByIndex(long num)
192 {
193 	if ((num >= 0) && ((size_t)num < MAX_LIGHTS))
194 	{
195 		if (GLight[num] != NULL)
196 		{
197 			if (GLight[num]->tl != -1) DynLight[GLight[num]->tl].exist = 0;
198 
199 			free(GLight[num]);
200 			GLight[num] = NULL;
201 		}
202 	}
203 }
204 
EERIE_LIGHT_ClearAll()205 void EERIE_LIGHT_ClearAll() {
206 	for(size_t i = 0; i < MAX_LIGHTS; i++) {
207 		EERIE_LIGHT_ClearByIndex(i);
208 	}
209 }
210 
EERIE_LIGHT_ClearSelected()211 void EERIE_LIGHT_ClearSelected() {
212 	for(size_t i = 0; i < MAX_LIGHTS; i++) {
213 		if(GLight[i] && GLight[i]->selected) {
214 			EERIE_LIGHT_ClearByIndex(i);
215 		}
216 	}
217 }
218 
EERIE_LIGHT_GlobalInit()219 void EERIE_LIGHT_GlobalInit() {
220 
221 	static long init = 0;
222 
223 	if(!init) {
224 		memset(GLight, 0, sizeof(*GLight) * MAX_LIGHTS);
225 		init = 1;
226 		return;
227 	}
228 
229 	for(size_t i = 0; i < MAX_LIGHTS; i++) {
230 		if(GLight[i]) {
231 			if(GLight[i]->tl > 0) {
232 				DynLight[GLight[i]->tl].exist = 0;
233 			}
234 			free(GLight[i]);
235 			GLight[i] = NULL;
236 		}
237 	}
238 }
239 
EERIE_LIGHT_GetFree()240 long EERIE_LIGHT_GetFree() {
241 
242 	for(size_t i = 0; i < MAX_LIGHTS; i++) {
243 		if(!GLight[i]) {
244 			return i;
245 		}
246 	}
247 
248 	return -1;
249 }
250 
EERIE_LIGHT_Create()251 long EERIE_LIGHT_Create() {
252 
253 	for (size_t i = 0; i < MAX_LIGHTS; i++) {
254 		if(!GLight[i]) {
255 
256 			GLight[i] = (EERIE_LIGHT *)malloc(sizeof(EERIE_LIGHT));
257 			if(!GLight[i]) {
258 				return -1;
259 			}
260 
261 			memset(GLight[i], 0, sizeof(EERIE_LIGHT));
262 			GLight[i]->sample = audio::INVALID_ID;
263 			GLight[i]->tl = -1;
264 			return i;
265 		}
266 	}
267 
268 	return -1;
269 }
270 
271 
EERIE_LIGHT_Count()272 long EERIE_LIGHT_Count() {
273 
274 	long count = 0;
275 	for(size_t i = 0; i < MAX_LIGHTS; i++) {
276 		if(GLight[i] && !(GLight[i]->type & TYP_SPECIAL1)) {
277 			count++;
278 		}
279 	}
280 
281 	return count;
282 }
283 
EERIE_LIGHT_GlobalAdd(const EERIE_LIGHT * el)284 void EERIE_LIGHT_GlobalAdd(const EERIE_LIGHT * el)
285 {
286 	long num = EERIE_LIGHT_GetFree();
287 
288 	if (num > -1)
289 	{
290 		GLight[num] = (EERIE_LIGHT *)malloc(sizeof(EERIE_LIGHT));
291 		memcpy(GLight[num], el, sizeof(EERIE_LIGHT));
292 		GLight[num]->tl = -1;
293 		GLight[num]->sample = audio::INVALID_ID;
294 	}
295 }
296 
EERIE_LIGHT_MoveAll(const Vec3f * trans)297 void EERIE_LIGHT_MoveAll(const Vec3f * trans) {
298 	for(size_t i = 0; i < MAX_LIGHTS; i++) {
299 		if(GLight[i]) {
300 			GLight[i]->pos += *trans;
301 		}
302 	}
303 }
304 
305 //*************************************************************************************
306 //*************************************************************************************
my_CheckInPoly(float x,float y,float z,EERIEPOLY * mon_ep,EERIE_LIGHT * light)307 float my_CheckInPoly(float x, float y, float z, EERIEPOLY * mon_ep, EERIE_LIGHT * light)
308 {
309 	long px, pz;
310 	px = x * ACTIVEBKG->Xmul;
311 
312 
313 	if (px > ACTIVEBKG->Xsize - 3)
314 	{
315 		return 0;
316 	}
317 
318 	if (px < 2)
319 	{
320 		return 0;
321 	}
322 
323 	pz = z * ACTIVEBKG->Zmul;
324 
325 	if (pz > ACTIVEBKG->Zsize - 3)
326 	{
327 		return 0;
328 	}
329 
330 	if (pz < 2)
331 	{
332 		return 0;
333 	}
334 
335 	float nb_shadowvertexinpoly = 0.0f;
336 	float nb_totalvertexinpoly = 0.0f;
337 
338 	EERIEPOLY * ep;
339 	EERIE_BKG_INFO * eg;
340 
341 	Vec3f dest;
342 	Vec3f hit;
343 
344 	Vec3f orgn = light->pos;
345 
346 	for (long j = pz - 2; j <= pz + 2; j++)
347 		for (long i = px - 2; i <= px + 2; i++)
348 		{
349 			eg = &ACTIVEBKG->Backg[i+j*ACTIVEBKG->Xsize];
350 
351 			for (long k = 0; k < eg->nbpoly; k++)
352 			{
353 				ep = &eg->polydata[k];
354 
355 				if (!(ep->type & POLY_WATER) &&  !(ep->type & POLY_TRANS))
356 				{
357 
358 					long nbvert;
359 					(ep->type & POLY_QUAD) ? nbvert = 4 : nbvert = 3;
360 
361 					long a, b;
362 
363 					for (a = 0; a < nbvert; a++)
364 					{
365 						float fDiff = 5.f;
366 
367 						if ((fabs(ep->v[a].p.x - x) <= fDiff) &&
368 								(fabs(ep->v[a].p.y - y) <= fDiff) &&
369 								(fabs(ep->v[a].p.z - z) <= fDiff))
370 						{
371 
372 							if(dot(*mon_ep->nrml, *ep->nrml) > 0.0f) {
373 								nb_totalvertexinpoly += nbvert;
374 								for(b = 0; b < nbvert; b++) {
375 									dest = ep->v[b].p;
376 									if(Visible(&orgn, &dest, ep, &hit)) {
377 										nb_shadowvertexinpoly ++;
378 									}
379 								}
380 							}
381 						}
382 					}
383 				}
384 			}
385 		}
386 
387 	return nb_shadowvertexinpoly / nb_totalvertexinpoly;
388 }
389 
ARX_EERIE_LIGHT_Make(EERIEPOLY * ep,float * epr,float * epg,float * epb,EERIE_LIGHT * light)390 static void ARX_EERIE_LIGHT_Make(EERIEPOLY * ep, float * epr, float * epg, float * epb, EERIE_LIGHT * light)
391 {
392 	int		i;				// iterator
393 	int		nbvert;			// number or vertices per face (3 or 4)
394 	float	distance[4];	// distance from light to each vertex
395 	float	fRes;			// value of light intensity for a given vertex
396 
397 	if (ep->type & POLY_IGNORE)
398 		return;
399 
400 	(ep->type & POLY_QUAD) ? nbvert = 4 : nbvert = 3;
401 
402 	// compute light - vertex distance
403 	for(i = 0; i < nbvert; i++) {
404 		distance[i] = dist(light->pos, ep->v[i].p);
405 	}
406 
407 	for (i = 0; i < nbvert; i++)
408 	{
409 		fRes = 1.0f;
410 
411 		if (distance[i] < light->fallend)
412 		{
413 			//---------------------- start MODE_NORMALS
414 			if (ModeLight & MODE_NORMALS)
415 			{
416 				Vec3f vLight = (light->pos - ep->v[i].p).getNormalized(); // vector (light to vertex)
417 
418 				fRes = dot(vLight, ep->nrml[i]);
419 
420 				if (fRes < 0.0f)
421 				{
422 					fRes = 0.0f;
423 				}
424 			}
425 
426 			//---------------------- end MODE_NORMALS
427 
428 			//---------------------- start MODE_RAYLAUNCH
429 			if ((ModeLight & MODE_RAYLAUNCH) && !(light->extras & EXTRAS_NOCASTED))
430 			{
431 				Vec3f orgn = light->pos, dest = ep->v[i].p, hit;
432 
433 				if (ModeLight & MODE_SMOOTH)
434 					fRes *= my_CheckInPoly(ep->v[i].p.x, ep->v[i].p.y, ep->v[i].p.z, ep, light);
435 				else
436 					fRes *= Visible(&orgn, &dest, ep, &hit);
437 			}
438 
439 			//---------------------- fin MODE_RAYLAUNCH
440 
441 			float fTemp1 = light->intensity * fRes * GLOBAL_LIGHT_FACTOR;
442 			float fr, fg, fb;
443 
444 			if (distance[i] <= light->fallstart)
445 			{
446 				fr = light->rgb.r * fTemp1;
447 				fg = light->rgb.g * fTemp1;
448 				fb = light->rgb.b * fTemp1;
449 			}
450 			else
451 			{
452 				float intensity = (light->falldiff - (distance[i] - light->fallstart)) * light->falldiffmul;
453 				float fTemp2 = fTemp1 * intensity;
454 				fr = light->rgb.r * fTemp2;
455 				fg = light->rgb.g * fTemp2;
456 				fb = light->rgb.b * fTemp2;
457 			}
458 
459 			epr[i] += fr;
460 			epg[i] += fg;
461 			epb[i] += fb;
462 		}
463 	}
464 }
465 
ComputeLight2DPos(EERIE_LIGHT * _pL)466 void ComputeLight2DPos(EERIE_LIGHT * _pL) {
467 
468 	TexturedVertex in, out;
469 	in.p = _pL->pos;
470 	EERIETreatPoint(&in, &out);
471 
472 	if ((out.p.z > 0.f) && (out.p.z < 1000.f) && (out.rhw > 0))
473 	{
474 		float t;
475 		float siz = 50;
476 		float fMaxdist = 300;
477 
478 		if (Project.telekinesis) fMaxdist = 850;
479 
480 		t = siz * (1.0f - 1.0f / (out.rhw * fMaxdist)) + 10;
481 
482 		_pL->maxs.x = out.p.x + t;
483 		_pL->mins.x = out.p.x - t;
484 		_pL->maxs.y = out.p.y + t;
485 		_pL->mins.y = out.p.y - t;
486 
487 
488 		if (0)
489 			if ((_pL->mins.x >= -200.f) && (_pL->mins.x <= 1000.f))
490 				if ((_pL->mins.y >= -200.f) && (_pL->mins.y <= 1000.f))
491 				{
492 
493 					EERIEDraw2DLine(_pL->mins.x, _pL->mins.y, _pL->maxs.x, _pL->mins.y, 0.00001f, Color::white);
494 					EERIEDraw2DLine(_pL->maxs.x, _pL->mins.y, _pL->maxs.x, _pL->maxs.y, 0.00001f, Color::white);
495 					EERIEDraw2DLine(_pL->maxs.x, _pL->maxs.y, _pL->mins.x, _pL->maxs.y, 0.00001f, Color::white);
496 					EERIEDraw2DLine(_pL->mins.x, _pL->maxs.y, _pL->mins.x, _pL->mins.y, 0.00001f, Color::white);
497 				}
498 	}
499 }
500 
501 //*************************************************************************************
502 //*************************************************************************************
TreatBackgroundDynlights()503 void TreatBackgroundDynlights()
504 {
505 	long n;
506 
507 	for (size_t i = 0; i < MAX_LIGHTS; i++)
508 	{
509 		if ((GLight[i] != NULL) && (GLight[i]->extras & EXTRAS_SEMIDYNAMIC))
510 		{
511 			float fMaxdist = 300;
512 
513 			if (Project.telekinesis) fMaxdist = 850;
514 
515 			if(!fartherThan(GLight[i]->pos, ACTIVECAM->pos, fMaxdist)) {
516 				ComputeLight2DPos(GLight[i]);
517 			}
518 
519 			if (GLight[i]->status == 0)
520 			{
521 				// vient de s'éteindre
522 				if (GLight[i]->tl > 0)
523 				{
524 					DynLight[GLight[i]->tl].exist = 0;
525 					GLight[i]->tl = -1;
526 					Vec3f _pos2;
527 
528 					for(size_t l = 0; l < entities.size(); l++) {
529 						if(entities[l] && (entities[l]->ioflags & IO_MARKER)) {
530 							GetItemWorldPosition(entities[l], &_pos2);
531 							if(!fartherThan(GLight[i]->pos, _pos2, 300.f)) {
532 								SendIOScriptEvent(entities[l], SM_CUSTOM, "douse");
533 							}
534 						}
535 					}
536 				}
537 			}
538 			else
539 			{
540 				// vient de s'allumer
541 				if (GLight[i]->tl <= 0)
542 				{
543 					Vec3f _pos2;
544 
545 					for(size_t l = 0; l < entities.size(); l++) {
546 						if(entities[l] && (entities[l]->ioflags & IO_MARKER)) {
547 							GetItemWorldPosition(entities[l], &_pos2);
548 							if(!fartherThan(GLight[i]->pos, _pos2, 300.f)) {
549 								SendIOScriptEvent(entities[l], SM_CUSTOM, "fire");
550 							}
551 						}
552 					}
553 
554 					GLight[i]->tl = GetFreeDynLight();
555 				}
556 
557 				n = GLight[i]->tl;
558 				if(n != -1) {
559 					DynLight[n].pos = GLight[i]->pos;
560 					DynLight[n].exist		=	1;
561 					DynLight[n].fallstart	=	GLight[i]->fallstart;
562 					DynLight[n].fallend		=	GLight[i]->fallend;
563 					DynLight[n].type		=	TYP_SPECIAL1;
564 					DynLight[n].intensity	=	GLight[i]->intensity;
565 					DynLight[n].ex_flaresize =	GLight[i]->ex_flaresize;
566 					DynLight[n].extras		=	GLight[i]->extras;
567 					DynLight[n].duration = std::numeric_limits<long>::max();
568 
569 					DynLight[n].rgb.r = GLight[i]->rgb.r - GLight[i]->rgb.r * GLight[i]->ex_flicker.r * rnd() * ( 1.0f / 2 );
570 					DynLight[n].rgb.g = GLight[i]->rgb.g - GLight[i]->rgb.g * GLight[i]->ex_flicker.g * rnd() * ( 1.0f / 2 );
571 					DynLight[n].rgb.b = GLight[i]->rgb.b - GLight[i]->rgb.b * GLight[i]->ex_flicker.b * rnd() * ( 1.0f / 2 );
572 
573 					DynLight[n].rgb = componentwise_max(DynLight[n].rgb, Color3f::black);
574 					DynLight[n].rgb255 = DynLight[n].rgb * 255.f;
575 					DynLight[n].falldiff = DynLight[n].fallend - DynLight[n].fallstart;
576 					DynLight[n].falldiffmul = 1.f / DynLight[n].falldiff;
577 					DynLight[n].precalc = DynLight[n].intensity * GLOBAL_LIGHT_FACTOR;
578 				}
579 			}
580 		}
581 
582 	}
583 }
584 
585 
PrecalcDynamicLighting(long x0,long z0,long x1,long z1)586 void PrecalcDynamicLighting(long x0, long z0, long x1, long z1) {
587 
588 	TreatBackgroundDynlights();
589 	TOTPDL = 0;
590 
591 	float fx0 = ACTIVEBKG->Xdiv * (float)x0;
592 	float fz0 = ACTIVEBKG->Zdiv * (float)z0;
593 	float fx1 = ACTIVEBKG->Xdiv * (float)x1;
594 	float fz1 = ACTIVEBKG->Zdiv * (float)z1;
595 
596 	for (size_t i = 0; i < MAX_DYNLIGHTS; i++)
597 	{
598 		EERIE_LIGHT * el = &DynLight[i];
599 
600 		if ((el->exist) && (el->rgb.r >= 0.f))
601 		{
602 
603 			bool bDist = (distSqr(el->pos, ACTIVECAM->pos) < square(ACTIVECAM->cdepth));
604 
605 			if ((el->pos.x >= fx0) && (el->pos.x <= fx1)
606 			        && (el->pos.z >= fz0) && (el->pos.z <= fz1)
607 			        && bDist)
608 			{
609 				el->treat = 1;
610 				el->rgb255 = el->rgb * 255.f;
611 				el->falldiff = el->fallend - el->fallstart;
612 				el->falldiffmul = 1.f / el->falldiff;
613 				el->precalc = el->intensity * GLOBAL_LIGHT_FACTOR;
614 				PDL[TOTPDL] = el;
615 				TOTPDL++;
616 
617 				if ((size_t)TOTPDL >= MAX_DYNLIGHTS) TOTPDL--;
618 			}
619 			else if (el->treat) el->treat = 0;
620 
621 			if (el->duration)
622 			{
623 				float tim = ((float)float(arxtime) - (float)el->time_creation);
624 				float duration = (float)el->duration;
625 
626 				if (tim >= duration)
627 				{
628 
629 
630 					float sub = framedelay * 0.001f;
631 					el->rgb.r -= sub;
632 
633 					if (el->rgb.r < 0) el->rgb.r = 0.f;
634 
635 					el->rgb.g -= sub;
636 
637 					if (el->rgb.g < 0) el->rgb.g = 0.f;
638 
639 					el->rgb.b -= sub;
640 
641 					if (el->rgb.b < 0) el->rgb.b = 0.f;
642 
643 					if (el->rgb.r + el->rgb.g + el->rgb.b == 0)
644 					{
645 						el->exist = 0;
646 						el->duration = 0;
647 					}
648 				}
649 			}
650 		}
651 	}
652 }
653 
EERIE_LIGHT_ChangeLighting()654 void EERIE_LIGHT_ChangeLighting()
655 {
656 	long i, j;
657 	EERIEPOLY * ep;
658 	EERIE_BKG_INFO * eg;
659 
660 	for (j = 0; j < ACTIVEBKG->Zsize; j++)
661 		for (i = 0; i < ACTIVEBKG->Xsize; i++)
662 		{
663 			eg = &ACTIVEBKG->Backg[i+j*ACTIVEBKG->Xsize];
664 
665 			for (long k = 0; k < eg->nbpoly; k++)
666 			{
667 				ep = &eg->polydata[k];
668 				ep->tv[0].color = ep->v[0].color;
669 				ep->tv[1].color = ep->v[1].color;
670 				ep->tv[2].color = ep->v[2].color;
671 
672 				if (ep->type & POLY_QUAD) ep->tv[3].color = ep->v[3].color;
673 			}
674 		}
675 }
676 
677 //*************************************************************************************
678 //*************************************************************************************
679 
EERIEPrecalcLights(long minx,long minz,long maxx,long maxz)680 void EERIEPrecalcLights(long minx, long minz, long maxx, long maxz)
681 {
682 	EERIE_BKG_INFO * eg;
683 
684 	if (minx < 0) minx = 0;
685 	else if (minx >= ACTIVEBKG->Xsize) minx = ACTIVEBKG->Xsize - 1;
686 
687 	if (maxx < 0) maxx = 0;
688 	else if (maxx >= ACTIVEBKG->Xsize) maxx = ACTIVEBKG->Xsize - 1;
689 
690 	if (minz < 0) minz = 0;
691 	else if (minz >= ACTIVEBKG->Zsize) minz = ACTIVEBKG->Zsize - 1;
692 
693 	if (maxz < 0) maxz = 0;
694 	else if (maxz >= ACTIVEBKG->Zsize) maxz = ACTIVEBKG->Zsize - 1;
695 
696 	for (size_t i = 0; i < MAX_LIGHTS; i++)
697 	{
698 		if (GLight[i] != NULL)
699 		{
700 			if ((GLight[i]->extras & EXTRAS_SEMIDYNAMIC))
701 			{
702 				GLight[i]->treat = 0;
703 			}
704 			else if (!GLight[i]->treat)
705 			{
706 				GLight[i]->treat = 1;
707 			}
708 
709 			GLight[i]->falldiff = GLight[i]->fallend - GLight[i]->fallstart;
710 			GLight[i]->falldiffmul = 1.f / GLight[i]->falldiff;
711 			GLight[i]->rgb255 = GLight[i]->rgb * 255.f;
712 			GLight[i]->precalc = GLight[i]->intensity * GLOBAL_LIGHT_FACTOR;
713 		}
714 	}
715 
716 	for (long j = minz; j <= maxz; j++)
717 	{
718 		for (long i = minx; i <= maxx; i++)
719 		{
720 			eg = &ACTIVEBKG->Backg[i+j*ACTIVEBKG->Xsize];
721 
722 			for (long k = 0; k < eg->nbpoly; k++)
723 			{
724 				EERIEPOLY * ep = &eg->polydata[k];
725 
726 				if(ep) {
727 					ep->type &= ~POLY_IGNORE;
728 					EERIE_LIGHT_Apply(ep);
729 				}
730 			}
731 		}
732 	}
733 }
734 
RecalcLightZone(float x,float z,long siz)735 void RecalcLightZone(float x, float z, long siz) {
736 
737 	long i, j, x0, x1, z0, z1;
738 
739 	i = x * ACTIVEBKG->Xmul;
740 	j = z * ACTIVEBKG->Zmul;
741 
742 	x0 = i - siz;
743 	x1 = i + siz;
744 	z0 = j - siz;
745 	z1 = j + siz;
746 
747 	if (x0 < 2) x0 = 2;
748 	else if (x0 >= ACTIVEBKG->Xsize - 2) x0 = ACTIVEBKG->Xsize - 3;
749 
750 	if (x1 < 2) x1 = 0;
751 	else if (x1 >= ACTIVEBKG->Xsize - 2) x1 = ACTIVEBKG->Xsize - 3;
752 
753 	if (z0 < 2) z0 = 0;
754 	else if (z0 >= ACTIVEBKG->Zsize - 2) z0 = ACTIVEBKG->Zsize - 3;
755 
756 	if (z1 < 2) z1 = 0;
757 	else if (z1 >= ACTIVEBKG->Zsize - 2) z1 = ACTIVEBKG->Zsize - 3;
758 
759 	LightMode oldml = ModeLight;
760 	ModeLight &= ~MODE_RAYLAUNCH;
761 	EERIEPrecalcLights(x0, z0, x1, z1);
762 	ModeLight = oldml;
763 }
764 
EERIERemovePrecalcLights()765 void EERIERemovePrecalcLights() {
766 
767 	EERIEPOLY * ep;
768 	EERIE_BKG_INFO * eg;
769 
770 	for(size_t i = 0; i < MAX_LIGHTS; i++) {
771 		if (GLight[i] != NULL) GLight[i]->treat = 1;
772 	}
773 
774 	for(int j = 0; j < ACTIVEBKG->Zsize; j++) {
775 		for(int i = 0; i < ACTIVEBKG->Xsize; i++) {
776 
777 			eg = &ACTIVEBKG->Backg[i+j*ACTIVEBKG->Xsize];
778 
779 			for (long k = 0; k < eg->nbpoly; k++) {
780 				ep = &eg->polydata[k];
781 				ep->v[3].color = ep->v[2].color = ep->v[1].color = ep->v[0].color = Color::white.toBGR();
782 			}
783 		}
784 	}
785 }
786