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