1 /*
2  * Copyright 2011-2013 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 // Code: Cyril Meynier
44 //
45 // Copyright (c) 1999 ARKANE Studios SA. All rights reserved
46 
47 #include "graphics/data/Mesh.h"
48 
49 #include <cstdlib>
50 #include <cstdio>
51 #include <map>
52 
53 #include <boost/scoped_array.hpp>
54 #include <boost/unordered_map.hpp>
55 
56 #include "ai/PathFinder.h"
57 #include "ai/PathFinderManager.h"
58 
59 #include "animation/Animation.h"
60 #include "animation/AnimationRender.h"
61 
62 #include "core/Config.h"
63 #include "core/Core.h"
64 #include "core/GameTime.h"
65 
66 #include "game/EntityManager.h"
67 #include "game/Player.h"
68 
69 #include "graphics/Draw.h"
70 #include "graphics/Math.h"
71 #include "graphics/VertexBuffer.h"
72 #include "graphics/data/TextureContainer.h"
73 #include "graphics/data/FastSceneFormat.h"
74 #include "graphics/particle/ParticleEffects.h"
75 
76 #include "io/resource/ResourcePath.h"
77 #include "io/fs/FileStream.h"
78 #include "io/resource/PakReader.h"
79 #include "io/fs/Filesystem.h"
80 #include "io/Blast.h"
81 #include "io/Implode.h"
82 #include "io/IO.h"
83 #include "io/log/Logger.h"
84 
85 #include "physics/Anchors.h"
86 
87 #include "scene/Scene.h"
88 #include "scene/Light.h"
89 #include "scene/Interactive.h"
90 
91 #include "util/String.h"
92 
93 using std::min;
94 using std::max;
95 using std::copy;
96 using std::string;
97 using std::vector;
98 
99 void ComputeFastBkgData(EERIE_BACKGROUND * eb);
100 
101 static void EERIE_PORTAL_Release();
102 
103 float Xratio = 1.f;
104 float Yratio = 1.f;
105 
106 
107 static int RayIn3DPolyNoCull(Vec3f * orgn, Vec3f * dest, EERIEPOLY * epp);
108 
109 EERIEMATRIX ProjectionMatrix;
110 
ReleaseAnimFromIO(Entity * io,long num)111 void ReleaseAnimFromIO(Entity * io, long num)
112 {
113 	for (long count = 0; count < MAX_ANIM_LAYERS; count++)
114 	{
115 		if (io->animlayer[count].cur_anim == io->anims[num])
116 		{
117 			memset(&io->animlayer[count], 0, sizeof(ANIM_USE));
118 			io->animlayer[count].cur_anim = NULL;
119 		}
120 
121 		if (io->animlayer[count].next_anim == io->anims[num])
122 			io->animlayer[count].next_anim = NULL;
123 	}
124 
125 	EERIE_ANIMMANAGER_ReleaseHandle(io->anims[num]);
126 	io->anims[num] = NULL;
127 }
128 
DebugSphere(float x,float y,float z,float siz,long tim,Color color)129 void DebugSphere(float x, float y, float z, float siz, long tim, Color color) {
130 
131 	arxtime.update();
132 
133 	PARTICLE_DEF * pd = createParticle();
134 	if(!pd) {
135 		return;
136 	}
137 
138 	pd->ov = Vec3f(x, y, z);
139 	pd->scale = Vec3f::ZERO;
140 	pd->tolive = tim;
141 	pd->tc = EERIE_DRAW_sphere_particle;
142 	pd->siz = siz;
143 	pd->rgb = color.to<float>();
144 }
145 
EERIE_CreateMatriceProj(float _fWidth,float _fHeight,float _fFOV,float _fZNear,float _fZFar)146 void EERIE_CreateMatriceProj(float _fWidth, float _fHeight, float _fFOV,
147                              float _fZNear, float _fZFar) {
148 
149 	float fAspect = _fHeight / _fWidth;
150 	float fFOV = radians(_fFOV);
151 	float fFarPlane = _fZFar;
152 	float fNearPlane = _fZNear;
153 	float w = fAspect * (cosf(fFOV / 2) / sinf(fFOV / 2));
154 	float h =   1.0f  * (cosf(fFOV / 2) / sinf(fFOV / 2));
155 	float Q = fFarPlane / (fFarPlane - fNearPlane);
156 
157 	memset(&ProjectionMatrix, 0, sizeof(EERIEMATRIX));
158 	ProjectionMatrix._11 = w;
159 	ProjectionMatrix._22 = h;
160 	ProjectionMatrix._33 = Q;
161 	ProjectionMatrix._43 = (-Q * fNearPlane);
162 	ProjectionMatrix._34 = 1.f;
163 	GRenderer->SetProjectionMatrix(ProjectionMatrix);
164 
165 	// Set view matrix to identity
166 	EERIEMATRIX mat;
167 	mat._11 = 1.f;
168 	mat._12 = 0.f;
169 	mat._13 = 0.f;
170 	mat._14 = 0.f;
171 	mat._21 = 0.f;
172 	mat._22 = 1.f;
173 	mat._23 = 0.f;
174 	mat._24 = 0.f;
175 	mat._31 = 0.f;
176 	mat._32 = 0.f;
177 	mat._33 = 1.f;
178 	mat._34 = 0.f;
179 	mat._41 = 0.f;
180 	mat._42 = 0.f;
181 	mat._43 = 0.f;
182 	mat._44 = 1.f;
183 	GRenderer->SetViewMatrix(mat);
184 
185 	ProjectionMatrix._11 *= _fWidth * .5f;
186 	ProjectionMatrix._22 *= _fHeight * .5f;
187 	ProjectionMatrix._33 = -(fFarPlane * fNearPlane) / (fFarPlane - fNearPlane);	//HYPERBOLIC
188 	ProjectionMatrix._43 = Q;
189 
190 	GRenderer->SetViewport(Rect(static_cast<s32>(_fWidth), static_cast<s32>(_fHeight)));
191 }
192 
specialEE_RTP(TexturedVertex * in,TexturedVertex * out)193 void specialEE_RTP(TexturedVertex * in, TexturedVertex * out) {
194 
195 	EERIE_TRANSFORM * et = &ACTIVECAM->transform;
196 	out->p = in->p - et->pos;
197 
198 	float temp = (out->p.z * et->ycos) - (out->p.x * et->ysin);
199 	out->p.x = (out->p.z * et->ysin) + (out->p.x * et->ycos);
200 	out->p.z = (out->p.y * et->xsin) + (temp * et->xcos);
201 	out->p.y = (out->p.y * et->xcos) - (temp * et->xsin);
202 
203 	float fZTemp = 1.f / out->p.z;
204 	out->p.z = fZTemp * ProjectionMatrix._33 + ProjectionMatrix._43; //HYPERBOLIC
205 
206 	out->p.x = out->p.x * ProjectionMatrix._11 * fZTemp + et->mod.x;
207 	out->p.y = out->p.y * ProjectionMatrix._22 * fZTemp + et->mod.y;
208 	out->rhw = fZTemp;
209 }
210 
IntersectLinePlane(const Vec3f & l1,const Vec3f & l2,const EERIEPOLY * ep,Vec3f * intersect)211 static bool IntersectLinePlane(const Vec3f & l1, const Vec3f & l2, const EERIEPOLY * ep, Vec3f * intersect) {
212 
213 	Vec3f v = l2 - l1;
214 
215 	float d = dot(v, ep->norm);
216 
217 	if (d != 0.0f) {
218 		Vec3f v1 = ep->center - l2;
219 		d = dot(v1, ep->norm) / d;
220 
221 		*intersect = (v * d) + l2;
222 
223 		return true;
224 	}
225 
226 	return false;
227 }
228 
RayCollidingPoly(Vec3f * orgn,Vec3f * dest,EERIEPOLY * ep,Vec3f * hit)229 bool RayCollidingPoly(Vec3f * orgn, Vec3f * dest, EERIEPOLY * ep, Vec3f * hit)
230 {
231 	if (IntersectLinePlane(*orgn, *dest, ep, hit))
232 	{
233 		if (RayIn3DPolyNoCull(orgn, dest, ep)) return true;
234 	}
235 
236 	return false;
237 }
238 
ResetBBox3D(Entity * io)239 void ResetBBox3D(Entity * io) {
240 	if(io) {
241 		io->bbox3D.min = Vec3f::repeat(99999999.f);
242 		io->bbox3D.max = Vec3f::repeat(-99999999.f);
243 	}
244 }
245 
AddToBBox3D(Entity * io,Vec3f * pos)246 void AddToBBox3D(Entity * io, Vec3f * pos) {
247 	if(io) {
248 		io->bbox3D.min = componentwise_min(io->bbox3D.min, *pos);
249 		io->bbox3D.max = componentwise_max(io->bbox3D.max, *pos);
250 	}
251 }
252 
MakeTopObjString(Entity * io,string & dest)253 long MakeTopObjString(Entity * io,  string & dest) {
254 
255 	if(!io) {
256 		return -1;
257 	}
258 
259 	Vec3f boxmin = Vec3f::repeat(999999999.f);
260 	Vec3f boxmax = Vec3f::repeat(-999999999.f);
261 	for(size_t i = 0; i < io->obj->vertexlist.size(); i++) {
262 		boxmin = componentwise_min(boxmin, io->obj->vertexlist3[i].v);
263 		boxmax = componentwise_max(boxmax, io->obj->vertexlist3[i].v);
264 	}
265 	boxmin.y -= 5.f;
266 	boxmax.y -= 5.f;
267 
268 	dest = "";
269 
270 	if ((player.pos.x > boxmin.x)
271 			&& (player.pos.x < boxmax.x)
272 			&& (player.pos.z > boxmin.z)
273 			&& (player.pos.z < boxmax.z))
274 	{
275 		{
276 			if (EEfabs(player.pos.y + 160.f - boxmin.y) < 50.f)
277 				dest += " player";
278 		}
279 	}
280 
281 	for(size_t i = 0; i < entities.size(); i++) {
282 		if(entities[i] && entities[i] != io) {
283 				if (entities[i]->show == SHOW_FLAG_IN_SCENE)
284 					if ((entities[i]->ioflags & IO_NPC) || (entities[i]->ioflags & IO_ITEM))
285 					{
286 						if (((entities[i]->pos.x) > boxmin.x)
287 								&& ((entities[i]->pos.x) < boxmax.x)
288 								&& ((entities[i]->pos.z) > boxmin.z)
289 								&& ((entities[i]->pos.z) < boxmax.z))
290 						{
291 							if (EEfabs(entities[i]->pos.y - boxmin.y) < 40.f)
292 							{
293 								dest += ' ' + entities[i]->long_name();
294 
295 							}
296 						}
297 
298 				}
299 		}
300 	}
301 
302 	if (dest.length() == 0) dest = "none";
303 
304 	return -1;
305 }
306 
307 
CheckInPoly(float x,float y,float z,float * needY)308 EERIEPOLY * CheckInPoly(float x, float y, float z, float * needY)
309 {
310 	long px, pz;
311 	Vec3f poss(x, y, z);
312 
313 	px = poss.x * ACTIVEBKG->Xmul;
314 	pz = poss.z * ACTIVEBKG->Zmul;
315 
316 	if ((pz >= ACTIVEBKG->Zsize - 1)
317 			||	(pz <= 0)
318 			||	(px >= ACTIVEBKG->Xsize - 1)
319 			||	(px <= 0))
320 		return NULL;
321 
322 	float rx, rz;
323 	rx = poss.x - ((float)px * ACTIVEBKG->Xdiv);
324 	rz = poss.z - ((float)pz * ACTIVEBKG->Zdiv);
325 
326 	EERIEPOLY * ep;
327 	FAST_BKG_DATA * feg;
328 	EERIEPOLY * found = NULL;
329 
330 	float foundY = 0.f;
331 	short pzi, pza, pxi, pxa;
332 
333 	(void)checked_range_cast<short>(pz - 1);
334 	(void)checked_range_cast<short>(pz + 1);
335 	short sPz = static_cast<short>(pz);
336 
337 	if (rz < -40.f)
338 	{
339 		pzi = sPz - 1;
340 		pza = sPz - 1;
341 	}
342 	else if (rz < 40.f)
343 	{
344 		pzi = sPz - 1;
345 		pza = sPz;
346 	}
347 	else if (rz > 60.f)
348 	{
349 		pzi = sPz;
350 		pza = sPz + 1;
351 	}
352 	else
353 	{
354 		pzi = sPz;
355 		pza = sPz;
356 	}
357 
358 	(void)checked_range_cast<short>(px - 1);
359 	(void)checked_range_cast<short>(px + 1);
360 	short sPx = static_cast<short>(px);
361 
362 	if (rx < -40.f)
363 	{
364 		pxi = sPx - 1;
365 		pxa = sPx - 1;
366 	}
367 
368 	else if (rx < 40.f)
369 	{
370 		pxi = sPx - 1;
371 		pxa = sPx;
372 	}
373 	else if (rx > 60.f)
374 	{
375 		pxi = sPx;
376 		pxa = sPx + 1;
377 	}
378 	else
379 	{
380 		pxi = sPx;
381 		pxa = sPx;
382 	}
383 
384 	int i, j, k;
385 
386 	for (j = pzi; j <= pza; j++)
387 		for (i = pxi; i <= pxa; i++)
388 		{
389 			feg = &ACTIVEBKG->fastdata[i][j];
390 
391 			for (k = 0; k < feg->nbpolyin; k++)
392 			{
393 				ep = feg->polyin[k];
394 
395 				if (
396 					(poss.x >= ep->min.x) && (poss.x <= ep->max.x)
397 					&&	(poss.z >= ep->min.z) && (poss.z <= ep->max.z)
398 					&& !(ep->type & (POLY_WATER | POLY_TRANS | POLY_NOCOL))
399 					&& (ep->max.y >= poss.y)
400 					&&	(ep != found)
401 					&&	(PointIn2DPolyXZ(ep, poss.x, poss.z))
402 				)
403 				{
404 					if ((GetTruePolyY(ep, &poss, &rz))
405 							&&	(rz >= poss.y)
406 							&&	((found == NULL) || ((found != NULL) && (rz <= foundY)))
407 					   )
408 					{
409 						found = ep;
410 						foundY = rz;
411 					}
412 				}
413 			}
414 		}
415 
416 	if (needY) *needY = foundY;
417 
418 	return found;
419 }
CheckInPolyPrecis(float x,float y,float z,float * needY)420 EERIEPOLY * CheckInPolyPrecis(float x, float y, float z, float * needY)
421 {
422 	long px, pz;
423 	Vec3f poss(x, y, z);
424 
425 	px = poss.x * ACTIVEBKG->Xmul;
426 	pz = poss.z * ACTIVEBKG->Zmul;
427 
428 	if ((pz >= ACTIVEBKG->Zsize - 1)
429 			||	(pz <= 0)
430 			||	(px >= ACTIVEBKG->Xsize - 1)
431 			||	(px <= 0))
432 		return NULL;
433 
434 	float rx, rz;
435 	rx = poss.x - ((float)px * ACTIVEBKG->Xdiv);
436 	rz = poss.z - ((float)pz * ACTIVEBKG->Zdiv);
437 
438 	EERIEPOLY * ep;
439 	FAST_BKG_DATA * feg;
440 	EERIEPOLY * found = NULL;
441 
442 	float foundY = 0.f;
443 	short pzi, pza, pxi, pxa;
444 
445 	(void)checked_range_cast<short>(pz - 1);
446 	(void)checked_range_cast<short>(pz + 1);
447 	short sPz = static_cast<short>(pz);
448 
449 	if (rz < -40.f)
450 	{
451 		pzi = sPz - 1;
452 		pza = sPz - 1;
453 	}
454 	else if (rz < 40.f)
455 	{
456 		pzi = sPz - 1;
457 		pza = sPz;
458 	}
459 	else if (rz > 60.f)
460 	{
461 		pzi = sPz;
462 		pza = sPz + 1;
463 	}
464 	else
465 	{
466 		pzi = sPz;
467 		pza = sPz;
468 	}
469 
470 	(void)checked_range_cast<short>(px + 1);
471 	(void)checked_range_cast<short>(px - 1);
472 	short sPx = static_cast<short>(px);
473 
474 	if (rx < -40.f)
475 	{
476 		pxi = sPx - 1;
477 		pxa = sPx - 1;
478 	}
479 	else if (rx < 40.f)
480 	{
481 		pxi = sPx - 1;
482 		pxa = sPx;
483 	}
484 	else if (rx > 60.f)
485 	{
486 		pxi = sPx;
487 		pxa = sPx + 1;
488 	}
489 	else
490 	{
491 		pxi = sPx;
492 		pxa = sPx;
493 	}
494 
495 	int i, j, k;
496 
497 	for (j = pzi; j <= pza; j++)
498 		for (i = pxi; i <= pxa; i++)
499 		{
500 			feg = &ACTIVEBKG->fastdata[i][j];
501 
502 			for (k = 0; k < feg->nbpolyin; k++)
503 			{
504 				ep = feg->polyin[k];
505 
506 				if (
507 					(poss.x >= ep->min.x) && (poss.x <= ep->max.x)
508 					&&	(poss.z >= ep->min.z) && (poss.z <= ep->max.z)
509 					&& !(ep->type & (POLY_WATER | POLY_TRANS | POLY_NOCOL))
510 					&& (ep->max.y >= poss.y)
511 					&&	(ep != found)
512 					&&	(PointIn2DPolyXZ(ep, poss.x, poss.z))
513 				)
514 				{
515 					if ((GetTruePolyY(ep, &poss, &rz))
516 							&&	(rz >= poss.y)
517 							&&	((found == NULL) || ((found != NULL) && (rz <= foundY)))
518 					   )
519 					{
520 						found = ep;
521 						foundY = rz;
522 					}
523 				}
524 			}
525 		}
526 
527 	if (needY) *needY = foundY;
528 
529 	return found;
530 }
531 
EECheckInPoly(const Vec3f * pos,float * needY)532 EERIEPOLY * EECheckInPoly(const Vec3f * pos, float * needY) {
533 	return CheckInPoly(pos->x, pos->y, pos->z, needY);
534 }
535 
getFastBackgroundData(float x,float z)536 static FAST_BKG_DATA * getFastBackgroundData(float x, float z) {
537 
538 	long px = x * ACTIVEBKG->Xmul;
539 	if(px < 0 || px >= ACTIVEBKG->Xsize) {
540 		return NULL;
541 	}
542 
543 	long pz = z * ACTIVEBKG->Zmul;
544 	if(pz < 0 || pz >= ACTIVEBKG->Zsize) {
545 		return NULL;
546 	}
547 
548 	return &ACTIVEBKG->fastdata[px][pz];
549 }
550 
CheckTopPoly(float x,float y,float z)551 EERIEPOLY * CheckTopPoly(float x, float y, float z) {
552 
553 	FAST_BKG_DATA * feg = getFastBackgroundData(x, z);
554 	if(!feg) {
555 		return NULL;
556 	}
557 
558 	EERIEPOLY * found = NULL;
559 	for (long k = 0; k < feg->nbpolyin; k++) {
560 
561 		EERIEPOLY * ep = feg->polyin[k];
562 
563 		if((!(ep->type & (POLY_WATER | POLY_TRANS | POLY_NOCOL)))
564 		   && (ep->min.y < y)
565 		   && (x >= ep->min.x) && (x <= ep->max.x)
566 		   && (z >= ep->min.z) && (z <= ep->max.z)
567 		   && (PointIn2DPolyXZ(ep, x, z))) {
568 
569 			if((EEfabs(ep->max.y - ep->min.y) > 50.f) && (y - ep->center.y < 60.f)) {
570 				continue;
571 			}
572 
573 			if(ep->tex != NULL) {
574 				if(found == NULL || ep->min.y > found->min.y) {
575 					found = ep;
576 				}
577 			}
578 		}
579 	}
580 
581 	return found;
582 }
583 
IsAnyPolyThere(float x,float z)584 bool IsAnyPolyThere(float x, float z) {
585 
586 	FAST_BKG_DATA * feg = getFastBackgroundData(x, z);
587 	if(!feg) {
588 		return false;
589 	}
590 
591 	for(long k = 0; k < feg->nbpolyin; k++) {
592 
593 		EERIEPOLY * ep = feg->polyin[k];
594 
595 		if(PointIn2DPolyXZ(ep, x, z)) {
596 			return true;
597 		}
598 	}
599 
600 	return false;
601 }
602 
FirstPolyPosY(float x,float z)603 float FirstPolyPosY(float x, float z)
604 {
605 	EERIEPOLY * ep = GetMinPoly(x, 0.f, z);
606 
607 	if (ep == NULL) return 99999999.f;
608 
609 	return ep->max.y;
610 }
611 
GetMinPoly(float x,float y,float z)612 EERIEPOLY * GetMinPoly(float x, float y, float z) {
613 
614 	FAST_BKG_DATA * feg = getFastBackgroundData(x, z);
615 	if(!feg) {
616 		return NULL;
617 	}
618 
619 	Vec3f pos(x, y, z);
620 
621 	EERIEPOLY * found = NULL;
622 	float foundy = 0.0f;
623 	for (long k = 0; k < feg->nbpolyin; k++) {
624 
625 		EERIEPOLY * ep = feg->polyin[k];
626 
627 		if(ep->type & POLY_WATER) continue;
628 
629 		if(ep->type & POLY_TRANS) continue;
630 
631 		if(ep->type & POLY_NOCOL) continue;
632 
633 		if(PointIn2DPolyXZ(ep, x, z)) {
634 			float ret;
635 			if(GetTruePolyY(ep, &pos, &ret)) {
636 				if(!found || ret > foundy) {
637 					found = ep;
638 					foundy = ret;
639 				}
640 			}
641 		}
642 	}
643 
644 	return found;
645 }
646 
GetMaxPoly(float x,float y,float z)647 EERIEPOLY * GetMaxPoly(float x, float y, float z) {
648 
649 	FAST_BKG_DATA * feg = getFastBackgroundData(x, z);
650 	if(!feg) {
651 		return NULL;
652 	}
653 
654 	Vec3f pos(x, y, z);
655 
656 	EERIEPOLY * found = NULL;
657 	float foundy = 0.0f;
658 	for(long k = 0; k < feg->nbpolyin; k++) {
659 
660 		EERIEPOLY * ep = feg->polyin[k];
661 
662 		if(ep->type & POLY_WATER) continue;
663 
664 		if(ep->type & POLY_TRANS) continue;
665 
666 		if(ep->type & POLY_NOCOL) continue;
667 
668 		if(PointIn2DPolyXZ(ep, x, z)) {
669 			float ret;
670 			if(GetTruePolyY(ep, &pos, &ret)) {
671 				if(!found || ret < foundy) {
672 					found = ep;
673 					foundy = ret;
674 				}
675 			}
676 		}
677 	}
678 
679 	return found;
680 }
681 
EEIsUnderWater(const Vec3f * pos)682 EERIEPOLY * EEIsUnderWater(const Vec3f * pos) {
683 
684 	FAST_BKG_DATA * feg = getFastBackgroundData(pos->x, pos->z);
685 	if(!feg) {
686 		return NULL;
687 	}
688 
689 	EERIEPOLY * found = NULL;
690 	for(short k = 0; k < feg->nbpolyin; k++) {
691 
692 		EERIEPOLY * ep = feg->polyin[k];
693 
694 		if(ep->type & POLY_WATER) {
695 			if(ep->max.y < pos->y && PointIn2DPolyXZ(ep, pos->x, pos->z)) {
696 				if(!found || ep->max.y < found->max.y) {
697 					found = ep;
698 				}
699 			}
700 		}
701 	}
702 	return found;
703 }
704 
GetTruePolyY(const EERIEPOLY * ep,const Vec3f * pos,float * ret)705 bool GetTruePolyY(const EERIEPOLY * ep, const Vec3f * pos, float * ret) {
706 
707 
708 	Vec3f s21 = ep->v[1].p - ep->v[0].p;
709 	Vec3f s31 = ep->v[2].p - ep->v[0].p;
710 
711 	Vec3f n;
712 	n.y = (s21.z * s31.x) - (s21.x * s31.z);
713 	if (n.y == 0.f) return false;
714 	n.x = (s21.y * s31.z) - (s21.z * s31.y);
715 	n.z = (s21.x * s31.y) - (s21.y * s31.x);
716 
717 	// uses s21.x instead of d
718 	s21.x = ep->v[0].p.x * n.x + ep->v[0].p.y * n.y + ep->v[0].p.z * n.z;
719 
720 	s21.x = (s21.x - (n.x * pos->x) - (n.z * pos->z)) / n.y;
721 
722 	// Perhaps we can remove the two following lines... (need to test)
723 	if (s21.x < ep->min.y) s21.x = ep->min.y;
724 	else if (s21.x > ep->max.y) s21.x = ep->max.y;
725 
726 	*ret = s21.x;
727 	return true;
728 }
729 
730 //*************************************************************************************
731 //*************************************************************************************
732 EERIE_BACKGROUND * ACTIVEBKG = NULL;
733 
734 //*************************************************************************************
735 // Selects Active Background Structure
736 //*************************************************************************************
737 EERIE_CAMERA * ACTIVECAM = NULL;
738 
739 //*************************************************************************************
740 // Selects Active Camera
741 //*************************************************************************************
SetActiveCamera(EERIE_CAMERA * cam)742 void SetActiveCamera(EERIE_CAMERA * cam)
743 {
744 	if (ACTIVECAM != cam) ACTIVECAM = cam;
745 }
746 
EERIETreatPoint(TexturedVertex * in,TexturedVertex * out)747 void EERIETreatPoint(TexturedVertex * in, TexturedVertex * out) {
748 	out->p = in->p - ACTIVECAM->pos;
749 	in->p.x = (out->p.x * ACTIVECAM->Ycos) + (out->p.z * ACTIVECAM->Ysin);
750 	in->p.z = (out->p.z * ACTIVECAM->Ycos) - (out->p.x * ACTIVECAM->Ysin);
751 	out->p.z = (out->p.y * ACTIVECAM->Xsin) + (in->p.z * ACTIVECAM->Xcos);
752 	out->p.y = (out->p.y * ACTIVECAM->Xcos) - (in->p.z * ACTIVECAM->Xsin);
753 
754 	if (ACTIVECAM->Zsin == 0)
755 	{
756 		in->p.y = out->p.y;
757 	}
758 	else
759 	{
760 		in->p.y = (out->p.y * ACTIVECAM->Zcos) - (in->p.x * ACTIVECAM->Zsin);
761 		in->p.x = (in->p.x * ACTIVECAM->Zcos) + (out->p.y * ACTIVECAM->Zsin);
762 	}
763 
764 	float fZTemp;
765 	fZTemp = 1.f / out->p.z;
766 	out->p.z = fZTemp * ProjectionMatrix._33 + ProjectionMatrix._43; //HYPERBOLIC
767 	out->p.x = in->p.x * ProjectionMatrix._11 * fZTemp + ACTIVECAM->pos2.x;
768 	out->p.y = in->p.y * ProjectionMatrix._22 * fZTemp + ACTIVECAM->pos2.y;
769 	out->rhw = fZTemp;
770 }
771 
EERIETreatPoint2(TexturedVertex * in,TexturedVertex * out)772 void EERIETreatPoint2(TexturedVertex * in, TexturedVertex * out) {
773 	out->p = in->p - ACTIVECAM->pos;
774 	in->p.x = (out->p.x * ACTIVECAM->Ycos) + (out->p.z * ACTIVECAM->Ysin);
775 	in->p.z = (out->p.z * ACTIVECAM->Ycos) - (out->p.x * ACTIVECAM->Ysin);
776 	out->p.z = (out->p.y * ACTIVECAM->Xsin) + (in->p.z * ACTIVECAM->Xcos);
777 	out->p.y = (out->p.y * ACTIVECAM->Xcos) - (in->p.z * ACTIVECAM->Xsin);
778 
779 	if (ACTIVECAM->Zsin == 0)
780 	{
781 		in->p.y = out->p.y;
782 	}
783 	else
784 	{
785 		in->p.y = (out->p.y * ACTIVECAM->Zcos) - (in->p.x * ACTIVECAM->Zsin);
786 		in->p.x = (in->p.x * ACTIVECAM->Zcos) + (out->p.y * ACTIVECAM->Zsin);
787 	}
788 
789 	float fZTemp;
790 	fZTemp = 1.f / out->p.z;
791 	out->p.z = fZTemp * ProjectionMatrix._33 + ProjectionMatrix._43; //HYPERBOLIC
792 	out->p.x = in->p.x * ProjectionMatrix._11 * fZTemp + ACTIVECAM->pos2.x;
793 	out->p.y = in->p.y * ProjectionMatrix._22 * fZTemp + ACTIVECAM->pos2.y;
794 	out->rhw = fZTemp * 3000.f;
795 
796 }
797 
EE_RT(TexturedVertex * in,Vec3f * out)798 void EE_RT(TexturedVertex * in, Vec3f * out) {
799 
800 	*out = in->p - ACTIVECAM->pos;
801 
802 	float temp = (out->z * ACTIVECAM->Ycos) - (out->x * ACTIVECAM->Ysin);
803 	out->x = (out->x * ACTIVECAM->Ycos) + (out->z * ACTIVECAM->Ysin);
804 
805 	out->z = (out->y * ACTIVECAM->Xsin) + (temp * ACTIVECAM->Xcos);
806 	out->y = (out->y * ACTIVECAM->Xcos) - (temp * ACTIVECAM->Xsin);
807 
808 	// Might Prove Usefull one day...
809 	temp = (out->y * ACTIVECAM->Zcos) - (out->x * ACTIVECAM->Zsin);
810 	out->x = (out->x * ACTIVECAM->Zcos) + (out->y * ACTIVECAM->Zsin);
811 	out->y = temp;
812 }
813 
EE_RT2(TexturedVertex * in,TexturedVertex * out)814 void EE_RT2(TexturedVertex * in, TexturedVertex * out) {
815 
816 	out->p = in->p - ACTIVECAM->pos;
817 
818 	float temp = (out->p.z * ACTIVECAM->Ycos) - (out->p.x * ACTIVECAM->Ysin);
819 	out->p.x = (out->p.x * ACTIVECAM->Ycos) + (out->p.z * ACTIVECAM->Ysin);
820 
821 	out->p.z = (out->p.y * ACTIVECAM->Xsin) + (temp * ACTIVECAM->Xcos);
822 	out->p.y = (out->p.y * ACTIVECAM->Xcos) - (temp * ACTIVECAM->Xsin);
823 
824 	// Might Prove Usefull one day...
825 	temp = (out->p.y * ACTIVECAM->Zcos) - (out->p.x * ACTIVECAM->Zsin);
826 	out->p.x = (out->p.x * ACTIVECAM->Zcos) + (out->p.y * ACTIVECAM->Zsin);
827 	out->p.y = temp;
828 }
829 
specialEE_RT(TexturedVertex * in,Vec3f * out)830 void specialEE_RT(TexturedVertex * in, Vec3f * out) {
831 
832 	EERIE_TRANSFORM * et = (EERIE_TRANSFORM *)&ACTIVECAM->transform;
833 	*out = in->p - et->pos;
834 
835 	float temp = (out->z * et->ycos) - (out->x * et->ysin);
836 	out->x = (out->z * et->ysin) + (out->x * et->ycos);
837 	out->z = (out->y * et->xsin) + (temp * et->xcos);
838 	out->y = (out->y * et->xcos) - (temp * et->xsin);
839 }
840 
841 // TODO get rid of sw transform
clamp_and_invert(float z)842 static inline float clamp_and_invert(float z) {
843 
844 	const float near_clamp = .000001f; // just a random small number
845 
846 	return 1.f / std::max(z, near_clamp);
847 }
848 
specialEE_P(Vec3f * in,TexturedVertex * out)849 void specialEE_P(Vec3f * in, TexturedVertex * out) {
850 
851 	EERIE_TRANSFORM * et = (EERIE_TRANSFORM *)&ACTIVECAM->transform;
852 
853 	float fZTemp = clamp_and_invert(in->z);
854 
855 	out->p.z = fZTemp * ProjectionMatrix._33 + ProjectionMatrix._43;
856 	out->p.x = in->x * ProjectionMatrix._11 * fZTemp + et->mod.x;
857 	out->p.y = in->y * ProjectionMatrix._22 * fZTemp + et->mod.y;
858 	out->rhw = fZTemp;
859 }
860 
EE_P(Vec3f * in,TexturedVertex * out)861 void EE_P(Vec3f * in, TexturedVertex * out) {
862 
863 	float fZTemp = clamp_and_invert(in->z);
864 
865 	out->p.z = fZTemp * ProjectionMatrix._33 + ProjectionMatrix._43; //HYPERBOLIC
866 	out->p.x = in->x * ProjectionMatrix._11 * fZTemp + ACTIVECAM->pos2.x;
867 	out->p.y = in->y * ProjectionMatrix._22 * fZTemp + ACTIVECAM->pos2.y;
868 	out->rhw = fZTemp;
869 }
870 
EE_P2(TexturedVertex * in,TexturedVertex * out)871 void EE_P2(TexturedVertex * in, TexturedVertex * out)
872 {
873 	float fZTemp;
874 	fZTemp = 1.f / in->p.z;
875 
876 	out->p.z = fZTemp * ProjectionMatrix._33 + ProjectionMatrix._43; //HYPERBOLIC
877 	out->p.x = in->p.x * ProjectionMatrix._11 * fZTemp + ACTIVECAM->pos2.x;
878 	out->p.y = in->p.y * ProjectionMatrix._22 * fZTemp + ACTIVECAM->pos2.y;
879 	out->rhw = fZTemp;
880 }
881 
EE_RTP(TexturedVertex * in,TexturedVertex * out)882 void EE_RTP(TexturedVertex * in, TexturedVertex * out) {
883 
884 	out->p = in->p - ACTIVECAM->pos;
885 
886 	float temp = (out->p.z * ACTIVECAM->Ycos) - (out->p.x * ACTIVECAM->Ysin);
887 	out->p.x = (out->p.x * ACTIVECAM->Ycos) + (out->p.z * ACTIVECAM->Ysin);
888 	out->p.z = (out->p.y * ACTIVECAM->Xsin) + (temp * ACTIVECAM->Xcos);
889 	out->p.y = (out->p.y * ACTIVECAM->Xcos) - (temp * ACTIVECAM->Xsin);
890 
891 	// Might Prove Usefull one day...
892 	temp = (out->p.y * ACTIVECAM->Zcos) - (out->p.x * ACTIVECAM->Zsin);
893 	out->p.x = (out->p.x * ACTIVECAM->Zcos) + (out->p.y * ACTIVECAM->Zsin);
894 	out->p.y = temp;
895 
896 	float fZTemp;
897 	fZTemp = 1.f / out->p.z;
898 	out->p.z = fZTemp * ProjectionMatrix._33 + ProjectionMatrix._43;
899 	out->p.x = out->p.x * ProjectionMatrix._11 * fZTemp + ACTIVECAM->pos2.x;
900 	out->p.y = out->p.y * ProjectionMatrix._22 * fZTemp + ACTIVECAM->pos2.y;
901 	out->rhw = fZTemp;
902 }
903 
camEE_RTP(TexturedVertex * in,TexturedVertex * out,EERIE_CAMERA * cam)904 static void camEE_RTP(TexturedVertex * in, TexturedVertex * out, EERIE_CAMERA * cam) {
905 
906 	TexturedVertex tout;
907 	out->p = in->p - cam->pos;
908 
909 	tout.p.x = (out->p.x * cam->Ycos) + (out->p.z * cam->Ysin);
910 	tout.p.z = (out->p.z * cam->Ycos) - (out->p.x * cam->Ysin);
911 
912 	out->p.z = (out->p.y * cam->Xsin) + (tout.p.z * cam->Xcos);
913 	out->p.y = (out->p.y * cam->Xcos) - (tout.p.z * cam->Xsin);
914 
915 	if (ACTIVECAM->Zsin == 0)
916 	{
917 		tout.p.y = out->p.y;
918 	}
919 	else
920 	{
921 		tout.p.y = (out->p.y * cam->Zcos) - (tout.p.x * cam->Zsin);
922 		tout.p.x = (tout.p.x * cam->Zcos) + (out->p.y * cam->Zsin);
923 	}
924 
925 	if (out->p.z <= 0.f)
926 	{
927 		out->rhw = 1.f - out->p.z;
928 	}
929 	else
930 	{
931 		out->rhw = 1.f / out->p.z;
932 	}
933 
934 	tout.rhw = cam->use_focal * out->rhw;
935 	out->p.z = out->p.z * cam->Zmul;
936 	out->p.x = cam->pos2.x + (tout.p.x * tout.rhw);
937 	out->p.y = cam->pos2.y + (tout.p.y * tout.rhw) ;
938 }
939 
940 //*************************************************************************************
941 //*************************************************************************************
EE_RTT(TexturedVertex * in,TexturedVertex * out)942 void EE_RTT(TexturedVertex * in, TexturedVertex * out)
943 {
944 	specialEE_RTP(in, out);
945 }
946 
947 //*************************************************************************************
948 //*************************************************************************************
EERIERTPPolyCam(EERIEPOLY * ep,EERIE_CAMERA * cam)949 static void EERIERTPPolyCam(EERIEPOLY * ep, EERIE_CAMERA * cam) {
950 
951 	camEE_RTP(&ep->v[0], &ep->tv[0], cam);
952 	camEE_RTP(&ep->v[1], &ep->tv[1], cam);
953 	camEE_RTP(&ep->v[2], &ep->tv[2], cam);
954 
955 	if (ep->type & POLY_QUAD) camEE_RTP(&ep->v[3], &ep->tv[3], cam);
956 }
957 
958 extern float GLOBAL_LIGHT_FACTOR;
959 //*************************************************************************************
960 //*************************************************************************************
961 
GetColorz(float x,float y,float z)962 float GetColorz(float x, float y, float z) {
963 
964 	Vec3f pos(x, y, z);
965 	llightsInit();
966 	float ffr, ffg, ffb;
967 	float dd, dc;
968 	float p;
969 
970 	for (long i = 0; i < TOTIOPDL; i++)
971 	{
972 		if ((IO_PDL[i]->fallstart > 10.f) && (IO_PDL[i]->fallend > 100.f))
973 			Insertllight(IO_PDL[i], fdist(IO_PDL[i]->pos, pos) - IO_PDL[i]->fallstart);
974 	}
975 
976 	for (int i = 0; i < TOTPDL; i++)
977 	{
978 		if ((PDL[i]->fallstart > 10.f) && (PDL[i]->fallend > 100.f))
979 			Insertllight(PDL[i], fdist(PDL[i]->pos, pos) - PDL[i]->fallstart);
980 	}
981 
982 	Preparellights(&pos);
983 	ffr = 0;
984 	ffg = 0;
985 	ffb = 0;
986 
987 	for (long k = 0; k < MAX_LLIGHTS; k++)
988 	{
989 		EERIE_LIGHT * el = llights[k];
990 
991 		if (el)
992 		{
993 			dd = fdist(el->pos, pos);
994 
995 			if (dd < el->fallend)
996 			{
997 				if (dd <= el->fallstart)
998 					dc = el->intensity * GLOBAL_LIGHT_FACTOR;
999 				else
1000 				{
1001 					p = ((el->fallend - dd) * el->falldiffmul);
1002 
1003 					if (p <= 0.f)
1004 						dc = 0.f;
1005 					else
1006 						dc = p * el->intensity * GLOBAL_LIGHT_FACTOR;
1007 				}
1008 
1009 				dc *= 0.4f * 255.f;
1010 				ffr = max(ffr, el->rgb.r * dc);
1011 				ffg = max(ffg, el->rgb.g * dc);
1012 				ffb = max(ffb, el->rgb.b * dc);
1013 			}
1014 		}
1015 	}
1016 
1017 
1018 	EERIEPOLY * ep;
1019 	float needy;
1020 	ep = CheckInPoly(x, y , z, &needy);
1021 
1022 	if (ep != NULL)
1023 	{
1024 		float _ffr = 0;
1025 		float _ffg = 0;
1026 		float _ffb = 0;
1027 		long to;
1028 		float div;
1029 
1030 		if (ep->type & POLY_QUAD)
1031 		{
1032 			to = 4;
1033 			div = ( 1.0f / 4 );
1034 		}
1035 		else
1036 		{
1037 			to = 3;
1038 			div = ( 1.0f / 3 );
1039 		}
1040 
1041 		ApplyDynLight(ep);
1042 
1043 		for(long i = 0; i < to; i++) {
1044 			Color col = Color::fromBGR(ep->tv[i].color);
1045 			_ffr += float(col.r);
1046 			_ffg += float(col.g);
1047 			_ffb += float(col.b);
1048 		}
1049 
1050 		_ffr *= div;
1051 		_ffg *= div;
1052 		_ffb *= div;
1053 		float ratio, ratio2;
1054 		ratio = EEfabs(needy - y) * ( 1.0f / 300 );
1055 		ratio = (1.f - ratio);
1056 		ratio2 = 1.f - ratio;
1057 		ffr = ffr * ratio2 + _ffr * ratio;
1058 		ffg = ffg * ratio2 + _ffg * ratio;
1059 		ffb = ffb * ratio2 + _ffb * ratio;
1060 	}
1061 
1062 	return (min(ffr, 255.f) + min(ffg, 255.f) + min(ffb, 255.f)) * (1.f/3);
1063 }
1064 
1065 //*************************************************************************************
1066 //*************************************************************************************
1067 
1068 extern float GetIOHeight(Entity * io);
1069 extern float GetIORadius(Entity * io);
1070 
GetVertexPos(Entity * io,long id,Vec3f * pos)1071 long GetVertexPos(Entity * io, long id, Vec3f * pos)
1072 {
1073 	if (!io) return 0;
1074 
1075 	if (id != -1)
1076 	{
1077 		*pos = io->obj->vertexlist3[id].v;
1078 		return 1;
1079 	}
1080 	else
1081 	{
1082 		*pos = io->pos + Vec3f(0.f, GetIOHeight(io), 0.f);
1083 		return 2;
1084 	}
1085 }
1086 
1087 long EERIEDrawnPolys = 0;
1088 
1089 // Checks if point (x,y) is in a 2D poly defines by ep
PointIn2DPoly(EERIEPOLY * ep,float x,float y)1090 int PointIn2DPoly(EERIEPOLY * ep, float x, float y) {
1091 
1092 	int i, j, c = 0;
1093 
1094 	for (i = 0, j = 2; i < 3; j = i++)
1095 	{
1096 		if ((((ep->tv[i].p.y <= y) && (y < ep->tv[j].p.y)) ||
1097 				((ep->tv[j].p.y <= y) && (y < ep->tv[i].p.y))) &&
1098 				(x < (ep->tv[j].p.x - ep->tv[i].p.x) *(y - ep->tv[i].p.y) / (ep->tv[j].p.y - ep->tv[i].p.y) + ep->tv[i].p.x))
1099 			c = !c;
1100 	}
1101 
1102 	if (c) return c;
1103 	else if (ep->type & POLY_QUAD)
1104 		for (i = 1, j = 3; i < 4; j = i++)
1105 		{
1106 			if ((((ep->tv[i].p.y <= y) && (y < ep->tv[j].p.y)) ||
1107 					((ep->tv[j].p.y <= y) && (y < ep->tv[i].p.y))) &&
1108 					(x < (ep->tv[j].p.x - ep->tv[i].p.x) *(y - ep->tv[i].p.y) / (ep->tv[j].p.y - ep->tv[i].p.y) + ep->tv[i].p.x))
1109 				c = !c;
1110 		}
1111 
1112 	return c;
1113 }
1114 
1115 //*************************************************************************************
1116 //*************************************************************************************
1117 
PtIn2DPolyProj(EERIE_3DOBJ * obj,EERIE_FACE * ef,float x,float z)1118 float PtIn2DPolyProj(EERIE_3DOBJ * obj, EERIE_FACE * ef, float x, float z) {
1119 
1120 	int i, j, c = 0;
1121 
1122 	for (i = 0, j = 2; i < 3; j = i++)
1123 	{
1124 		if ((((obj->vertexlist[ef->vid[i]].vert.p.y <= z) && (z < obj->vertexlist[ef->vid[j]].vert.p.y)) ||
1125 				((obj->vertexlist[ef->vid[j]].vert.p.y <= z) && (z < obj->vertexlist[ef->vid[i]].vert.p.y))) &&
1126 				(x < (obj->vertexlist[ef->vid[j]].vert.p.x - obj->vertexlist[ef->vid[i]].vert.p.x) *(z - obj->vertexlist[ef->vid[i]].vert.p.y) / (obj->vertexlist[ef->vid[j]].vert.p.y - obj->vertexlist[ef->vid[i]].vert.p.y) + obj->vertexlist[ef->vid[i]].vert.p.x))
1127 			c = !c;
1128 	}
1129 
1130 	if (c)
1131 		return obj->vertexlist[ef->vid[0]].vert.p.z;
1132 	else
1133 		return 0.f;
1134 }
1135 
CEDRIC_PtIn2DPolyProjV2(EERIE_3DOBJ * obj,EERIE_FACE * ef,float x,float z)1136 float CEDRIC_PtIn2DPolyProjV2(EERIE_3DOBJ * obj, EERIE_FACE * ef, float x, float z) {
1137 
1138 	int i, j, c = 0;
1139 
1140 	for (i = 0, j = 2; i < 3; j = i++)
1141 	{
1142 		if ((((obj->vertexlist3[ef->vid[i]].vert.p.y <= z) && (z < obj->vertexlist3[ef->vid[j]].vert.p.y)) ||
1143 				((obj->vertexlist3[ef->vid[j]].vert.p.y <= z) && (z < obj->vertexlist3[ef->vid[i]].vert.p.y))) &&
1144 				(x < (obj->vertexlist3[ef->vid[j]].vert.p.x - obj->vertexlist3[ef->vid[i]].vert.p.x) *(z - obj->vertexlist3[ef->vid[i]].vert.p.y) / (obj->vertexlist3[ef->vid[j]].vert.p.y - obj->vertexlist3[ef->vid[i]].vert.p.y) + obj->vertexlist3[ef->vid[i]].vert.p.x))
1145 			c = !c;
1146 	}
1147 
1148 	if (c) return obj->vertexlist3[ef->vid[0]].vert.p.z;
1149 	else return 0.f;
1150 }
1151 
PointIn2DPolyXZ(const EERIEPOLY * ep,float x,float z)1152 int PointIn2DPolyXZ(const EERIEPOLY * ep, float x, float z) {
1153 
1154 	int i, j, c = 0, d = 0;
1155 
1156 	for (i = 0, j = 2; i < 3; j = i++)
1157 	{
1158 		if ((((ep->v[i].p.z <= z) && (z < ep->v[j].p.z)) ||
1159 				((ep->v[j].p.z <= z) && (z < ep->v[i].p.z))) &&
1160 				(x < (ep->v[j].p.x - ep->v[i].p.x) *(z - ep->v[i].p.z) / (ep->v[j].p.z - ep->v[i].p.z) + ep->v[i].p.x))
1161 			c = !c;
1162 	}
1163 
1164 	if (ep->type & POLY_QUAD)
1165 		for (i = 1, j = 3; i < 4; j = i++)
1166 		{
1167 			if ((((ep->v[i].p.z <= z) && (z < ep->v[j].p.z)) ||
1168 					((ep->v[j].p.z <= z) && (z < ep->v[i].p.z))) &&
1169 					(x < (ep->v[j].p.x - ep->v[i].p.x) *(z - ep->v[i].p.z) / (ep->v[j].p.z - ep->v[i].p.z) + ep->v[i].p.x))
1170 				d = !d;
1171 		}
1172 
1173 	return c + d;
1174 }
1175 
1176 //*************************************************************************************
1177 // Sets the target of a camera...
1178 //*************************************************************************************
1179 
SetTargetCamera(EERIE_CAMERA * cam,float x,float y,float z)1180 void SetTargetCamera(EERIE_CAMERA * cam, float x, float y, float z)
1181 {
1182 	if ((cam->pos.x == x) && (cam->pos.y == y) && (cam->pos.z == z)) return;
1183 
1184 	cam->angle.a = (degrees(getAngle(cam->pos.y, cam->pos.z, y, cam->pos.z + dist(Vec2f(x, z), Vec2f(cam->pos.x, cam->pos.z))))); //alpha entre orgn et dest;
1185 	cam->angle.b = (180.f + degrees(getAngle(cam->pos.x, cam->pos.z, x, z))); //beta entre orgn et dest;
1186 	cam->angle.g = 0.f;
1187 }
1188 
BackFaceCull2D(TexturedVertex * tv)1189 int BackFaceCull2D(TexturedVertex * tv) {
1190 	if ((tv[0].p.x - tv[1].p.x)*(tv[2].p.y - tv[1].p.y) - (tv[0].p.y - tv[1].p.y)*(tv[2].p.x - tv[1].p.x) > 0.f)
1191 		return 0;
1192 	else return 1;
1193 }
1194 
1195 extern EERIE_CAMERA raycam;
1196 
SP_PrepareCamera(EERIE_CAMERA * cam)1197 static void SP_PrepareCamera(EERIE_CAMERA * cam) {
1198 	float tmp = radians(cam->angle.a);
1199 	cam->transform.use_focal = cam->use_focal = cam->focal * Xratio;
1200 	cam->transform.xcos = cam->Xcos = (float)EEcos(tmp);
1201 	cam->transform.xsin = cam->Xsin = (float)EEsin(tmp);
1202 	tmp = radians(cam->angle.b);
1203 	cam->transform.ycos = cam->Ycos = (float)EEcos(tmp);
1204 	cam->transform.ysin = cam->Ysin = (float)EEsin(tmp);
1205 	tmp = radians(cam->angle.g);
1206 	cam->Zcos = (float)EEcos(tmp);
1207 	cam->Zsin = (float)EEsin(tmp);
1208 	cam->transform.mod = cam->pos2 = (cam->center + cam->clip.origin).to<float>();
1209 	cam->transform.pos = cam->pos;
1210 }
1211 
RayIn3DPolyNoCull(Vec3f * orgn,Vec3f * dest,EERIEPOLY * epp)1212 static int RayIn3DPolyNoCull(Vec3f * orgn, Vec3f * dest, EERIEPOLY * epp) {
1213 
1214 	EERIEPOLY ep;
1215 	memcpy(&ep, epp, sizeof(EERIEPOLY));
1216 	raycam.pos = *orgn;
1217 	SetTargetCamera(&raycam, dest->x, dest->y, dest->z);
1218 	SP_PrepareCamera(&raycam);
1219 	EERIERTPPolyCam(&ep, &raycam);
1220 
1221 	if (PointIn2DPoly(&ep, 320.f, 320.f))	return 1;
1222 
1223 	return 0;
1224 }
1225 
EERIELaunchRay3(Vec3f * orgn,Vec3f * dest,Vec3f * hit,EERIEPOLY * epp,long flag)1226 int EERIELaunchRay3(Vec3f * orgn, Vec3f * dest,  Vec3f * hit, EERIEPOLY * epp, long flag) {
1227 
1228 	Vec3f p; //current ray pos
1229 	Vec3f d; // ray incs
1230 	Vec3f ad; // absolute ray incs
1231 	Vec3f i;
1232 	long lpx, lpz;
1233 	long voidlast;
1234 	long px, pz;
1235 	float pas = 1.5f;
1236 
1237 	long iii = 0;
1238 	float maxstepp = 20000.f / pas;
1239 	*hit = p = *orgn;
1240 
1241 	voidlast = 0;
1242 	lpx = lpz = -1;
1243 	d.x = (dest->x - orgn->x);
1244 	ad.x = EEfabs(d.x);
1245 	d.y = (dest->y - orgn->y);
1246 	ad.y = EEfabs(d.y);
1247 	d.z = (dest->z - orgn->z);
1248 	ad.z = EEfabs(d.z);
1249 
1250 	if(ad.x >= ad.y && ad.x >= ad.z) {
1251 		i.x = (ad.x != d.x) ? (-1.f * pas) : (1.f * pas);
1252 		i.y = d.y / (ad.x / pas);
1253 		i.z = d.z / (ad.x / pas);
1254 	} else if(ad.y >= ad.x && ad.y >= ad.z) {
1255 		i.x = d.x / (ad.y / pas);
1256 		i.y = (ad.y != d.y) ? (-1.f * pas) : (1.f * pas);
1257 		i.z = d.z / (ad.y / pas);
1258 	} else {
1259 		i.x = d.x / (ad.z / pas);
1260 		i.y = d.y / (ad.z / pas);
1261 		i.z = (ad.z != d.z) ? (-1.f * pas) : (1.f * pas);
1262 	}
1263 
1264 	for(;;) {
1265 
1266 		p += i;
1267 
1268 		if(i.x == -1.f * pas && p.x <= dest->x) {
1269 			*hit = p;
1270 			return 0;
1271 		}
1272 
1273 		if(i.x == 1.f * pas && p.x >= dest->x) {
1274 			*hit = p;
1275 			return 0;
1276 		}
1277 
1278 		if(i.y == -1.f * pas && p.y <= dest->y) {
1279 			*hit = p;
1280 			return 0;
1281 		}
1282 
1283 		if(i.y == 1.f * pas && p.y >= dest->y) {
1284 			*hit = p;
1285 			return 0;
1286 		}
1287 
1288 		if(i.z == -1.f * pas && p.z <= dest->z) {
1289 			*hit = p;
1290 			return 0;
1291 		}
1292 
1293 		if(i.z == 1.f * pas && p.z >= dest->z) {
1294 			*hit = p;
1295 			return 0;
1296 		}
1297 
1298 		iii++;
1299 
1300 		if(iii > maxstepp) {
1301 			*hit = p;
1302 			return -1;
1303 		}
1304 
1305 		px = long(p.x * ACTIVEBKG->Xmul);
1306 		pz = long(p.z * ACTIVEBKG->Zmul);
1307 
1308 		if(px > ACTIVEBKG->Xsize - 1 || px < 0) {
1309 			*hit = p;
1310 			return -1;
1311 		}
1312 
1313 		if(pz > ACTIVEBKG->Zsize - 1 || pz < 0) {
1314 			*hit = p;
1315 			return -1;
1316 		}
1317 
1318 		if(lpx == px && lpz == pz && voidlast) {
1319 			continue;
1320 		}
1321 
1322 		lpx = px;
1323 		lpz = pz;
1324 		voidlast = !flag;
1325 		long jx1 = clamp(px - 1l, 0l, ACTIVEBKG->Xsize - 1l);
1326 		long jx2 = clamp(px + 1l, 0l, ACTIVEBKG->Xsize - 1l);
1327 		long jz1 = clamp(pz - 1l, 0l, ACTIVEBKG->Zsize - 1l);
1328 		long jz2 = clamp(pz + 1l, 0l, ACTIVEBKG->Zsize - 1l);
1329 
1330 		EERIE_BKG_INFO * eg = &ACTIVEBKG->Backg[px + pz * ACTIVEBKG->Xsize];
1331 		if(eg->nbpoly == 0) {
1332 			*hit = p;
1333 			return 1;
1334 		}
1335 
1336 		for(pz = jz1; pz < jz2; pz++) for (px = jx1; px < jx2; px++) {
1337 			eg = &ACTIVEBKG->Backg[px + pz * ACTIVEBKG->Xsize];
1338 			for(long k = 0; k < eg->nbpoly; k++) {
1339 				EERIEPOLY * ep = &eg->polydata[k];
1340 				if(ep->type & POLY_TRANS) {
1341 					continue;
1342 				}
1343 				if(p.y < ep->min.y - 10.f || p.y > ep->max.y + 10.f
1344 				   || p.x < ep->min.x - 10.f || p.x > ep->max.x + 10.f
1345 				   || p.z < ep->min.z - 10.f || p.z > ep->max.z + 10.f) {
1346 					continue;
1347 				}
1348 				voidlast = 0;
1349 				if(RayIn3DPolyNoCull(orgn, dest, ep)) {
1350 					*hit = p;
1351 					return (ep == epp) ? 0 : 1;
1352 				}
1353 			}
1354 		}
1355 	}
1356 }
1357 
1358 // Computes the visibility from a point to another... (sort of...)
Visible(Vec3f * orgn,Vec3f * dest,EERIEPOLY * epp,Vec3f * hit)1359 bool Visible(Vec3f * orgn, Vec3f * dest, EERIEPOLY * epp, Vec3f * hit)
1360 {
1361 	float			x, y, z; //current ray pos
1362 	float			dx, dy, dz; // ray incs
1363 	float			adx, ady, adz; // absolute ray incs
1364 	float			ix, iy, iz;
1365 	long			px, pz;
1366 	EERIEPOLY	*	ep;
1367 	EERIE_BKG_INFO	* eg;
1368 	float			pas			=	35.f;
1369 	Vec3f found_hit = Vec3f::ZERO;
1370 	EERIEPOLY	*	found_ep	=	NULL;
1371 	float iter, t;
1372 
1373 	x	=	orgn->x;
1374 	y	=	orgn->y;
1375 	z	=	orgn->z;
1376 
1377 	float			distance;
1378 	float			nearest		=	distance	=	fdist(*orgn, *dest);
1379 
1380 	if (distance < pas) pas	=	distance * .5f;
1381 
1382 	dx	=	(dest->x - orgn->x);
1383 	adx	=	EEfabs(dx);
1384 	dy	=	(dest->y - orgn->y);
1385 	ady	=	EEfabs(dy);
1386 	dz	=	(dest->z - orgn->z);
1387 	adz	=	EEfabs(dz);
1388 
1389 	if ((adx >= ady) && (adx >= adz))
1390 	{
1391 		if (adx != dx)
1392 		{
1393 			ix = -pas;
1394 		}
1395 		else
1396 		{
1397 			ix = pas;
1398 		}
1399 
1400 		iter = adx / pas;
1401 		t = 1.f / (iter);
1402 		iy = dy * t;
1403 		iz = dz * t;
1404 	}
1405 	else if ((ady >= adx) && (ady >= adz))
1406 	{
1407 		if (ady != dy)
1408 		{
1409 			iy = -pas;
1410 		}
1411 		else
1412 		{
1413 			iy = pas;
1414 		}
1415 
1416 		iter = ady / pas;
1417 		t = 1.f / (iter);
1418 		ix = dx * t;
1419 		iz = dz * t;
1420 	}
1421 	else
1422 	{
1423 		if (adz != dz)
1424 		{
1425 			iz = -pas;
1426 		}
1427 		else
1428 		{
1429 			iz = pas;
1430 		}
1431 
1432 		iter = adz / pas;
1433 		t = 1.f / (iter);
1434 		ix = dx * t;
1435 		iy = dy * t;
1436 	}
1437 
1438 	float dd;
1439 	x -= ix;
1440 	y -= iy;
1441 	z -= iz;
1442 
1443 	while (iter > 0.f)
1444 	{
1445 		iter -= 1.f;
1446 		x += ix;
1447 		y += iy;
1448 		z += iz;
1449 
1450 		px = (long)(x * ACTIVEBKG->Xmul);
1451 		pz = (long)(z * ACTIVEBKG->Zmul);
1452 
1453 		if (px > ACTIVEBKG->Xsize - 1)		goto fini;
1454 		else if (px < 0)					goto fini;
1455 
1456 		if (pz > ACTIVEBKG->Zsize - 1)		goto fini;
1457 		else if (pz < 0)					goto fini;
1458 
1459 		{
1460 			eg = &ACTIVEBKG->Backg[px+pz*ACTIVEBKG->Xsize];
1461 
1462 			for (long k = 0; k < eg->nbpolyin; k++)
1463 			{
1464 				ep = eg->polyin[k];
1465 
1466 				if (ep)
1467 					if ((ep->min.y - pas < y) && (ep->max.y + pas > y))
1468 						if ((ep->min.x - pas < x) && (ep->max.x + pas > x))
1469 							if ((ep->min.z - pas < z) && (ep->max.z + pas > z))
1470 							{
1471 								if (RayCollidingPoly(orgn, dest, ep, hit))
1472 								{
1473 									dd = fdist(*orgn, *hit);
1474 
1475 									if (dd < nearest)
1476 									{
1477 										nearest		=	dd;
1478 										found_ep	=	ep;
1479 										found_hit = *hit;
1480 									}
1481 								}
1482 							}
1483 			}
1484 		}
1485 	}
1486 
1487 fini:
1488 	;
1489 
1490 	if (!found_ep) return true;
1491 
1492 	if (found_ep == epp) return true;
1493 
1494 	*hit = found_hit;
1495 
1496 	return false;
1497 }
1498 
1499 
1500 //*************************************************************************************
1501 // Counts total number of polys in a background
1502 //*************************************************************************************
BKG_CountPolys(EERIE_BACKGROUND * eb)1503 long BKG_CountPolys(EERIE_BACKGROUND * eb)
1504 {
1505 	long count = 0;
1506 	EERIE_BKG_INFO * eg;
1507 
1508 	for (long i = 0; i < eb->Xsize * eb->Zsize; i++)
1509 	{
1510 		eg = &eb->Backg[i];
1511 		count += eg->nbpoly;
1512 	}
1513 
1514 	return count;
1515 }
1516 
1517 //*************************************************************************************
1518 // Counts number of ignored polys in a background
1519 //*************************************************************************************
1520 
BKG_CountIgnoredPolys(EERIE_BACKGROUND * eb)1521 long BKG_CountIgnoredPolys(EERIE_BACKGROUND * eb)
1522 {
1523 	long count = 0;
1524 	EERIE_BKG_INFO * eg;
1525 	EERIEPOLY * pol = NULL;
1526 
1527 	for (long i = 0; i < eb->Xsize * eb->Zsize; i++)
1528 	{
1529 		eg = &eb->Backg[i];
1530 
1531 		for (long k = 0; k < eg->nbpoly; k++)
1532 		{
1533 			pol = &eg->polydata[k];
1534 
1535 			if (pol->type & POLY_IGNORE)
1536 				count++;
1537 		}
1538 	}
1539 
1540 	return count;
1541 }
1542 
1543 // Releases BKG_INFO from a tile
ReleaseBKG_INFO(EERIE_BKG_INFO * eg)1544 void ReleaseBKG_INFO(EERIE_BKG_INFO * eg) {
1545 	free(eg->polydata), eg->polydata = NULL;
1546 	free(eg->polyin), eg->polyin = NULL;
1547 	eg->nbpolyin = 0;
1548 	memset(eg, 0, sizeof(EERIE_BKG_INFO));
1549 }
1550 
ARX_PORTALS_SWAP_EPs(short px,short py,short ep_idx,short ep_idx2)1551 void ARX_PORTALS_SWAP_EPs(short px, short py, short ep_idx, short ep_idx2)
1552 {
1553 	if (!portals) return;
1554 
1555 	for (long room_num = 0; room_num <= portals->nb_rooms; room_num++)
1556 	{
1557 		for (long  lll = 0; lll < portals->room[room_num].nb_polys; lll++)
1558 		{
1559 			if ((portals->room[room_num].epdata[lll].px == px)
1560 					&& (portals->room[room_num].epdata[lll].py == py))
1561 			{
1562 				if (portals->room[room_num].epdata[lll].idx == ep_idx)
1563 					portals->room[room_num].epdata[lll].idx = ep_idx2;
1564 				else if (portals->room[room_num].epdata[lll].idx == ep_idx2)
1565 					portals->room[room_num].epdata[lll].idx = ep_idx;
1566 			}
1567 		}
1568 	}
1569 }
1570 
1571 //*************************************************************************************
1572 //*************************************************************************************
1573 
AddAData(ANCHOR_DATA * ad,long linked)1574 void AddAData(ANCHOR_DATA * ad, long linked)
1575 {
1576 	for (long i=0;i<ad->nblinked;i++)
1577 		if (ad->linked[i] == linked) return;
1578 
1579 	ad->linked = (long *)realloc(ad->linked, sizeof(long) * (ad->nblinked + 1));
1580 
1581 	ad->linked[ad->nblinked] = linked;
1582 	ad->nblinked++;
1583 }
1584 
UpdateIORoom(Entity * io)1585 void UpdateIORoom(Entity * io)
1586 {
1587 	Vec3f pos = io->pos;
1588 	pos.y -= 60.f;
1589 
1590 	long roo = ARX_PORTALS_GetRoomNumForPosition(&pos, 2);
1591 
1592 	if (roo >= 0)
1593 		io->room = checked_range_cast<short>(roo);
1594 
1595 	io->room_flags &= ~1;
1596 }
1597 
GetRoomCenter(long room_num,Vec3f * center)1598 bool GetRoomCenter(long room_num, Vec3f * center) {
1599 
1600 	if(!portals || room_num > portals->nb_rooms || portals->room[room_num].nb_polys <= 0) {
1601 		return false;
1602 	}
1603 
1604 	EERIE_3D_BBOX bbox;
1605 	bbox.min = Vec3f::repeat(99999999.f);
1606 	bbox.max = Vec3f::repeat(-99999999.f);
1607 
1608 	for(long  lll = 0; lll < portals->room[room_num].nb_polys; lll++) {
1609 		FAST_BKG_DATA * feg;
1610 		feg = &ACTIVEBKG->fastdata[portals->room[room_num].epdata[lll].px][portals->room[room_num].epdata[lll].py];
1611 		EERIEPOLY * ep = &feg->polydata[portals->room[room_num].epdata[lll].idx];
1612 		bbox.min = componentwise_min(bbox.min, ep->center);
1613 		bbox.max = componentwise_max(bbox.max, ep->center);
1614 	}
1615 
1616 	*center = (bbox.max + bbox.min) * .5f;
1617 
1618 	portals->room[room_num].center = *center;
1619 	portals->room[room_num].radius = fdist(*center, bbox.max);
1620 	return true;
1621 }
1622 
1623 ROOM_DIST_DATA * RoomDistance = NULL;
1624 static long NbRoomDistance = 0;
1625 
SetRoomDistance(long i,long j,float val,const Vec3f * p1,const Vec3f * p2)1626 static void SetRoomDistance(long i, long j, float val, const Vec3f * p1, const Vec3f * p2) {
1627 
1628 	if((i < 0) || (j < 0) || (i >= NbRoomDistance) || (j >= NbRoomDistance) || !RoomDistance) {
1629 		return;
1630 	}
1631 
1632 	long offs = i + j * NbRoomDistance;
1633 
1634 	if (p1) RoomDistance[offs].startpos = *p1;
1635 
1636 	if (p2) RoomDistance[offs].endpos = *p2;
1637 
1638 	RoomDistance[offs].distance = val;
1639 }
GetRoomDistance(long i,long j,Vec3f * p1,Vec3f * p2)1640 static float GetRoomDistance(long i, long j, Vec3f * p1, Vec3f * p2)
1641 {
1642 	if ((i < 0) || (j < 0) || (i >= NbRoomDistance) || (j >= NbRoomDistance))
1643 		return -1.f;
1644 
1645 	long offs = i + j * NbRoomDistance;
1646 
1647 	if (p1) *p1 = RoomDistance[offs].startpos;
1648 
1649 	if (p2) *p2 = RoomDistance[offs].endpos;
1650 
1651 	return (RoomDistance[offs].distance);
1652 }
SP_GetRoomDist(Vec3f * pos,Vec3f * c_pos,long io_room,long Cam_Room)1653 float SP_GetRoomDist(Vec3f * pos, Vec3f * c_pos, long io_room, long Cam_Room)
1654 {
1655 	float dst = fdist(*pos, *c_pos);
1656 
1657 	if (dst < 150.f) return dst;
1658 
1659 	if ((!portals) || (!RoomDistance))
1660 		return dst;
1661 
1662 	long Room=io_room;
1663 
1664 	if (Room >= 0)
1665 	{
1666 		Vec3f p1, p2;
1667 		float v = GetRoomDistance(Cam_Room, Room, &p1, &p2);
1668 
1669 		if (v > 0.f)
1670 		{
1671 			v += fdist(*pos, p2);
1672 			v += fdist(*c_pos, p1);
1673 			return v;
1674 		}
1675 	}
1676 
1677 	return dst;
1678 }
1679 
1680 // Clears a background of its infos
ClearBackground(EERIE_BACKGROUND * eb)1681 void ClearBackground(EERIE_BACKGROUND * eb) {
1682 
1683 	if(eb == NULL) {
1684 		return;
1685 	}
1686 
1687 	AnchorData_ClearAll(eb);
1688 
1689 	free(eb->minmax), eb->minmax = NULL;
1690 
1691 	for(long i = 0; i < eb->Xsize * eb->Zsize; i++) {
1692 		ReleaseBKG_INFO(&eb->Backg[i]);
1693 	}
1694 	free(eb->Backg), eb->Backg = NULL;
1695 
1696 	free(RoomDistance), RoomDistance = NULL;
1697 	NbRoomDistance = 0;
1698 }
1699 
InitBkg(EERIE_BACKGROUND * eb,short sx,short sz,short Xdiv,short Zdiv)1700 int InitBkg(EERIE_BACKGROUND * eb, short sx, short sz, short Xdiv, short Zdiv) {
1701 
1702 	EERIE_BKG_INFO * eg;
1703 
1704 	if (eb == NULL) return 0;
1705 
1706 	if(eb->exist) {
1707 		EERIE_PORTAL_Release();
1708 		ClearBackground(eb);
1709 	}
1710 
1711 	eb->exist = 1;
1712 	eb->anchors = NULL;
1713 	eb->nbanchors = 0;
1714 	eb->Xsize = sx;
1715 	eb->Zsize = sz;
1716 
1717 	if (Xdiv < 0) Xdiv = 1;
1718 
1719 	if (Zdiv < 0) Xdiv = 1;
1720 
1721 	eb->Xdiv = Xdiv;
1722 	eb->Zdiv = Zdiv;
1723 	eb->Xmul = 1.f / (float)eb->Xdiv;
1724 	eb->Zmul = 1.f / (float)eb->Zdiv;
1725 
1726 	//todo free
1727 	eb->Backg = (EERIE_BKG_INFO *)malloc(sizeof(EERIE_BKG_INFO) * sx * sz);
1728 
1729 	memset(eb->Backg, 0, sizeof(EERIE_BKG_INFO)*sx * sz);
1730 
1731 	for (int i = 0; i < eb->Xsize * eb->Zsize; i++)
1732 	{
1733 		eg = &eb->Backg[i];
1734 		eg->treat = 0;
1735 		eg->nothing = 1;
1736 		eg->nbianchors = 0;
1737 		eg->ianchors = NULL;
1738 	}
1739 
1740 	for (long j = 0; j < eb->Zsize; j++)
1741 		for (int i = 0; i < eb->Xsize; i++)
1742 		{
1743 			FAST_BKG_DATA * feg = &eb->fastdata[i][j];
1744 			memset(feg, 0, sizeof(FAST_BKG_DATA));
1745 		}
1746 
1747 	//todo free
1748 	eb->minmax = (EERIE_SMINMAX *)malloc(sizeof(EERIE_SMINMAX) * eb->Zsize);
1749 
1750 	for (int i = 0; i < eb->Zsize; i++)
1751 	{
1752 		eb->minmax[i].min = 9999;
1753 		eb->minmax[i].max = -1;
1754 	}
1755 
1756 	return 1;
1757 }
1758 //*************************************************************************************
1759 // Checks for angular difference between normals
1760 //*************************************************************************************
LittleAngularDiff(Vec3f * norm,Vec3f * norm2)1761 bool LittleAngularDiff(Vec3f * norm, Vec3f * norm2) {
1762 	return closerThan(*norm, *norm2, 1.41421f);
1763 }
1764 
1765 //*************************************************************************************
1766 //*************************************************************************************
1767 
DeclareEGInfo(float x,float z)1768 void DeclareEGInfo(float x, float z)
1769 {
1770 	long posx = x * ACTIVEBKG->Xmul;
1771 
1772 	if (posx < 0) return;
1773 	else if (posx >= ACTIVEBKG->Xsize) return;
1774 
1775 	long posz = (long)(float)(z * ACTIVEBKG->Zmul);
1776 
1777 	if (posz < 0) return;
1778 	else if (posz >= ACTIVEBKG->Zsize) return;
1779 
1780 	EERIE_BKG_INFO * eg;
1781 	eg = &ACTIVEBKG->Backg[posx+posz*ACTIVEBKG->Xsize];
1782 	eg->nothing = 0;
1783 }
1784 
EERIEPOLY_Add_PolyIn(EERIE_BKG_INFO * eg,EERIEPOLY * ep)1785 void EERIEPOLY_Add_PolyIn(EERIE_BKG_INFO * eg, EERIEPOLY * ep) {
1786 
1787 	for(long i = 0; i < eg->nbpolyin; i++) {
1788 		if (eg->polyin[i] == ep) return;
1789 	}
1790 
1791 	eg->polyin = (EERIEPOLY **)realloc(eg->polyin, sizeof(EERIEPOLY *) * (eg->nbpolyin + 1));
1792 
1793 	eg->polyin[eg->nbpolyin] = ep;
1794 	eg->nbpolyin++;
1795 }
1796 
PointInBBox(Vec3f * point,EERIE_2D_BBOX * bb)1797 bool PointInBBox(Vec3f * point, EERIE_2D_BBOX * bb)
1798 {
1799 	if ((point->x > bb->max.x)
1800 			||	(point->x < bb->min.x)
1801 			||	(point->z > bb->max.y)
1802 			||	(point->z < bb->min.y)
1803 	   )
1804 		return false;
1805 
1806 	return true;
1807 }
1808 
EERIEPOLY_Compute_PolyIn()1809 void EERIEPOLY_Compute_PolyIn()
1810 {
1811 	EERIE_BKG_INFO * eg;
1812 	EERIE_BKG_INFO * eg2;
1813 	EERIEPOLY * ep2;
1814 
1815 	long ii, ij;
1816 	long ai, aj;
1817 	long nbvert;
1818 
1819 	for(long j = 0; j < ACTIVEBKG->Zsize; j++)
1820 		for(long i = 0; i < ACTIVEBKG->Xsize; i++) {
1821 
1822 			eg = &ACTIVEBKG->Backg[i+j*ACTIVEBKG->Xsize];
1823 
1824 			free(eg->polyin), eg->polyin = NULL;
1825 			eg->nbpolyin = 0;
1826 
1827 			ii = max(i - 2, 0L);
1828 			ij = max(j - 2, 0L);
1829 			ai = min(i + 2, ACTIVEBKG->Xsize - 1L);
1830 			aj = min(j + 2, ACTIVEBKG->Zsize - 1L);
1831 
1832 			EERIE_2D_BBOX bb;
1833 			bb.min.x = (float)i * ACTIVEBKG->Xdiv - 10;
1834 			bb.max.x = (float)bb.min.x + ACTIVEBKG->Xdiv + 20;
1835 			bb.min.y = (float)j * ACTIVEBKG->Zdiv - 10;
1836 			bb.max.y = (float)bb.min.y + ACTIVEBKG->Zdiv + 20;
1837 			Vec3f bbcenter;
1838 			bbcenter.x = (bb.min.x + bb.max.x) * .5f;
1839 			bbcenter.z = (bb.min.y + bb.max.y) * .5f;
1840 
1841 			for (long cj = ij; cj < aj; cj++)
1842 				for (long ci = ii; ci < ai; ci++)
1843 				{
1844 
1845 					eg2 = &ACTIVEBKG->Backg[ci+cj*ACTIVEBKG->Xsize];
1846 
1847 					for (long l = 0; l < eg2->nbpoly; l++)
1848 					{
1849 
1850 						ep2 = &eg2->polydata[l];
1851 
1852 						if(fartherThan(Vec2f(bbcenter.x, bbcenter.z), Vec2f(ep2->center.x, ep2->center.z), 120.f)) {
1853 							continue;
1854 						}
1855 
1856 						if (ep2->type & POLY_QUAD) nbvert = 4;
1857 						else nbvert = 3;
1858 
1859 						if (PointInBBox(&ep2->center, &bb))
1860 						{
1861 							EERIEPOLY_Add_PolyIn(eg, ep2);
1862 						}
1863 						else
1864 							for (long k = 0; k < nbvert; k++)
1865 							{
1866 
1867 								if(PointInBBox(&ep2->v[k].p, &bb)) {
1868 									EERIEPOLY_Add_PolyIn(eg, ep2);
1869 									break;
1870 
1871 								} else {
1872 
1873 									Vec3f pt = (ep2->v[k].p + ep2->center) * .5f;
1874 									if(PointInBBox(&pt, &bb)) {
1875 										EERIEPOLY_Add_PolyIn(eg, ep2);
1876 										break;
1877 									}
1878 								}
1879 							}
1880 					}
1881 				}
1882 
1883 			if (eg->nbpolyin) eg->nothing = 0;
1884 			else eg->nothing = 1;
1885 		}
1886 
1887 	for (int j = 0; j < ACTIVEBKG->Zsize; j++)
1888 		for (long i = 0; i < ACTIVEBKG->Xsize; i++)
1889 		{
1890 			eg = &ACTIVEBKG->Backg[i+j*ACTIVEBKG->Xsize];
1891 			eg->tile_miny = 999999999.f;
1892 			eg->tile_maxy = -999999999.f;
1893 
1894 			for (long kk = 0; kk < eg->nbpolyin; kk++)
1895 			{
1896 				EERIEPOLY * ep = eg->polyin[kk];
1897 				eg->tile_miny = min(eg->tile_miny, ep->min.y);
1898 				eg->tile_maxy = max(eg->tile_maxy, ep->max.y);
1899 			}
1900 
1901 			FAST_BKG_DATA * fbd = &ACTIVEBKG->fastdata[i][j];
1902 			fbd->treat = eg->treat;
1903 			fbd->nothing = eg->nothing;
1904 			fbd->nbpoly = eg->nbpoly;
1905 			fbd->nbianchors = eg->nbianchors;
1906 			fbd->nbpolyin = eg->nbpolyin;
1907 			fbd->frustrum_miny = eg->frustrum_miny;
1908 			fbd->frustrum_maxy = eg->frustrum_maxy;
1909 			fbd->polydata = eg->polydata;
1910 			fbd->polyin = eg->polyin;
1911 			fbd->ianchors = eg->ianchors;
1912 		}
1913 }
1914 
GetTileMinY(long i,long j)1915 float GetTileMinY(long i, long j)
1916 {
1917 	float minf = 9999999999.f;
1918 	EERIE_BKG_INFO * eg;
1919 	eg = &ACTIVEBKG->Backg[i+j*ACTIVEBKG->Xsize];
1920 
1921 	for (long kk = 0; kk < eg->nbpolyin; kk++)
1922 	{
1923 		EERIEPOLY * ep = eg->polyin[kk];
1924 		minf = min(minf, ep->min.y);
1925 	}
1926 
1927 	return minf;
1928 }
GetTileMaxY(long i,long j)1929 float GetTileMaxY(long i, long j)
1930 {
1931 	float maxf = -9999999999.f;
1932 	EERIE_BKG_INFO * eg;
1933 	eg = &ACTIVEBKG->Backg[i+j*ACTIVEBKG->Xsize];
1934 
1935 	for (long kk = 0; kk < eg->nbpolyin; kk++)
1936 	{
1937 		EERIEPOLY * ep = eg->polyin[kk];
1938 		maxf = max(maxf, ep->max.y);
1939 	}
1940 
1941 	return maxf;
1942 }
1943 
1944 //*************************************************************************************
1945 //*************************************************************************************
1946 
1947 #define TYPE_PORTAL	1
1948 #define TYPE_ROOM	2
GetNameInfo(const string & name,long & type,long & val1,long & val2)1949 bool GetNameInfo(const string & name, long& type, long& val1, long& val2)
1950 {
1951 
1952 	if (name[0] == 'r')
1953 	{
1954 		if (name[1] == '_')
1955 		{
1956 			type = TYPE_ROOM;
1957 			val1 = atoi(name.c_str() + 2);
1958 			val2 = 0;
1959 			return true;
1960 		}
1961 
1962 		if ((name[1] == 'o') && (name[2] == 'o')
1963 				&& (name[3] == 'm') && (name[4] == '_'))
1964 		{
1965 			type = TYPE_ROOM;
1966 			val1 = atoi(name.c_str() + 5);
1967 			val2 = 0;
1968 			return true;
1969 		}
1970 	}
1971 
1972 	if ((name[0] == 'p') && (name[1] == 'o') && (name[2] == 'r')
1973 			&& (name[3] == 't') && (name[4] == 'a') && (name[5] == 'l')
1974 			&& (name[6] == '_'))
1975 	{
1976 		type = TYPE_PORTAL;
1977 		char temp[16];
1978 		strcpy(temp, name.c_str() + 7);
1979 		temp[3] = 0;
1980 		val1 = atoi(temp);
1981 		val2 = atoi(name.c_str() + 11);
1982 		return true;
1983 	}
1984 
1985 	return false;
1986 }
1987 
EERIE_PORTAL_Blend_Portals_And_Rooms()1988 void EERIE_PORTAL_Blend_Portals_And_Rooms() {
1989 
1990 	if (!portals) return;
1991 
1992 	for (long num = 0; num < portals->nb_total; num++)
1993 	{
1994 		CalcFaceNormal(&portals->portals[num].poly, portals->portals[num].poly.v);
1995 		EERIEPOLY * ep = &portals->portals[num].poly;
1996 		ep->center = ep->v[0].p;
1997 		long to = 3;
1998 		float divide = ( 1.0f / 3 );
1999 
2000 		if (ep->type & POLY_QUAD)
2001 		{
2002 			to = 4;
2003 			divide = ( 1.0f / 4 );
2004 		}
2005 
2006 		ep->max = ep->min = ep->v[0].p;
2007 		for(long i = 1; i < to; i++) {
2008 			ep->center += ep->v[i].p;
2009 			ep->min = componentwise_min(ep->min, ep->v[i].p);
2010 			ep->max = componentwise_max(ep->max, ep->v[i].p);
2011 		}
2012 
2013 		ep->center *= divide;
2014 		float d = 0.f;
2015 
2016 		for (long ii = 0; ii < to; ii++)
2017 		{
2018 			d = max(d, dist(ep->center, ep->v[ii].p));
2019 		}
2020 
2021 		ep->norm2.x = d;
2022 
2023 		for (long nroom = 0; nroom <= portals->nb_rooms; nroom++)
2024 		{
2025 			if ((nroom == portals->portals[num].room_1)
2026 					||	(nroom == portals->portals[num].room_2))
2027 			{
2028 				portals->room[nroom].portals = (long *)realloc(portals->room[nroom].portals, sizeof(long) * (portals->room[nroom].nb_portals + 1));
2029 				portals->room[nroom].portals[portals->room[nroom].nb_portals] = num;
2030 				portals->room[nroom].nb_portals++;
2031 			}
2032 		}
2033 	}
2034 }
2035 
EERIE_PORTAL_Release()2036 static void EERIE_PORTAL_Release() {
2037 
2038 	if(!portals) {
2039 		return;
2040 	}
2041 
2042 	free(portals->portals), portals->portals = NULL;
2043 
2044 	if(portals->room) {
2045 		if(portals->nb_rooms > 0) {
2046 			for(long nn = 0; nn < portals->nb_rooms + 1; nn++) {
2047 				free(portals->room[nn].epdata), portals->room[nn].epdata = NULL;
2048 				free(portals->room[nn].portals), portals->room[nn].portals = NULL;
2049 				delete portals->room[nn].pVertexBuffer, portals->room[nn].pVertexBuffer = NULL;
2050 				free(portals->room[nn].pussIndice), portals->room[nn].pussIndice = NULL;
2051 				free(portals->room[nn].ppTextureContainer);
2052 				portals->room[nn].ppTextureContainer = NULL;
2053 			}
2054 		}
2055 		free(portals->room), portals->room = NULL;
2056 	}
2057 
2058 	free(portals), portals = NULL;
2059 }
2060 
EERIE_TransformOldFocalToNewFocal(float _fOldFocal)2061 float EERIE_TransformOldFocalToNewFocal(float _fOldFocal)
2062 {
2063 	if (_fOldFocal < 200)
2064 	{
2065 		return (-.34f * _fOldFocal + 168.5f);
2066 	}
2067 	else
2068 	{
2069 		if (_fOldFocal < 300)
2070 		{
2071 			return (-.25f * _fOldFocal + 150.5f);
2072 		}
2073 		else
2074 		{
2075 			if (_fOldFocal < 400)
2076 			{
2077 				return (-.155f * _fOldFocal + 124.f);
2078 			}
2079 			else
2080 			{
2081 				if (_fOldFocal < 500)
2082 				{
2083 					return (-.11f * _fOldFocal + 106.f);
2084 				}
2085 				else
2086 				{
2087 					if (_fOldFocal < 600)
2088 					{
2089 						return (-.075f * _fOldFocal + 88.5f);
2090 					}
2091 					else
2092 					{
2093 						if (_fOldFocal < 700)
2094 						{
2095 							return (-.055f * _fOldFocal + 76.5f);
2096 						}
2097 						else
2098 						{
2099 							if (_fOldFocal < 800)
2100 							{
2101 								return (-.045f * _fOldFocal + 69.5f);
2102 							}
2103 							else
2104 							{
2105 								return 33.5f;
2106 							}
2107 						}
2108 					}
2109 				}
2110 			}
2111 		}
2112 	}
2113 }
2114 
PrepareActiveCamera()2115 void PrepareActiveCamera() {
2116 
2117 	float tmp = radians(ACTIVECAM->angle.a);
2118 	ACTIVECAM->Xcos = (float)EEcos(tmp);
2119 	ACTIVECAM->Xsin = (float)EEsin(tmp);
2120 	tmp = radians(ACTIVECAM->angle.b);
2121 	ACTIVECAM->Ycos = (float)EEcos(tmp);
2122 	ACTIVECAM->Ysin = (float)EEsin(tmp);
2123 	tmp = radians(ACTIVECAM->angle.g);
2124 	ACTIVECAM->Zcos = (float)EEcos(tmp);
2125 	ACTIVECAM->Zsin = (float)EEsin(tmp);
2126 	ACTIVECAM->pos2 = (ACTIVECAM->center + ACTIVECAM->clip.origin).to<float>();
2127 
2128 	MatrixReset(&ACTIVECAM->matrix);
2129 
2130 	float cx = ACTIVECAM->Xcos;
2131 	float sx = ACTIVECAM->Xsin;
2132 	float cy = ACTIVECAM->Ycos;
2133 	float sy = ACTIVECAM->Ysin;
2134 	float cz = ACTIVECAM->Zcos;
2135 	float sz = ACTIVECAM->Zsin;
2136 	float const1, const2, const3, const4 ;
2137 
2138 	const1 = -sz * cx;
2139 	const2 = cx * cz;
2140 	const3 = sx * sz;
2141 	const4 = -sx * cz;
2142 
2143 	ACTIVECAM->matrix._11 = cz * cy;
2144 	ACTIVECAM->matrix._21 = const4 * sy + const1;
2145 	ACTIVECAM->matrix._31 = const3 - const2 * sy;
2146 	ACTIVECAM->matrix._12 = cy * sz;
2147 	ACTIVECAM->matrix._22 = const2 - const3 * sy;
2148 	ACTIVECAM->matrix._32 = const1 * sy + const4;
2149 	ACTIVECAM->matrix._13 = sy;
2150 	ACTIVECAM->matrix._23 = sx * cy;
2151 	ACTIVECAM->matrix._33 = cx * cy;
2152 
2153 	EERIE_CreateMatriceProj(static_cast<float>(DANAESIZX),
2154 	                        static_cast<float>(DANAESIZY),
2155 	                        EERIE_TransformOldFocalToNewFocal(ACTIVECAM->focal),
2156 	                        1.f, ACTIVECAM->cdepth);
2157 }
2158 
F_PrepareCamera(EERIE_CAMERA * cam)2159 void F_PrepareCamera(EERIE_CAMERA * cam)
2160 {
2161 	float tmp = radians(cam->angle.a);
2162 	cam->use_focal = cam->focal * Xratio;
2163 	cam->Xcos = (float)EEcos(tmp);
2164 	cam->Xsin = (float)EEsin(tmp);
2165 	tmp = radians(cam->angle.b);
2166 	cam->Ycos = (float)EEcos(tmp);
2167 	cam->Ysin = (float)EEsin(tmp);
2168 	cam->Zcos = 1;
2169 	cam->Zsin = 0.f;
2170 }
2171 
PrepareCamera(EERIE_CAMERA * cam)2172 void PrepareCamera(EERIE_CAMERA * cam)
2173 {
2174 	SP_PrepareCamera(cam);
2175 
2176 	EERIE_CreateMatriceProj(static_cast<float>(DANAESIZX),
2177 							static_cast<float>(DANAESIZY),
2178 							EERIE_TransformOldFocalToNewFocal(cam->focal),
2179 							1.f,
2180 							cam->cdepth);
2181 
2182 }
2183 
SetCameraDepth(float depth)2184 void SetCameraDepth(float depth) {
2185 	ACTIVECAM->cdepth = depth;
2186 	ACTIVECAM->Zdiv = depth * 1.2f;
2187 	ACTIVECAM->Zmul = 1.f / ACTIVECAM->Zdiv;
2188 	long l = depth * 0.42f;
2189 	ACTIVECAM->clip3D = (l / (long)BKG_SIZX) + 1;
2190 }
2191 
RecalcLight(EERIE_LIGHT * el)2192 void RecalcLight(EERIE_LIGHT * el) {
2193 	el->rgb255 = el->rgb * 255.f;
2194 	el->falldiff = el->fallend - el->fallstart;
2195 	el->falldiffmul = 1.f / el->falldiff;
2196 	el->precalc = el->intensity * GLOBAL_LIGHT_FACTOR;
2197 }
2198 
ClearDynLights()2199 void ClearDynLights() {
2200 
2201 	for(size_t i = 0; i < MAX_DYNLIGHTS; i++) {
2202 		if(DynLight[i].exist) {
2203 			DynLight[i].exist = 0;
2204 		}
2205 	}
2206 
2207 	for(size_t i = 0; i < MAX_LIGHTS; i++) {
2208 		if(GLight[i] && GLight[i]->tl > 0) {
2209 			GLight[i]->tl = 0;
2210 		}
2211 	}
2212 
2213 	TOTPDL = 0;
2214 	TOTIOPDL = 0;
2215 }
2216 
GetFreeDynLight()2217 long GetFreeDynLight() {
2218 
2219 	for(size_t i = 1; i < MAX_DYNLIGHTS; i++) {
2220 		if(!(DynLight[i].exist)) {
2221 			DynLight[i].type = 0;
2222 			DynLight[i].intensity = 1.3f;
2223 			DynLight[i].treat = 1;
2224 			DynLight[i].time_creation = (unsigned long)(arxtime);
2225 			DynLight[i].duration = 0;
2226 			DynLight[i].extras = 0;
2227 			return i;
2228 		}
2229 	}
2230 
2231 	return -1;
2232 }
2233 
2234 //*************************************************************************************
2235 //*************************************************************************************
CountBkgVertex()2236 long CountBkgVertex()
2237 {
2238 	long i, j;
2239 	EERIEPOLY * ep;
2240 	EERIE_BKG_INFO * eg;
2241 	long count = 0;
2242 
2243 	for (j = 0; j < ACTIVEBKG->Zsize; j++)
2244 		for (i = 0; i < ACTIVEBKG->Xsize; i++)
2245 		{
2246 			eg = &ACTIVEBKG->Backg[i+j*ACTIVEBKG->Xsize];
2247 
2248 			for (long l = 0; l < eg->nbpoly; l++)
2249 			{
2250 				ep = &eg->polydata[l];
2251 
2252 				if (ep != NULL)
2253 				{
2254 					if (ep->type & POLY_QUAD) count += 4;
2255 					else count += 3;
2256 				}
2257 			}
2258 		}
2259 
2260 	return count;
2261 }
2262 
2263 
DrawEERIEObjEx(EERIE_3DOBJ * eobj,Anglef * angle,Vec3f * pos,Vec3f * scale,Color3f * col)2264 void DrawEERIEObjEx(EERIE_3DOBJ * eobj, Anglef * angle, Vec3f  * pos, Vec3f * scale, Color3f * col) {
2265 
2266 	if(eobj == NULL) {
2267 		return;
2268 	}
2269 
2270 	float    Xcos, Ycos, Zcos, Xsin, Ysin, Zsin;
2271 	TexturedVertex v;
2272 	TexturedVertex rv;
2273 	TexturedVertex vert_list[4];
2274 
2275 
2276 	Zsin = radians(angle->a);
2277 	Xcos = (float)EEcos(Zsin);
2278 	Xsin = (float)EEsin(Zsin);
2279 	Zsin = radians(angle->b);
2280 	Ycos = (float)EEcos(Zsin);
2281 	Ysin = (float)EEsin(Zsin);
2282 	Zsin = radians(angle->g);
2283 	Zcos = (float)EEcos(Zsin);
2284 	Zsin = (float)EEsin(Zsin);
2285 
2286 	for (size_t i = 0; i < eobj->vertexlist.size(); i++)
2287 	{
2288 		v.p = eobj->vertexlist[i].v * *scale;
2289 
2290 		YRotatePoint(&v.p, &rv.p, Ycos, Ysin);
2291 		XRotatePoint(&rv.p, &v.p, Xcos, Xsin);
2292 		ZRotatePoint(&v.p, &rv.p, Zcos, Zsin);
2293 
2294 		eobj->vertexlist3[i].v = (rv.p += *pos);
2295 
2296 		EE_RT(&rv, &eobj->vertexlist[i].vworld);
2297 		EE_P(&eobj->vertexlist[i].vworld, &eobj->vertexlist[i].vert);
2298 	}
2299 
2300 	ColorBGRA coll = col->toBGR();
2301 
2302 	for(size_t i = 0; i < eobj->facelist.size(); i++) {
2303 		vert_list[0].p = eobj->vertexlist[eobj->facelist[i].vid[0]].vworld;
2304 		vert_list[1].p = eobj->vertexlist[eobj->facelist[i].vid[1]].vworld;
2305 		vert_list[2].p = eobj->vertexlist[eobj->facelist[i].vid[2]].vworld;
2306 		vert_list[0].uv.x = eobj->facelist[i].u[0];
2307 		vert_list[0].uv.y = eobj->facelist[i].v[0];
2308 		vert_list[1].uv.x = eobj->facelist[i].u[1];
2309 		vert_list[1].uv.y = eobj->facelist[i].v[1];
2310 		vert_list[2].uv.x = eobj->facelist[i].u[2];
2311 		vert_list[2].uv.y = eobj->facelist[i].v[2];
2312 		vert_list[0].color = vert_list[1].color = vert_list[2].color = coll;
2313 
2314 		if ((eobj->facelist[i].facetype == 0)
2315 				|| (eobj->texturecontainer[eobj->facelist[i].texid] == NULL))
2316 		{
2317 			GRenderer->ResetTexture(0);
2318 		}
2319 		else
2320 		{
2321 			GRenderer->SetTexture(0, eobj->texturecontainer[eobj->facelist[i].texid]);
2322 		}
2323 
2324 		if (eobj->facelist[i].facetype & POLY_DOUBLESIDED)
2325 			GRenderer->SetCulling(Renderer::CullNone);
2326 		else GRenderer->SetCulling(Renderer::CullCW);
2327 
2328 		ARX_DrawPrimitive(&vert_list[0],
2329 									 &vert_list[1],
2330 									 &vert_list[2]);
2331 	}
2332 }
2333 //*************************************************************************************
2334 //routine qui gere l'alpha au vertex SEB
2335 //*************************************************************************************
DrawEERIEObjExEx(EERIE_3DOBJ * eobj,Anglef * angle,Vec3f * pos,Vec3f * scale,int coll)2336 void DrawEERIEObjExEx(EERIE_3DOBJ * eobj,
2337 					  Anglef * angle, Vec3f  * pos, Vec3f * scale, int coll)
2338 {
2339 	if (eobj == NULL) return;
2340 
2341 	float    Xcos, Ycos, Zcos, Xsin, Ysin, Zsin;
2342 	TexturedVertex v;
2343 	TexturedVertex rv;
2344 	TexturedVertex vert_list[4];
2345 
2346 
2347 	Zsin = radians(angle->a);
2348 	Xcos = (float)EEcos(Zsin);
2349 	Xsin = (float)EEsin(Zsin);
2350 	Zsin = radians(angle->b);
2351 	Ycos = (float)EEcos(Zsin);
2352 	Ysin = (float)EEsin(Zsin);
2353 	Zsin = radians(angle->g);
2354 	Zcos = (float)EEcos(Zsin);
2355 	Zsin = (float)EEsin(Zsin);
2356 
2357 	for (size_t i = 0; i < eobj->vertexlist.size(); i++)
2358 	{
2359 		v.p = eobj->vertexlist[i].v * *scale;
2360 
2361 		YRotatePoint(&v.p, &rv.p, Ycos, Ysin);
2362 		XRotatePoint(&rv.p, &v.p, Xcos, Xsin);
2363 		ZRotatePoint(&v.p, &rv.p, Zcos, Zsin);
2364 
2365 		eobj->vertexlist3[i].v = (rv.p += *pos);
2366 
2367 		EE_RT(&rv, &eobj->vertexlist[i].vworld);
2368 		EE_P(&eobj->vertexlist[i].vworld, &eobj->vertexlist[i].vert);
2369 	}
2370 
2371 	for(size_t i = 0; i < eobj->facelist.size(); i++) {
2372 
2373 		vert_list[0].p = eobj->vertexlist[eobj->facelist[i].vid[0]].vworld;
2374 		vert_list[1].p = eobj->vertexlist[eobj->facelist[i].vid[1]].vworld;
2375 		vert_list[2].p = eobj->vertexlist[eobj->facelist[i].vid[2]].vworld;
2376 
2377 		vert_list[0].uv.x = eobj->facelist[i].u[0];
2378 		vert_list[0].uv.y = eobj->facelist[i].v[0];
2379 		vert_list[1].uv.x = eobj->facelist[i].u[1];
2380 		vert_list[1].uv.y = eobj->facelist[i].v[1];
2381 		vert_list[2].uv.x = eobj->facelist[i].u[2];
2382 		vert_list[2].uv.y = eobj->facelist[i].v[2];
2383 		vert_list[0].color = vert_list[1].color = vert_list[2].color = coll;
2384 
2385 		if ((eobj->facelist[i].facetype == 0)
2386 				|| (eobj->texturecontainer[eobj->facelist[i].texid] == NULL))
2387 		{
2388 			GRenderer->ResetTexture(0);
2389 		}
2390 		else
2391 		{
2392 			GRenderer->SetTexture(0, eobj->texturecontainer[eobj->facelist[i].texid]);
2393 		}
2394 
2395 		if (eobj->facelist[i].facetype & POLY_DOUBLESIDED)
2396 			GRenderer->SetCulling(Renderer::CullNone);
2397 		else GRenderer->SetCulling(Renderer::CullCW);
2398 
2399 		ARX_DrawPrimitive(&vert_list[0],
2400 									 &vert_list[1],
2401 									 &vert_list[2]);
2402 	}
2403 }
2404 
2405 Vec3f BBOXMIN, BBOXMAX;
2406 
2407 //*************************************************************************************
2408 // Memorizes information for animation to animation smoothing interpolation
2409 //*************************************************************************************
AcquireLastAnim(Entity * io)2410 void AcquireLastAnim(Entity * io)
2411 {
2412 	if ((!io->animlayer[0].cur_anim)
2413 			&&	(!io->animlayer[1].cur_anim)
2414 			&&	(!io->animlayer[2].cur_anim)
2415 			&&	(!io->animlayer[3].cur_anim)) return;
2416 
2417 	// Stores Frametime and number of vertex for later interpolation
2418 	io->lastanimtime = checked_range_cast<unsigned long>(arxtime.get_frame_time());
2419 	io->nb_lastanimvertex = 1;
2420 }
2421 
2422 // Declares an Animation as finished.
2423 // Usefull to update object true position with object virtual pos.
FinishAnim(Entity * io,ANIM_HANDLE * eanim)2424 void FinishAnim(Entity * io, ANIM_HANDLE * eanim) {
2425 
2426 	if(!io || !eanim) {
2427 		return;
2428 	}
2429 
2430 	// Only layer 0 controls movement...
2431 	if(eanim == io->animlayer[0].cur_anim && (io->ioflags & IO_NPC)) {
2432 		io->move = io->lastmove = Vec3f::ZERO;
2433 	}
2434 
2435 	return;
2436 }
2437 
IsVertexIdxInGroup(EERIE_3DOBJ * eobj,long idx,long grs)2438 bool IsVertexIdxInGroup(EERIE_3DOBJ * eobj, long idx, long grs)
2439 {
2440 
2441 	if (eobj == NULL) return false;
2442 
2443 	for (size_t i = 0; i < eobj->grouplist[grs].indexes.size(); i++)
2444 	{
2445 		long ii = eobj->grouplist[grs].indexes[i];
2446 
2447 		if (ii == idx) return true;
2448 	}
2449 
2450 	return false;
2451 }
2452 
2453 extern void LoadLevelScreen();
2454 extern void LoadLevelScreen(long lev);
2455 
2456 extern float PROGRESS_BAR_COUNT;
2457 
2458 
2459 struct file_truncated_exception { };
2460 
2461 template <typename T>
fts_read(const char * & data,const char * end,size_t n=1)2462 const T * fts_read(const char * & data, const char * end, size_t n = 1) {
2463 
2464 	size_t toread = sizeof(T) * n;
2465 
2466 	if(data + toread > end) {
2467 		LogDebug(sizeof(T) << " * " << n << " > " << (end - data));
2468 		throw file_truncated_exception();
2469 	}
2470 
2471 	const T * result = reinterpret_cast<const T *>(data);
2472 
2473 	data += toread;
2474 
2475 	return result;
2476 }
2477 
2478 
2479 static bool loadFastScene(const res::path & file, const char * data,
2480                           const char * end);
2481 
2482 template <typename T>
2483 class scoped_malloc {
2484 
2485 	T * data;
2486 
2487 public:
2488 
scoped_malloc(T * data)2489 	explicit scoped_malloc(T * data) : data(data) { }
2490 
~scoped_malloc()2491 	~scoped_malloc() { free(data); }
2492 
get()2493 	T * get() { return data; }
get() const2494 	const T * get() const { return data; }
2495 
2496 };
2497 
FastSceneLoad(const res::path & partial_path)2498 bool FastSceneLoad(const res::path & partial_path) {
2499 
2500 	res::path file = "game" / partial_path / "fast.fts";
2501 
2502 	const char * data = NULL, * end = NULL;
2503 	boost::scoped_array<char> bytes;
2504 
2505 	try {
2506 
2507 		// Load the whole file
2508 		LogDebug("Loading " << file);
2509 		size_t size;
2510 		scoped_malloc<char> dat(resources->readAlloc(file, size));
2511 		data = dat.get(), end = dat.get() + size;
2512 		// TODO use new[] instead of malloc so we can use (boost::)unique_ptr
2513 		LogDebug("FTS: read " << size << " bytes");
2514 		if(!data) {
2515 			LogError << "FTS: could not read " << file;
2516 			return false;
2517 		}
2518 
2519 
2520 		// Read the file header
2521 		const UNIQUE_HEADER * uh = fts_read<UNIQUE_HEADER>(data, end);
2522 		if(uh->version != FTS_VERSION) {
2523 			LogError << "FTS version mismatch: got " << uh->version << ", expected "
2524 			         << FTS_VERSION << " in " << file;
2525 			return false;
2526 		}
2527 		PROGRESS_BAR_COUNT += 1.f, LoadLevelScreen();
2528 
2529 
2530 		// Skip .scn file list and initialize the scene data
2531 		(void)fts_read<UNIQUE_HEADER3>(data, end, uh->count);
2532 		InitBkg(ACTIVEBKG, MAX_BKGX, MAX_BKGZ, BKG_SIZX, BKG_SIZZ);
2533 		PROGRESS_BAR_COUNT += 1.f, LoadLevelScreen();
2534 
2535 
2536 		// Decompress the actual scene data
2537 		size_t input_size = end - data;
2538 		LogDebug("FTS: decompressing " << input_size << " -> "
2539 		                               << uh->uncompressedsize);
2540 		bytes.reset(new char[uh->uncompressedsize]);
2541 		if(!bytes) {
2542 			LogError << "FTS: can't allocate buffer for uncompressed data";
2543 			return false;
2544 		}
2545 		size = blastMem(data, input_size, bytes.get(), uh->uncompressedsize);
2546 		data = bytes.get(), end = bytes.get() + size;
2547 		if(!size) {
2548 			LogError << "FTS: error decompressing scene data in " << file;
2549 			return false;
2550 		} else if(size != size_t(uh->uncompressedsize)) {
2551 			LogWarning << "FTS: unexpected decompressed size: " << size << " < "
2552 			           << uh->uncompressedsize << " in " << file;
2553 		}
2554 		PROGRESS_BAR_COUNT += 3.f, LoadLevelScreen();
2555 
2556 
2557 	} catch(file_truncated_exception) {
2558 		LogError << "FTS: truncated file " << file;
2559 		return false;
2560 	}
2561 
2562 	try {
2563 		return loadFastScene(file, data, end);
2564 	} catch(file_truncated_exception) {
2565 		LogError << "FTS: truncated compressed data in " << file;
2566 		return false;
2567 	}
2568 }
2569 
2570 
loadFastScene(const res::path & file,const char * data,const char * end)2571 static bool loadFastScene(const res::path & file, const char * data,
2572                           const char * end) {
2573 
2574 	// Read the scene header
2575 	const FAST_SCENE_HEADER * fsh = fts_read<FAST_SCENE_HEADER>(data, end);
2576 	if(fsh->version != FTS_VERSION) {
2577 		LogError << "FTS: version mismatch: got " << fsh->version << ", expected "
2578 		         << FTS_VERSION << " in " << file;
2579 		return false;
2580 	}
2581 	if(fsh->sizex != ACTIVEBKG->Xsize || fsh->sizez != ACTIVEBKG->Zsize) {
2582 		LogError << "FTS: size mismatch in FAST_SCENE_HEADER";
2583 		return false;
2584 	}
2585 	player.pos = fsh->playerpos;
2586 	Mscenepos = fsh->Mscenepos;
2587 
2588 
2589 	// Load textures
2590 	typedef std::map<s32, TextureContainer *> TextureContainerMap;
2591 	TextureContainerMap textures;
2592 	const FAST_TEXTURE_CONTAINER * ftc;
2593 	ftc = fts_read<FAST_TEXTURE_CONTAINER>(data, end, fsh->nb_textures);
2594 	for(long k = 0; k < fsh->nb_textures; k++) {
2595 		res::path file = res::path::load(util::loadString(ftc[k].fic)).remove_ext();
2596 		TextureContainer * tmpTC;
2597 		tmpTC = TextureContainer::Load(file, TextureContainer::Level);
2598 		if(tmpTC) {
2599 			textures[ftc[k].tc] = tmpTC;
2600 		}
2601 	}
2602 	PROGRESS_BAR_COUNT += 4.f, LoadLevelScreen();
2603 
2604 
2605 	// Load cells with polygons and anchors
2606 	LogDebug("FTS: loading " << fsh->sizex << " x " << fsh->sizez
2607 	         << " cells ...");
2608 	for(long j = 0; j < fsh->sizez; j++) {
2609 		for(long i = 0; i < fsh->sizex; i++) {
2610 
2611 			const FAST_SCENE_INFO * fsi = fts_read<FAST_SCENE_INFO>(data, end);
2612 
2613 			EERIE_BKG_INFO & bkg = ACTIVEBKG->Backg[i + (j * fsh->sizex)];
2614 
2615 			bkg.nbianchors = (short)fsi->nbianchors;
2616 			bkg.nbpoly = (short)fsi->nbpoly;
2617 
2618 			if(fsi->nbpoly > 0) {
2619 				bkg.polydata = (EERIEPOLY *)malloc(sizeof(EERIEPOLY) * fsi->nbpoly);
2620 			} else {
2621 				bkg.polydata = NULL;
2622 			}
2623 
2624 			bkg.treat = 0;
2625 			bkg.nothing = fsi->nbpoly ? 0 : 1;
2626 
2627 			bkg.frustrum_maxy = -99999999.f;
2628 			bkg.frustrum_miny = 99999999.f;
2629 
2630 			const FAST_EERIEPOLY * eps;
2631 			eps = fts_read<FAST_EERIEPOLY>(data, end, fsi->nbpoly);
2632 			for(long k = 0; k < fsi->nbpoly; k++) {
2633 
2634 				const FAST_EERIEPOLY * ep = &eps[k];
2635 				EERIEPOLY * ep2 = &bkg.polydata[k];
2636 
2637 				memset(ep2, 0, sizeof(EERIEPOLY));
2638 
2639 				ep2->room = ep->room;
2640 				ep2->area = ep->area;
2641 				ep2->norm = ep->norm;
2642 				ep2->norm2 = ep->norm2;
2643 				copy(ep->nrml, ep->nrml + 4, ep2->nrml);
2644 
2645 				if(ep->tex != 0) {
2646 					TextureContainerMap::const_iterator cit = textures.find(ep->tex);
2647 					ep2->tex = (cit != textures.end()) ? cit->second : NULL;
2648 				} else {
2649 					ep2->tex = NULL;
2650 				}
2651 
2652 				ep2->transval = ep->transval;
2653 				ep2->type = PolyType::load(ep->type);
2654 
2655 				for(size_t kk = 0; kk < 4; kk++) {
2656 					ep2->v[kk].color = 0xFFFFFFFF;
2657 					ep2->v[kk].rhw = 1;
2658 					ep2->v[kk].specular = 1;
2659 					ep2->v[kk].p.x = ep->v[kk].ssx;
2660 					ep2->v[kk].p.y = ep->v[kk].sy;
2661 					ep2->v[kk].p.z = ep->v[kk].ssz;
2662 					ep2->v[kk].uv.x = ep->v[kk].stu;
2663 					ep2->v[kk].uv.y = ep->v[kk].stv;
2664 				}
2665 
2666 				memcpy(ep2->tv, ep2->v, sizeof(TexturedVertex) * 4);
2667 
2668 				for(size_t kk = 0; kk < 4; kk++) {
2669 					ep2->tv[kk].color = 0xFF000000;
2670 				}
2671 
2672 				long to;
2673 				float div;
2674 				if(ep->type & POLY_QUAD) {
2675 					to = 4;
2676 					div = 0.25f;
2677 				} else {
2678 					to = 3;
2679 					div = 0.333333333333f;
2680 				}
2681 
2682 				ep2->center = Vec3f::ZERO;
2683 				for(long h = 0; h < to; h++) {
2684 					ep2->center += ep2->v[h].p;
2685 					if(h != 0) {
2686 						ep2->max = componentwise_max(ep2->max, ep2->v[h].p);
2687 						ep2->min = componentwise_min(ep2->min, ep2->v[h].p);
2688 					} else {
2689 						ep2->min = ep2->max = ep2->v[0].p;
2690 					}
2691 				}
2692 				ep2->center *= div;
2693 
2694 				float dist = 0.f;
2695 				for(int h = 0; h < to; h++) {
2696 					float x = ep2->v[h].p.x - ep2->center.x;
2697 					float y = ep2->v[h].p.y - ep2->center.y;
2698 					float z = ep2->v[h].p.z - ep2->center.z;
2699 					float d = sqrt((x * x) + (y * y) + (z * z));
2700 					dist = max(dist, d);
2701 				}
2702 				ep2->v[0].rhw = dist;
2703 
2704 				DeclareEGInfo(ep2->center.x, ep2->center.z);
2705 				DeclareEGInfo(ep2->v[0].p.x, ep2->v[0].p.z);
2706 				DeclareEGInfo(ep2->v[1].p.x, ep2->v[1].p.z);
2707 				DeclareEGInfo(ep2->v[2].p.x, ep2->v[2].p.z);
2708 				if(ep->type & POLY_QUAD) {
2709 					DeclareEGInfo(ep2->v[3].p.x, ep2->v[3].p.z);
2710 				}
2711 			}
2712 
2713 			if(fsi->nbianchors <= 0) {
2714 				bkg.ianchors = NULL;
2715 			} else {
2716 				bkg.ianchors = (long *)malloc(sizeof(long) * fsi->nbianchors);
2717 				const s32 * anchors = fts_read<s32>(data, end, fsi->nbianchors);
2718 				std::copy(anchors, anchors + fsi->nbianchors, bkg.ianchors);
2719 			}
2720 
2721 		}
2722 	}
2723 	PROGRESS_BAR_COUNT += 4.f, LoadLevelScreen();
2724 
2725 
2726 	// Load anchor links
2727 	LogDebug("FTS: loading " << fsh->nb_anchors << " anchors ...");
2728 	ACTIVEBKG->nbanchors = fsh->nb_anchors;
2729 	if(fsh->nb_anchors > 0) {
2730 		size_t anchorsize = sizeof(ANCHOR_DATA) * fsh->nb_anchors;
2731 		ACTIVEBKG->anchors = (ANCHOR_DATA *)malloc(anchorsize);
2732 		memset(ACTIVEBKG->anchors, 0, anchorsize);
2733 	} else {
2734 		ACTIVEBKG->anchors = NULL;
2735 	}
2736 	for(long i = 0; i < fsh->nb_anchors; i++) {
2737 
2738 		const FAST_ANCHOR_DATA * fad = fts_read<FAST_ANCHOR_DATA>(data, end);
2739 
2740 		ANCHOR_DATA & anchor = ACTIVEBKG->anchors[i];
2741 		anchor.flags = AnchorFlags::load(fad->flags); // TODO save/load flags
2742 		anchor.pos = fad->pos;
2743 		anchor.nblinked = fad->nb_linked;
2744 		anchor.height = fad->height;
2745 		anchor.radius = fad->radius;
2746 
2747 		if(fad->nb_linked <= 0) {
2748 			anchor.linked = NULL;
2749 		} else {
2750 			anchor.linked = (long *)malloc(sizeof(long) * fad->nb_linked);
2751 			const s32 * links = fts_read<s32>(data, end, fad->nb_linked);
2752 			std::copy(links, links + fad->nb_linked, anchor.linked);
2753 		}
2754 	}
2755 	PROGRESS_BAR_COUNT += 1.f, LoadLevelScreen();
2756 
2757 
2758 	// Load rooms and portals
2759 	if(fsh->nb_rooms <= 0) {
2760 		USE_PORTALS = 0;
2761 	} else {
2762 
2763 		EERIE_PORTAL_Release();
2764 
2765 		portals = (EERIE_PORTAL_DATA *)malloc(sizeof(EERIE_PORTAL_DATA));
2766 		portals->nb_rooms = fsh->nb_rooms;
2767 		portals->room = (EERIE_ROOM_DATA *)malloc(sizeof(EERIE_ROOM_DATA)
2768 		                                          * (portals->nb_rooms + 1));
2769 		portals->nb_total = fsh->nb_portals;
2770 		portals->portals = (EERIE_PORTALS *)malloc(sizeof(EERIE_PORTALS)
2771 		                                           * portals->nb_total);
2772 
2773 
2774 		LogDebug("FTS: loading " << portals->nb_total << " portals ...");
2775 		const EERIE_SAVE_PORTALS * epos;
2776 		epos = fts_read<EERIE_SAVE_PORTALS>(data, end, portals->nb_total);
2777 		for(long i = 0; i < portals->nb_total; i++) {
2778 
2779 			const EERIE_SAVE_PORTALS * epo = &epos[i];
2780 			EERIE_PORTALS & portal = portals->portals[i];
2781 
2782 			memset(&portal, 0, sizeof(EERIE_PORTALS));
2783 
2784 			portal.room_1 = epo->room_1;
2785 			portal.room_2 = epo->room_2;
2786 			portal.useportal = epo->useportal;
2787 			portal.paddy = epo->paddy;
2788 			portal.poly.area = epo->poly.area;
2789 			portal.poly.type = PolyType::load(epo->poly.type);
2790 			portal.poly.transval = epo->poly.transval;
2791 			portal.poly.room = epo->poly.room;
2792 			portal.poly.misc = epo->poly.misc;
2793 			portal.poly.center = epo->poly.center;
2794 			portal.poly.max = epo->poly.max;
2795 			portal.poly.min = epo->poly.min;
2796 			portal.poly.norm = epo->poly.norm;
2797 			portal.poly.norm2 = epo->poly.norm2;
2798 
2799 			std::copy(epo->poly.nrml, epo->poly.nrml + 4, portal.poly.nrml);
2800 			std::copy(epo->poly.v, epo->poly.v + 4, portal.poly.v);
2801 			std::copy(epo->poly.tv, epo->poly.tv + 4, portal.poly.tv);
2802 		}
2803 
2804 
2805 		LogDebug("FTS: loading " << (portals->nb_rooms + 1) << " rooms ...");
2806 		for(long i = 0; i < portals->nb_rooms + 1; i++) {
2807 
2808 			const EERIE_SAVE_ROOM_DATA * erd;
2809 			erd = fts_read<EERIE_SAVE_ROOM_DATA>(data, end);
2810 
2811 			EERIE_ROOM_DATA & room = portals->room[i];
2812 
2813 			memset(&room, 0, sizeof(EERIE_ROOM_DATA));
2814 			room.nb_portals = erd->nb_portals;
2815 			room.nb_polys = erd->nb_polys;
2816 
2817 			LogDebug(" - room " << i << ": " << room.nb_portals << " portals, "
2818 			         << room.nb_polys << " polygons");
2819 
2820 			if(room.nb_portals) {
2821 				room.portals = (long *)malloc(sizeof(long) * room.nb_portals);
2822 				const s32 * start = fts_read<s32>(data, end, room.nb_portals);
2823 				std::copy(start, start + room.nb_portals, room.portals);
2824 			} else {
2825 				room.portals = NULL;
2826 			}
2827 
2828 			if(room.nb_polys) {
2829 				room.epdata = (EP_DATA *)malloc(sizeof(EP_DATA) * room.nb_polys);
2830 				const FAST_EP_DATA * ed;
2831 				ed = fts_read<FAST_EP_DATA>(data, end, room.nb_polys);
2832 				std::copy(ed, ed + room.nb_polys, room.epdata);
2833 			} else {
2834 				portals->room[i].epdata = NULL;
2835 			}
2836 
2837 		}
2838 
2839 		USE_PORTALS = 4;
2840 	}
2841 
2842 
2843 	// Load distances between rooms
2844 	free(RoomDistance), RoomDistance = NULL;
2845 	NbRoomDistance = 0;
2846 	if(portals) {
2847 		NbRoomDistance = portals->nb_rooms + 1;
2848 		RoomDistance = (ROOM_DIST_DATA *)malloc(sizeof(ROOM_DIST_DATA)
2849 		                                        * NbRoomDistance * NbRoomDistance);
2850 		LogDebug("FTS: loading " << (NbRoomDistance * NbRoomDistance)
2851 		         << " room distances ...");
2852 		for(long n = 0; n < NbRoomDistance; n++) {
2853 			for(long m = 0; m < NbRoomDistance; m++) {
2854 				const ROOM_DIST_DATA_SAVE * rdds;
2855 				rdds = fts_read<ROOM_DIST_DATA_SAVE>(data, end);
2856 				Vec3f start = rdds->startpos;
2857 				Vec3f end = rdds->endpos;
2858 				SetRoomDistance(m, n, rdds->distance, &start, &end);
2859 			}
2860 		}
2861 	}
2862 	PROGRESS_BAR_COUNT += 1.f, LoadLevelScreen();
2863 
2864 
2865 	// Prepare the loaded data
2866 
2867 	LogDebug("FTS: preparing scene data ...");
2868 
2869 	EERIEPOLY_Compute_PolyIn();
2870 	PROGRESS_BAR_COUNT += 3.f, LoadLevelScreen();
2871 
2872 	EERIE_PATHFINDER_Create();
2873 	EERIE_PORTAL_Blend_Portals_And_Rooms();
2874 	PROGRESS_BAR_COUNT += 1.f, LoadLevelScreen();
2875 
2876 	ComputePortalVertexBuffer();
2877 	PROGRESS_BAR_COUNT += 1.f, LoadLevelScreen();
2878 
2879 
2880 	if(data != end) {
2881 		LogWarning << "FTS: ignoring " << (end - data) << " bytes at the end of "
2882 		           << file;
2883 	}
2884 	LogDebug("FTS: done loading");
2885 
2886 	return true;
2887 }
2888 
EERIEPOLY_FillMissingVertex(EERIEPOLY * po,EERIEPOLY * ep)2889 void EERIEPOLY_FillMissingVertex(EERIEPOLY * po, EERIEPOLY * ep)
2890 {
2891 	long missing = -1;
2892 
2893 	for (long i = 0; i < 3; i++)
2894 	{
2895 		long same = 0;
2896 
2897 		for (long j = 0; j < 3; j++)
2898 		{
2899 			if	((po->v[j].p.x == ep->v[i].p.x)
2900 					&&	(po->v[j].p.y == ep->v[i].p.y)
2901 					&&	(po->v[j].p.z == ep->v[i].p.z))
2902 				same = 1;
2903 		}
2904 
2905 		if (!same) missing = i;
2906 	}
2907 
2908 	if(missing >= 0) {
2909 		Vec3f temp = po->v[2].p;
2910 		po->v[2].p = ep->v[missing].p;
2911 		po->v[3].p = temp;
2912 		po->type |= POLY_QUAD;
2913 	}
2914 }
2915 
2916 #ifdef BUILD_EDIT_LOADSAVE
2917 
ComputeRoomDistance()2918 void ComputeRoomDistance() {
2919 
2920 	free(RoomDistance), RoomDistance = NULL;
2921 	NbRoomDistance = 0;
2922 
2923 	if(portals == NULL) {
2924 		return;
2925 	}
2926 
2927 	NbRoomDistance = portals->nb_rooms + 1;
2928 	RoomDistance =
2929 		(ROOM_DIST_DATA *)malloc(sizeof(ROOM_DIST_DATA) * (NbRoomDistance) * (NbRoomDistance));
2930 
2931 	for (long n = 0; n < NbRoomDistance; n++)
2932 		for (long m = 0; m < NbRoomDistance; m++)
2933 			SetRoomDistance(m, n, -1.f, NULL, NULL);
2934 
2935 	long nb_anchors = NbRoomDistance + (portals->nb_total * 9);
2936 	ANCHOR_DATA * ad = (ANCHOR_DATA *)malloc(sizeof(ANCHOR_DATA) * nb_anchors);
2937 
2938 	memset(ad, 0, sizeof(ANCHOR_DATA)*nb_anchors);
2939 
2940 	void ** ptr = NULL;
2941 	ptr = (void **)malloc(sizeof(*ptr) * nb_anchors);
2942 	memset(ptr, 0, sizeof(*ptr)*nb_anchors);
2943 
2944 
2945 	for (long i = 0; i < NbRoomDistance; i++)
2946 	{
2947 		GetRoomCenter(i, &ad[i].pos);
2948 		ptr[i] = (void *)&portals->room[i];
2949 	}
2950 
2951 	long curpos = NbRoomDistance;
2952 
2953 	for (int i = 0; i < portals->nb_total; i++)
2954 	{
2955 		// Add 4 portal vertices
2956 		for(int nn = 0; nn < 4; nn++) {
2957 			ad[curpos].pos = portals->portals[i].poly.v[nn].p;
2958 			ptr[curpos] = (void *)&portals->portals[i];
2959 			curpos++;
2960 		}
2961 
2962 		// Add center;
2963 		ad[curpos].pos = portals->portals[i].poly.center;
2964 		ptr[curpos] = (void *)&portals->portals[i];
2965 		curpos++;
2966 
2967 		// Add V centers;
2968 		for (int nn = 0, nk = 3; nn < 4; nk = nn++)
2969 		{
2970 			ad[curpos].pos = (portals->portals[i].poly.v[nn].p
2971 			                + portals->portals[i].poly.v[nk].p) * 0.5f;
2972 			ptr[curpos] = (void *)&portals->portals[i];
2973 			curpos++;
2974 		}
2975 	}
2976 
2977 	// Link Room Centers to all its Room portals...
2978 	for (int i = 0; i <= portals->nb_rooms; i++)
2979 	{
2980 		for (long j = 0; j < portals->nb_total; j++)
2981 		{
2982 			if ((portals->portals[j].room_1 == i)
2983 					||	(portals->portals[j].room_2 == i))
2984 			{
2985 				for (long tt = 0; tt < nb_anchors; tt++)
2986 				{
2987 					if (ptr[tt] == (void *)(&portals->portals[j]))
2988 					{
2989 						AddAData(&ad[tt], i);
2990 						AddAData(&ad[i], tt);
2991 					}
2992 				}
2993 			}
2994 		}
2995 	}
2996 
2997 	// Link All portals of a room to all other portals of that room
2998 	for (int i = 0; i <= portals->nb_rooms; i++)
2999 	{
3000 		for (long j = 0; j < portals->nb_total; j++)
3001 		{
3002 			if (((portals->portals[j].room_1 == i)
3003 					|| (portals->portals[j].room_2 == i)))
3004 				for (long jj = 0; jj < portals->nb_total; jj++)
3005 				{
3006 					if ((jj != j)
3007 							&&	((portals->portals[jj].room_1 == i)
3008 								 ||	(portals->portals[jj].room_2 == i)))
3009 					{
3010 						long p1 = -1;
3011 						long p2 = -1;
3012 
3013 						for (long tt = 0; tt < nb_anchors; tt++)
3014 						{
3015 							if (ptr[tt] == (void *)(&portals->portals[jj]))
3016 								p1 = tt;
3017 
3018 							if (ptr[tt] == (void *)(&portals->portals[j]))
3019 								p2 = tt;
3020 						}
3021 
3022 						if ((p1 >= 0) && (p2 >= 0))
3023 						{
3024 							AddAData(&ad[p1], p2);
3025 							AddAData(&ad[p2], p1);
3026 						}
3027 					}
3028 				}
3029 		}
3030 	}
3031 
3032 	PathFinder pathfinder(NbRoomDistance, ad, 0, NULL);
3033 
3034 	for (int i = 0; i < NbRoomDistance; i++)
3035 		for (long j = 0; j < NbRoomDistance; j++)
3036 		{
3037 			if (i == j)
3038 			{
3039 				SetRoomDistance(i, j, -1, NULL, NULL);
3040 				continue;
3041 			}
3042 
3043 			PathFinder::Result rl;
3044 
3045 			bool found = pathfinder.move(i, j, rl);
3046 
3047 			if (found)
3048 			{
3049 				float d = 0.f;
3050 
3051 				for (size_t id = 1; id < rl.size() - 1; id++)
3052 				{
3053 					d += dist(ad[rl[id-1]].pos, ad[rl[id]].pos);
3054 				}
3055 
3056 				if (d < 0.f) d = 0.f;
3057 
3058 				float old = GetRoomDistance(i, j, NULL, NULL);
3059 
3060 				if (((d < old) || (old < 0.f)) && rl.size() >= 2)
3061 					SetRoomDistance(i, j, d, &ad[rl[1]].pos, &ad[rl[rl.size()-2]].pos);
3062 			}
3063 
3064 		}
3065 
3066 	// Don't use this for contiguous rooms !
3067 	for (int i = 0; i < portals->nb_total; i++)
3068 	{
3069 		SetRoomDistance(portals->portals[i].room_1, portals->portals[i].room_2, -1, NULL, NULL);
3070 		SetRoomDistance(portals->portals[i].room_2, portals->portals[i].room_1, -1, NULL, NULL);
3071 	}
3072 
3073 	// Release our temporary Pathfinder data
3074 	for (int ii = 0; ii < nb_anchors; ii++)
3075 	{
3076 		if (ad[ii].nblinked)
3077 		{
3078 			free(ad[ii].linked);
3079 		}
3080 	}
3081 
3082 	free(ad);
3083 	free(ptr);
3084 }
3085 
3086 long NEED_ANCHORS = 1;
3087 
EERIE_PORTAL_Room_Poly_Add(EERIEPOLY * ep,long nr,long px,long py,long idx)3088 static void EERIE_PORTAL_Room_Poly_Add(EERIEPOLY * ep, long nr, long px, long py, long idx) {
3089 
3090 	portals->room[nr].epdata = (EP_DATA *)realloc(portals->room[nr].epdata, sizeof(EP_DATA) * (portals->room[nr].nb_polys + 1));
3091 	portals->room[nr].epdata[portals->room[nr].nb_polys].idx = checked_range_cast<short>(idx);
3092 	portals->room[nr].epdata[portals->room[nr].nb_polys].px = checked_range_cast<short>(px);
3093 	portals->room[nr].epdata[portals->room[nr].nb_polys].py = checked_range_cast<short>(py);
3094 	ep->room = checked_range_cast<short>(nr);
3095 	portals->room[nr].nb_polys++;
3096 }
3097 
EERIE_PORTAL_Poly_Add(EERIEPOLY * ep,const std::string & name,long px,long py,long idx)3098 static void EERIE_PORTAL_Poly_Add(EERIEPOLY * ep, const std::string& name, long px, long py, long idx) {
3099 
3100 	long type, val1, val2;
3101 
3102 	if (!GetNameInfo(name, type, val1, val2)) return;
3103 
3104 	if (portals == NULL)
3105 	{
3106 		portals = (EERIE_PORTAL_DATA *)malloc(sizeof(EERIE_PORTAL_DATA));
3107 
3108 		if (!portals) return;
3109 
3110 		portals->nb_rooms = 0;
3111 		portals->room = NULL;
3112 		portals->nb_total = 0;
3113 		portals->portals = NULL;
3114 		USE_PORTALS = 4;
3115 	}
3116 
3117 	if (type == TYPE_PORTAL) //portal_def
3118 	{
3119 		portals->portals = (EERIE_PORTALS *)realloc(portals->portals, sizeof(EERIE_PORTALS) * (portals->nb_total + 1));
3120 		portals->portals[portals->nb_total].room_1 = val1;
3121 		portals->portals[portals->nb_total].room_2 = val2;
3122 		memcpy(&portals->portals[portals->nb_total].poly, ep, sizeof(EERIEPOLY));
3123 
3124 		float fDistMin = std::numeric_limits<float>::max();
3125 		float fDistMax = std::numeric_limits<float>::min();
3126 		int nbvert = (ep->type & POLY_QUAD) ? 4 : 3;
3127 
3128 		ep->center = ep->v[0].p;
3129 		for(long ii = 1; ii < nbvert; ii++) {
3130 			ep->center += ep->v[ii].p;
3131 		}
3132 
3133 		ep->center /= nbvert;
3134 
3135 		for(int ii = 0; ii < nbvert; ii++) {
3136 			float fDist = dist(ep->center, ep->v[ii].p);
3137 			fDistMin = min(fDistMin, fDist);
3138 			fDistMax = max(fDistMax, fDist);
3139 		}
3140 
3141 		fDistMin = (fDistMax + fDistMin) * .5f;
3142 		portals->portals[portals->nb_total].poly.v[0].rhw = fDistMin;
3143 
3144 		portals->nb_total++;
3145 	}
3146 	else if (type == TYPE_ROOM)
3147 	{
3148 		if (val1 > portals->nb_rooms)
3149 		{
3150 			portals->room = (EERIE_ROOM_DATA *)realloc(portals->room, sizeof(EERIE_ROOM_DATA) * (val1 + 1));
3151 
3152 			if (portals->nb_rooms == 0)
3153 			{
3154 				memset(portals->room, 0, sizeof(EERIE_ROOM_DATA)*(val1 + 1));
3155 			}
3156 			else for (long i = portals->nb_rooms + 1; i <= val1; i++)
3157 				{
3158 					memset(&portals->room[i], 0, sizeof(EERIE_ROOM_DATA));
3159 				}
3160 
3161 			portals->nb_rooms = val1;
3162 		}
3163 
3164 		EERIE_PORTAL_Room_Poly_Add(ep, val1, px, py, idx);
3165 	}
3166 }
3167 
BkgAddPoly(EERIEPOLY * ep,EERIE_3DOBJ * eobj)3168 static int BkgAddPoly(EERIEPOLY * ep, EERIE_3DOBJ * eobj) {
3169 
3170 	long j, posx, posz, posy;
3171 	float cx, cy, cz;
3172 	EERIE_BKG_INFO * eg;
3173 	long type, val1;
3174 	type = -1;
3175 	val1 = -1;
3176 
3177 	if (TryToQuadify(ep, eobj)) return 0;
3178 
3179 	cx = (ep->v[0].p.x + ep->v[1].p.x + ep->v[2].p.x);
3180 	cy = (ep->v[0].p.y + ep->v[1].p.y + ep->v[2].p.y);
3181 	cz = (ep->v[0].p.z + ep->v[1].p.z + ep->v[2].p.z);
3182 	posx = (long)(float)(cx * ( 1.0f / 3 ) * ACTIVEBKG->Xmul);
3183 	posz = (long)(float)(cz * ( 1.0f / 3 ) * ACTIVEBKG->Zmul);
3184 	posy = (long)(float)(cy * ( 1.0f / 3 ) * ACTIVEBKG->Xmul + ACTIVEBKG->Xsize * .5f);
3185 
3186 	if (posy < 0) return 0;
3187 	else if (posy >= ACTIVEBKG->Xsize) return 0;
3188 
3189 	if (posx < 0) return 0;
3190 	else if (posx >= ACTIVEBKG->Xsize) return 0;
3191 
3192 	if (posz < 0) return 0;
3193 	else if (posz >= ACTIVEBKG->Zsize) return 0;
3194 
3195 	eg = &ACTIVEBKG->Backg[posx+posz*ACTIVEBKG->Xsize];
3196 
3197 	DeclareEGInfo(cx * ( 1.0f / 3 ), cz * ( 1.0f / 3 ));
3198 	DeclareEGInfo(ep->v[0].p.x, ep->v[0].p.z);
3199 	DeclareEGInfo(ep->v[1].p.x, ep->v[1].p.z);
3200 	DeclareEGInfo(ep->v[2].p.x, ep->v[2].p.z);
3201 
3202 	cx *= ( 1.0f / 3 );
3203 	cy *= ( 1.0f / 3 );
3204 	cz *= ( 1.0f / 3 );
3205 	long t = (((eg->nbpoly) >> 1) << 1) + 2;
3206 	long tt = (((eg->nbpoly - 1) >> 1) << 1) + 2;
3207 
3208 	if (eg->polydata == NULL)
3209 	{
3210 		eg->polydata = (EERIEPOLY *)malloc(sizeof(EERIEPOLY) * t);
3211 	}
3212 	else if (tt != t)
3213 	{
3214 		eg->polydata = (EERIEPOLY *)realloc(eg->polydata, sizeof(EERIEPOLY) * t);
3215 	}
3216 
3217 	memcpy(&eg->polydata[eg->nbpoly], ep, sizeof(EERIEPOLY));
3218 
3219 	EERIEPOLY * epp = &eg->polydata[eg->nbpoly];
3220 
3221 	for(j = 0; j < 3; j++) {
3222 		epp->tv[j].uv = epp->v[j].uv;
3223 		epp->tv[j].color = epp->v[j].color;
3224 		epp->tv[j].rhw = 1.f;
3225 	}
3226 
3227 	epp->center.x = cx;
3228 	epp->center.y = cy;
3229 	epp->center.z = cz;
3230 	epp->max.x = max(epp->v[0].p.x, epp->v[1].p.x);
3231 	epp->max.x = max(epp->max.x, epp->v[2].p.x);
3232 	epp->min.x = min(epp->v[0].p.x, epp->v[1].p.x);
3233 	epp->min.x = min(epp->min.x, epp->v[2].p.x);
3234 
3235 	epp->max.y = max(epp->v[0].p.y, epp->v[1].p.y);
3236 	epp->max.y = max(epp->max.y, epp->v[2].p.y);
3237 	epp->min.y = min(epp->v[0].p.y, epp->v[1].p.y);
3238 	epp->min.y = min(epp->min.y, epp->v[2].p.y);
3239 
3240 	epp->max.z = max(epp->v[0].p.z, epp->v[1].p.z);
3241 	epp->max.z = max(epp->max.z, epp->v[2].p.z);
3242 	epp->min.z = min(epp->v[0].p.z, epp->v[1].p.z);
3243 	epp->min.z = min(epp->min.z, epp->v[2].p.z);
3244 	epp->type = ep->type;
3245 	epp->type &= ~POLY_QUAD;
3246 
3247 	CalcFaceNormal(epp, epp->v);
3248 	epp->area = fdist((epp->v[0].p + epp->v[1].p) * .5f, epp->v[2].p)
3249 	            * fdist(epp->v[0].p, epp->v[1].p) * .5f;
3250 
3251 	if (type == TYPE_ROOM)
3252 		epp->room = checked_range_cast<short>(val1);
3253 	else
3254 		epp->room = -1;
3255 
3256 	eg->nbpoly++;
3257 
3258 	eg->treat = 0;
3259 
3260 	if (ep != NULL)
3261 		if (ep->tex != NULL)
3262 			if ( !ep->tex->m_texName.empty() )
3263 			{
3264 				if ( ep->tex->m_texName.string().find("stone") != std::string::npos )         ep->type |= POLY_STONE;
3265 				else if ( ep->tex->m_texName.string().find("pierre") != std::string::npos )   ep->type |= POLY_STONE;
3266 				else if ( ep->tex->m_texName.string().find("wood") != std::string::npos )     ep->type |= POLY_WOOD;
3267 				else if ( ep->tex->m_texName.string().find("bois") != std::string::npos )     ep->type |= POLY_STONE;
3268 				else if ( ep->tex->m_texName.string().find("gavier") != std::string::npos )   ep->type |= POLY_GRAVEL;
3269 				else if ( ep->tex->m_texName.string().find("earth") != std::string::npos )    ep->type |= POLY_EARTH;
3270 			}
3271 
3272 	EERIE_PORTAL_Poly_Add(epp, eobj->name, posx, posz, eg->nbpoly - 1);
3273 	return 1;
3274 }
3275 
EERIEAddPolyToBackground(TexturedVertex * vert2,TextureContainer * tex,PolyType render,float transval,EERIE_3DOBJ * eobj)3276 static void EERIEAddPolyToBackground(TexturedVertex * vert2, TextureContainer * tex, PolyType render, float transval, EERIE_3DOBJ * eobj) {
3277 
3278 	EERIEPOLY ep;
3279 
3280 	memset(ep.tv, 0, sizeof(TexturedVertex) * 3);
3281 
3282 	if(vert2 != NULL) {
3283 		memcpy(ep.v, vert2, sizeof(TexturedVertex) * 3);
3284 	} else {
3285 		memset(ep.tv, 0, sizeof(TexturedVertex) * 3);
3286 	}
3287 
3288 	ep.type = render;
3289 	ep.tex = tex;
3290 	ep.transval = transval;
3291 	BkgAddPoly(&ep, eobj);
3292 }
3293 
SceneAddObjToBackground(EERIE_3DOBJ * eobj)3294 static void SceneAddObjToBackground(EERIE_3DOBJ * eobj) {
3295 
3296 	float       Xcos, Ycos, Zcos, Xsin, Ysin, Zsin;
3297 	Vec3f      p, rp;
3298 
3299 	TexturedVertex vlist[3];
3300 	Zsin = radians(eobj->angle.a);
3301 	Xcos = (float)EEcos(Zsin);
3302 	Xsin = (float)EEsin(Zsin);
3303 	Zsin = radians(eobj->angle.b);
3304 	Ycos = (float)EEcos(Zsin);
3305 	Ysin = (float)EEsin(Zsin);
3306 	Zsin = radians(eobj->angle.g);
3307 	Zcos = (float)EEcos(Zsin);
3308 	Zsin = (float)EEsin(Zsin);
3309 
3310 	for (size_t i = 0; i < eobj->vertexlist.size(); i++)
3311 	{
3312 		//Local Transform
3313 		p = eobj->vertexlist[i].v - eobj->point0;
3314 		YRotatePoint(&p, &rp, Ycos, Ysin);
3315 		XRotatePoint(&rp, &p, Xcos, Xsin);
3316 		ZRotatePoint(&p, &rp, Zcos, Zsin);
3317 		eobj->vertexlist[i].vert.p = rp + eobj->pos + eobj->point0;
3318 	}
3319 
3320 	long type, val1, val2;
3321 
3322 	if (GetNameInfo(eobj->name, type, val1, val2))
3323 	{
3324 		if (type == TYPE_PORTAL)
3325 		{
3326 			EERIEPOLY ep;
3327 			EERIEPOLY epp;
3328 
3329 			for (size_t i = 0; i < eobj->facelist.size(); i++)
3330 			{
3331 				for (long kk = 0; kk < 3; kk++)
3332 				{
3333 					memcpy(&ep.v[kk], &eobj->vertexlist[eobj->facelist[i].vid[kk]].vert, sizeof(TexturedVertex));
3334 				}
3335 
3336 				if (i == 0)
3337 				{
3338 					memcpy(&epp, &ep, sizeof(EERIEPOLY));
3339 					epp.type = 0;
3340 				}
3341 				else if (i == 1)
3342 				{
3343 					EERIEPOLY_FillMissingVertex(&epp, &ep);
3344 				}
3345 				else break;
3346 			}
3347 
3348 			if(!eobj->facelist.empty()) {
3349 				EERIE_PORTAL_Poly_Add(&epp, eobj->name, -1, -1, -1);
3350 			}
3351 
3352 			return;
3353 		}
3354 	}
3355 
3356 	for (size_t i = 0; i < eobj->facelist.size(); i++)
3357 	{
3358 		vlist[0] = eobj->vertexlist[eobj->facelist[i].vid[0]].vert;
3359 		vlist[1] = eobj->vertexlist[eobj->facelist[i].vid[1]].vert;
3360 		vlist[2] = eobj->vertexlist[eobj->facelist[i].vid[2]].vert;
3361 
3362 		vlist[0].color = vlist[1].color = vlist[2].color = Color::white.toBGR();
3363 		if (eobj->facelist[i].facetype & POLY_NO_SHADOW)
3364 		{
3365 			vlist[0].uv.x = eobj->facelist[i].u[0];
3366 			vlist[0].uv.y = eobj->facelist[i].v[0];
3367 			vlist[1].uv.x = eobj->facelist[i].u[1];
3368 			vlist[1].uv.y = eobj->facelist[i].v[1];
3369 			vlist[2].uv.x = eobj->facelist[i].u[2];
3370 			vlist[2].uv.y = eobj->facelist[i].v[2];
3371 
3372 			if (eobj->facelist[i].texid >= 0)
3373 				EERIEAddPolyToBackground(vlist,eobj->texturecontainer[eobj->facelist[i].texid],eobj->facelist[i].facetype,eobj->facelist[i].transval,eobj);
3374 		} else {
3375 			EERIEAddPolyToBackground(vlist, NULL, eobj->facelist[i].facetype, eobj->facelist[i].transval, eobj);
3376 		}
3377 	}
3378 }
3379 
3380 /*!
3381  * Save the currently loaded scene.
3382  * @param partal_path Where to save the scene to.
3383  */
FastSceneSave(const fs::path & partial_path)3384 static bool FastSceneSave(const fs::path & partial_path) {
3385 
3386 	fs::path path = "game" / partial_path;
3387 
3388 	LogDebug("FastSceneSave" << path);
3389 
3390 	if(!fs::create_directories(path)) {
3391 		return false;
3392 	}
3393 
3394 	size_t allocsize = (256) * 60 + 1000000 + sizeof(FAST_SCENE_HEADER)
3395 	                   + sizeof(FAST_TEXTURE_CONTAINER) * 1000
3396 	                   + sizeof(FAST_ANCHOR_DATA) * ACTIVEBKG->nbanchors * 2;
3397 
3398 	if(portals) {
3399 
3400 		for(long i = 0; i < portals->nb_total + 1; i++) {
3401 			allocsize += sizeof(EERIE_SAVE_PORTALS);
3402 		}
3403 
3404 		for(long i = 0; i < portals->nb_rooms + 1; i++) {
3405 			allocsize += sizeof(EERIE_SAVE_ROOM_DATA);
3406 			allocsize += sizeof(s32) * portals->room[i].nb_portals;
3407 			allocsize += sizeof(FAST_EP_DATA) * portals->room[i].nb_polys;
3408 		}
3409 
3410 		allocsize += sizeof(ROOM_DIST_DATA_SAVE) * (portals->nb_rooms + 1) * (portals->nb_rooms + 1);
3411 	}
3412 
3413 	for(long i = 0; i < ACTIVEBKG->nbanchors; i++) {
3414 		allocsize += ACTIVEBKG->anchors[i].nblinked * sizeof(s32);
3415 	}
3416 
3417 	for(long j = 0; j < ACTIVEBKG->Zsize; j++) {
3418 		for(long i = 0; i < ACTIVEBKG->Xsize; i++) {
3419 			allocsize += sizeof(FAST_SCENE_INFO);
3420 			allocsize += ACTIVEBKG->Backg[i+j*ACTIVEBKG->Xsize].nbpoly * (sizeof(EERIEPOLY) + 1);
3421 		}
3422 	}
3423 
3424 
3425 	size_t pos = 0;
3426 	char * dat = new char[allocsize];
3427 
3428 	memset(dat, 0, allocsize);
3429 	UNIQUE_HEADER * uh = reinterpret_cast<UNIQUE_HEADER *>(dat);
3430 	pos += sizeof(UNIQUE_HEADER);
3431 	strncpy(uh->path, path.string().c_str(), sizeof(uh->path));
3432 	uh->version = FTS_VERSION;
3433 
3434 	long count = 0;
3435 
3436 	for(fs::directory_iterator it(partial_path); !it.end(); ++it) {
3437 
3438 		fs::path path = partial_path / it.name();
3439 
3440 		if(!path.has_ext("scn") || !it.is_regular_file()) {
3441 			continue;
3442 		}
3443 
3444 		UNIQUE_HEADER2 * uh2 = reinterpret_cast<UNIQUE_HEADER2 *>(dat + pos);
3445 		pos += sizeof(UNIQUE_HEADER2);
3446 		strncpy(uh2->path, path.filename().c_str(), sizeof(uh2->path));
3447 
3448 		char check[512];
3449 		HERMES_CreateFileCheck(path, check, 512, FTS_VERSION);
3450 
3451 		memcpy(dat + pos, check, 512);
3452 		pos += 512;
3453 
3454 		count++;
3455 
3456 		if(count > 60) {
3457 			delete[] dat;
3458 			return false;
3459 		}
3460 	}
3461 
3462 	uh->count = count;
3463 	fs::path file = path / "fast.fts";
3464 	long compressedstart = pos;
3465 
3466 	FAST_SCENE_HEADER * fsh = reinterpret_cast<FAST_SCENE_HEADER *>(dat + pos);
3467 	pos += sizeof(FAST_SCENE_HEADER);
3468 
3469 	fsh->version = FTS_VERSION;
3470 	fsh->sizex = ACTIVEBKG->Xsize;
3471 	fsh->sizez = ACTIVEBKG->Zsize;
3472 	fsh->nb_textures = 0;
3473 	fsh->playerpos = player.pos;
3474 	fsh->Mscenepos = Mscenepos;
3475 	fsh->nb_anchors = ACTIVEBKG->nbanchors;
3476 	fsh->nb_portals = 0;
3477 	fsh->nb_rooms = 0;
3478 
3479 	if(portals) {
3480 		fsh->nb_portals = portals->nb_total;
3481 		fsh->nb_rooms = portals->nb_rooms;
3482 	}
3483 
3484 	fsh->nb_polys = 0;
3485 
3486 	//Count textures...
3487 	typedef std::map<TextureContainer *, s32> TextureContainerMap;
3488 	TextureContainerMap textures;
3489 	s32 texid = 0;
3490 	for(long j = 0; j < fsh->sizez; j++) {
3491 		for(long i = 0; i < fsh->sizex; i++) {
3492 			for(long k = 0; k < ACTIVEBKG->Backg[i+j*fsh->sizex].nbpoly; k++) {
3493 
3494 				EERIEPOLY * ep = &ACTIVEBKG->Backg[i+j*fsh->sizex].polydata[k];
3495 
3496 				if(ep && ep->tex) {
3497 
3498 					if(textures.find(ep->tex) == textures.end()) {
3499 						textures[ep->tex] = ++texid;
3500 
3501 						FAST_TEXTURE_CONTAINER * ftc = reinterpret_cast<FAST_TEXTURE_CONTAINER *>(dat + pos);
3502 						pos += sizeof(FAST_TEXTURE_CONTAINER);
3503 						ftc->tc = texid;
3504 						strncpy(ftc->fic, ep->tex->m_texName.string().c_str(), sizeof(ftc->fic));
3505 						ftc->temp = 0;
3506 						fsh->nb_textures++;
3507 
3508 						if(pos >= allocsize - 100000) {
3509 							delete[] dat;
3510 							return false;
3511 						}
3512 					}
3513 				}
3514 			}
3515 		}
3516 	}
3517 
3518 	for(long j = 0; j < fsh->sizez; j++) {
3519 		for(long i = 0; i < fsh->sizex; i++) {
3520 			FAST_SCENE_INFO * fsi = reinterpret_cast<FAST_SCENE_INFO *>(dat + pos);
3521 			pos += sizeof(FAST_SCENE_INFO);
3522 
3523 			if(pos >= allocsize - 100000) {
3524 				delete[] dat;
3525 				return false;
3526 			}
3527 
3528 			fsi->nbianchors = ACTIVEBKG->Backg[i+j*fsh->sizex].nbianchors;
3529 			fsi->nbpoly = ACTIVEBKG->Backg[i+j*fsh->sizex].nbpoly;
3530 
3531 			for(long k = 0; k < fsi->nbpoly; k++) {
3532 				fsh->nb_polys++;
3533 
3534 				FAST_EERIEPOLY * ep = reinterpret_cast<FAST_EERIEPOLY *>(dat + pos);
3535 				pos += sizeof(FAST_EERIEPOLY);
3536 				EERIEPOLY * ep2 = &ACTIVEBKG->Backg[i+j*fsh->sizex].polydata[k];
3537 
3538 				if(pos >= allocsize - 100000) {
3539 					delete[] dat;
3540 					return false;
3541 				}
3542 
3543 				ep->room = ep2->room;
3544 				ep->paddy = 0;
3545 				ep->area = ep2->area;
3546 				ep->norm = ep2->norm;
3547 				ep->norm2 = ep2->norm2;
3548 				std::copy(ep2->nrml, ep2->nrml + 4, ep->nrml);
3549 				ep->tex = textures[ep2->tex];
3550 				ep->transval = ep2->transval;
3551 				ep->type = ep2->type;
3552 
3553 				for(long kk = 0; kk < 4; kk++) {
3554 					ep->v[kk].ssx = ep2->v[kk].p.x;
3555 					ep->v[kk].sy = ep2->v[kk].p.y;
3556 					ep->v[kk].ssz = ep2->v[kk].p.z;
3557 					ep->v[kk].stu = ep2->v[kk].uv.x;
3558 					ep->v[kk].stv = ep2->v[kk].uv.y;
3559 				}
3560 			}
3561 
3562 			for(long k = 0; k < fsi->nbianchors; k++) {
3563 				s32 * ianch = (s32 *)(dat + pos);
3564 				pos += sizeof(s32);
3565 				if(pos >= allocsize - 100000) {
3566 					delete[] dat;
3567 					return false;
3568 				}
3569 				*ianch = ACTIVEBKG->Backg[i+j*fsh->sizex].ianchors[k];
3570 			}
3571 		}
3572 	}
3573 
3574 	for(long i = 0; i < ACTIVEBKG->nbanchors; i++) {
3575 
3576 		FAST_ANCHOR_DATA * fad = reinterpret_cast<FAST_ANCHOR_DATA *>(dat + pos);
3577 		pos += sizeof(FAST_ANCHOR_DATA);
3578 
3579 		if(pos >= allocsize - 100000) {
3580 			delete[] dat;
3581 			return false;
3582 		}
3583 
3584 		fad->flags = ACTIVEBKG->anchors[i].flags;
3585 		fad->pos = ACTIVEBKG->anchors[i].pos;
3586 		fad->nb_linked = ACTIVEBKG->anchors[i].nblinked;
3587 		fad->radius = ACTIVEBKG->anchors[i].radius;
3588 		fad->height = ACTIVEBKG->anchors[i].height;
3589 
3590 		for(long kk = 0; kk < fad->nb_linked; kk++) {
3591 			s32 * lng = reinterpret_cast<s32 *>(dat + pos);
3592 			pos += sizeof(s32);
3593 			if(pos >= allocsize - 100000) {
3594 				delete[] dat;
3595 				return false;
3596 			}
3597 			*lng = ACTIVEBKG->anchors[i].linked[kk];
3598 		}
3599 	}
3600 
3601 	if(portals) {
3602 
3603 		for(long i = 0; i < portals->nb_total; i++) {
3604 
3605 			EERIE_SAVE_PORTALS * epo = reinterpret_cast<EERIE_SAVE_PORTALS *>(dat + pos);
3606 			pos += sizeof(EERIE_SAVE_PORTALS);
3607 
3608 			const EERIE_PORTALS & portal = portals->portals[i];
3609 
3610 			epo->room_1 = portal.room_1;
3611 			epo->room_2 = portal.room_2;
3612 			epo->useportal = portal.useportal;
3613 			epo->paddy = portal.paddy;
3614 			epo->poly.area = portal.poly.area;
3615 			epo->poly.type = portal.poly.type;
3616 			epo->poly.transval = portal.poly.transval;
3617 			epo->poly.room = portal.poly.room;
3618 			epo->poly.misc = portal.poly.misc;
3619 			epo->poly.center = portal.poly.center;
3620 			epo->poly.max = portal.poly.max;
3621 			epo->poly.min = portal.poly.min;
3622 			epo->poly.norm = portal.poly.norm;
3623 			epo->poly.norm2 = portal.poly.norm2;
3624 
3625 			copy(portal.poly.nrml, portal.poly.nrml + 4, epo->poly.nrml);
3626 			copy(portal.poly.v, portal.poly.v + 4, epo->poly.v);
3627 			copy(portal.poly.tv, portal.poly.tv + 4, epo->poly.tv);
3628 		}
3629 
3630 		for(long i = 0; i < portals->nb_rooms + 1; i++) {
3631 
3632 			EERIE_SAVE_ROOM_DATA * erd = reinterpret_cast<EERIE_SAVE_ROOM_DATA *>(dat + pos);
3633 			pos += sizeof(EERIE_SAVE_ROOM_DATA);
3634 
3635 			memset(erd, 0, sizeof(EERIE_SAVE_ROOM_DATA));
3636 			erd->nb_polys = portals->room[i].nb_polys;
3637 			erd->nb_portals = portals->room[i].nb_portals;
3638 
3639 			for(long jj = 0; jj < portals->room[i].nb_portals; jj++) {
3640 				s32 * lng = reinterpret_cast<s32 *>(dat + pos);
3641 				pos += sizeof(s32);
3642 				*lng = portals->room[i].portals[jj];
3643 			}
3644 
3645 			if(portals->room[i].nb_polys) {
3646 				EP_DATA * ed = reinterpret_cast<EP_DATA *>(dat + pos);
3647 				pos += sizeof(EP_DATA) * portals->room[i].nb_polys;
3648 				memcpy(ed, portals->room[i].epdata, sizeof(EP_DATA)*portals->room[i].nb_polys);
3649 			}
3650 		}
3651 	}
3652 
3653 	if(!RoomDistance) {
3654 		ComputeRoomDistance();
3655 	}
3656 
3657 	if(portals && RoomDistance && NbRoomDistance > 0) {
3658 		for(long n = 0; n < NbRoomDistance; n++) {
3659 			for(long m = 0; m < NbRoomDistance; m++) {
3660 				ROOM_DIST_DATA_SAVE * rdds = reinterpret_cast<ROOM_DIST_DATA_SAVE *>(dat + pos);
3661 				pos += sizeof(ROOM_DIST_DATA_SAVE);
3662 				Vec3f start;
3663 				Vec3f end;
3664 				rdds->distance = GetRoomDistance(m, n, &start, &end);
3665 				rdds->startpos = start;
3666 				rdds->endpos = end;
3667 			}
3668 		}
3669 	}
3670 
3671 	// Now Saving Whole Buffer
3672 	uh->uncompressedsize = pos - compressedstart;
3673 
3674 	fs::ofstream ofs(file, fs::fstream::out | fs::fstream::binary | fs::fstream::trunc);
3675 	if(!ofs.is_open()) {
3676 		delete[] dat;
3677 		return false;
3678 	}
3679 
3680 	if(ofs.write(dat, compressedstart).fail()) {
3681 		delete[] dat;
3682 		return false;
3683 	}
3684 
3685 	size_t compressedSize;
3686 	char * compressed = implodeAlloc(dat + compressedstart, pos - compressedstart, compressedSize);
3687 	delete[] dat;
3688 	if(!compressed) {
3689 		LogError << "Error compressing scene";
3690 		return false;
3691 	}
3692 
3693 	ofs.write(compressed, compressedSize);
3694 
3695 	delete[] compressed;
3696 
3697 	return !ofs.fail();
3698 }
3699 
SceneAddMultiScnToBackground(EERIE_MULTI3DSCENE * ms)3700 void SceneAddMultiScnToBackground(EERIE_MULTI3DSCENE * ms) {
3701 
3702 	res::path ftemp = LastLoadedScene.parent();
3703 
3704 	// First Release Any Portal Data
3705 	EERIE_PORTAL_Release();
3706 
3707 	// Try to Load Fast Scene
3708 	if(!FastSceneLoad(ftemp)) {
3709 
3710 		//failure: Not-Fast Load
3711 
3712 		for(long j = 0; j < ms->nb_scenes; j++) {
3713 			EERIE_3DSCENE * escn = ms->scenes[j];
3714 			for(long i = 0; i < escn->nbobj; i++) {
3715 				escn->objs[i]->pos += ms->pos;
3716 				SceneAddObjToBackground(escn->objs[i]);
3717 			}
3718 		}
3719 
3720 		EERIE_LIGHT_MoveAll(&ms->pos);
3721 		ARX_PrepareBackgroundNRMLs();
3722 		EERIEPOLY_Compute_PolyIn();
3723 		EERIE_PORTAL_Blend_Portals_And_Rooms();
3724 
3725 		if(NEED_ANCHORS) {
3726 			AnchorData_Create(ACTIVEBKG);
3727 		}
3728 
3729 		FastSceneSave(ftemp.string());
3730 		ComputePortalVertexBuffer();
3731 		ComputeRoomDistance();
3732 	}
3733 
3734 }
3735 
3736 #endif // BUILD_EDIT_LOADSAVE
3737 
EERIE_PORTAL_ReleaseOnlyVertexBuffer()3738 void EERIE_PORTAL_ReleaseOnlyVertexBuffer() {
3739 
3740 	if(!portals) {
3741 		return;
3742 	}
3743 
3744 	if(!portals->room || portals->nb_rooms <= 0) {
3745 		return;
3746 	}
3747 
3748 	LogDebug("Destroying scene VBOs");
3749 
3750 	for(long i = 0; i < portals->nb_rooms + 1; i++) {
3751 		portals->room[i].usNbTextures = 0;
3752 		delete portals->room[i].pVertexBuffer, portals->room[i].pVertexBuffer = NULL;
3753 		free(portals->room[i].pussIndice), portals->room[i].pussIndice = NULL;
3754 		free(portals->room[i].ppTextureContainer), portals->room[i].ppTextureContainer = NULL;
3755 	}
3756 }
3757 
3758 namespace {
3759 
3760 struct SINFO_TEXTURE_VERTEX {
3761 
3762 	int opaque;
3763 	int multiplicative;
3764 	int additive;
3765 	int blended;
3766 	int subtractive;
3767 
SINFO_TEXTURE_VERTEX__anon41ea1ef50111::SINFO_TEXTURE_VERTEX3768 	SINFO_TEXTURE_VERTEX()
3769 		: opaque(0), multiplicative(0), additive(0), blended(0), subtractive(0) { }
3770 };
3771 
3772 } // anonymous namespace
3773 
ComputePortalVertexBuffer()3774 void ComputePortalVertexBuffer() {
3775 
3776 	if(!portals) {
3777 		return;
3778 	}
3779 
3780 	EERIE_PORTAL_ReleaseOnlyVertexBuffer();
3781 
3782 	LogDebug("Creating scene VBOs");
3783 
3784 	if(portals->nb_rooms > 255) {
3785 		LogError << "Too many rooms: " << portals->nb_rooms + 1;
3786 		return;
3787 	}
3788 
3789 	typedef boost::unordered_map<TextureContainer *,  SINFO_TEXTURE_VERTEX>
3790 		TextureMap;
3791 	TextureMap infos;
3792 
3793 	for(int i = 0; i < portals->nb_rooms + 1; i++) {
3794 
3795 		EERIE_ROOM_DATA * room = &portals->room[i];
3796 
3797 		// Skip empty rooms
3798 		if(!room->nb_polys) {
3799 			continue;
3800 		}
3801 
3802 		infos.clear();
3803 
3804 		// Count vertices / indices for each texture and blend types
3805 		int vertexCount = 0, indexCount = 0, ignored = 0, hidden = 0, notex = 0;
3806 		for(int j = 0; j < room->nb_polys; j++) {
3807 			int x = room->epdata[j].px, y = room->epdata[j].py;
3808 			EERIE_BKG_INFO & cell = ACTIVEBKG->Backg[x + y * ACTIVEBKG->Xsize];
3809 			EERIEPOLY & poly = cell.polydata[room->epdata[j].idx];
3810 
3811 			if(poly.type & POLY_IGNORE) {
3812 				ignored++;
3813 				continue;
3814 			}
3815 
3816 			if(poly.type & POLY_HIDE) {
3817 				hidden++;
3818 				continue;
3819 			}
3820 
3821 			if(!poly.tex) {
3822 				notex++;
3823 				continue;
3824 			}
3825 
3826 			if(!poly.tex->tMatRoom) {
3827 				poly.tex->tMatRoom = (SMY_ARXMAT *)malloc(sizeof(SMY_ARXMAT)
3828 				                                           * (portals->nb_rooms + 1));
3829 			}
3830 
3831 			SINFO_TEXTURE_VERTEX & info = infos[poly.tex];
3832 
3833 			int nvertices = (poly.type & POLY_QUAD) ? 4 : 3;
3834 			int nindices  = (poly.type & POLY_QUAD) ? 6 : 3;
3835 
3836 			if(poly.type & POLY_TRANS) {
3837 
3838 				float trans = poly.transval;
3839 
3840 				if(poly.transval >= 2.f) { // multiplicative
3841 					info.multiplicative += nindices;
3842 					trans = trans * 0.5f + 0.5f;
3843 				} else if(poly.transval >= 1.f) { // additive
3844 					info.additive += nindices;
3845 					trans -= 1.f;
3846 				} else if(poly.transval > 0.f) { // normal trans
3847 					info.blended += nindices;
3848 					trans = 1.f - trans;
3849 				} else { // subtractive
3850 					info.subtractive += nindices;
3851 					trans = 1.f - trans;
3852 				}
3853 
3854 				poly.v[3].color = poly.v[2].color = poly.v[1].color = poly.v[0].color
3855 					= Color::gray(trans).toBGR();
3856 
3857 			} else {
3858 				info.opaque += nindices;
3859 			}
3860 
3861 			vertexCount += nvertices;
3862 			indexCount += nindices;
3863 		}
3864 
3865 
3866 		if(!vertexCount) {
3867 			LogWarning << "No visible vertices in room " << i << ": "
3868 			           << ignored << " ignored, " << hidden << " hidden, "
3869 			           << notex << " untextured";
3870 			continue;
3871 		}
3872 
3873 
3874 		// Allocate the index buffer for this room
3875 		room->pussIndice = (unsigned short *)malloc(sizeof(unsigned short)
3876 		                                            * indexCount);
3877 
3878 		// Allocate the vertex buffer for this room
3879 		// TODO should be static, but is updated for dynamic lighting
3880 		room->pVertexBuffer = GRenderer->createVertexBuffer(vertexCount,
3881 		                                                    Renderer::Dynamic);
3882 
3883 
3884 		// Now fill the buffers
3885 
3886 		SMY_VERTEX * vertex = room->pVertexBuffer->lock(NoOverwrite);
3887 
3888 		int startIndex = 0;
3889 		int startIndexCull = 0;
3890 
3891 		size_t ntextures = infos.size();
3892 
3893 		LogDebug(" - room " << i << ": " << ntextures << " textures, "
3894 		         << vertexCount << " vertices, " << indexCount << " indices");
3895 
3896 		// Allocate space to list all textures for this room
3897 		// TODO use std::vector
3898 		room->ppTextureContainer = (TextureContainer **)realloc(
3899 			room->ppTextureContainer,
3900 			sizeof(*room->ppTextureContainer) * (room->usNbTextures + ntextures)
3901 		);
3902 
3903 		TextureMap::const_iterator it;
3904 		for(it = infos.begin(); it != infos.end(); ++it) {
3905 
3906 			TextureContainer * texture = it->first;
3907 			const SINFO_TEXTURE_VERTEX & info = it->second;
3908 
3909 			unsigned short index = 0;
3910 
3911 			// Upload all vertices for this texture and remember the indices
3912 			for(int j = 0; j < room->nb_polys; j++) {
3913 				int x = room->epdata[j].px, y = room->epdata[j].py;
3914 				EERIE_BKG_INFO & cell = ACTIVEBKG->Backg[x + y * ACTIVEBKG->Xsize];
3915 				EERIEPOLY & poly = cell.polydata[room->epdata[j].idx];
3916 
3917 				if((poly.type & POLY_IGNORE) || (poly.type & POLY_HIDE) || !poly.tex) {
3918 					continue;
3919 				}
3920 
3921 				if(poly.tex != texture) {
3922 					continue;
3923 				}
3924 
3925 				vertex->p.x = poly.v[0].p.x;
3926 				vertex->p.y = -(poly.v[0].p.y);
3927 				vertex->p.z = poly.v[0].p.z;
3928 				vertex->color = poly.v[0].color;
3929 				vertex->uv = poly.v[0].uv + texture->hd;
3930 				vertex++;
3931 				poly.uslInd[0] = index++;
3932 
3933 				vertex->p.x = poly.v[1].p.x;
3934 				vertex->p.y = -(poly.v[1].p.y);
3935 				vertex->p.z = poly.v[1].p.z;
3936 				vertex->color = poly.v[1].color;
3937 				vertex->uv = poly.v[1].uv + texture->hd;
3938 				vertex++;
3939 				poly.uslInd[1] = index++;
3940 
3941 				vertex->p.x = poly.v[2].p.x;
3942 				vertex->p.y = -(poly.v[2].p.y);
3943 				vertex->p.z = poly.v[2].p.z;
3944 				vertex->color = poly.v[2].color;
3945 				vertex->uv = poly.v[2].uv + texture->hd;
3946 				vertex++;
3947 				poly.uslInd[2] = index++;
3948 
3949 				if(poly.type & POLY_QUAD) {
3950 					vertex->p.x = poly.v[3].p.x;
3951 					vertex->p.y = -(poly.v[3].p.y);
3952 					vertex->p.z = poly.v[3].p.z;
3953 					vertex->color = poly.v[3].color;
3954 					vertex->uv = poly.v[3].uv + texture->hd;
3955 					vertex++;
3956 					poly.uslInd[3] = index++;
3957 				}
3958 			}
3959 
3960 			// Record that the texture is used for this room
3961 			room->ppTextureContainer[room->usNbTextures++] = texture;
3962 
3963 			// Save the
3964 
3965 			SMY_ARXMAT & m = texture->tMatRoom[i];
3966 
3967 			m.uslStartVertex = startIndex;
3968 			m.uslNbVertex = index;
3969 
3970 			m.uslStartCull                 =  startIndexCull;
3971 			m.uslStartCull_TNormalTrans    = (startIndexCull += info.opaque);
3972 			m.uslStartCull_TMultiplicative = (startIndexCull += info.blended);
3973 			m.uslStartCull_TAdditive       = (startIndexCull += info.multiplicative);
3974 			m.uslStartCull_TSubstractive   = (startIndexCull += info.additive);
3975 			                                 (startIndexCull += info.subtractive);
3976 
3977 			m.uslNbIndiceCull = 0;
3978 			m.uslNbIndiceCull_TNormalTrans = 0;
3979 			m.uslNbIndiceCull_TMultiplicative = 0;
3980 			m.uslNbIndiceCull_TAdditive = 0;
3981 			m.uslNbIndiceCull_TSubstractive = 0;
3982 
3983 			if(info.opaque > 65535 || info.multiplicative > 65535
3984 			   || info.additive > 65535 || info.blended > 65535
3985 			   || info.subtractive > 65535) {
3986 				LogWarning << "Too many indices for texture " << texture->m_texName
3987 				           << " in room " << i;
3988 			}
3989 
3990 			startIndex += index;
3991 		}
3992 
3993 		room->pVertexBuffer->unlock();
3994 	}
3995 }
3996 
EERIERTPPoly(EERIEPOLY * ep)3997 long EERIERTPPoly(EERIEPOLY *ep)
3998 {
3999 	specialEE_RTP(&ep->v[0],&ep->tv[0]);
4000 	specialEE_RTP(&ep->v[1],&ep->tv[1]);
4001 	specialEE_RTP(&ep->v[2],&ep->tv[2]);
4002 
4003 	if (ep->type & POLY_QUAD)
4004 	{
4005 		specialEE_RTP(&ep->v[3],&ep->tv[3]);
4006 
4007 		if ((ep->tv[0].p.z<=0.f) &&
4008 			(ep->tv[1].p.z<=0.f) &&
4009 			(ep->tv[2].p.z<=0.f) &&
4010 			(ep->tv[3].p.z<=0.f) )
4011 		{
4012 			return 0;
4013 		}
4014 	}
4015 	else
4016 	{
4017 		if ((ep->tv[0].p.z<=0.f) &&
4018 			(ep->tv[1].p.z<=0.f) &&
4019 			(ep->tv[2].p.z<=0.f)  )
4020 		{
4021 			return 0;
4022 		}
4023 	}
4024 
4025 	return 1;
4026 }
4027