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