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-2001 ARKANE Studios SA. All rights reserved
46 
47 #include "animation/Animation.h"
48 
49 #include <algorithm>
50 #include <cmath>
51 #include <cstdlib>
52 #include <cstdio>
53 #include <cstring>
54 #include <sstream>
55 #include <vector>
56 
57 #include <boost/foreach.hpp>
58 #include <boost/lexical_cast.hpp>
59 
60 #include "animation/AnimationRender.h"
61 
62 #include "core/Application.h"
63 #include "core/GameTime.h"
64 #include "core/Core.h"
65 
66 #include "game/Damage.h"
67 #include "game/EntityManager.h"
68 #include "game/NPC.h"
69 #include "game/Player.h"
70 #include "game/Spells.h"
71 
72 #include "graphics/BaseGraphicsTypes.h"
73 #include "graphics/Color.h"
74 #include "graphics/Draw.h"
75 #include "graphics/GraphicsTypes.h"
76 #include "graphics/Math.h"
77 #include "graphics/Renderer.h"
78 #include "graphics/data/Mesh.h"
79 #include "graphics/data/TextureContainer.h"
80 #include "graphics/particle/ParticleEffects.h"
81 #include "graphics/texture/TextureStage.h"
82 
83 #include "io/resource/ResourcePath.h"
84 #include "io/resource/PakReader.h"
85 #include "io/log/Logger.h"
86 
87 #include "math/Angle.h"
88 #include "math/Vector3.h"
89 
90 #include "platform/Platform.h"
91 
92 #include "scene/Object.h"
93 #include "scene/GameSound.h"
94 #include "scene/Scene.h"
95 #include "scene/Interactive.h"
96 
97 #include "script/Script.h"
98 
99 using std::min;
100 using std::max;
101 using std::string;
102 using std::ostringstream;
103 using std::vector;
104 
105 static const float IN_FRONT_DIVIDER_ITEMS = 0.7505f;
106 
107 long MAX_LLIGHTS = 18;
108 //-----------------------------------------------------------------------------
109 extern EERIE_CAMERA TCAM[32];
110 extern QUAKE_FX_STRUCT QuakeFx;
111 extern long INTER_DRAW;
112 extern long FRAME_COUNT;
113 extern Color ulBKGColor;
114 extern long ZMAPMODE;
115 
116 ANIM_HANDLE animations[MAX_ANIMATIONS];
117 
118 TexturedVertex LATERDRAWHALO[HALOMAX * 4];
119 EERIE_LIGHT * llights[32];
120 EERIE_QUAT * BIGQUAT;
121 EERIEMATRIX * BIGMAT;
122 float dists[32];
123 float values[32];
124 float vdist;
125 long MUST_DRAW = 0;
126 long FORCE_NO_HIDE = 0;
127 extern unsigned char * grps;
128 long TRAP_DETECT = -1;
129 long TRAP_SECRET = -1;
130 long USEINTERNORM = 1;
131 long HALOCUR = 0;
132 
133 static const long anim_power[] = { 100, 20, 15, 12, 8, 6, 5, 4, 3, 2, 2, 1, 1, 1, 1 };
134 
135 static TexturedVertex tTexturedVertexTab2[4000];
136 
137 extern long EXTERNALVIEW;
EERIE_ANIM_Get_Scale_Invisibility(Entity * io,float & invisibility,float & scale)138 void EERIE_ANIM_Get_Scale_Invisibility(Entity * io, float & invisibility,
139                                        float & scale) {
140 
141 	if(io) {
142 		invisibility = io->invisibility;
143 
144 		if (invisibility > 1.f) invisibility -= 1.f;
145 
146 		if(io != entities.player() && invisibility > 0.f && !EXTERNALVIEW) {
147 			long num = ARX_SPELLS_GetSpellOn(io, SPELL_INVISIBILITY);
148 
149 			if(num >= 0) {
150 				if(player.Full_Skill_Intuition>spells[num].caster_level * 10) {
151 					invisibility -= (float)player.Full_Skill_Intuition * .01f
152 					                + (float)spells[num].caster_level * .1f;
153 
154 					if (invisibility < 0.1f) invisibility = 0.1f;
155 					else if (invisibility > 1.f) invisibility = 1.f;
156 				}
157 			}
158 		}
159 
160 		// Scaling Value for this object (Movements will also be scaled)
161 		scale = io->scale;
162 
163 	} else {
164 		invisibility = 0.f;
165 		scale = 1.f;
166 	}
167 }
168 
169 // ANIMATION HANDLES handling
170 
ANIM_GetAltIdx(ANIM_HANDLE * ah,long old)171 short ANIM_GetAltIdx(ANIM_HANDLE * ah, long old) {
172 
173 	if (ah->alt_nb == 1) return 0;
174 
175 	float tot=(float)anim_power[0];
176 
177 	for (long i=1;i<ah->alt_nb;i++)
178 	{
179 		tot+=anim_power[min(i,14L)];
180 	}
181 
182 	while (1)
183 	{
184 		for (short i=0;i<ah->alt_nb;i++)
185 		{
186 			float r = rnd()*tot;
187 
188 			if ((r < anim_power[min((int)i,14)]) && (i!=old))
189 				return i;
190 		}
191 	}
192 }
193 
194 //-----------------------------------------------------------------------------
ANIM_Set(ANIM_USE * au,ANIM_HANDLE * anim)195 void ANIM_Set(ANIM_USE * au,ANIM_HANDLE * anim)
196 {
197 	if ((!au)
198 		|| (!anim) )
199 		return;
200 
201 	au->cur_anim=anim;
202 	au->altidx_cur=ANIM_GetAltIdx(anim,au->altidx_cur);
203 
204 	if (au->altidx_cur>au->cur_anim->alt_nb)
205 		au->altidx_cur=0;
206 
207 	au->ctime=0;
208 	au->lastframe=-1;
209 	au->flags&=~EA_PAUSED;
210 	au->flags&=~EA_ANIMEND;
211 	au->flags&=~EA_LOOP;
212 	au->flags&=~EA_FORCEPLAY;
213 }
214 
ANIM_HANDLE()215 ANIM_HANDLE::ANIM_HANDLE() : path() {
216 
217 	anims = NULL, alt_nb = 0;
218 
219 	locks = 0;
220 }
221 
EERIE_ANIMMANAGER_PurgeUnused()222 void EERIE_ANIMMANAGER_PurgeUnused() {
223 
224 	for(size_t i = 0; i < MAX_ANIMATIONS; i++) {
225 		if(!animations[i].path.empty() && animations[i].locks == 0) {
226 			for(long k = 0; k < animations[i].alt_nb; k++) {
227 				ReleaseAnim(animations[i].anims[k]);
228 				animations[i].anims[k] = NULL;
229 			}
230 			free(animations[i].anims), animations[i].anims = NULL;
231 			animations[i].path.clear();
232 		}
233 	}
234 }
235 
EERIE_ANIMMANAGER_ReleaseHandle(ANIM_HANDLE * anim)236 void EERIE_ANIMMANAGER_ReleaseHandle(ANIM_HANDLE * anim) {
237 	if(anim) {
238 		anim->locks--;
239 		if(anim->locks < 0) {
240 			anim->locks = 0;
241 		}
242 	}
243 }
244 
EERIE_ANIMMANAGER_GetHandle(const res::path & path)245 static ANIM_HANDLE * EERIE_ANIMMANAGER_GetHandle(const res::path & path) {
246 
247 	for(size_t i = 0; i < MAX_ANIMATIONS; i++) {
248 		if(animations[i].path == path) {
249 			return &animations[i];
250 		}
251 	}
252 
253 	return NULL;
254 }
255 
EERIE_ANIMMANAGER_AddAltAnim(ANIM_HANDLE * ah,const res::path & path)256 static bool EERIE_ANIMMANAGER_AddAltAnim(ANIM_HANDLE * ah, const res::path & path) {
257 
258 	if(!ah || ah->path.empty()) {
259 		return false;
260 	}
261 
262 	size_t FileSize;
263 	char * adr = resources->readAlloc(path, FileSize);
264 	if(!adr) {
265 		return false;
266 	}
267 
268 	EERIE_ANIM * temp = TheaToEerie(adr, FileSize, path);
269 	free(adr);
270 	if(!temp) {
271 		return false;
272 	}
273 
274 	ah->alt_nb++;
275 	ah->anims = (EERIE_ANIM **)realloc(ah->anims, sizeof(EERIE_ANIM *) * ah->alt_nb);
276 	ah->anims[ah->alt_nb - 1] = temp;
277 
278 	return true;
279 }
280 
EERIE_ANIMMANAGER_Load(const res::path & path)281 ANIM_HANDLE * EERIE_ANIMMANAGER_Load(const res::path & path) {
282 
283 	ANIM_HANDLE * anim = EERIE_ANIMMANAGER_Load_NoWarning(path);
284 	if(!anim) {
285 		LogWarning << "Animation not found: " << path;
286 	}
287 
288 	return anim;
289 }
290 
EERIE_ANIMMANAGER_Load_NoWarning(const res::path & path)291 ANIM_HANDLE * EERIE_ANIMMANAGER_Load_NoWarning(const res::path & path) {
292 
293 	ANIM_HANDLE * handl = EERIE_ANIMMANAGER_GetHandle(path);
294 	if(handl) {
295 		handl->locks++;
296 		return handl;
297 	}
298 
299 	for(size_t i = 0; i < MAX_ANIMATIONS; i++) {
300 
301 		if(!animations[i].path.empty()) {
302 			continue;
303 		}
304 
305 		size_t FileSize;
306 		char * adr = resources->readAlloc(path, FileSize);
307 		if(!adr) {
308 			return NULL;
309 		}
310 
311 		animations[i].anims = (EERIE_ANIM **)malloc(sizeof(EERIE_ANIM *));
312 		animations[i].anims[0] = TheaToEerie(adr, FileSize, path);
313 		animations[i].alt_nb = 1;
314 
315 		free(adr);
316 
317 		if(!animations[i].anims[0]) {
318 			return NULL;
319 		}
320 
321 		animations[i].path = path;
322 		animations[i].locks = 1;
323 
324 		int pathcount = 2;
325 		res::path altpath;
326 		do {
327 			altpath = res::path(path);
328 			altpath.append_basename(boost::lexical_cast<std::string>(pathcount++));
329 		} while(EERIE_ANIMMANAGER_AddAltAnim(&animations[i], altpath));
330 
331 		return &animations[i];
332 	}
333 
334 	return NULL;
335 }
336 
337 //-----------------------------------------------------------------------------
338 // tex Must be of sufficient size...
EERIE_ANIMMANAGER_Count(std::string & tex,long * memsize)339 long EERIE_ANIMMANAGER_Count( std::string& tex, long * memsize)
340 {
341 	char temp[512];
342 	long count=0;
343 	*memsize=0;
344 
345 	for(size_t i = 0; i < MAX_ANIMATIONS; i++) {
346 
347 		if(!animations[i].path.empty())
348 		{
349 			count++;
350 			char txx[256];
351 			strcpy(txx,animations[i].path.string().c_str());
352 			long totsize=0;
353 
354 			sprintf(temp, "%3ld[%3lu] %s size %ld Locks %ld Alt %d\r\n", count, (unsigned long)i,
355 			        txx, totsize, animations[i].locks, animations[i].alt_nb - 1);
356 			memsize+=totsize;
357 			tex += temp;
358 		}
359 	}
360 
361 	return count;
362 }
363 
364 // Fill "pos" with "eanim" total translation
GetAnimTotalTranslate(ANIM_HANDLE * eanim,long alt_idx,Vec3f * pos)365 void GetAnimTotalTranslate( ANIM_HANDLE * eanim, long alt_idx, Vec3f * pos) {
366 
367 	if(!pos) {
368 		return;
369 	}
370 
371 	if(!eanim || !eanim->anims[alt_idx] || !eanim->anims[alt_idx]->frames
372 	   || eanim->anims[alt_idx]->nb_key_frames <= 0) {
373 		*pos = Vec3f::ZERO;
374 	} else {
375 		long idx = eanim->anims[alt_idx]->nb_key_frames - 1;
376 		*pos = eanim->anims[alt_idx]->frames[idx].translate;
377 	}
378 }
379 
380 // Main Procedure to draw an animated object
381 //------------------------------------------
382 // Needs some update...
383 //  EERIE_3DOBJ * eobj    main object data
384 //  EERIE_ANIM * eanim    Animation data
385 //  EERIE_3D * angle      Object Angle
386 //  EERIE_3D  * pos       Object Position
387 //  unsigned long time    Time increment to current animation in Ms
388 //  Entity * io  Referrence to Interactive Object (NULL if no IO)
389 //  long typ              Misc Type 0=World View 1=1st Person View
PrepareAnim(EERIE_3DOBJ * eobj,ANIM_USE * eanim,unsigned long time,Entity * io)390 void PrepareAnim(EERIE_3DOBJ * eobj, ANIM_USE * eanim,unsigned long time,
391                  Entity * io) {
392 
393 	long tcf,tnf;
394 	long fr;
395 	float pour;
396 	long tim;
397 
398 	if ((!eobj)
399 		|| (!eanim))
400 		return;
401 
402 	if (eanim->flags & EA_PAUSED) time=0;
403 
404 	if ((io) && (io->ioflags & IO_FREEZESCRIPT)) time=0;
405 
406 	if (eanim->altidx_cur>= eanim->cur_anim->alt_nb) eanim->altidx_cur=0;
407 
408 	if (!(eanim->flags & EA_EXCONTROL))
409 		eanim->ctime+=time;
410 
411 	eanim->flags&=~EA_ANIMEND;
412 
413 	if ((eanim->flags & EA_STOPEND)
414 		&& (eanim->ctime > eanim->cur_anim->anims[eanim->altidx_cur]->anim_time))
415 	{
416 		eanim->ctime = eanim->cur_anim->anims[eanim->altidx_cur]->anim_time;
417 	}
418 
419 	if((eanim->flags & EA_LOOP)
420 	   || (io && ((eanim->cur_anim == io->anims[ANIM_WALK])
421 	              || (eanim->cur_anim == io->anims[ANIM_WALK2])
422 	              || (eanim->cur_anim == io->anims[ANIM_WALK3])
423 	              || (eanim->cur_anim==io->anims[ANIM_RUN])
424 	              || (eanim->cur_anim==io->anims[ANIM_RUN2])
425 	              || (eanim->cur_anim==io->anims[ANIM_RUN3])))) {
426 
427 		if(eanim->ctime > eanim->cur_anim->anims[eanim->altidx_cur]->anim_time) {
428 
429 			long lost = eanim->ctime - long(eanim->cur_anim->anims[eanim->altidx_cur]->anim_time);
430 
431 			if(eanim->next_anim==NULL) {
432 
433 				long t = eanim->cur_anim->anims[eanim->altidx_cur]->anim_time;
434 				eanim->ctime= eanim->ctime % t;
435 
436 					if (io) FinishAnim(io,eanim->cur_anim);
437 
438 				}
439 			else
440 			{
441 				if(io) {
442 
443 					FinishAnim(io,eanim->cur_anim);
444 
445 					if (io->lastanimtime!=0) AcquireLastAnim(io);
446 					else io->lastanimtime=1;
447 				}
448 
449 				eanim->cur_anim=eanim->next_anim;
450 				eanim->altidx_cur=ANIM_GetAltIdx(eanim->next_anim,eanim->altidx_cur);
451 				eanim->next_anim=NULL;
452 				ResetAnim(eanim);
453 				eanim->ctime = lost;
454 				eanim->flags=eanim->nextflags;
455 				eanim->flags&=~EA_ANIMEND;
456 				goto suite;
457 			}
458 		}
459 	}
460 	else if (eanim->ctime > eanim->cur_anim->anims[eanim->altidx_cur]->anim_time)
461 	{
462 		if (io)
463 		{
464 			long lost = eanim->ctime - long(eanim->cur_anim->anims[eanim->altidx_cur]->anim_time);
465 
466 			if (eanim->next_anim!=NULL)
467 			{
468 
469 				FinishAnim(io,eanim->cur_anim);
470 
471 				if (io->lastanimtime!=0) AcquireLastAnim(io);
472 				else io->lastanimtime=1;
473 
474 				eanim->cur_anim=eanim->next_anim;
475 				eanim->altidx_cur=ANIM_GetAltIdx(eanim->next_anim,eanim->altidx_cur);
476 				eanim->next_anim=NULL;
477 				ResetAnim(eanim);
478 				eanim->ctime = lost;
479 				eanim->flags=eanim->nextflags;
480 				eanim->flags&=~EA_ANIMEND;
481 				goto suite;
482 			}
483 			else
484 			{
485 				eanim->ctime=(long)eanim->cur_anim->anims[eanim->altidx_cur]->anim_time;
486 				eanim->flags&=~EA_ANIMEND;
487 			}
488 		}
489 
490 		eanim->flags|=EA_ANIMEND;
491 		eanim->ctime=(unsigned long)eanim->cur_anim->anims[eanim->altidx_cur]->anim_time;
492 	}
493 
494 suite:
495 
496 	if (!eanim->cur_anim)
497 		return;
498 
499 	if (eanim->flags & EA_REVERSE)
500 		tim=(unsigned long)eanim->cur_anim->anims[eanim->altidx_cur]->anim_time - eanim->ctime;
501 	else
502 		tim=eanim->ctime;
503 
504 	eanim->fr=eanim->cur_anim->anims[eanim->altidx_cur]->nb_key_frames-2;
505 	eanim->pour=1.f;
506 
507 	for (long i=1;i<eanim->cur_anim->anims[eanim->altidx_cur]->nb_key_frames;i++)
508 	{
509 		tcf=(long)eanim->cur_anim->anims[eanim->altidx_cur]->frames[i-1].time;
510 		tnf=(long)eanim->cur_anim->anims[eanim->altidx_cur]->frames[i].time;
511 
512 		if (tcf == tnf) return;
513 
514 		if(((tim<tnf) && (tim>=tcf))
515 		   || ((i==eanim->cur_anim->anims[eanim->altidx_cur]->nb_key_frames-1) && (tim==tnf))) {
516 
517 			fr=i-1;
518 			tim-=tcf;
519 			pour=(float)((float)tim/((float)tnf-(float)tcf));
520 
521 			// Frame Sound Management
522 			if(!(eanim->flags & EA_ANIMEND) && time
523 			   && (eanim->cur_anim->anims[eanim->altidx_cur]->frames[fr].sample != -1)
524 			   && (eanim->lastframe != fr)) {
525 
526 				if ((eanim->lastframe<fr) && (eanim->lastframe!=-1))
527 				{
528 					for (long n=eanim->lastframe+1;n<=fr;n++)
529 						ARX_SOUND_PlayAnim(eanim->cur_anim->anims[eanim->altidx_cur]->frames[n].sample,
530 						                   io ? &io->pos : NULL);
531 				}
532 				else
533 				{
534 					ARX_SOUND_PlayAnim(eanim->cur_anim->anims[eanim->altidx_cur]->frames[fr].sample,
535 					                   io ? &io->pos : NULL);
536 				}
537 			}
538 
539 			// Frame Flags Management
540 			if(!(eanim->flags & EA_ANIMEND) && time
541 			   && (eanim->cur_anim->anims[eanim->altidx_cur]->frames[fr].flag > 0)
542 			   && (eanim->lastframe != fr)) {
543 
544 				if (io!=entities.player())
545 				{
546 					if ((eanim->lastframe<fr) && (eanim->lastframe!=-1))
547 					{
548 						for (long n=eanim->lastframe+1;n<=fr;n++)
549 						{
550 							if (eanim->cur_anim->anims[eanim->altidx_cur]->frames[n].flag==9)
551 								ARX_NPC_NeedStepSound(io, &io->pos);
552 						}
553 					}
554 					else if (eanim->cur_anim->anims[eanim->altidx_cur]->frames[fr].flag == 9)
555 						ARX_NPC_NeedStepSound(io, &io->pos);
556 				}
557 			}
558 
559 			// Memorize this frame as lastframe.
560 			eanim->lastframe=fr;
561 			eanim->fr=fr;
562 			eanim->pour=pour;
563 			break;
564 		}
565 	}
566 }
567 Entity * DESTROYED_DURING_RENDERING=NULL;
568 
EERIEDrawAnimQuat(EERIE_3DOBJ * eobj,ANIM_USE * eanim,Anglef * angle,Vec3f * pos,unsigned long time,Entity * io,bool render,bool update_movement)569 void EERIEDrawAnimQuat(EERIE_3DOBJ * eobj,
570                        ANIM_USE * eanim,
571                        Anglef * angle,
572                        Vec3f * pos,
573                        unsigned long time,
574                        Entity * io,
575                        bool render,
576                        bool update_movement) {
577 
578 	if(io && io != entities.player()) {
579 
580 		float speedfactor = io->basespeed+io->speed_modif;
581 
582 		if (speedfactor < 0) speedfactor = 0;
583 
584 		float tim=(float)time*(speedfactor);
585 
586 		if (tim<=0.f) time=0;
587 		else time=(unsigned long)tim;
588 
589 		io->frameloss+=tim-time;
590 
591 		if (io->frameloss>1.f) // recover lost time...
592 		{
593 			long tt = io->frameloss;
594 			io->frameloss-=tt;
595 			time+=tt;
596 		}
597 	}
598 
599 	if (time <= 0) goto suite;
600 
601 	if (time>200) time=200; // TO REMOVE !!!!!!!!!
602 
603 	PrepareAnim(eobj,eanim,time,io);
604 
605 	if (io)
606 	for (long count=1;count<MAX_ANIM_LAYERS;count++)
607 	{
608 		ANIM_USE * animuse=&io->animlayer[count];
609 
610 		if (animuse->cur_anim)
611 			PrepareAnim(eobj,animuse,time,io);
612 	}
613 
614 suite:
615 
616 	DESTROYED_DURING_RENDERING=NULL;
617 
618 	Cedric_AnimateDrawEntity(eobj, eanim, angle, pos, io, render, update_movement);
619 }
620 
621 
622 // Procedure for drawing Interactive Objects (Not Animated)
DrawEERIEInterMatrix(EERIE_3DOBJ * eobj,EERIEMATRIX * mat,Vec3f * poss,Entity * io,EERIE_MOD_INFO * modinfo)623 void DrawEERIEInterMatrix(EERIE_3DOBJ * eobj, EERIEMATRIX * mat, Vec3f  * poss,
624                           Entity * io, EERIE_MOD_INFO * modinfo) {
625 
626 	BIGQUAT=NULL;
627 	BIGMAT=mat;
628 
629 	if (BIGMAT==NULL) return;
630 
631 	DrawEERIEInter(eobj,NULL,poss,io,modinfo);
632 	BIGMAT=NULL;
633 }
634 // List of TO-TREAT vertex for MIPMESHING
635 
636 void specialEE_P(TexturedVertex *in,TexturedVertex *out);
637 
638 // TODO: Convert to a RenderBatch & make TextureContainer constructor private
639 TextureContainer TexSpecialColor("specialcolor_list", TextureContainer::NoInsert);
640 
641 //-----------------------------------------------------------------------------
PushVertexInTableCull(TextureContainer * pTex)642 TexturedVertex * PushVertexInTableCull(TextureContainer *pTex)
643 {
644 	if((pTex->ulNbVertexListCull+3)>pTex->ulMaxVertexListCull)
645 	{
646 		pTex->ulMaxVertexListCull+=10*3;
647 		pTex->pVertexListCull = (TexturedVertex *)realloc(pTex->pVertexListCull,
648 		                         pTex->ulMaxVertexListCull * sizeof(TexturedVertex));
649 	}
650 
651 	pTex->ulNbVertexListCull+=3;
652 	return &pTex->pVertexListCull[pTex->ulNbVertexListCull-3];
653 }
654 
655 //-----------------------------------------------------------------------------
PushVertexInTableCull_TNormalTrans(TextureContainer * pTex)656 TexturedVertex * PushVertexInTableCull_TNormalTrans(TextureContainer *pTex)
657 {
658 	if((pTex->ulNbVertexListCull_TNormalTrans+3)>pTex->ulMaxVertexListCull_TNormalTrans)
659 	{
660 		pTex->ulMaxVertexListCull_TNormalTrans+=20*3;
661 		pTex->pVertexListCull_TNormalTrans = (TexturedVertex *)realloc(
662 		                                      pTex->pVertexListCull_TNormalTrans,
663 		                                      pTex->ulMaxVertexListCull_TNormalTrans
664 		                                      * sizeof(TexturedVertex));
665 
666 		if (!pTex->pVertexListCull_TNormalTrans)
667 		{
668 			pTex->ulMaxVertexListCull_TNormalTrans=0;
669 			pTex->ulNbVertexListCull_TNormalTrans=0;
670 			return NULL;
671 		}
672 	}
673 
674 	pTex->ulNbVertexListCull_TNormalTrans+=3;
675 	return &pTex->pVertexListCull_TNormalTrans[pTex->ulNbVertexListCull_TNormalTrans-3];
676 }
677 
678 //-----------------------------------------------------------------------------
PushVertexInTableCull_TAdditive(TextureContainer * pTex)679 TexturedVertex * PushVertexInTableCull_TAdditive(TextureContainer *pTex)
680 {
681 	if((pTex->ulNbVertexListCull_TAdditive+3)>pTex->ulMaxVertexListCull_TAdditive)
682 	{
683 		pTex->ulMaxVertexListCull_TAdditive+=20*3;
684 		pTex->pVertexListCull_TAdditive = (TexturedVertex * )realloc(
685 		                                   pTex->pVertexListCull_TAdditive,
686 		                                   pTex->ulMaxVertexListCull_TAdditive
687 		                                   * sizeof(TexturedVertex));
688 
689 		if (!pTex->pVertexListCull_TAdditive)
690 		{
691 			pTex->ulMaxVertexListCull_TAdditive=0;
692 			pTex->ulNbVertexListCull_TAdditive=0;
693 			return NULL;
694 		}
695 	}
696 
697 	pTex->ulNbVertexListCull_TAdditive+=3;
698 	return &pTex->pVertexListCull_TAdditive[pTex->ulNbVertexListCull_TAdditive-3];
699 }
700 
701 //-----------------------------------------------------------------------------
PushVertexInTableCull_TSubstractive(TextureContainer * pTex)702 TexturedVertex * PushVertexInTableCull_TSubstractive(TextureContainer *pTex)
703 {
704 	if((pTex->ulNbVertexListCull_TSubstractive+3)>pTex->ulMaxVertexListCull_TSubstractive)
705 	{
706 		pTex->ulMaxVertexListCull_TSubstractive+=20*3;
707 		pTex->pVertexListCull_TSubstractive = (TexturedVertex *)realloc(
708 		                                       pTex->pVertexListCull_TSubstractive,
709 		                                       pTex->ulMaxVertexListCull_TSubstractive
710 		                                       * sizeof(TexturedVertex));
711 
712 		if (!pTex->pVertexListCull_TSubstractive)
713 		{
714 			pTex->ulMaxVertexListCull_TSubstractive=0;
715 			pTex->ulNbVertexListCull_TSubstractive=0;
716 			return NULL;
717 		}
718 	}
719 
720 	pTex->ulNbVertexListCull_TSubstractive+=3;
721 	return &pTex->pVertexListCull_TSubstractive[pTex->ulNbVertexListCull_TSubstractive-3];
722 }
723 
724 //-----------------------------------------------------------------------------
PushVertexInTableCull_TMultiplicative(TextureContainer * pTex)725 TexturedVertex * PushVertexInTableCull_TMultiplicative(TextureContainer *pTex)
726 {
727 	if((pTex->ulNbVertexListCull_TMultiplicative+3)>pTex->ulMaxVertexListCull_TMultiplicative)
728 	{
729 		pTex->ulMaxVertexListCull_TMultiplicative+=20*3;
730 		pTex->pVertexListCull_TMultiplicative = (TexturedVertex *)realloc(
731 		                                         pTex->pVertexListCull_TMultiplicative,
732 		                                         pTex->ulMaxVertexListCull_TMultiplicative
733 		                                         * sizeof(TexturedVertex));
734 
735 		if (!pTex->pVertexListCull_TMultiplicative)
736 		{
737 			pTex->ulMaxVertexListCull_TMultiplicative=0;
738 			pTex->ulNbVertexListCull_TMultiplicative=0;
739 			return NULL;
740 		}
741 	}
742 
743 	pTex->ulNbVertexListCull_TMultiplicative+=3;
744 	return &pTex->pVertexListCull_TMultiplicative[pTex->ulNbVertexListCull_TMultiplicative-3];
745 }
746 
PopOneTriangleList(TextureContainer * _pTex)747 static void PopOneTriangleList(TextureContainer *_pTex) {
748 
749 	if(!_pTex->ulNbVertexListCull) {
750 		return;
751 	}
752 
753 	GRenderer->SetCulling(Renderer::CullNone);
754 	GRenderer->SetTexture(0, _pTex);
755 
756 	if(_pTex->userflags & POLY_LATE_MIP) {
757 		const float GLOBAL_NPC_MIPMAP_BIAS = -2.2f;
758 		GRenderer->GetTextureStage(0)->SetMipMapLODBias(GLOBAL_NPC_MIPMAP_BIAS);
759 	}
760 
761 
762 	EERIEDRAWPRIM(Renderer::TriangleList, _pTex->pVertexListCull, _pTex->ulNbVertexListCull);
763 
764 	_pTex->ulNbVertexListCull = 0;
765 
766 	if(_pTex->userflags & POLY_LATE_MIP) {
767 		float biasResetVal = 0;
768 		GRenderer->GetTextureStage(0)->SetMipMapLODBias(biasResetVal);
769 	}
770 
771 }
772 
PopOneTriangleListTransparency(TextureContainer * _pTex)773 static void PopOneTriangleListTransparency(TextureContainer *_pTex) {
774 
775 	if(!_pTex->ulNbVertexListCull_TNormalTrans
776 	   && !_pTex->ulNbVertexListCull_TAdditive
777 	   && !_pTex->ulNbVertexListCull_TSubstractive
778 	   && !_pTex->ulNbVertexListCull_TMultiplicative) {
779 		return;
780 	}
781 
782 	GRenderer->SetCulling(Renderer::CullNone);
783 	GRenderer->SetTexture(0, _pTex);
784 
785 	if(_pTex->ulNbVertexListCull_TNormalTrans) {
786 		GRenderer->SetBlendFunc(Renderer::BlendDstColor, Renderer::BlendSrcColor);
787 		if(_pTex->ulNbVertexListCull_TNormalTrans) {
788 			EERIEDRAWPRIM(Renderer::TriangleList, _pTex->pVertexListCull_TNormalTrans,
789 			              _pTex->ulNbVertexListCull_TNormalTrans);
790 			_pTex->ulNbVertexListCull_TNormalTrans=0;
791 		}
792 	}
793 
794 	if(_pTex->ulNbVertexListCull_TAdditive) {
795 		GRenderer->SetBlendFunc(Renderer::BlendOne, Renderer::BlendOne);
796 		if(_pTex->ulNbVertexListCull_TAdditive) {
797 			EERIEDRAWPRIM(Renderer::TriangleList, _pTex->pVertexListCull_TAdditive,
798 			              _pTex->ulNbVertexListCull_TAdditive);
799 			_pTex->ulNbVertexListCull_TAdditive=0;
800 		}
801 	}
802 
803 	if(_pTex->ulNbVertexListCull_TSubstractive) {
804 		GRenderer->SetBlendFunc(Renderer::BlendZero, Renderer::BlendInvSrcColor);
805 		if(_pTex->ulNbVertexListCull_TSubstractive) {
806 			EERIEDRAWPRIM(Renderer::TriangleList, _pTex->pVertexListCull_TSubstractive,
807 			              _pTex->ulNbVertexListCull_TSubstractive);
808 			_pTex->ulNbVertexListCull_TSubstractive=0;
809 		}
810 	}
811 
812 	if(_pTex->ulNbVertexListCull_TMultiplicative) {
813 		GRenderer->SetBlendFunc(Renderer::BlendOne, Renderer::BlendOne);
814 		if(_pTex->ulNbVertexListCull_TMultiplicative) {
815 			EERIEDRAWPRIM(Renderer::TriangleList, _pTex->pVertexListCull_TMultiplicative,
816 			              _pTex->ulNbVertexListCull_TMultiplicative);
817 			_pTex->ulNbVertexListCull_TMultiplicative = 0;
818 		}
819 	}
820 }
821 
PopAllTriangleList()822 void PopAllTriangleList() {
823 	GRenderer->SetAlphaFunc(Renderer::CmpGreater, .5f);
824 	TextureContainer * pTex = GetTextureList();
825 	while(pTex) {
826 		PopOneTriangleList(pTex);
827 		pTex = pTex->m_pNext;
828 	}
829 	GRenderer->SetAlphaFunc(Renderer::CmpNotEqual, 0.f);
830 }
831 
832 //-----------------------------------------------------------------------------
PopOneInterZMapp(TextureContainer * _pTex)833 void PopOneInterZMapp(TextureContainer *_pTex)
834 {
835 	if(!_pTex->TextureRefinement) return;
836 
837 	GRenderer->SetBlendFunc(Renderer::BlendZero, Renderer::BlendInvSrcColor);
838 
839 	if(_pTex->TextureRefinement->vPolyInterZMap.size())
840 	{
841 		GRenderer->SetTexture(0, _pTex->TextureRefinement);
842 
843 		int iPos=0;
844 
845 		vector<SMY_ZMAPPINFO>::iterator it;
846 
847 		for (it = _pTex->TextureRefinement->vPolyInterZMap.begin();
848 			it != _pTex->TextureRefinement->vPolyInterZMap.end();
849 			++it)
850 		{
851 			SMY_ZMAPPINFO *pSMY = &(*it);
852 
853 			tTexturedVertexTab2[iPos]        = pSMY->pVertex[0];
854 			tTexturedVertexTab2[iPos].color  = Color::gray(pSMY->color[0]).toBGR();
855 			tTexturedVertexTab2[iPos].uv.x   = pSMY->uv[0];
856 			tTexturedVertexTab2[iPos++].uv.y = pSMY->uv[1];
857 			tTexturedVertexTab2[iPos]        = pSMY->pVertex[1];
858 			tTexturedVertexTab2[iPos].color  = Color::gray(pSMY->color[1]).toBGR();
859 			tTexturedVertexTab2[iPos].uv.x   = pSMY->uv[2];
860 			tTexturedVertexTab2[iPos++].uv.y = pSMY->uv[3];
861 			tTexturedVertexTab2[iPos]        = pSMY->pVertex[2];
862 			tTexturedVertexTab2[iPos].color  = Color::gray(pSMY->color[2]).toBGR();
863 			tTexturedVertexTab2[iPos].uv.x   = pSMY->uv[4];
864 			tTexturedVertexTab2[iPos++].uv.y = pSMY->uv[5];
865 		}
866 
867 		EERIEDRAWPRIM(Renderer::TriangleList, tTexturedVertexTab2, iPos);
868 
869 		_pTex->TextureRefinement->vPolyInterZMap.clear();
870 	}
871 }
872 
873 //-----------------------------------------------------------------------------
PopAllTriangleListTransparency()874 void PopAllTriangleListTransparency() {
875 
876 	GRenderer->SetFogColor(Color::none);
877 	GRenderer->SetRenderState(Renderer::AlphaBlending, true);
878 	GRenderer->SetRenderState(Renderer::DepthWrite, false);
879 	GRenderer->SetBlendFunc(Renderer::BlendDstColor, Renderer::BlendOne);
880 	GRenderer->SetAlphaFunc(Renderer::CmpGreater, .5f);
881 
882 	PopOneTriangleList(&TexSpecialColor);
883 
884 	TextureContainer * pTex = GetTextureList();
885 
886 	while(pTex)
887 	{
888 		PopOneTriangleListTransparency(pTex);
889 
890 		//ZMAP
891 		PopOneInterZMapp(pTex);
892 
893 		pTex=pTex->m_pNext;
894 	}
895 
896 	GRenderer->SetFogColor(ulBKGColor);
897 	GRenderer->SetRenderState(Renderer::AlphaBlending, false);
898 	GRenderer->SetRenderState(Renderer::DepthWrite, true);
899 	GRenderer->SetAlphaFunc(Renderer::CmpNotEqual, 0.f);
900 }
901 
902 float INVISIBILITY_OVERRIDE=0.f;
903 
904 //-----------------------------------------------------------------------------
CalculateInterZMapp(EERIE_3DOBJ * _pobj3dObj,long lIdList,long * _piInd,TextureContainer * _pTex,TexturedVertex * _pVertex)905 void CalculateInterZMapp(EERIE_3DOBJ * _pobj3dObj, long lIdList, long * _piInd,
906                          TextureContainer * _pTex, TexturedVertex * _pVertex) {
907 
908 	SMY_ZMAPPINFO sZMappInfo;
909 
910 	if( (!ZMAPMODE)||
911 		(!_pTex->TextureRefinement) ) return;
912 
913 	bool bUp = false;
914 
915 	if(fabs(_pobj3dObj->vertexlist[_piInd[0]].norm.y) >= .9f
916 	   || fabs(_pobj3dObj->vertexlist[_piInd[1]].norm.y) >= .9f
917 	   || fabs(_pobj3dObj->vertexlist[_piInd[2]].norm.y) >= .9f) {
918 		bUp = true;
919 	}
920 
921 	for(int iI=0;iI<3;iI++)
922 	{
923 		if(bUp)
924 		{
925 			sZMappInfo.uv[iI<<1]=(_pobj3dObj->vertexlist3[_piInd[iI]].v.x*( 1.0f / 50 ));
926 			sZMappInfo.uv[(iI<<1)+1]=(_pobj3dObj->vertexlist3[_piInd[iI]].v.z*( 1.0f / 50 ));
927 		}
928 		else
929 		{
930 			sZMappInfo.uv[iI<<1]=(_pobj3dObj->facelist[lIdList].u[iI]*4.f);
931 			sZMappInfo.uv[(iI<<1)+1]=(_pobj3dObj->facelist[lIdList].v[iI]*4.f);
932 		}
933 
934 		float fDist=fdist(ACTIVECAM->pos, _pobj3dObj->vertexlist3[_piInd[iI]].v)-80.f;
935 
936 		if (fDist<10.f) fDist=10.f;
937 
938 		sZMappInfo.color[iI] = (150.f - fDist) * 0.006666666f;
939 
940 		if (sZMappInfo.color[iI]<0.f) sZMappInfo.color[iI]=0.f;
941 
942 		sZMappInfo.pVertex[iI]=_pVertex[iI];
943 	}
944 
945 	//optim
946 	if(sZMappInfo.color[0] != 0.f || sZMappInfo.color[1] != 0.f || sZMappInfo.color[2] != 0.f) {
947 		_pTex->TextureRefinement->vPolyInterZMap.push_back(sZMappInfo);
948 	}
949 }
950 
951 extern long FORCE_FRONT_DRAW;
952 
DrawEERIEInter(EERIE_3DOBJ * eobj,Anglef * angle,Vec3f * poss,Entity * io,EERIE_MOD_INFO * modinfo)953 void DrawEERIEInter(EERIE_3DOBJ * eobj, Anglef * angle, Vec3f  * poss,
954                     Entity * io, EERIE_MOD_INFO * modinfo) {
955 
956 	if(!eobj) {
957 		return;
958 	}
959 
960 	DESTROYED_DURING_RENDERING = NULL;
961 
962 	// Resets 2D Bounding Box
963 	BBOXMIN.y = BBOXMIN.x = 32000;
964 	BBOXMAX.y = BBOXMAX.x = -32000;
965 	Vec3f pos = *poss;
966 
967 	// Avoids To treat an object that isn't Visible
968 	if(io && io != entities.player() && !modinfo && !MUST_DRAW && ACTIVEBKG) {
969 
970 		long xx, yy;
971 		xx = (pos.x) * ACTIVEBKG->Xmul;
972 		yy = (pos.z) * ACTIVEBKG->Zmul;
973 
974 		if(xx >= 1 && yy >= 1 && xx < ACTIVEBKG->Xsize - 1 && yy < ACTIVEBKG->Zsize - 1) {
975 
976 			long ok = 0;
977 
978 			for (long ky = yy - 1 ; ky <= yy + 1 ; ky++ )
979 			{
980 				for ( long kx = xx - 1 ; kx <= xx + 1 ; kx++ )
981 				{
982 					FAST_BKG_DATA * feg = (FAST_BKG_DATA *)&ACTIVEBKG->fastdata[kx][ky];
983 
984 					if(feg->treat) {
985 						ok = 1;
986 						break;
987 					}
988 				}
989 
990 				if ( ok )
991 					break;
992 			}
993 
994 			if ( !ok ) return;
995 		}
996 	}
997 
998 	float Xcos = 0, Ycos = 0, Zcos = 0, Xsin = 0, Ysin = 0, Zsin = 0;
999 	TexturedVertex vert_list_static[4];
1000 	long k;
1001 
1002 	long lfr, lfg, lfb;
1003 	Vec3f temporary3D;
1004 	EERIE_CAMERA Ncam;
1005 	Color3f infra;
1006 	float invisibility;
1007 	float scale;
1008 
1009 	EERIE_ANIM_Get_Scale_Invisibility(io, invisibility, scale);
1010 
1011 	if ( ( !io ) && ( INVISIBILITY_OVERRIDE != 0.f ) )
1012 		invisibility = INVISIBILITY_OVERRIDE;
1013 
1014 	// Precalc rotations
1015 	if ( angle != NULL )
1016 	{
1017 		if ( modinfo )
1018 			Zsin = radians(MAKEANGLE(angle->a + modinfo->rot.a));
1019 		else
1020 			Zsin = radians(angle->a);
1021 
1022 		Ncam.Xcos = Xcos = EEcos(Zsin);
1023 		Ncam.Xsin = Xsin = EEsin(Zsin);
1024 
1025 		if ( modinfo )
1026 			Zsin = radians(MAKEANGLE(angle->b + modinfo->rot.b));
1027 		else
1028 			Zsin = radians(angle->b);
1029 
1030 		Ncam.Ycos = Ycos = EEcos(Zsin);
1031 		Ncam.Ysin = Ysin = EEsin(Zsin);
1032 
1033 		if ( modinfo )
1034 			Zsin = radians(MAKEANGLE(angle->g + modinfo->rot.g));
1035 		else
1036 			Zsin = radians(angle->g);
1037 
1038 		Ncam.Zcos = Zcos = EEcos(Zsin);
1039 		Ncam.Zsin = Zsin = EEsin(Zsin);
1040 	}
1041 
1042 	// Test for Mipmeshing then pre-computes vertices
1043 	vdist = 0.f;
1044 	{
1045 		ResetBBox3D( io );
1046 
1047 		for(size_t i = 0 ; i < eobj->vertexlist.size(); i++) {
1048 
1049 			if(modinfo && !angle && BIGMAT) {
1050 				vert_list_static[0].p = (eobj->vertexlist[i].v - modinfo->link_position) * scale;
1051 			} else if(scale != 1.f) {
1052 				vert_list_static[0].p = eobj->vertexlist[i].v * scale;
1053 			} else {
1054 				vert_list_static[0].p = eobj->vertexlist[i].v;
1055 			}
1056 
1057 			if ( !angle )
1058 			{
1059 				if ( ( io != NULL ) && ( modinfo == NULL ) )
1060 				{
1061 
1062 					vert_list_static[0].p -= io->obj->pbox->vert[0].initpos * scale-io->obj->point0;
1063 				}
1064 
1065 				if(BIGQUAT == NULL) {
1066 					VectorMatrixMultiply(&vert_list_static[1].p, &vert_list_static[0].p, BIGMAT);
1067 				} else {
1068 					TransformVertexQuat(BIGQUAT, &vert_list_static[0].p, &vert_list_static[1].p);
1069 				}
1070 
1071 				eobj->vertexlist3[i].v = vert_list_static[1].p += pos;
1072 
1073 				specialEE_RT( &vert_list_static[1], &eobj->vertexlist[i].vworld );
1074 				specialEE_P( &eobj->vertexlist[i].vworld, &eobj->vertexlist[i].vert );
1075 			}
1076 			else
1077 			{
1078 				YRotatePoint(&vert_list_static[0].p, &vert_list_static[1].p, Ycos, Ysin);
1079 				XRotatePoint(&vert_list_static[1].p, &vert_list_static[0].p, Xcos, Xsin);
1080 
1081 				// Misc Optim to avoid 1 infrequent rotation around Z
1082 				if(Zsin == 0.f) {
1083 
1084 					eobj->vertexlist3[i].v = vert_list_static[0].p += pos;
1085 
1086 					specialEE_RT(&vert_list_static[0],&eobj->vertexlist[i].vworld);
1087 					specialEE_P(&eobj->vertexlist[i].vworld,&eobj->vertexlist[i].vert);
1088 				}
1089 				else
1090 				{
1091 					ZRotatePoint(&vert_list_static[0].p, &vert_list_static[1].p, Zcos, Zsin);
1092 					eobj->vertexlist3[i].v = vert_list_static[1].p += pos;
1093 
1094 					specialEE_RT( &vert_list_static[1], &eobj->vertexlist[i].vworld);
1095 					specialEE_P( &eobj->vertexlist[i].vworld, &eobj->vertexlist[i].vert);
1096 				}
1097 			}
1098 
1099 			// Memorizes 2D Bounding Box using vertex min/max x,y pos
1100 			if(eobj->vertexlist[i].vert.rhw > 0.f) {
1101 
1102 				if ((eobj->vertexlist[i].vert.p.x >= -32000) &&
1103 					(eobj->vertexlist[i].vert.p.x <= 32000) &&
1104 					(eobj->vertexlist[i].vert.p.y >= -32000) &&
1105 					(eobj->vertexlist[i].vert.p.y <= 32000))
1106 				{
1107 					BBOXMIN.x=min(BBOXMIN.x,eobj->vertexlist[i].vert.p.x);
1108 					BBOXMAX.x=max(BBOXMAX.x,eobj->vertexlist[i].vert.p.x);
1109 					BBOXMIN.y=min(BBOXMIN.y,eobj->vertexlist[i].vert.p.y);
1110 					BBOXMAX.y=max(BBOXMAX.y,eobj->vertexlist[i].vert.p.y);
1111 				}
1112 			}
1113 
1114 			AddToBBox3D(io,&eobj->vertexlist3[i].v);
1115 		}
1116 	}
1117 
1118 	if(BBOXMAX.x <= 1 || BBOXMIN.x >= DANAESIZX - 1
1119 	   || BBOXMAX.y <= 1 || BBOXMIN.y >= DANAESIZY - 1) {
1120 		goto finish;
1121 	}
1122 
1123 	if ((!modinfo) && (ARX_SCENE_PORTAL_ClipIO(io,&pos)))
1124 		return;
1125 
1126 
1127 	// Precalc local lights for this object then interpolate
1128 	if(FRAME_COUNT <= 0) {
1129 		MakeCLight(io,&infra,angle,&pos,eobj,BIGMAT,BIGQUAT);
1130 	}
1131 
1132 	INTER_DRAW++;
1133 	float ddist;
1134 	ddist=0;
1135 	long need_halo;
1136 	need_halo=0;
1137 
1138 	if(io && (io->halo.flags & HALO_ACTIVE)) {
1139 
1140 		float mdist=ACTIVECAM->cdepth;
1141 		ddist=mdist-fdist(pos, ACTIVECAM->pos);
1142 		ddist=(ddist/mdist);
1143 		ddist*=ddist*ddist*ddist*ddist*ddist;
1144 
1145 		if (ddist<=0.25f) ddist=0.25f;
1146 		else if (ddist>0.9f) ddist=0.9f;
1147 
1148 		need_halo=1;
1149 	}
1150 
1151 	{
1152 	long special_color_flag = 0;
1153 	Color3f special_color = Color3f::black;
1154 
1155 	if(io) {
1156 
1157 		float poisonpercent = 0.f;
1158 		float trappercent = 0.f;
1159 		float secretpercent = 0.f;
1160 
1161 		if ( io->ioflags & IO_NPC )
1162 		{
1163 			if ( io->_npcdata->poisonned > 0.f )
1164 			{
1165 				poisonpercent = io->_npcdata->poisonned * ( 1.0f / 20 );
1166 
1167 				if ( poisonpercent > 1.f ) poisonpercent = 1.f;
1168 			}
1169 		}
1170 
1171 		if((io->ioflags & IO_ITEM) && io->poisonous > 0.f && io->poisonous_count != 0) {
1172 			poisonpercent = io->poisonous * (1.f / 20);
1173 			if(poisonpercent > 1.f) {
1174 				poisonpercent = 1.f;
1175 			}
1176 		}
1177 
1178 		if ((io->ioflags & IO_FIX) && (io->_fixdata->trapvalue>-1))
1179 		{
1180 			trappercent=(float)TRAP_DETECT-(float)io->_fixdata->trapvalue;
1181 
1182 			if (trappercent>0.f)
1183 			{
1184 				trappercent = 0.6f + trappercent * ( 1.0f / 100 );
1185 
1186 				if (trappercent<0.6f) trappercent=0.6f;
1187 
1188 				if (trappercent>1.f) trappercent=1.f;
1189 			}
1190 		}
1191 
1192 		if((io->ioflags & IO_FIX) && io->secretvalue > -1) {
1193 
1194 			secretpercent=(float)TRAP_SECRET-(float)io->secretvalue;
1195 
1196 			if (secretpercent>0.f)
1197 			{
1198 				secretpercent = 0.6f + secretpercent * .01f;
1199 
1200 				if (secretpercent<0.6f) secretpercent=0.6f;
1201 
1202 				if (secretpercent>1.f) secretpercent=1.f;
1203 			}
1204 		}
1205 
1206 		if(poisonpercent > 0.f) {
1207 			special_color_flag = 1;
1208 			special_color = Color3f::green;
1209 		}
1210 
1211 		if(trappercent > 0.f) {
1212 			special_color_flag = 1;
1213 			special_color = Color3f(trappercent, 1.f - trappercent, 1.f - trappercent);
1214 		}
1215 
1216 		if(secretpercent > 0.f) {
1217 			special_color_flag = 1;
1218 			special_color = Color3f(1.f - secretpercent, 1.f - secretpercent, secretpercent);
1219 		}
1220 
1221 		if (io->sfx_flag & SFX_TYPE_YLSIDE_DEATH)
1222 		{
1223 			if (io->show==SHOW_FLAG_TELEPORTING)
1224 			{
1225 				float fCalc = io->sfx_time + FrameDiff;
1226 				io->sfx_time = checked_range_cast<unsigned long>(fCalc);
1227 
1228 				if (io->sfx_time >= (unsigned long)(arxtime))
1229 					io->sfx_time = (unsigned long)(arxtime);
1230 			}
1231 			else
1232 			{
1233 				special_color_flag = 1;
1234 				float elapsed = float(arxtime) - io->sfx_time;
1235 
1236 				if(elapsed > 0.f) {
1237 
1238 					if(elapsed < 3000.f) { // 5 seconds to red
1239 						float ratio = elapsed * (1.0f / 3000);
1240 						special_color = Color3f(1.f, 1.f - ratio, 1.f - ratio);
1241 						AddRandomSmoke( io, 1 );
1242 
1243 					} else if(elapsed < 6000.f) { // 5 seconds to White
1244 						float ratio = ( elapsed - 3000.f ) * ( 1.0f / 3000 );
1245 						special_color = Color3f(1.f, ratio, ratio);
1246 						special_color_flag = 2;
1247 						AddRandomSmoke(io, 2);
1248 
1249 					} else if (elapsed < 8000.f) { // 5 seconds to White
1250 						special_color = Color3f::gray((elapsed - 6000.f) * (1.f / 2000));
1251 						special_color_flag = 2;
1252 						AddRandomSmoke(io, 2);
1253 
1254 					} else { // SFX finish
1255 
1256 						special_color_flag = 0;
1257 
1258 						io->sfx_time=0;
1259 
1260 						if (io->ioflags & IO_NPC)
1261 						{
1262 							MakePlayerAppearsFX(io);
1263 							AddRandomSmoke(io,50);
1264 							Color3f rgb = io->_npcdata->blood_color.to<float>();
1265 							EERIE_SPHERE sp;
1266 							sp.origin = io->pos;
1267 							sp.radius = 200.f;
1268 							long count=6;
1269 
1270 							while(count--) {
1271 
1272 								SpawnGroundSplat(&sp,&rgb,rnd()*30.f+30.f,1);
1273 								sp.origin.y-=rnd()*150.f;
1274 
1275 								ARX_PARTICLES_Spawn_Splat(sp.origin, 200.f, io->_npcdata->blood_color);
1276 
1277 								sp.origin.x=io->pos.x+rnd()*200.f-100.f;
1278 								sp.origin.y=io->pos.y+rnd()*20.f-10.f;
1279 								sp.origin.z=io->pos.z+rnd()*200.f-100.f;
1280 								sp.radius=rnd()*100.f+100.f;
1281 							}
1282 
1283 							if (io->sfx_flag & SFX_TYPE_INCINERATE)
1284 							{
1285 								io->sfx_flag&=~SFX_TYPE_INCINERATE;
1286 								io->sfx_flag&=~SFX_TYPE_YLSIDE_DEATH;
1287 								long num=ARX_SPELLS_GetSpellOn(io, SPELL_INCINERATE);
1288 
1289 								while (num>=0)
1290 								{
1291 									spells[num].tolive=0;
1292 									ARX_DAMAGES_DamageNPC(io,20,0,1,&entities.player()->pos);
1293 									num=ARX_SPELLS_GetSpellOn(io, SPELL_INCINERATE);
1294 								}
1295 							}
1296 							else
1297 							{
1298 								io->sfx_flag&=~SFX_TYPE_YLSIDE_DEATH;
1299 								ARX_INTERACTIVE_DestroyIO(io);
1300 								DESTROYED_DURING_RENDERING=io;
1301 								return;
1302 							}
1303 
1304 						}
1305 					}
1306 				}
1307 				else
1308 				{
1309 					ARX_DEAD_CODE();
1310 					//To avoid using special_color when it is not defined, currently equal 0
1311 				}
1312 			}
1313 		}
1314 	}
1315 
1316 	float prec;
1317 	prec=1.f/(ACTIVECAM->cdepth*ACTIVECAM->Zmul);
1318 
1319 	for(size_t i = 0; i < eobj->facelist.size(); i++) {
1320 		long paf[3];
1321 		paf[0]=eobj->facelist[i].vid[0];
1322 		paf[1]=eobj->facelist[i].vid[1];
1323 		paf[2]=eobj->facelist[i].vid[2];
1324 
1325 		//CULL3D
1326 		Vec3f nrm = eobj->vertexlist3[paf[0]].v - ACTIVECAM->pos;
1327 
1328 		if(!(eobj->facelist[i].facetype&POLY_DOUBLESIDED)) {
1329 			Vec3f normV10;
1330 			Vec3f normV20;
1331 			normV10 = eobj->vertexlist3[paf[1]].v - eobj->vertexlist3[paf[0]].v;
1332 			normV20 = eobj->vertexlist3[paf[2]].v - eobj->vertexlist3[paf[0]].v;
1333 			Vec3f normFace;
1334 			normFace.x=(normV10.y*normV20.z)-(normV10.z*normV20.y);
1335 			normFace.y=(normV10.z*normV20.x)-(normV10.x*normV20.z);
1336 			normFace.z=(normV10.x*normV20.y)-(normV10.y*normV20.x);
1337 
1338 			if((dot( normFace , nrm )>0.f) ) continue;
1339 		}
1340 
1341 		TexturedVertex * vert_list;
1342 		TextureContainer * pTex;
1343 
1344 		if(eobj->facelist[i].texid<0)
1345 			continue;
1346 
1347 		pTex = eobj->texturecontainer[eobj->facelist[i].texid];
1348 		if(!pTex)
1349 			continue;
1350 
1351 		if ((io) && (io->ioflags & IO_ANGULAR))
1352 			MakeCLight2(io,&infra,angle,&pos,eobj,BIGMAT,BIGQUAT,i);
1353 
1354 		float			fTransp = 0.f;
1355 
1356 		if(	(eobj->facelist[i].facetype&POLY_TRANS) ||
1357 			(invisibility>0.f) )
1358 		{
1359 			if(invisibility>0.f)
1360 				fTransp=2.f-invisibility;
1361 			else
1362 				fTransp=eobj->facelist[i].transval;
1363 
1364 			if (fTransp>=2.f)  //MULTIPLICATIVE
1365 			{
1366 				fTransp*=( 1.0f / 2 );
1367 				fTransp+=0.5f;
1368 
1369 				{
1370 					vert_list=PushVertexInTableCull_TMultiplicative(pTex);
1371 				}
1372 			}
1373 			else
1374 			{
1375 				if(fTransp>=1.f) //ADDITIVE
1376 				{
1377 					fTransp-=1.f;
1378 
1379 					{
1380 						vert_list=PushVertexInTableCull_TAdditive(pTex);
1381 					}
1382 				}
1383 				else
1384 				{
1385 					if(fTransp>0.f)  //NORMAL TRANS
1386 					{
1387 						fTransp=1.f-fTransp;
1388 
1389 						{
1390 							vert_list=PushVertexInTableCull_TNormalTrans(pTex);
1391 						}
1392 					}
1393 					else  //SUBTRACTIVE
1394 					{
1395 						fTransp=1.f-fTransp;
1396 
1397 						{
1398 							vert_list=PushVertexInTableCull_TSubstractive(pTex);
1399 						}
1400 					}
1401 				}
1402 			}
1403 		}
1404 		else
1405 		{
1406 			{
1407 				vert_list=PushVertexInTableCull(pTex);
1408 			}
1409 		}
1410 
1411 		vert_list[0]=eobj->vertexlist[paf[0]].vert;
1412 		vert_list[1]=eobj->vertexlist[paf[1]].vert;
1413 		vert_list[2]=eobj->vertexlist[paf[2]].vert;
1414 
1415 		vert_list[0].uv.x=eobj->facelist[i].u[0];
1416 		vert_list[0].uv.y=eobj->facelist[i].v[0];
1417 		vert_list[1].uv.x=eobj->facelist[i].u[1];
1418 		vert_list[1].uv.y=eobj->facelist[i].v[1];
1419 		vert_list[2].uv.x=eobj->facelist[i].u[2];
1420 		vert_list[2].uv.y=eobj->facelist[i].v[2];
1421 
1422 		if(FORCE_FRONT_DRAW) {
1423 			vert_list[0].p.z *= IN_FRONT_DIVIDER_ITEMS;
1424 			vert_list[1].p.z *= IN_FRONT_DIVIDER_ITEMS;
1425 			vert_list[2].p.z *= IN_FRONT_DIVIDER_ITEMS;
1426 		}
1427 
1428 		// Treat WATER Polys (modify UVs)
1429 		if (eobj->facelist[i].facetype & POLY_WATER)
1430 		{
1431 			for (k=0;k<3;k++)
1432 			{
1433 				vert_list[k].uv.x=eobj->facelist[i].u[k];
1434 				vert_list[k].uv.y=eobj->facelist[i].v[k];
1435 				ApplyWaterFXToVertex(&eobj->vertexlist[eobj->facelist[i].vid[k]].v, &vert_list[k], 0.3f);
1436 			}
1437 		}
1438 
1439 	if (FRAME_COUNT<=0)
1440 	{
1441 		if (io)
1442 		{
1443 			// Frozen status override all other colors
1444 			if (io->ioflags & IO_FREEZESCRIPT)
1445 			{
1446 				vert_list[0].color=vert_list[1].color=vert_list[2].color=0xFF0000FF;
1447 			}
1448 			// Is it a Glowing Poly ?
1449 			else if (eobj->facelist[i].facetype & POLY_GLOW)
1450 				vert_list[0].color=vert_list[1].color=vert_list[2].color=0xffffffff;
1451 			// Are we using Normal Illuminations ?
1452 			else if (USEINTERNORM)
1453 			{
1454 				for (long j=0;j<3;j++)
1455 				{
1456 					vert_list[j].color=eobj->vertexlist3[paf[j]].vert.color;
1457 				}
1458 			}
1459 			// Are we using IMPROVED VISION view ?
1460 			else if(Project.improve) {
1461 				vert_list[0].color = vert_list[1].color = vert_list[2].color = io->infracolor.toBGR();
1462 			} else {
1463 				vert_list[0].color = vert_list[1].color = vert_list[2].color = Color::white.toBGR();
1464 			}
1465 
1466 			if(Project.improve)
1467 			{
1468 				int to=3;
1469 
1470 				for (long k=0;k<to;k++)
1471 				{
1472 					long lfr,lfb;
1473 					float fr,fb;
1474 					long lr=(vert_list[k].color>>16) & 255;
1475 					float ffr=(float)(lr);
1476 
1477 					float dd=(vert_list[k].rhw*prec);
1478 
1479 					if (dd>1.f) dd=1.f;
1480 
1481 					if (dd<0.f) dd=0.f;
1482 
1483 					fb = ((1.f - dd) * 6.f + (EEfabs(eobj->vertexlist[paf[k]].norm.x)
1484 					      + EEfabs(eobj->vertexlist[paf[k]].norm.y))) * 0.125f;
1485 					fr = ((.6f - dd) * 6.f + (EEfabs(eobj->vertexlist[paf[k]].norm.z)
1486 					      + EEfabs(eobj->vertexlist[paf[k]].norm.y))) * 0.125f;
1487 
1488 					if (fr<0.f) fr=0.f;
1489 					else fr=max(ffr,fr*255.f);
1490 
1491 					fr=min(fr,255.f);
1492 					fb*=255.f;
1493 					fb=min(fb,255.f);
1494 					lfr = fr;
1495 					lfb = fb;
1496 					vert_list[k].color=( 0xff001E00L | ( (lfr & 255) << 16) | (lfb & 255) );
1497 				}
1498 			}
1499 		}
1500 		else
1501 		{
1502 			// Treating GLOWING POLY (unaffected by light)
1503 			if (eobj->facelist[i].facetype & POLY_GLOW)
1504 				vert_list[0].color=vert_list[1].color=vert_list[2].color=0xffffffff;
1505 				else if (USEINTERNORM) // using INTERNORM lighting
1506 			{
1507 				for (long j=0;j<3;j++) {
1508 					vert_list[j].color = eobj->vertexlist3[paf[j]].vert.color;
1509 				}
1510 			} else if(Project.improve) {
1511 				// using IMPROVED VISION view
1512 				vert_list[2].color = Color3f(.6f, 0.f, 1.f).toBGR();
1513 				vert_list[0].color = vert_list[1].color = vert_list[2].color;
1514 			} else {
1515 				// using default white
1516 				vert_list[0].color = vert_list[1].color = vert_list[2].color = Color::white.toBGR();
1517 			}
1518 		}
1519 
1520 		if(special_color_flag & 1) {
1521 			for(long j = 0 ; j < 3 ; j++) {
1522 				Color color = Color::fromBGR(vert_list[j].color);
1523 				color.r = long(color.r * special_color.r) & 255;
1524 				color.g = long(color.g * special_color.g) & 255;
1525 				color.b = long(color.b * special_color.b) & 255;
1526 				vert_list[j].color = color.toBGR();
1527 			}
1528 		}
1529 
1530 	}
1531 
1532 	if (FRAME_COUNT!=0)
1533 	for (long j=0;j<3;j++)
1534 		vert_list[j].color = eobj->facelist[i].color[j].toBGRA();
1535 	else
1536 	for (long j=0;j<3;j++)
1537 		eobj->facelist[i].color[j]=Color::fromBGRA(vert_list[j].color);
1538 
1539 	// Transparent poly: storing info to draw later
1540 	if((eobj->facelist[i].facetype & POLY_TRANS) || invisibility > 0.f) {
1541 		vert_list[0].color = vert_list[1].color = vert_list[2].color = Color::gray(fTransp).toBGR();
1542 	}
1543 
1544 	if((io)&&(io->ioflags&IO_ZMAP)) {
1545 		CalculateInterZMapp(eobj,i,paf,pTex,vert_list);
1546 	}
1547 
1548 	////////////////////////////////////////////////////////////////////////
1549 	// HALO HANDLING START
1550 	if	(need_halo)
1551 	{
1552 		Ncam.Xcos = 1.f;
1553 		Ncam.Xsin = 0.f;
1554 		Ncam.Zcos = 1.f;
1555 		Ncam.Zsin = 0.f;
1556 		float power=radians(MAKEANGLE(subj.angle.b));
1557 		Ncam.Ycos = (float)EEcos(power);
1558 		Ncam.Ysin = (float)EEsin(power);
1559 		float tot=0;
1560 		float _ffr[3];
1561 
1562 		TexturedVertex * workon=vert_list;
1563 
1564 		for (long o=0;o<3;o++)
1565 		{
1566 			if(BIGMAT) {
1567 				VectorMatrixMultiply(&temporary3D, &eobj->vertexlist[paf[o]].norm, BIGMAT);
1568 			} else {
1569 				YXZRotatePoint(&eobj->vertexlist[paf[o]].norm, &temporary3D, &Ncam);
1570 			}
1571 
1572 			power=255.f-(float)EEfabs(255.f*(temporary3D.z)*( 1.0f / 2 ));
1573 
1574 			if (power>255.f)
1575 			{
1576 				power=255.f;
1577 			}
1578 			else if (power<0.f)
1579 				power=0.f;
1580 
1581 			tot+=power;
1582 
1583 			_ffr[o]=power;
1584 			lfr = io->halo.color.r * power;
1585 			lfg = io->halo.color.g * power;
1586 			lfb = io->halo.color.b * power;
1587 			workon[o].color = (0xFF << 24) | ((lfr & 0xFF) << 16) | ((lfg & 0xFF) << 8) | (lfb & 0xFF);
1588 		}
1589 
1590 			if (tot>150.f)
1591 			{
1592 				long first;
1593 				long second;
1594 				long third;
1595 
1596 				if ( (_ffr[0]>=_ffr[1]) && (_ffr[1]>=_ffr[2]))
1597 			{
1598 				first = 0;
1599 				second = 1;
1600 				third = 2;
1601 			}
1602 				else if ( (_ffr[0]>=_ffr[2]) && (_ffr[2]>=_ffr[1]))
1603 			{
1604 				first = 0;
1605 				second = 2;
1606 				third = 1;
1607 			}
1608 				else if ( (_ffr[1]>=_ffr[0]) && (_ffr[0]>=_ffr[2]))
1609 			{
1610 				first = 1;
1611 				second = 0;
1612 				third = 2;
1613 			}
1614 				else if ( (_ffr[1]>=_ffr[2]) && (_ffr[2]>=_ffr[0]))
1615 			{
1616 				first = 1;
1617 				second = 2;
1618 				third = 0;
1619 			}
1620 				else if ( (_ffr[2]>=_ffr[0]) && (_ffr[0]>=_ffr[1]))
1621 			{
1622 				first = 2;
1623 				second = 0;
1624 				third = 1;
1625 			}
1626 				else
1627 			{
1628 				first = 2;
1629 				second = 1;
1630 				third = 0;
1631 			}
1632 
1633 			if ((_ffr[first] > 70.f) && (_ffr[second] > 60.f))
1634 				{
1635 					Vec3f vect1,vect2;
1636 					TexturedVertex * vert=&LATERDRAWHALO[(HALOCUR<<2)];
1637 
1638 					if(HALOCUR < ((long)HALOMAX) - 1) {
1639 						HALOCUR++;
1640 					}
1641 
1642 					memcpy(&vert[0],&workon[first],sizeof(TexturedVertex));
1643 					memcpy(&vert[1],&workon[first],sizeof(TexturedVertex));
1644 					memcpy(&vert[2],&workon[second],sizeof(TexturedVertex));
1645 					memcpy(&vert[3],&workon[second],sizeof(TexturedVertex));
1646 
1647 					float siz = ddist * (io->halo.radius * 1.5f * (EEsin((arxtime.get_frame_time()+i) * .01f) * .1f
1648 					                                               + .7f)) * .6f;
1649 					vect1.x=workon[first].p.x-workon[third].p.x;
1650 					vect1.y=workon[first].p.y-workon[third].p.y;
1651 					float len1=1.f/ffsqrt(vect1.x*vect1.x+vect1.y*vect1.y);
1652 
1653 					if (vect1.x<0.f) len1*=1.2f;
1654 
1655 					vect1.x*=len1;
1656 					vect1.y*=len1;
1657 					vect2.x=workon[second].p.x-workon[third].p.x;
1658 					vect2.y=workon[second].p.y-workon[third].p.y;
1659 					float len2=1.f/ffsqrt(vect2.x*vect2.x+vect2.y*vect2.y);
1660 
1661 					if (vect2.x<0.f) len2*=1.2f;
1662 
1663 					vect2.x*=len2;
1664 					vect2.y*=len2;
1665 				vert[1].p.x += (vect1.x + 0.2f - rnd() * 0.1f) * siz;
1666 				vert[1].p.y += (vect1.y + 0.2f - rnd() * 0.1f) * siz;
1667 					vert[1].color=0xFF000000;
1668 
1669 					vert[0].p.z += 0.0001f;
1670 					vert[3].p.z += 0.0001f;
1671 
1672 					vert[1].rhw*=.8f;
1673 					vert[2].rhw*=.8f;
1674 				vert[2].p.x += (vect2.x + 0.2f - rnd() * 0.1f) * siz;
1675 				vert[2].p.y += (vect2.y + 0.2f - rnd() * 0.1f) * siz;
1676 
1677 					if (io->halo.flags & HALO_NEGATIVE)
1678 						vert[2].color=0x00000000;
1679 					else
1680 						vert[2].color=0xFF000000;
1681 				}
1682 			}
1683 		}
1684 	}
1685 
1686 // HALO HANDLING END
1687 ////////////////////////////////////////////////////////////////////////
1688 	}
1689 finish:
1690 
1691 	// storing 2D Bounding Box info
1692 	if (io)
1693 	{
1694 		io->bbox1.x=(short)BBOXMIN.x;
1695 		io->bbox2.x=(short)BBOXMAX.x;
1696 		io->bbox1.y=(short)BBOXMIN.y;
1697 		io->bbox2.y=(short)BBOXMAX.y;
1698 	}
1699 }
1700 
ResetAnim(ANIM_USE * eanim)1701 void ResetAnim(ANIM_USE * eanim)
1702 {
1703 	if (eanim==NULL) return;
1704 
1705 	eanim->ctime=0;
1706 	eanim->lastframe=-1;
1707 	eanim->flags&=~EA_PAUSED;
1708 	eanim->flags&=~EA_ANIMEND;
1709 	eanim->flags&=~EA_LOOP;
1710 	eanim->flags&=~EA_FORCEPLAY;
1711 }
1712 
llightsInit()1713 void llightsInit() {
1714 	for(long i = 0; i < MAX_LLIGHTS; i++) {
1715 		llights[i] = NULL;
1716 		dists[i] = 999999999.f;
1717 		values[i] = 999999999.f;
1718 	}
1719 }
1720 
1721 // Inserts Light in the List of Nearest Lights
Insertllight(EERIE_LIGHT * el,float dist)1722 void Insertllight(EERIE_LIGHT * el,float dist)
1723 {
1724 	if (el==NULL) return;
1725 
1726 	float threshold=el->fallend+560.f;
1727 	if (dist > threshold) return;
1728 
1729 	{
1730 		float val = dist - el->fallend;
1731 
1732 		if (val<0) val=0;
1733 
1734 		for (long i=0;i<MAX_LLIGHTS;i++)
1735 		{
1736 			if (llights[i]==NULL)
1737 			{
1738 				llights[i]=el;
1739 				dists[i]=dist;
1740 				values[i]=val;
1741 				return;
1742 			}
1743 			else if (val <= values[i])  // Inserts light at the right place
1744 			{
1745 				for (long j=MAX_LLIGHTS-2;j>=i;j--)
1746 				{
1747 					if (llights[j])
1748 					{
1749 						llights[j+1]=llights[j];
1750 						dists[j+1]=dists[j];
1751 						values[j+1]=values[j];
1752 					}
1753 				}
1754 
1755 				llights[i]=el;
1756 				dists[i]=dist;
1757 				values[i]=val;
1758 				return;
1759 			}
1760 		}
1761 	}
1762 }
1763 
1764 // Precalcs some misc things for lights
Preparellights(Vec3f * pos)1765 void Preparellights(Vec3f * pos) {
1766 	for (long i = 0; i < MAX_LLIGHTS; i++) {
1767 		EERIE_LIGHT * el = llights[i];
1768 		if(el) {
1769 			TCAM[i].pos = el->pos;
1770 			SetTargetCamera(&TCAM[i],pos->x,pos->y,pos->z);
1771 			F_PrepareCamera(&TCAM[i]);
1772 		}
1773 	}
1774 }
1775 
EERIE_ANIMMANAGER_Clear(long i)1776 void EERIE_ANIMMANAGER_Clear(long i) {
1777 
1778 	for(long k = 0; k < animations[i].alt_nb; k++) {
1779 		ReleaseAnim(animations[i].anims[k]), animations[i].anims[k] = NULL;
1780 	}
1781 
1782 	free(animations[i].anims), animations[i].anims = NULL;
1783 
1784 	animations[i].path.clear();
1785 }
1786 
EERIE_ANIMMANAGER_ClearAll()1787 void EERIE_ANIMMANAGER_ClearAll() {
1788 
1789 	for(size_t i = 0; i < MAX_ANIMATIONS; i++) {
1790 		if(!animations[i].path.empty()) {
1791 			EERIE_ANIMMANAGER_Clear(i);
1792 		}
1793 	}
1794 
1795 	free(grps), grps = NULL;
1796 }
1797 
EERIE_ANIMMANAGER_ReloadAll()1798 void EERIE_ANIMMANAGER_ReloadAll() {
1799 
1800 	BOOST_FOREACH(Entity * e, entities) {
1801 		if(e) {
1802 
1803 			for(size_t j = 0; j < MAX_ANIMS; j++) {
1804 				EERIE_ANIMMANAGER_ReleaseHandle(e->anims[j]);
1805 				e->anims[j] = NULL;
1806 			}
1807 
1808 			for(size_t count = 0; count < MAX_ANIM_LAYERS; count++) {
1809 				memset(&e->animlayer[count], 0, sizeof(ANIM_USE));
1810 				e->animlayer[count].cur_anim = NULL;
1811 				e->animlayer[count].next_anim = NULL;
1812 			}
1813 		}
1814 	}
1815 
1816 	for(size_t i = 0; i < MAX_ANIMATIONS; i++) {
1817 		if(!animations[i].path.empty()) {
1818 			res::path path = animations[i].path;
1819 			EERIE_ANIMMANAGER_Clear(i);
1820 			EERIE_ANIMMANAGER_Load(path);
1821 		}
1822 	}
1823 }
1824