1 /*
2  * Copyright 2011-2012 Arx Libertatis Team (see the AUTHORS file)
3  *
4  * This file is part of Arx Libertatis.
5  *
6  * Arx Libertatis is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Arx Libertatis is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Arx Libertatis.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 /* Based on:
20 ===========================================================================
21 ARX FATALIS GPL Source Code
22 Copyright (C) 1999-2010 Arkane Studios SA, a ZeniMax Media company.
23 
24 This file is part of the Arx Fatalis GPL Source Code ('Arx Fatalis Source Code').
25 
26 Arx Fatalis Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
27 License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
28 
29 Arx Fatalis Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
30 warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
31 
32 You should have received a copy of the GNU General Public License along with Arx Fatalis Source Code.  If not, see
33 <http://www.gnu.org/licenses/>.
34 
35 In addition, the Arx Fatalis Source Code is also subject to certain additional terms. You should have received a copy of these
36 additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Arx
37 Fatalis Source Code. If not, please request a copy in writing from Arkane Studios at the address below.
38 
39 If you have questions concerning this license or the applicable additional terms, you may contact in writing Arkane Studios, c/o
40 ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
41 ===========================================================================
42 */
43 
44 #include "animation/AnimationRender.h"
45 
46 #include <stddef.h>
47 #include <cstdlib>
48 #include <cstring>
49 #include <algorithm>
50 
51 #include "animation/Animation.h"
52 
53 #include "core/Application.h"
54 #include "core/GameTime.h"
55 #include "core/Core.h"
56 
57 #include "game/Damage.h"
58 #include "game/Equipment.h"
59 #include "game/EntityManager.h"
60 #include "game/NPC.h"
61 #include "game/Player.h"
62 #include "game/Spells.h"
63 
64 #include "graphics/BaseGraphicsTypes.h"
65 #include "graphics/GraphicsTypes.h"
66 #include "graphics/Draw.h"
67 #include "graphics/Math.h"
68 #include "graphics/Renderer.h"
69 #include "graphics/Vertex.h"
70 #include "graphics/data/Mesh.h"
71 #include "graphics/data/MeshManipulation.h"
72 #include "graphics/data/TextureContainer.h"
73 #include "graphics/particle/ParticleEffects.h"
74 
75 #include "math/Angle.h"
76 #include "math/Vector3.h"
77 
78 #include "physics/Collisions.h"
79 
80 #include "platform/Platform.h"
81 
82 #include "scene/Light.h"
83 #include "scene/GameSound.h"
84 #include "scene/Scene.h"
85 #include "scene/Interactive.h"
86 
87 using std::min;
88 using std::max;
89 
90 unsigned char * grps = NULL;
91 static long max_grps = 0;
92 extern long FORCE_NO_HIDE;
93 extern long USEINTERNORM;
94 extern long INTER_DRAW;
95 
96 extern float dists[];
97 extern long BH_MODE;
98 extern int iHighLight;
99 
100 extern TextureContainer TexSpecialColor;
101 
102 extern long TSU_TEST_NB;
103 extern long TSU_TEST_NB_LIGHT;
104 
105 //#define USE_SOFTWARE_CLIPPING
106 #ifdef USE_SOFTWARE_CLIPPING
107 	float SOFTNEARCLIPPZ=1.f;
108 #endif
109 
110 /* Init bounding box */
Cedric_ResetBoundingBox(Entity * io)111 inline	static	void	Cedric_ResetBoundingBox(Entity * io)
112 {
113 	// resets 2D Bounding Box
114 	BBOXMIN.y = BBOXMIN.x = 32000;
115 	BBOXMAX.y = BBOXMAX.x = -32000;
116 	// Resets 3D Bounding Box
117 	ResetBBox3D(io);
118 }
119 
120 extern float INVISIBILITY_OVERRIDE;
121 extern long EXTERNALVIEW;
Cedric_GetScale(float & scale,float & invisibility,Entity * io)122 static	void	Cedric_GetScale(float & scale, float & invisibility, Entity * io)
123 {
124 	if (io)
125 	{
126 		invisibility = io->invisibility;
127 
128 		if (invisibility > 1.f) invisibility -= 1.f;
129 
130 		if ((io != entities.player()) && (invisibility > 0.f) && (!EXTERNALVIEW))
131 		{
132 			long num = ARX_SPELLS_GetSpellOn(io, SPELL_INVISIBILITY);
133 
134 			if (num >= 0)
135 			{
136 				if (player.Full_Skill_Intuition > spells[num].caster_level * 10)
137 				{
138 					invisibility -= (float)player.Full_Skill_Intuition * ( 1.0f / 100 ) + (float)spells[num].caster_level * ( 1.0f / 10 );
139 
140 					if (invisibility < 0.1f) invisibility = 0.1f;
141 					else if (invisibility > 1.f) invisibility = 1.f;
142 				}
143 			}
144 		}
145 
146 		// Scaling Value for this object (Movements will also be scaled)
147 		scale = io->scale;
148 	}
149 	else
150 	{
151 		if (INVISIBILITY_OVERRIDE != 0.f)
152 		{
153 			invisibility = INVISIBILITY_OVERRIDE;
154 
155 			if (invisibility > 1.f) invisibility -= 1.f;
156 		}
157 		else
158 		{
159 			invisibility = 0.f;
160 		}
161 
162 		scale = 1.f;
163 	}
164 }
165 
Cedric_GetTime(float & timm,Entity * io)166 static void Cedric_GetTime(float & timm, Entity * io) {
167 
168 	if(!io || !io->nb_lastanimvertex) {
169 		timm = 0.f;
170 		return;
171 	}
172 
173 	timm = (arxtime.get_frame_time() - io->lastanimtime) + 0.0001f;
174 
175 	if(timm >= 300.f) {
176 		timm = 0.f;
177 		io->nb_lastanimvertex = 0;
178 	} else {
179 		timm *= ( 1.0f / 300 );
180 		if(timm >= 1.f) {
181 			timm = 0.f;
182 		} else if(timm < 0.f) {
183 			timm = 0.f;
184 		}
185 	}
186 }
187 
188 /* Evaluate main entity translation */
Cedric_AnimCalcTranslation(Entity * io,ANIM_USE * animuse,float scale,Vec3f & ftr,bool update_movement)189 static void Cedric_AnimCalcTranslation(Entity * io, ANIM_USE * animuse, float scale,
190                                        Vec3f & ftr, bool update_movement) {
191 
192 	// Resets Frame Translate
193 	ftr = Vec3f::ZERO;
194 	Vec3f ftr2 = Vec3f::ZERO;
195 
196 
197 	// Fill frame translate values with multi-layer translate informations...
198 	for (int count = MAX_ANIM_LAYERS - 1; count >= 0; count--)
199 	{
200 		EERIE_ANIM	*	eanim;
201 
202 		if (!io)
203 		{
204 			count = -1;
205 		}
206 		else
207 		{
208 			animuse = &io->animlayer[count];
209 		}
210 
211 		if (!animuse) continue;
212 
213 		if (!animuse->cur_anim) continue;
214 
215 		eanim = animuse->cur_anim->anims[animuse->altidx_cur];
216 
217 		if (!eanim) continue;
218 
219 		//Avoiding impossible cases
220 		if (animuse->fr < 0)
221 		{
222 			animuse->fr = 0;
223 			animuse->pour = 0.f;
224 		}
225 		else if (animuse->fr >= eanim->nb_key_frames - 1)
226 		{
227 			animuse->fr = eanim->nb_key_frames - 2;
228 			animuse->pour = 1.f;
229 		}
230 		else if (animuse->pour > 1.f) animuse->pour = 1.f;
231 		else if (animuse->pour < 0.f) animuse->pour = 0.f;
232 
233 
234 		// FRAME TRANSLATE : Gives the Virtual pos of Main Object
235 		if (((eanim->frames[animuse->fr].f_translate) && (!(animuse->flags & EA_STATICANIM))))
236 		{
237 			EERIE_FRAME * sFrame = &eanim->frames[animuse->fr];
238 			EERIE_FRAME * eFrame = &eanim->frames[animuse->fr+1];
239 
240 			// Linear interpolation of object translation (MOVE)
241 			ftr = sFrame->translate + (eFrame->translate - sFrame->translate) * animuse->pour;
242 
243 			if(io && update_movement) {
244 
245 				ftr *= scale;
246 
247 				float temp = radians(MAKEANGLE(180.f - io->angle.b));
248 
249 				if (io == entities.player()) temp = radians(MAKEANGLE(180.f - player.angle.b));
250 
251 				YRotatePoint(&ftr, &ftr2, (float)EEcos(temp), (float)EEsin(temp));
252 
253 				// stores Translations for a later use
254 				io->move = ftr2;
255 			}
256 		}
257 	}
258 
259 	if(io && io->animlayer[0].cur_anim && update_movement) {
260 
261 		// Use calculated value to notify the Movement engine of the translation to do
262 		if(io->ioflags & IO_NPC) {
263 			ftr = Vec3f::ZERO;
264 			io->move -= io->lastmove;
265 		} else if (io->gameFlags & GFLAG_ELEVATOR) {
266 			// Must recover translations for NON-NPC IO
267 			PushIO_ON_Top(io, io->move.y - io->lastmove.y);
268 		}
269 
270 		io->lastmove = ftr2;
271 	}
272 }
273 
274 
275 // Animate skeleton
Cedric_AnimateObject(Entity * io,EERIE_3DOBJ * eobj,ANIM_USE * animuse)276 static	void	Cedric_AnimateObject(Entity * io, EERIE_3DOBJ * eobj, ANIM_USE * animuse)
277 {
278 	int				j, l;
279 	EERIE_C_DATA	* obj = eobj->c_data;
280 
281 	for (long count = MAX_ANIM_LAYERS - 1; count >= 0; count--)
282 	{
283 		EERIE_QUAT		t, temp;
284 		Vec3f		vect;
285 		Vec3f		scale;
286 
287 		if(!io) {
288 			count = -1;
289 		} else {
290 			animuse = &io->animlayer[count];
291 		}
292 
293 		if(!animuse) {
294 			continue;
295 		}
296 
297 		if(!animuse->cur_anim) {
298 			continue;
299 		}
300 
301 		EERIE_ANIM * eanim = animuse->cur_anim->anims[animuse->altidx_cur];
302 
303 		if (!eanim) continue;
304 
305 		if (animuse->fr < 0)
306 		{
307 			animuse->fr = 0;
308 			animuse->pour = 0.f;
309 		}
310 		else if (animuse->fr >= eanim->nb_key_frames - 1)
311 		{
312 			animuse->fr = eanim->nb_key_frames - 2;
313 			animuse->pour = 1.f;
314 		}
315 		else if (animuse->pour > 1.f) animuse->pour = 1.f;
316 		else if (animuse->pour < 0.f) animuse->pour = 0.f;
317 
318 		// Now go for groups rotation/translation/scaling, And transform Linked objects by the way
319 		l = min(eobj->nbgroups - 1, eanim->nb_groups - 1);
320 
321 		for (j = l; j >= 0; j--)
322 		{
323 			if (grps[j])
324 				continue;
325 
326 			EERIE_GROUP * sGroup = &eanim->groups[j+(animuse->fr*eanim->nb_groups)];
327 			EERIE_GROUP * eGroup = &eanim->groups[j+(animuse->fr*eanim->nb_groups)+eanim->nb_groups];
328 
329 			if (!eanim->voidgroups[j])
330 				grps[j] = 1;
331 
332 			if (eanim->nb_key_frames != 1)
333 			{
334 				Quat_Slerp(&t, &sGroup->quat, &eGroup->quat, animuse->pour);
335 				Quat_Copy(&temp, &obj->bones[j].quatinit);
336 				Quat_Multiply(&obj->bones[j].quatinit, &temp, &t);
337 
338 				vect = sGroup->translate + (eGroup->translate - sGroup->translate) * animuse->pour;
339 				obj->bones[j].transinit = vect + obj->bones[j].transinit_global;
340 
341 				scale = sGroup->zoom + (eGroup->zoom - sGroup->zoom) * animuse->pour;
342 				if(BH_MODE && j == eobj->fastaccess.head_group) {
343 					scale += Vec3f::ONE;
344 				}
345 
346 				obj->bones[j].scaleinit = scale;
347 			}
348 		}
349 	}
350 }
351 
352 
353 
354 /* Apply transformations on all bones */
Cedric_ConcatenateTM(Entity * io,EERIE_C_DATA * obj,Anglef * angle,Vec3f * pos,Vec3f & ftr,float g_scale)355 static void	Cedric_ConcatenateTM(Entity * io, EERIE_C_DATA * obj, Anglef * angle, Vec3f * pos, Vec3f & ftr, float g_scale)
356 {
357 	int i;
358 
359 	if (!obj)
360 		return;
361 
362 	for (i = 0; i != obj->nb_bones; i++)
363 	{
364 		EERIE_QUAT	qt2;
365 
366 		if (obj->bones[i].father >= 0) // Child Bones
367 		{
368 			// Rotation
369 			Quat_Multiply(&obj->bones[i].quatanim, &obj->bones[obj->bones[i].father].quatanim, &obj->bones[i].quatinit);
370 
371 			// Translation
372 			obj->bones[i].transanim = obj->bones[i].transinit * obj->bones[obj->bones[i].father].scaleanim;
373 			TransformVertexQuat(&obj->bones[obj->bones[i].father].quatanim, &obj->bones[i].transanim, &obj->bones[i].transanim);
374 			obj->bones[i].transanim = obj->bones[obj->bones[i].father].transanim + obj->bones[i].transanim;
375 
376 			/* Scale */
377 			obj->bones[i].scaleanim = (obj->bones[i].scaleinit + Vec3f::ONE) * obj->bones[obj->bones[i].father].scaleanim;
378 
379 		}
380 		else // Root Bone
381 		{
382 			// Rotation
383 			if ((io) && !(io->ioflags & IO_NPC))
384 			{
385 				// To correct invalid angle in Animated FIX/ITEMS
386 				Anglef ang = *angle;
387 				ang.a = (360 - ang.a);
388 				ang.b = (ang.b);
389 				ang.g = (ang.g);
390 				EERIEMATRIX mat;
391 				Vec3f vect(0, 0, 1);
392 				Vec3f up(0, 1, 0);
393 				VRotateY(&vect, ang.b);
394 				VRotateX(&vect, ang.a);
395 				VRotateZ(&vect, ang.g);
396 				VRotateY(&up, ang.b);
397 				VRotateX(&up, ang.a);
398 				VRotateZ(&up, ang.g);
399 				MatrixSetByVectors(&mat, &vect, &up);
400 				QuatFromMatrix(qt2, mat);
401 				Quat_Multiply(&obj->bones[i].quatanim, &qt2, &obj->bones[i].quatinit);
402 			}
403 			else
404 			{
405 				Anglef vt1 = Anglef(radians(angle->a), radians(angle->b), radians(angle->g));
406 				QuatFromAngles(&qt2, &vt1);
407 				Quat_Multiply(&obj->bones[i].quatanim, &qt2, &obj->bones[i].quatinit);
408 			}
409 
410 			// Translation
411 			Vec3f	vt1 = obj->bones[i].transinit + ftr;
412 			TransformVertexQuat(&qt2, &vt1, &obj->bones[i].transanim);
413 			obj->bones[i].transanim *= g_scale;
414 			obj->bones[i].transanim = *pos + obj->bones[i].transanim;
415 
416 			// Compute Global Object Scale AND Global Animation Scale
417 			obj->bones[i].scaleanim = (obj->bones[i].scaleinit + Vec3f::ONE) * g_scale;
418 		}
419 	}
420 }
421 
422 void EE_RT(TexturedVertex * in, Vec3f * out);
423 void EE_P(Vec3f * in, TexturedVertex * out);
424 void EE_P2(TexturedVertex * in, TexturedVertex * out);
425 
426 /* Transform object vertices  */
Cedric_TransformVerts(Entity * io,EERIE_3DOBJ * eobj,EERIE_C_DATA * obj,Vec3f * pos)427 int Cedric_TransformVerts(Entity * io, EERIE_3DOBJ * eobj, EERIE_C_DATA * obj,
428                           Vec3f * pos) {
429 	int v;
430 
431 	EERIE_3DPAD * inVert;
432 	EERIE_VERTEX * outVert;
433 
434  	/* Transform & project all vertices */
435 	for (long i = 0; i != obj->nb_bones; i++)
436 	{
437 		EERIEMATRIX	 matrix;
438 
439 		MatrixFromQuat(&matrix, &obj->bones[i].quatanim);
440 		Vec3f vector = obj->bones[i].transanim;
441 
442 		// Apply Scale
443 		matrix._11 *= obj->bones[i].scaleanim.x;
444 		matrix._12 *= obj->bones[i].scaleanim.x;
445 		matrix._13 *= obj->bones[i].scaleanim.x;
446 
447 		matrix._21 *= obj->bones[i].scaleanim.y;
448 		matrix._22 *= obj->bones[i].scaleanim.y;
449 		matrix._23 *= obj->bones[i].scaleanim.y;
450 
451 		matrix._31 *= obj->bones[i].scaleanim.z;
452 		matrix._32 *= obj->bones[i].scaleanim.z;
453 		matrix._33 *= obj->bones[i].scaleanim.z;
454 
455 		for(v = 0; v != obj->bones[i].nb_idxvertices; v++) {
456 			inVert  = &eobj->vertexlocal[obj->bones[i].idxvertices[v]];
457 			outVert = &eobj->vertexlist3[obj->bones[i].idxvertices[v]];
458 			TransformVertexMatrix(&matrix, inVert, &outVert->v);
459 			outVert->v += vector;
460 			outVert->vert.p = outVert->v;
461 		}
462 	}
463 
464 	if(eobj->cdata && eobj->sdata) {
465 		for(size_t i = 0; i < eobj->vertexlist.size(); i++) {
466 			eobj->vertexlist[i].vert.p = eobj->vertexlist3[i].v - *pos;
467 		}
468 	}
469 
470 	for (size_t i = 0; i < eobj->vertexlist.size(); i++)
471 	{
472 		outVert = &eobj->vertexlist3[i];
473 		AddToBBox3D(io, &outVert->v);
474 		EE_RT(&outVert->vert, &outVert->vworld);
475 		EE_P(&outVert->vworld, &outVert->vert);
476 
477 		// Updates 2D Bounding Box
478 		if (outVert->vert.rhw > 0.f)
479 		{
480 			BBOXMIN.x = min(BBOXMIN.x, outVert->vert.p.x);
481 			BBOXMAX.x = max(BBOXMAX.x, outVert->vert.p.x);
482 			BBOXMIN.y = min(BBOXMIN.y, outVert->vert.p.y);
483 			BBOXMAX.y = max(BBOXMAX.y, outVert->vert.p.y);
484 		}
485 	}
486 
487 	if ((io)
488 	        &&	(io->ioflags & IO_NPC)
489 	        &&	(io->_npcdata->behavior & BEHAVIOUR_FIGHT)
490 	        &&	(distSqr(io->pos, player.pos) < square(240.f)))
491 		return true;
492 
493 	if ((io != entities.player())
494 	        &&	(!EXTERNALVIEW)
495 	        &&	(!eobj->cdata)
496 	        &&	((BBOXMIN.x >= DANAESIZX - 1)
497 	             ||	(BBOXMAX.x <= 1)
498 	             ||	(BBOXMIN.y >= DANAESIZY - 1)
499 	             ||	(BBOXMAX.y <= 1))
500 	   )
501 	{
502 		return false;
503 	}
504 
505 	if (ARX_SCENE_PORTAL_ClipIO(io, pos))
506 		return false;
507 
508 	return true;
509 }
510 extern Entity * DESTROYED_DURING_RENDERING;
511 long special_color_flag = 0;
512 Color3f special_color;
513 extern long TRAP_DETECT;
514 extern long TRAP_SECRET;
515 extern long FRAME_COUNT;
516 
517 extern float GLOBAL_LIGHT_FACTOR;
518 
519 /* Object dynamic lighting */
Cedric_ApplyLighting(EERIE_3DOBJ * eobj,EERIE_C_DATA * obj,Entity * io,Vec3f * pos)520 static bool Cedric_ApplyLighting(EERIE_3DOBJ * eobj, EERIE_C_DATA * obj, Entity * io, Vec3f * pos) {
521 
522 	Color3f infra = Color3f::black;
523 	int				i, v, l;
524 	Vec3f		tv;
525 	Vec3f		vTLights[32]; /* Same as above but in bone space (for faster calculation) */
526 
527 
528 
529 	special_color_flag = 0;
530 
531 	if (io)
532 	{
533 		float poisonpercent = 0.f;
534 		float trappercent = 0.f;
535 		float secretpercent = 0.f;
536 
537 		if (io->ioflags & IO_NPC)
538 		{
539 			if (io->_npcdata->poisonned > 0.f)
540 			{
541 				poisonpercent = io->_npcdata->poisonned * ( 1.0f / 20 );
542 
543 				if (poisonpercent > 1.f) poisonpercent = 1.f;
544 			}
545 		}
546 
547 		if ((io->ioflags & IO_ITEM) && (io->poisonous > 0.f) && (io->poisonous_count != 0))
548 		{
549 			poisonpercent = (float)io->poisonous * ( 1.0f / 20 );
550 
551 			if (poisonpercent > 1.f) poisonpercent = 1.f;
552 		}
553 
554 		if ((io->ioflags & IO_FIX) && (io->_fixdata->trapvalue > -1))
555 		{
556 			trappercent = (float)TRAP_DETECT - (float)io->_fixdata->trapvalue;
557 
558 			if (trappercent > 0.f)
559 			{
560 				trappercent = 0.6f + trappercent * ( 1.0f / 100 );
561 
562 				if (trappercent < 0.6f) trappercent = 0.6f;
563 
564 				if (trappercent > 1.f) trappercent = 1.f;
565 			}
566 		}
567 
568 		if ((io->ioflags & IO_FIX) && (io->secretvalue > -1))
569 		{
570 			secretpercent = (float)TRAP_SECRET - (float)io->secretvalue;
571 
572 			if (secretpercent > 0.f)
573 			{
574 				secretpercent = 0.6f + secretpercent * ( 1.0f / 100 );
575 				if (secretpercent < 0.6f) secretpercent = 0.6f;
576 				else if (secretpercent > 1.f) secretpercent = 1.f;
577 			}
578 		}
579 
580 		if (poisonpercent > 0.f)
581 		{
582 			special_color_flag = 1;
583 			special_color.r = 0.f;
584 			special_color.g = 1.f;
585 			special_color.b = 0.f;
586 		}
587 
588 		if (trappercent > 0.f)
589 		{
590 			special_color_flag = 1;
591 			special_color.r = trappercent;
592 			special_color.g = 1.f - trappercent;
593 			special_color.b = 1.f - trappercent;
594 		}
595 
596 		if (secretpercent > 0.f)
597 		{
598 			special_color_flag = 1;
599 			special_color.r = 1.f - secretpercent;
600 			special_color.g = 1.f - secretpercent;
601 			special_color.b = secretpercent;
602 		}
603 
604 		if (io->ioflags & IO_FREEZESCRIPT)
605 		{
606 			special_color_flag = 1;
607 			special_color.r = 0.f;
608 			special_color.g = 0.f;
609 			special_color.b = 1.f;
610 		}
611 
612 		if (io->sfx_flag & SFX_TYPE_YLSIDE_DEATH)
613 		{
614 			if (io->show == SHOW_FLAG_TELEPORTING)
615 			{
616 
617 				float fTime = io->sfx_time + FrameDiff;
618 				io->sfx_time = checked_range_cast<unsigned long>(fTime);
619 
620 				if (io->sfx_time >= (unsigned long)(arxtime))
621 					io->sfx_time = (unsigned long)(arxtime);
622 
623 
624 			}
625 			else
626 			{
627 				special_color_flag = 1;
628 				float elapsed = float(arxtime) - io->sfx_time;
629 
630 				if (elapsed > 0.f)
631 				{
632 					if (elapsed < 3000.f) // 5 seconds to red
633 					{
634 						float ratio = elapsed * ( 1.0f / 3000 );
635 						special_color.r = 1.f;
636 						special_color.g = 1.f - ratio;
637 						special_color.b = 1.f - ratio;
638 						AddRandomSmoke(io, 1);
639 					}
640 					else if (elapsed < 6000.f) // 5 seconds to White
641 					{
642 						float ratio = (elapsed - 3000.f) * ( 1.0f / 3000 );
643 						special_color.r = ratio;
644 						special_color_flag = 2;
645 						AddRandomSmoke(io, 2);
646 					}
647 					else // SFX finish
648 					{
649 						special_color_flag = 0;
650 
651 						io->sfx_time = 0;
652 
653 						if (io->ioflags & IO_NPC)
654 						{
655 							MakePlayerAppearsFX(io);
656 							AddRandomSmoke(io, 50);
657 							Color3f rgb = io->_npcdata->blood_color.to<float>();
658 							EERIE_SPHERE sp;
659 							sp.origin = io->pos;
660 							sp.radius = 200.f;
661 							long count = 6;
662 
663 							while (count--)
664 							{
665 								SpawnGroundSplat(&sp, &rgb, rnd() * 30.f + 30.f, 1);
666 								sp.origin.y -= rnd() * 150.f;
667 
668 								ARX_PARTICLES_Spawn_Splat(sp.origin, 200.f, io->_npcdata->blood_color);
669 
670 								sp.origin.x = io->pos.x + rnd() * 200.f - 100.f;
671 								sp.origin.y = io->pos.y + rnd() * 20.f - 10.f;
672 								sp.origin.z = io->pos.z + rnd() * 200.f - 100.f;
673 								sp.radius = rnd() * 100.f + 100.f;
674 							}
675 
676 							long nn = GetFreeDynLight();
677 
678 							if (nn >= 0)
679 							{
680 								DynLight[nn].exist = 1;
681 								DynLight[nn].intensity = 0.7f + 2.f * rnd();
682 								DynLight[nn].fallend = 600.f;
683 								DynLight[nn].fallstart = 400.f;
684 								DynLight[nn].rgb.r = 1.0f;
685 								DynLight[nn].rgb.g = 0.8f;
686 								DynLight[nn].rgb.b = .0f;
687 								DynLight[nn].pos.x = io->pos.x;
688 								DynLight[nn].pos.y = io->pos.y - 80.f;
689 								DynLight[nn].pos.z = io->pos.z;
690 								DynLight[nn].duration = 600;
691 							}
692 
693 							if (io->sfx_flag & SFX_TYPE_INCINERATE)
694 							{
695 								io->sfx_flag &= ~SFX_TYPE_INCINERATE;
696 								io->sfx_flag &= ~SFX_TYPE_YLSIDE_DEATH;
697 								long num = ARX_SPELLS_GetSpellOn(io, SPELL_INCINERATE);
698 
699 								if (num < 0)
700 									num = ARX_SPELLS_GetSpellOn(io, SPELL_MASS_INCINERATE);
701 
702 								if (num >= 0)
703 								{
704 									spells[num].tolive = 0;
705 									float damages = 20 * spells[num].caster_level;
706 									damages = ARX_SPELLS_ApplyFireProtection(io, damages);
707 
708 									if (ValidIONum(spells[num].caster))
709 										ARX_DAMAGES_DamageNPC(io, damages, spells[num].caster, 1, &entities[spells[num].caster]->pos);
710 									else
711 										ARX_DAMAGES_DamageNPC(io, damages, spells[num].caster, 1, &io->pos);
712 
713 									ARX_SOUND_PlaySFX(SND_SPELL_FIRE_HIT, &io->pos);
714 								}
715 							}
716 							else
717 							{
718 								io->sfx_flag &= ~SFX_TYPE_YLSIDE_DEATH;
719 								ARX_INTERACTIVE_DestroyIO(io);
720 								DESTROYED_DURING_RENDERING = io;
721 								return false;
722 							}
723 						}
724 					}
725 				}
726 			}
727 		}
728 	}
729 
730 	if(eobj->drawflags & DRAWFLAG_HIGHLIGHT) {
731 		special_color_flag	=	4;
732 		special_color = Color3f::gray(float(iHighLight));
733 	}
734 
735 	if(FRAME_COUNT > 0) {
736 		return true;
737 	}
738 
739 	if(Project.improve) {
740 		infra = (io) ? io->infracolor : Color3f(0.6f, 0.f, 1.f);
741 	}
742 
743 	/* Get nearest lights */
744 	tv = *pos;
745 
746 	if ((io) && (io->obj->fastaccess.view_attach >= 0) && (io->obj->fastaccess.head_group_origin != -1))
747 	{
748 		tv.y = io->obj->vertexlist3[io->obj->fastaccess.head_group_origin].v.y + 10;
749 	}
750 	else tv.y -= 90.f;
751 
752 	llightsInit();
753 
754 	for (i = 0; i < TOTIOPDL; i++)
755 	{
756 		if (IO_PDL[i]->fallend + 500.f < 0)
757 			continue;
758 
759 		Insertllight(IO_PDL[i], dist(IO_PDL[i]->pos, tv));
760 	}
761 
762 	for (i = 0; i < TOTPDL; i++)
763 	{
764 		if (PDL[i]->fallend + 500.f < 0)
765 			continue;
766 
767 		Insertllight(PDL[i], dist(PDL[i]->pos, tv));
768 	}
769 
770 	if (!USEINTERNORM)
771 	{
772 		/* Apply light on all vertices */
773 		for (i = 0; i != obj->nb_bones; i++)
774 		{
775 			/* Get light value for each vertex */
776 			for (v = 0; v != obj->bones[i].nb_idxvertices; v++)
777 			{
778 				Vec3f	*	posVert;
779 				float			r, g, b;
780 				long	ir, ig, ib;
781 
782 				if(io) {
783 					posVert = &io->obj->vertexlist3[obj->bones[i].idxvertices[v]].v;
784 				} else {
785 					posVert = &eobj->vertexlist3[obj->bones[i].idxvertices[v]].v;
786 				}
787 
788 				/* Ambient light */
789 				if ((io) && (io->ioflags & (IO_NPC | IO_ITEM)))
790 				{
791 					r = g = b = NPC_ITEMS_AMBIENT_VALUE_255;
792 				}
793 				else
794 				{
795 					r = ACTIVEBKG->ambient255.r;
796 					g = ACTIVEBKG->ambient255.g;
797 					b = ACTIVEBKG->ambient255.b;
798 				}
799 
800 				/* Dynamic lights */
801 				for (l = 0 ; l != MAX_LLIGHTS; l++)
802 				{
803 					EERIE_LIGHT * Cur_llights = llights[l];
804 
805 					if (Cur_llights)
806 					{
807 						// tsu
808 						if (Cur_llights->fallend < 0)
809 						{
810 							TSU_TEST_NB_LIGHT ++;
811 							continue;
812 						}
813 
814 						float	cosangle;
815 						float distance = fdist(Cur_llights->pos, *posVert);
816 
817 						/* Evaluate its intensity depending on the distance Light<->Object */
818 						if (distance <= Cur_llights->fallstart)
819 							cosangle = Cur_llights->intensity * GLOBAL_LIGHT_FACTOR;
820 						else
821 						{
822 							float p = ((Cur_llights->fallend - distance) * Cur_llights->falldiffmul);
823 
824 							if (p <= 0.f)
825 								cosangle = 0.f;
826 							else
827 								cosangle = p * Cur_llights->precalc;
828 						}
829 
830 						r += Cur_llights->rgb255.r * cosangle;
831 						g += Cur_llights->rgb255.g * cosangle;
832 						b += Cur_llights->rgb255.b * cosangle;
833 					}
834 					else
835 						break;
836 				}
837 
838 				if (special_color_flag)
839 				{
840 					if (special_color_flag & 1)
841 					{
842 						r *= special_color.r;
843 						g *= special_color.g;
844 						b *= special_color.b;
845 					}
846 					else if (special_color_flag & 2)
847 					{
848 						r = 1.f;
849 						g = 0.f;
850 						b = 0.f;
851 					}
852 					else if (special_color_flag & 4) // HIGHLIGHT
853 					{
854 						r += special_color.r;
855 						g += special_color.g;
856 						b += special_color.b;
857 					}
858 				}
859 
860 				/* PACK color */
861 				ir = clipByte255(r);
862 				ig = clipByte255(g);
863 				ib = clipByte255(b);
864 
865 				eobj->vertexlist3[obj->bones[i].idxvertices[v]].vert.color = (0xFF000000L | ((ir) << 16) | ((ig) << 8) | (ib));
866 			}
867 		}
868 	}
869 
870 	else
871 	{
872 		/* Apply light on all vertices */
873 		for (i = 0; i != obj->nb_bones; i++)
874 		{
875 			EERIE_QUAT	qt1;
876 
877 			EERIEMATRIX matrix;//,omatrix;
878 			Quat_Copy(&qt1, &obj->bones[i].quatanim);
879 			Quat_Reverse(&qt1);
880 			MatrixFromQuat(&matrix, &qt1);
881 			//	FMatrixInvert(matrix,omatrix);
882 
883 			/* Get light value for each vertex */
884 			for (v = 0; v != obj->bones[i].nb_idxvertices; v++)
885 			{
886 				EERIE_3DPAD *	inVert;
887 
888 				float			r, g, b;
889 				long	ir, ig, ib;
890 
891 				inVert  = (EERIE_3DPAD *)&eobj->vertexlist[obj->bones[i].idxvertices[v]].norm;
892 
893 				/* Ambient light */
894 				if ((io) && (io->ioflags & (IO_NPC | IO_ITEM)))
895 				{
896 					r = g = b = NPC_ITEMS_AMBIENT_VALUE_255;
897 				}
898 				else
899 				{
900 					r = ACTIVEBKG->ambient255.r;
901 					g = ACTIVEBKG->ambient255.g;
902 					b = ACTIVEBKG->ambient255.b;
903 				}
904 
905 
906 				/* Dynamic lights */
907 				for (l = 0 ; l != MAX_LLIGHTS; l++)
908 				{
909 					EERIE_LIGHT * Cur_llights = llights[l];
910 
911 					if (Cur_llights)
912 					{
913 						Vec3f & Cur_vTLights = vTLights[l];
914 						Vec3f tl;
915 						tl = (Cur_llights->pos - eobj->vertexlist3[obj->bones[i].idxvertices[v]].v);
916 						float dista = ffsqrt(tl.lengthSqr());
917 
918 						if(dista < Cur_llights->fallend) {
919 
920 							tl *= 1.f / dista;
921 
922 							VectorMatrixMultiply(&Cur_vTLights, &tl, &matrix);
923 
924 							float cosangle = dot(*inVert, Cur_vTLights);
925 
926 							/* If light visible */
927 							if (cosangle > 0.0f)
928 							{
929 								/* Evaluate its intensity depending on the distance Light<->Object */
930 								if (dista <= Cur_llights->fallstart)
931 									cosangle *= Cur_llights->precalc;
932 								else
933 								{
934 									float p = ((Cur_llights->fallend - dista) * Cur_llights->falldiffmul);
935 
936 									if (p <= 0.f)
937 										cosangle = 0.f;
938 									else
939 										cosangle *= p * Cur_llights->precalc;
940 								}
941 
942 								r += Cur_llights->rgb255.r * cosangle;
943 								g += Cur_llights->rgb255.g * cosangle;
944 								b += Cur_llights->rgb255.b * cosangle;
945 							}
946 						}
947 					}
948 					else
949 						break;
950 				}
951 
952 				/* Fake adjust */
953 				if (Project.improve)
954 				{
955 					r *= infra.r;
956 					g *= infra.g;
957 					b *= infra.b;
958 				}
959 
960 				if (special_color_flag)
961 				{
962 					if (special_color_flag & 1)
963 					{
964 						r *= special_color.r;
965 						g *= special_color.g;
966 						b *= special_color.b;
967 					}
968 					else if (special_color_flag & 2)
969 					{
970 						r = 1.f;
971 						g = 0.f;
972 						b = 0.f;
973 					}
974 					else if (special_color_flag & 4) // HIGHLIGHT
975 					{
976 						r += special_color.r;
977 						g += special_color.g;
978 						b += special_color.b;
979 					}
980 				}
981 
982 				/* PACK color */
983 				ir = clipByte255(r);
984 				ig = clipByte255(g);
985 				ib = clipByte255(b);
986 
987 				eobj->vertexlist3[obj->bones[i].idxvertices[v]].vert.color = (0xFF000000L | ((ir) << 16) | ((ig) << 8) | (ib));
988 			}
989 		}
990 	}
991 
992 	return true;
993 }
994 
Cedric_PrepareHalo(EERIE_3DOBJ * eobj,EERIE_C_DATA * obj)995 void Cedric_PrepareHalo(EERIE_3DOBJ * eobj, EERIE_C_DATA * obj) {
996 	Vec3f cam_vector, t_vector;
997 	cam_vector.x = -EEsin(radians(ACTIVECAM->angle.b)) * EEcos(radians(ACTIVECAM->angle.a));
998 	cam_vector.y = EEsin(radians(ACTIVECAM->angle.a));
999 	cam_vector.z = EEcos(radians(ACTIVECAM->angle.b)) * EEcos(radians(ACTIVECAM->angle.a));
1000 
1001 	/* Apply light on all vertices */
1002 	for (long i = 0; i != obj->nb_bones; i++)
1003 	{
1004 		EERIE_QUAT	qt1;
1005 		Quat_Copy(&qt1, &obj->bones[i].quatanim);
1006 		TransformInverseVertexQuat(&qt1, &cam_vector, &t_vector);
1007 
1008 		/* Get light value for each vertex */
1009 		for (long v = 0; v != obj->bones[i].nb_idxvertices; v++)
1010 		{
1011 			EERIE_3DPAD *	inVert;
1012 			//inVert  = &eobj->normallocal[obj->bones[i].idxvertices[v]];
1013 			inVert  = (EERIE_3DPAD *)&eobj->vertexlist[obj->bones[i].idxvertices[v]].norm;
1014 			/* Get cos angle between light and vertex norm */
1015 			eobj->vertexlist3[obj->bones[i].idxvertices[v]].norm.z =
1016 			    (inVert->x * t_vector.x + inVert->y * t_vector.y + inVert->z * t_vector.z);
1017 
1018 		}
1019 	}
1020 }
1021 
1022 #ifdef USE_SOFTWARE_CLIPPING
1023 //-----------------------------------------------------------------------------
ARX_ClippZ(TexturedVertex * _pA,TexturedVertex * _pB,EERIE_VERTEX * _pVertexA,EERIE_VERTEX * _pVertexB,TexturedVertex * _pOut)1024 void ARX_ClippZ(TexturedVertex * _pA, TexturedVertex * _pB, EERIE_VERTEX * _pVertexA, EERIE_VERTEX * _pVertexB, TexturedVertex * _pOut)
1025 {
1026 	Vec3f e3dTemp;
1027 
1028 	float fDenom	=	(SOFTNEARCLIPPZ - _pVertexB->vworld.z) / (_pVertexA->vworld.z - _pVertexB->vworld.z);
1029 	e3dTemp.x		=	(_pVertexA->vworld.x - _pVertexB->vworld.x) * fDenom + _pVertexB->vworld.x;
1030 	e3dTemp.y		=	(_pVertexA->vworld.y - _pVertexB->vworld.y) * fDenom + _pVertexB->vworld.y;
1031 	e3dTemp.z		=	SOFTNEARCLIPPZ ;
1032 
1033 	float fRA, fGA, fBA;
1034 	float fRB, fGB, fBB;
1035 
1036 	fRA = checked_range_cast<float>((_pA->color >> 16) & 255);
1037 	fGA = checked_range_cast<float>((_pA->color >> 8) & 255);
1038 	fBA = checked_range_cast<float>(_pA->color & 255);
1039 	fRB = checked_range_cast<float>((_pB->color >> 16) & 255);
1040 	fGB = checked_range_cast<float>((_pB->color >> 8) & 255);
1041 	fBB = checked_range_cast<float>(_pB->color & 255);
1042 
1043 	float fRC, fGC, fBC;
1044 	fRC = (fRA - fRB) * fDenom + fRB;
1045 	fGC = (fGA - fGB) * fDenom + fGB;
1046 	fBC = (fBA - fBB) * fDenom + fBB;
1047 
1048 	_pOut->color	=	(((int)fRC) << 16) | (((int)fGC) << 8) | ((int)fBC);
1049 	_pOut->uv		=	(_pA->uv - _pB->uv) * fDenom + _pB->uv;
1050 
1051 	EE_P(&e3dTemp, _pOut);
1052 }
1053 
1054 //-----------------------------------------------------------------------------
1055 void ARX_DrawPrimitive_ClippZ(TexturedVertex * _pVertexA, TexturedVertex * _pVertexB, TexturedVertex * _pOut, float _fAdd = 0.f);
ARX_DrawPrimitive_ClippZ(TexturedVertex * _pVertexA,TexturedVertex * _pVertexB,TexturedVertex * _pOut,float _fAdd)1056 void ARX_DrawPrimitive_ClippZ(TexturedVertex * _pVertexA, TexturedVertex * _pVertexB, TexturedVertex * _pOut, float _fAdd)
1057 {
1058 	Vec3f e3dTemp;
1059 	float fDenom = ((SOFTNEARCLIPPZ + _fAdd) - _pVertexB->p.z) / (_pVertexA->p.z - _pVertexB->p.z);
1060 	e3dTemp.x = (_pVertexA->p.x - _pVertexB->p.x) * fDenom + _pVertexB->p.x;
1061 	e3dTemp.y = (_pVertexA->p.y - _pVertexB->p.y) * fDenom + _pVertexB->p.y;
1062 	e3dTemp.z = SOFTNEARCLIPPZ + _fAdd;
1063 
1064 	float fRA, fGA, fBA;
1065 	float fRB, fGB, fBB;
1066 
1067 	fRA = checked_range_cast<float>((_pVertexA->color >> 16) & 255);
1068 	fGA = checked_range_cast<float>((_pVertexA->color >> 8) & 255);
1069 	fBA = checked_range_cast<float>(_pVertexA->color & 255);
1070 	fRB = checked_range_cast<float>((_pVertexB->color >> 16) & 255);
1071 	fGB = checked_range_cast<float>((_pVertexB->color >> 8) & 255);
1072 	fBB = checked_range_cast<float>(_pVertexB->color & 255);
1073 
1074 	float fRC, fGC, fBC;
1075 	fRC = (fRA - fRB) * fDenom + fRB;
1076 	fGC = (fGA - fGB) * fDenom + fGB;
1077 	fBC = (fBA - fBB) * fDenom + fBB;
1078 
1079 	_pOut->color	= (((int) fRC) << 16) | (((int)fGC) << 8) | ((int) fBC);
1080 	_pOut->uv		= (_pVertexA->uv - _pVertexB->uv) * fDenom + _pVertexB->uv;
1081 
1082 	EE_P(&e3dTemp, _pOut);
1083 }
1084 #endif
1085 
1086 //-----------------------------------------------------------------------------
GetNewVertexList(EERIE_FACE * _pFace,float _fInvisibility,TextureContainer * _pTex)1087 TexturedVertex * GetNewVertexList(EERIE_FACE * _pFace, float _fInvisibility, TextureContainer * _pTex) {
1088 
1089 	if(!(_pFace->facetype & POLY_TRANS) && !(_fInvisibility > 0.f)) {
1090 		return PushVertexInTableCull(_pTex);
1091 	}
1092 
1093 	float fTransp;
1094 
1095 	if(_fInvisibility > 0.f) {
1096 		fTransp = 2.f - _fInvisibility;
1097 	} else {
1098 		fTransp = _pFace->transval;
1099 	}
1100 
1101 	if(fTransp >= 2.f) { //MULTIPLICATIVE
1102 		return PushVertexInTableCull_TMultiplicative(_pTex);
1103 	} else if(fTransp >= 1.f) { //ADDITIVE
1104 		return PushVertexInTableCull_TAdditive(_pTex);
1105 	} else if(fTransp > 0.f) { //NORMAL TRANS
1106 		return PushVertexInTableCull_TNormalTrans(_pTex);
1107 	} else { //SUBTRACTIVE
1108 		return PushVertexInTableCull_TSubstractive(_pTex);
1109 	}
1110 }
1111 
1112 #ifdef USE_SOFTWARE_CLIPPING
1113 
ARX_SoftClippZ(EERIE_VERTEX * _pVertex1,EERIE_VERTEX * _pVertex2,EERIE_VERTEX * _pVertex3,TexturedVertex ** _ptV,EERIE_FACE * _pFace,float _fInvibility,TextureContainer * _pTex,bool _bZMapp,EERIE_3DOBJ * _pObj,int _iNumFace,long * _pInd,Entity * _pioInteractive,bool _bNPC,long _lSpecialColorFlag,Color3f * _pRGB)1114 int ARX_SoftClippZ(EERIE_VERTEX * _pVertex1, EERIE_VERTEX * _pVertex2, EERIE_VERTEX * _pVertex3, TexturedVertex ** _ptV, EERIE_FACE * _pFace, float _fInvibility, TextureContainer * _pTex, bool _bZMapp, EERIE_3DOBJ * _pObj, int _iNumFace, long * _pInd, Entity * _pioInteractive, bool _bNPC, long _lSpecialColorFlag, Color3f * _pRGB) {
1115 
1116 	int iPointAdd = 3;
1117 	int iClipp = 0;
1118 
1119 	if ((_pVertex1->vworld.z) < SOFTNEARCLIPPZ) iClipp |= 1;
1120 
1121 	if ((_pVertex2->vworld.z) < SOFTNEARCLIPPZ) iClipp |= 2;
1122 
1123 	if ((_pVertex3->vworld.z) < SOFTNEARCLIPPZ) iClipp |= 4;
1124 
1125 	TexturedVertex ClippZ1, ClippZ2;
1126 	TexturedVertex * pPointAdd = NULL;
1127 	TexturedVertex * ptV = *_ptV;
1128 
1129 	switch (iClipp)
1130 	{
1131 		case 1:						//pt1 outside
1132 			ARX_ClippZ(&ptV[0], &ptV[1], _pVertex1, _pVertex2, &ClippZ1);
1133 			ARX_ClippZ(&ptV[0], &ptV[2], _pVertex1, _pVertex3, &ClippZ2);
1134 			pPointAdd = GetNewVertexList(_pFace,
1135 			                                _fInvibility,
1136 			                                _pTex);
1137 			ptV = pPointAdd - 3;
1138 
1139 			if (pPointAdd)
1140 			{
1141 				pPointAdd[0] = ClippZ1;
1142 				pPointAdd[1] = ptV[1];
1143 				pPointAdd[2] = ClippZ2;
1144 			}
1145 
1146 			ptV[0] = ClippZ2;
1147 			iPointAdd = 6;
1148 			break;
1149 		case 2:						//pt2 outside
1150 			ARX_ClippZ(&ptV[1], &ptV[2], _pVertex2, _pVertex3, &ClippZ1);
1151 			ARX_ClippZ(&ptV[1], &ptV[0], _pVertex2, _pVertex1, &ClippZ2);
1152 			pPointAdd = GetNewVertexList(_pFace,
1153 			                                _fInvibility,
1154 			                                _pTex);
1155 			ptV = pPointAdd - 3;
1156 
1157 			if (pPointAdd)
1158 			{
1159 				pPointAdd[0] = ptV[2];
1160 				pPointAdd[1] = ClippZ1;
1161 				pPointAdd[2] = ClippZ2;
1162 			}
1163 
1164 			ptV[1] = ClippZ2;
1165 			iPointAdd = 6;
1166 			break;
1167 		case 4:						//pt3 outside
1168 			ARX_ClippZ(&ptV[2], &ptV[0], _pVertex3, _pVertex1, &ClippZ1);
1169 			ARX_ClippZ(&ptV[2], &ptV[1], _pVertex3, _pVertex2, &ClippZ2);
1170 			pPointAdd = GetNewVertexList(_pFace,
1171 			                                _fInvibility,
1172 			                                _pTex);
1173 			ptV = pPointAdd - 3;
1174 
1175 			if (pPointAdd)
1176 			{
1177 				pPointAdd[0] = ptV[0];
1178 				pPointAdd[1] = ClippZ2;
1179 				pPointAdd[2] = ClippZ1;
1180 			}
1181 
1182 			ptV[2] = ClippZ2;
1183 			iPointAdd = 6;
1184 			break;
1185 		case 3:						//pt1_2 outside
1186 			ARX_ClippZ(&ptV[0], &ptV[2], _pVertex1, _pVertex3, &ClippZ1);
1187 			ARX_ClippZ(&ptV[1], &ptV[2], _pVertex2, _pVertex3, &ClippZ2);
1188 			ptV[0] = ClippZ1;
1189 			ptV[1] = ClippZ2;
1190 			break;
1191 		case 5:						//pt1_3 outside
1192 			ARX_ClippZ(&ptV[0], &ptV[1], _pVertex1, _pVertex2, &ClippZ1);
1193 			ARX_ClippZ(&ptV[2], &ptV[1], _pVertex3, _pVertex2, &ClippZ2);
1194 			ptV[0] = ClippZ1;
1195 			ptV[2] = ClippZ2;
1196 			break;
1197 		case 6:						//pt2_3 outside
1198 			ARX_ClippZ(&ptV[2], &ptV[0], _pVertex3, _pVertex1, &ClippZ1);
1199 			ARX_ClippZ(&ptV[1], &ptV[0], _pVertex2, _pVertex1, &ClippZ2);
1200 			ptV[1] = ClippZ1;
1201 			ptV[2] = ClippZ2;
1202 			break;
1203 		case 7:
1204 			return 0;
1205 	}
1206 
1207 	if (pPointAdd)
1208 	{
1209 		*_ptV = ptV;
1210 
1211 		if (_bZMapp)
1212 		{
1213 			CalculateInterZMapp(_pObj, _iNumFace, _pInd, _pTex, pPointAdd);
1214 		}
1215 	}
1216 
1217 	return iPointAdd;
1218 }
1219 #endif
1220 
1221 extern long IsInGroup(EERIE_3DOBJ * obj, long vert, long tw);
1222 
ARX_DrawPrimitive(TexturedVertex * _pVertex1,TexturedVertex * _pVertex2,TexturedVertex * _pVertex3,float _fAddZ)1223 void ARX_DrawPrimitive(TexturedVertex * _pVertex1, TexturedVertex * _pVertex2, TexturedVertex * _pVertex3, float _fAddZ) {
1224 
1225 #ifdef USE_SOFTWARE_CLIPPING
1226 	int iClipp = 0;
1227 
1228 	if (_pVertex1->p.z < (SOFTNEARCLIPPZ + _fAddZ)) iClipp |= 1;
1229 
1230 	if (_pVertex2->p.z < (SOFTNEARCLIPPZ + _fAddZ)) iClipp |= 2;
1231 
1232 	if (_pVertex3->p.z < (SOFTNEARCLIPPZ + _fAddZ)) iClipp |= 4;
1233 
1234 	TexturedVertex ClippZ1, ClippZ2;
1235 	TexturedVertex pPointAdd[6];
1236 	int			iNbTotVertex = 3;
1237 
1238 	switch (iClipp)
1239 	{
1240 		case 0: {
1241 			EE_P(&_pVertex1->p, &pPointAdd[0]);
1242 			EE_P(&_pVertex2->p, &pPointAdd[1]);
1243 			EE_P(&_pVertex3->p, &pPointAdd[2]);
1244 			pPointAdd[0].color = _pVertex1->color;
1245 			pPointAdd[0].specular = _pVertex1->specular;
1246 			pPointAdd[0].uv = _pVertex1->uv;
1247 			pPointAdd[1].specular = _pVertex2->specular;
1248 			pPointAdd[1].uv = _pVertex2->uv;
1249 			pPointAdd[2].color = _pVertex3->color;
1250 			pPointAdd[2].specular = _pVertex3->specular;
1251 			pPointAdd[2].uv = _pVertex3->uv;
1252 			break;
1253 		}
1254 		case 1:						//pt1 outside
1255 			ARX_DrawPrimitive_ClippZ(_pVertex1, _pVertex2, &ClippZ1, _fAddZ);
1256 			ARX_DrawPrimitive_ClippZ(_pVertex1, _pVertex3, &ClippZ2, _fAddZ);
1257 			pPointAdd[0] = ClippZ2;
1258 			pPointAdd[1] = *_pVertex2;
1259 			EE_P2(&pPointAdd[1], &pPointAdd[1]);
1260 			pPointAdd[2] = *_pVertex3;
1261 			EE_P2(&pPointAdd[2], &pPointAdd[2]);
1262 			pPointAdd[3] = ClippZ1;
1263 			pPointAdd[4] = pPointAdd[1];
1264 			pPointAdd[5] = ClippZ2;
1265 			iNbTotVertex = 6;
1266 			break;
1267 		case 2:						//pt2 outside
1268 			ARX_DrawPrimitive_ClippZ(_pVertex2, _pVertex3, &ClippZ1, _fAddZ);
1269 			ARX_DrawPrimitive_ClippZ(_pVertex2, _pVertex1, &ClippZ2, _fAddZ);
1270 			pPointAdd[0] = *_pVertex1;
1271 			EE_P2(&pPointAdd[0], &pPointAdd[0]);
1272 			pPointAdd[1] = ClippZ2;
1273 			pPointAdd[2] = *_pVertex3;
1274 			EE_P2(&pPointAdd[2], &pPointAdd[2]);
1275 			pPointAdd[3] = pPointAdd[2];
1276 			pPointAdd[4] = ClippZ1;
1277 			pPointAdd[5] = ClippZ2;
1278 			iNbTotVertex = 6;
1279 			break;
1280 		case 4:						//pt3 outside
1281 			ARX_DrawPrimitive_ClippZ(_pVertex3, _pVertex1, &ClippZ1, _fAddZ);
1282 			ARX_DrawPrimitive_ClippZ(_pVertex3, _pVertex2, &ClippZ2, _fAddZ);
1283 			pPointAdd[0] = *_pVertex1;
1284 			EE_P2(&pPointAdd[0], &pPointAdd[0]);
1285 			pPointAdd[1] = *_pVertex2;
1286 			EE_P2(&pPointAdd[1], &pPointAdd[1]);
1287 			pPointAdd[2] = ClippZ2;
1288 			pPointAdd[3] = pPointAdd[0];
1289 			pPointAdd[4] = ClippZ2;
1290 			pPointAdd[5] = ClippZ1;
1291 			iNbTotVertex = 6;
1292 			break;
1293 		case 3:						//pt1_2 outside
1294 			ARX_DrawPrimitive_ClippZ(_pVertex1, _pVertex3, &ClippZ1, _fAddZ);
1295 			ARX_DrawPrimitive_ClippZ(_pVertex2, _pVertex3, &ClippZ2, _fAddZ);
1296 			pPointAdd[0] = ClippZ1;
1297 			pPointAdd[1] = ClippZ2;
1298 			pPointAdd[2] = *_pVertex3;
1299 			EE_P2(&pPointAdd[2], &pPointAdd[2]);
1300 			break;
1301 		case 5:						//pt1_3 outside
1302 			ARX_DrawPrimitive_ClippZ(_pVertex1, _pVertex2, &ClippZ1, _fAddZ);
1303 			ARX_DrawPrimitive_ClippZ(_pVertex3, _pVertex2, &ClippZ2, _fAddZ);
1304 			pPointAdd[0] = ClippZ1;
1305 			pPointAdd[1] = *_pVertex2;
1306 			EE_P2(&pPointAdd[1], &pPointAdd[1]);
1307 			pPointAdd[2] = ClippZ2;
1308 			break;
1309 		case 6:						//pt2_3 outside
1310 			ARX_DrawPrimitive_ClippZ(_pVertex3, _pVertex1, &ClippZ1, _fAddZ);
1311 			ARX_DrawPrimitive_ClippZ(_pVertex2, _pVertex1, &ClippZ2, _fAddZ);
1312 			pPointAdd[0] = *_pVertex1;
1313 			EE_P2(&pPointAdd[0], &pPointAdd[0]);
1314 			pPointAdd[1] = ClippZ1;
1315 			pPointAdd[2] = ClippZ2;
1316 			break;
1317 		case 7:
1318 			return;
1319 	}
1320 #else
1321 
1322 	ARX_UNUSED(_fAddZ);
1323 
1324 	TexturedVertex pPointAdd[3];
1325 	EE_P(&_pVertex1->p, &pPointAdd[0]);
1326 	EE_P(&_pVertex2->p, &pPointAdd[1]);
1327 	EE_P(&_pVertex3->p, &pPointAdd[2]);
1328 	pPointAdd[0].color = _pVertex1->color;
1329 	pPointAdd[0].specular = _pVertex1->specular;
1330 	pPointAdd[0].uv = _pVertex1->uv;
1331 	pPointAdd[1].color = _pVertex2->color;
1332 	pPointAdd[1].specular = _pVertex2->specular;
1333 	pPointAdd[1].uv = _pVertex2->uv;
1334 	pPointAdd[2].color = _pVertex3->color;
1335 	pPointAdd[2].specular = _pVertex3->specular;
1336 	pPointAdd[2].uv = _pVertex3->uv;
1337 #endif
1338 
1339 	EERIEDRAWPRIM(Renderer::TriangleList, pPointAdd);
1340 }
1341 
1342 long FORCE_FRONT_DRAW = 0;
1343 
1344 //-----------------------------------------------------------------------------
1345 extern long IN_BOOK_DRAW;
1346 
1347 /* Render object */
Cedric_RenderObject(EERIE_3DOBJ * eobj,EERIE_C_DATA * obj,Entity * io,Vec3f * pos,Vec3f & ftr,float invisibility)1348 static void Cedric_RenderObject(EERIE_3DOBJ * eobj, EERIE_C_DATA * obj, Entity * io, Vec3f * pos, Vec3f & ftr, float invisibility) {
1349 
1350 	float MAX_ZEDE = 0.f;
1351 
1352 	// Sets IO BBox to calculated BBox :)
1353 	if (io)
1354 	{
1355 		io->bbox1.x = (short) BBOXMIN.x;
1356 		io->bbox2.x = (short) BBOXMAX.x;
1357 		io->bbox1.y = (short) BBOXMIN.y;
1358 		io->bbox2.y = (short) BBOXMAX.y;
1359 	}
1360 
1361 	if (invisibility == 1.f)
1362 		return;
1363 
1364 	float	ddist		= 0.f;
1365 	long	need_halo;
1366 
1367 	need_halo = 0;
1368 
1369 	Entity * hio_helmet	= NULL;
1370 	Entity * hio_armor		= NULL;
1371 	Entity * hio_leggings	= NULL;
1372 	Entity * hio_player	= NULL;
1373 	Entity * use_io		= io;
1374 
1375 	if ((!io)
1376 	        &&	(IN_BOOK_DRAW)
1377 	        &&	(eobj == entities.player()->obj))
1378 		use_io = entities.player();
1379 
1380 	if (use_io)
1381 	{
1382 		if (use_io == entities.player())
1383 		{
1384 			if ((player.equiped[EQUIP_SLOT_HELMET] != 0)
1385 			        && ValidIONum(player.equiped[EQUIP_SLOT_HELMET]))
1386 			{
1387 				Entity * tio = entities[player.equiped[EQUIP_SLOT_HELMET]];
1388 
1389 				if (tio->halo.flags & HALO_ACTIVE)
1390 					hio_helmet = tio;
1391 			}
1392 
1393 			if ((player.equiped[EQUIP_SLOT_ARMOR] != 0)
1394 			        &&	ValidIONum(player.equiped[EQUIP_SLOT_ARMOR]))
1395 			{
1396 				Entity * tio = entities[player.equiped[EQUIP_SLOT_ARMOR]];
1397 
1398 				if (tio->halo.flags & HALO_ACTIVE)
1399 					hio_armor = tio;
1400 			}
1401 
1402 			if ((player.equiped[EQUIP_SLOT_LEGGINGS] != 0)
1403 			        &&	ValidIONum(player.equiped[EQUIP_SLOT_LEGGINGS]))
1404 			{
1405 				Entity * tio = entities[player.equiped[EQUIP_SLOT_LEGGINGS]];
1406 
1407 				if (tio->halo.flags & HALO_ACTIVE)
1408 					hio_leggings = tio;
1409 			}
1410 
1411 			if (use_io->halo.flags & HALO_ACTIVE)
1412 				hio_player = use_io;
1413 		}
1414 
1415 		if (hio_player
1416 		        ||	hio_armor
1417 		        ||	hio_leggings
1418 		        ||	hio_helmet
1419 		        ||	(use_io->halo.flags & HALO_ACTIVE))
1420 		{
1421 
1422 			float mdist = ACTIVECAM->cdepth * ( 1.0f / 2 );
1423 
1424 			ddist = mdist - fdist(*pos + ftr, ACTIVECAM->pos);
1425 
1426 			ddist = (ddist / mdist);  //*0.1f;
1427 			ddist *= ddist * ddist * ddist * ddist * ddist;
1428 
1429 			if (ddist <= 0.25f) ddist = 0.25f;
1430 
1431 			else if (ddist > 0.9f) ddist = 0.9f;
1432 
1433 			Cedric_PrepareHalo(eobj, obj);
1434 			need_halo	= 1;
1435 			MAX_ZEDE	= 0.f;
1436 
1437 			for (size_t i = 0 ; i < eobj->vertexlist.size() ; i++)
1438 			{
1439 				if (eobj->vertexlist3[i].vert.rhw > 0.f)
1440 					MAX_ZEDE = max(eobj->vertexlist3[i].vert.p.z, MAX_ZEDE);
1441 			}
1442 
1443 		}
1444 	}
1445 
1446 	{
1447 		for (size_t i = 0 ; i < eobj->facelist.size() ; i++)
1448 		{
1449 			TexturedVertex	* tv			= NULL;
1450 
1451 
1452 			EERIE_FACE	*	eface;
1453 			long 			paf[3];
1454 
1455 			eface = &eobj->facelist[i];
1456 
1457 			if ((eface->facetype & POLY_HIDE) && (!FORCE_NO_HIDE))
1458 				continue;
1459 
1460 			//CULL3D
1461 			Vec3f nrm = eobj->vertexlist3[eface->vid[0]].v - ACTIVECAM->pos;
1462 
1463 			if(!(eface->facetype & POLY_DOUBLESIDED)) {
1464 				Vec3f normV10;
1465 				Vec3f normV20;
1466 				normV10 = eobj->vertexlist3[eface->vid[1]].v - eobj->vertexlist3[eface->vid[0]].v;
1467 				normV20 = eobj->vertexlist3[eface->vid[2]].v - eobj->vertexlist3[eface->vid[0]].v;
1468 				Vec3f normFace;
1469 				normFace.x = (normV10.y * normV20.z) - (normV10.z * normV20.y);
1470 				normFace.y = (normV10.z * normV20.x) - (normV10.x * normV20.z);
1471 				normFace.z = (normV10.x * normV20.y) - (normV10.y * normV20.x);
1472 
1473 				if ((dot(normFace , nrm) > 0.f)) continue;
1474 			}
1475 
1476 			TextureContainer * pTex;
1477 
1478 			if(eobj->facelist[i].texid < 0)
1479 				continue;
1480 
1481 			pTex = eobj->texturecontainer[eobj->facelist[i].texid];
1482 			if(!pTex)
1483 				continue;
1484 
1485 			float			fTransp = 0;
1486 
1487 			if((eobj->facelist[i].facetype & POLY_TRANS) || invisibility > 0.f) {
1488 
1489 				fTransp = (invisibility > 0.f) ? 2.f - invisibility : eobj->facelist[i].transval;
1490 
1491 				if(fTransp >= 2.f) {
1492 					//MULTIPLICATIVE
1493 					fTransp *= (1.f/2);
1494 					fTransp += .5f;
1495 					tv = PushVertexInTableCull_TMultiplicative(pTex);
1496 				} else if(fTransp >= 1.f) {
1497 					//ADDITIVE
1498 					fTransp -= 1.f;
1499 					tv = PushVertexInTableCull_TAdditive(pTex);
1500 				} else if(fTransp > 0.f) {
1501 					//NORMAL TRANS
1502 					fTransp = 1.f - fTransp;
1503 					tv = PushVertexInTableCull_TNormalTrans(pTex);
1504 				} else {
1505 					//SUBTRACTIVE
1506 					fTransp = 1.f - fTransp;
1507 					tv = PushVertexInTableCull_TSubstractive(pTex);
1508 				}
1509 			} else {
1510 				tv = PushVertexInTableCull(pTex);
1511 			}
1512 
1513 			for(long n = 0 ; n < 3 ; n++) {
1514 				paf[n] = eface->vid[n];
1515 				tv[n].p = eobj->vertexlist3[paf[n]].vert.p;
1516 
1517 				// Nuky - this code takes 20% of the whole game performance O_O
1518 				//        AFAIK it allows to correctly display the blue magic effects
1519 				//        when one's hands are inside a wall. I've only managed to do that
1520 				//        while in combat mode, looking straight down, and touching a wall
1521 				//        So, for the greater good I think it's best to simply skip this test
1522 				//const float IN_FRONT_DIVIDER = 0.75f;
1523 				//const float IN_FRONT_DIVIDER_FEET = 0.998f;
1524 				//if (FORCE_FRONT_DRAW)
1525 				//{
1526 				//	if (IsInGroup(eobj, paf[n], 1) != -1)
1527 				//		tv[n].sz *= IN_FRONT_DIVIDER;
1528 				//	else
1529 				//		tv[n].sz *= IN_FRONT_DIVIDER_FEET;
1530 				//}
1531 
1532 				tv[n].rhw	= eobj->vertexlist3[paf[n]].vert.rhw;
1533 				tv[n].uv.x	= eface->u[n];
1534 				tv[n].uv.y	= eface->v[n];
1535 				tv[n].color = eobj->vertexlist3[paf[n]].vert.color;
1536 			}
1537 
1538 			if (special_color_flag)
1539 			{
1540 				if (special_color_flag & 1)
1541 				{
1542 					for (long j = 0 ; j < 3 ; j++)
1543 					{
1544 						tv[j].color = 0xFF000000L
1545 						               | (((long)((float)((long)((tv[j].color >> 16) & 255)) * (special_color.r)) & 255) << 16)
1546 						               | (((long)((float)((long)((tv[j].color >> 8) & 255)) * special_color.g) & 255) << 8)
1547 						               | ((long)((float)((long)(tv[j].color & 255)) * (special_color.b)) & 255);
1548 					}
1549 				}
1550 				else if (special_color_flag & 2)
1551 				{
1552 					for (long j = 0 ; j < 3 ; j++)
1553 					{
1554 						tv[j].color = 0xFFFF0000;
1555 					}
1556 				}
1557 			}
1558 
1559 			if((eobj->facelist[i].facetype & POLY_TRANS) || invisibility > 0.f) {
1560 				tv[0].color = tv[1].color = tv[2].color = Color::gray(fTransp).toBGR();
1561 			}
1562 
1563 #ifdef USE_SOFTWARE_CLIPPING
1564 			if (!(ARX_SoftClippZ(&eobj->vertexlist3[paf[0]],
1565 			                                   &eobj->vertexlist3[paf[1]],
1566 			                                   &eobj->vertexlist3[paf[2]],
1567 			                                   &tv,
1568 			                                   eface,
1569 			                                   invisibility,
1570 			                                   pTex,
1571 			                                   (io) && (io->ioflags & IO_ZMAP),
1572 			                                   eobj,
1573 			                                   i,
1574 			                                   paf,
1575 			                                   NULL,
1576 			                                   true,
1577 			                                   special_color_flag,
1578 			                                   &special_color)))
1579 			{
1580 				continue;
1581 			}
1582 #endif
1583 
1584 			if ((io) && (io->ioflags & IO_ZMAP))
1585 			{
1586 				CalculateInterZMapp(eobj, i, paf, pTex, tv);
1587 			}
1588 
1589 			////////////////////////////////////////////////////////////////////////
1590 			// HALO HANDLING START
1591 			if ( need_halo && io )
1592 			{
1593 				long	lfr, lfg, lfb;
1594 				float	ffr, ffg, ffb;
1595 				float	tot	=	0;
1596 				float	_ffr[3];
1597 
1598 				IO_HALO curhalo;
1599 				memcpy(&curhalo, &io->halo, sizeof(IO_HALO));
1600 				int curhaloInitialized = 0;
1601 
1602 				long max_c;
1603 
1604 				if (use_io == entities.player())
1605 					max_c = 4;
1606 				else
1607 					max_c = 1;
1608 
1609 				for (long cnt = 0 ; cnt < max_c ; cnt++)
1610 				{
1611 					switch (cnt)
1612 					{
1613 						case 0:
1614 
1615 							if (use_io == entities.player())
1616 							{
1617 								if (hio_player)
1618 								{
1619 									memcpy(&curhalo, &use_io->halo, sizeof(IO_HALO));
1620 									++curhaloInitialized;
1621 								}
1622 								else continue;
1623 							}
1624 							else
1625 							{
1626 								memcpy(&curhalo, &io->halo, sizeof(IO_HALO));
1627 								++curhaloInitialized;
1628 							}
1629 
1630 							break;
1631 						case 1:
1632 
1633 							if ((hio_helmet)
1634 							        &&	(IsInSelection(use_io->obj, paf[0], use_io->obj->fastaccess.sel_head) >= 0))
1635 							{
1636 								memcpy(&curhalo, &hio_helmet->halo, sizeof(IO_HALO));
1637 								++curhaloInitialized;
1638 							}
1639 							else continue;
1640 
1641 							break;
1642 						case 2:
1643 
1644 							if ((hio_armor)
1645 							        &&	(IsInSelection(use_io->obj, paf[0], use_io->obj->fastaccess.sel_chest) >= 0))
1646 							{
1647 								memcpy(&curhalo, &hio_armor->halo, sizeof(IO_HALO));
1648 								++curhaloInitialized;
1649 							}
1650 							else continue;
1651 
1652 							break;
1653 						case 3:
1654 
1655 							if ((hio_leggings)
1656 							        &&	(IsInSelection(use_io->obj, paf[0], use_io->obj->fastaccess.sel_leggings) >= 0))
1657 							{
1658 								memcpy(&curhalo, &hio_leggings->halo, sizeof(IO_HALO)) ;
1659 								++curhaloInitialized;
1660 							}
1661 							else continue;
1662 
1663 							break;
1664 					}
1665 
1666 					arx_assert(curhaloInitialized > 0);
1667 
1668 					TexturedVertex * workon;
1669 					workon	= tv;
1670 
1671 					long o;
1672 
1673 					for (o = 0 ; o < 3 ; o++)
1674 					{
1675 						float tttz	= EEfabs(eobj->vertexlist3[paf[o]].norm.z) * ( 1.0f / 2 );
1676 						float power	=	255.f - (float)(255.f * tttz);
1677 						power		*=	(1.f - invisibility);
1678 
1679 						if (power > 255.f) power = 255.f;
1680 						else if (power < 0.f) power = 0.f;
1681 
1682 						ffr			=	curhalo.color.r * power;
1683 						ffg			=	curhalo.color.g * power;
1684 						ffb			=	curhalo.color.b * power;
1685 						tot			+=	power;
1686 						_ffr[o]		=	power;
1687 						lfr = ffr;
1688 						lfg = ffg;
1689 						lfb = ffb;
1690 						tv[o].color = 0xFF000000L | (((lfr) & 255) << 16) |	(((lfg) & 255) << 8) | ((lfb) & 255);
1691 					}
1692 
1693 					//GRenderer->SetCulling(Renderer::CullNone);
1694 					if (tot > 260)   //260.f)
1695 					{
1696 						long first;
1697 						long second;
1698 						long third;
1699 
1700 						if ((_ffr[0] >= _ffr[1]) && (_ffr[1] >= _ffr[2]))
1701 						{
1702 							first = 0;
1703 							second = 1;
1704 							third = 2;
1705 						}
1706 						else if ((_ffr[0] >= _ffr[2]) && (_ffr[2] >= _ffr[1]))
1707 						{
1708 							first = 0;
1709 							second = 2;
1710 							third = 1;
1711 						}
1712 						else if ((_ffr[1] >= _ffr[0]) && (_ffr[0] >= _ffr[2]))
1713 						{
1714 							first = 1;
1715 							second = 0;
1716 							third = 2;
1717 						}
1718 						else if ((_ffr[1] >= _ffr[2]) && (_ffr[2] >= _ffr[0]))
1719 						{
1720 							first = 1;
1721 							second = 2;
1722 							third = 0;
1723 						}
1724 						else if ((_ffr[2] >= _ffr[0]) && (_ffr[0] >= _ffr[1]))
1725 						{
1726 							first = 2;
1727 							second = 0;
1728 							third = 1;
1729 						}
1730 						else
1731 						{
1732 							first = 2;
1733 							second = 1;
1734 							third = 0;
1735 						}
1736 
1737 
1738 						if ((_ffr[first] > 150.f) && (_ffr[second] > 110.f))
1739 						{
1740 							Vec3f		vect1, vect2;
1741 							TexturedVertex *	vert = &LATERDRAWHALO[(HALOCUR << 2)];
1742 
1743 							if(HALOCUR < ((long)HALOMAX) - 1) {
1744 								HALOCUR++;
1745 							}
1746 
1747 							memcpy(&vert[0], &workon[first], sizeof(TexturedVertex));
1748 							memcpy(&vert[1], &workon[first], sizeof(TexturedVertex));
1749 							memcpy(&vert[2], &workon[second], sizeof(TexturedVertex));
1750 							memcpy(&vert[3], &workon[second], sizeof(TexturedVertex));
1751 
1752 							float siz = ddist * (curhalo.radius * (EEsin((float)(arxtime.get_frame_time() + i) * ( 1.0f / 100 )) * ( 1.0f / 10 ) + 1.f)) * 0.6f;
1753 
1754 							if ((io == entities.player()) && (ddist > 0.8f) && !EXTERNALVIEW)
1755 								siz *= 1.5f;
1756 
1757 							vect1.x = workon[first].p.x - workon[third].p.x;
1758 							vect1.y = workon[first].p.y - workon[third].p.y;
1759 							float len1 = 2.f / ffsqrt(vect1.x * vect1.x + vect1.y * vect1.y);
1760 
1761 							if (vect1.x < 0.f) len1 *= 1.2f;
1762 
1763 							vect1.x *= len1;
1764 							vect1.y *= len1;
1765 							vect2.x	 = workon[second].p.x - workon[third].p.x;
1766 							vect2.y	 = workon[second].p.y - workon[third].p.y;
1767 
1768 							float len2 = 1.f / ffsqrt(vect2.x * vect2.x + vect2.y * vect2.y);
1769 
1770 							if (vect2.x < 0.f) len2 *= 1.2f;
1771 
1772 							vect2.x		*= len2;
1773 							vect2.y		*= len2;
1774 							vert[1].p.x	+= (vect1.x + 0.2f - rnd() * 0.1f) * siz;
1775 							vert[1].p.y	+= (vect1.y + 0.2f - rnd() * 0.1f) * siz;
1776 							vert[1].color = 0xFF000000;
1777 
1778 							float valll;
1779 							valll = 0.005f + (EEfabs(workon[first].p.z) - EEfabs(workon[third].p.z))
1780 							               + (EEfabs(workon[second].p.z) - EEfabs(workon[third].p.z));
1781 							valll = 0.0001f + valll * ( 1.0f / 10 );
1782 
1783 							if (valll < 0.f) valll = 0.f;
1784 
1785 							vert[1].p.z	+= valll;
1786 							vert[2].p.z	+= valll;
1787 							vert[0].p.z	+= 0.0001f;
1788 							vert[3].p.z	+= 0.0001f;//*( 1.0f / 2 );
1789 							vert[1].rhw	*= .98f;
1790 							vert[2].rhw	*= .98f;
1791 							vert[0].rhw	*= .98f;
1792 							vert[3].rhw	*= .98f;
1793 
1794 							vert[2].p.x += (vect2.x + 0.2f - rnd() * 0.1f) * siz;
1795 							vert[2].p.y += (vect2.y + 0.2f - rnd() * 0.1f) * siz;
1796 
1797 							vert[1].p.z = (vert[1].p.z + MAX_ZEDE) * ( 1.0f / 2 );
1798 							vert[2].p.z = (vert[2].p.z + MAX_ZEDE) * ( 1.0f / 2 );
1799 
1800 							if (curhalo.flags & HALO_NEGATIVE)
1801 								vert[2].color = 0x00000000;
1802 							else
1803 								vert[2].color = 0xFF000000;
1804 						}
1805 					}
1806 				}
1807 
1808 				for (long o = 0 ; o < 3 ; o++)
1809 				{
1810 					paf[o]		= eface->vid[o];
1811 					tv[o].color = eobj->vertexlist3[paf[o]].vert.color;
1812 				}
1813 			}
1814 
1815 			////////////////////////////////////////////////////////////////////////
1816 			// HALO HANDLING END
1817 			////////////////////////////////////////////////////////////////////////
1818 
1819 			if (special_color_flag & 2)
1820 			{
1821 				TexturedVertex * tv2;
1822 				{
1823 					tv2 = PushVertexInTableCull(&TexSpecialColor);
1824 				}
1825 				memcpy(tv2, tv, sizeof(TexturedVertex) * 3);
1826 
1827 				tv2[0].color = tv2[1].color = tv2[2].color = Color::gray(special_color.r).toBGR();
1828 			}
1829 		}
1830 	}
1831 }
1832 
Cedric_BlendAnimation(EERIE_3DOBJ * eobj,float timm)1833 void Cedric_BlendAnimation(EERIE_3DOBJ * eobj, float timm) {
1834 	for (long i = 0; i < eobj->c_data->nb_bones; i++)
1835 	{
1836 		EERIE_QUAT tquat;
1837 		Quat_Copy(&tquat, &eobj->c_data->bones[i].quatinit);
1838 		EERIE_QUAT q2;
1839 		Quat_Copy(&q2, &eobj->c_data->bones[i].quatlast);
1840 
1841 		Quat_Slerp(&eobj->c_data->bones[i].quatinit , &q2, &tquat, timm);
1842 
1843 		eobj->c_data->bones[i].transinit = eobj->c_data->bones[i].translast
1844 		                                   + (eobj->c_data->bones[i].transinit
1845 		                                      - eobj->c_data->bones[i].translast) * timm;
1846 	}
1847 }
1848 
Cedric_SaveBlendData(Entity * io)1849 void Cedric_SaveBlendData(Entity * io) {
1850 	if (io->obj->c_data)
1851 	{
1852 		for (long i = 0; i < io->obj->c_data->nb_bones; i++)
1853 		{
1854 			Quat_Copy(&io->obj->c_data->bones[i].quatlast, &io->obj->c_data->bones[i].quatinit);
1855 			io->obj->c_data->bones[i].scalelast = io->obj->c_data->bones[i].scaleinit;
1856 			io->obj->c_data->bones[i].translast = io->obj->c_data->bones[i].transinit;
1857 		}
1858 	}
1859 }
1860 
Cedric_ManageExtraRotationsFirst(Entity * io,EERIE_3DOBJ * obj)1861 void Cedric_ManageExtraRotationsFirst(Entity * io, EERIE_3DOBJ * obj)
1862 {
1863 	for (long i = 0; i != obj->c_data->nb_bones; i++)
1864 	{
1865 		Quat_Init(&obj->c_data->bones[i].quatinit);
1866 		obj->c_data->bones[i].transinit = obj->c_data->bones[i].transinit_global;
1867 	}
1868 
1869 	if ((io) && (io->ioflags & IO_NPC) && (io->_npcdata->ex_rotate))
1870 	{
1871 		for (long k = 0; k < MAX_EXTRA_ROTATE; k++)
1872 		{
1873 			long i = io->_npcdata->ex_rotate->group_number[k];
1874 
1875 			if(i >= 0) {
1876 				Anglef vt1;
1877 				EERIE_QUAT quat1;
1878 				vt1.a = radians(io->_npcdata->ex_rotate->group_rotate[k].g);
1879 				vt1.b = radians(io->_npcdata->ex_rotate->group_rotate[k].b);
1880 				vt1.g = radians(io->_npcdata->ex_rotate->group_rotate[k].a);
1881 				QuatFromAngles(&quat1, &vt1);
1882 				Quat_Copy(&obj->c_data->bones[i].quatinit, &quat1);
1883 			}
1884 		}
1885 	}
1886 }
1887 
Cedric_IO_Visible(Entity * io)1888 static bool Cedric_IO_Visible(Entity * io) {
1889 	if (io == entities.player()) return true;
1890 
1891 	if(ACTIVEBKG && io) {
1892 
1893 		if (distSqr(io->pos, ACTIVECAM->pos) > square(ACTIVECAM->cdepth) * square(0.6f))
1894 			return false;
1895 
1896 		long xx, yy;
1897 		xx = io->pos.x * ACTIVEBKG->Xmul;
1898 		yy = io->pos.z * ACTIVEBKG->Zmul;
1899 
1900 		if ((xx >= 1) && (yy >= 1) && (xx < ACTIVEBKG->Xsize - 1) && (yy < ACTIVEBKG->Zsize - 1))
1901 		{
1902 			for (long ky = yy - 1; ky <= yy + 1; ky++)
1903 				for (long kx = xx - 1; kx <= xx + 1; kx++)
1904 				{
1905 					FAST_BKG_DATA * feg = (FAST_BKG_DATA *)&ACTIVEBKG->fastdata[kx][ky];
1906 
1907 					if (feg->treat)
1908 						return true;
1909 				}
1910 
1911 			return false;
1912 		}
1913 	}
1914 
1915 	return true;
1916 }
1917 
1918 extern long MUST_DRAW;
1919 extern long EXTERNALVIEW;
1920 
1921 /* Apply animation and draw object */
Cedric_AnimateDrawEntity(EERIE_3DOBJ * eobj,ANIM_USE * animuse,Anglef * angle,Vec3f * pos,Entity * io,bool render,bool update_movement)1922 void Cedric_AnimateDrawEntity(EERIE_3DOBJ * eobj,
1923                               ANIM_USE * animuse,
1924                               Anglef * angle,
1925                               Vec3f * pos,
1926                               Entity * io,
1927                               bool render,
1928                               bool update_movement) {
1929 
1930 	float 				invisibility;
1931 	float 				scale;
1932 	float				timm;
1933 	Vec3f			ftr;
1934 	EERIE_C_DATA	*	obj;
1935 
1936 	// Init some data
1937 	Cedric_ResetBoundingBox(io);
1938 
1939 	// Set scale and invisibility factors
1940 	Cedric_GetScale(scale, invisibility, io);
1941 
1942 	// Flag linked objects
1943 	//Cedric_FlagLinkedObjects(eobj); ???
1944 
1945 	// Is There any Between-Animations Interpolation to make ? timm>0.f
1946 	Cedric_GetTime(timm, io);
1947 
1948 	// Buffer size check
1949 	if(eobj->nbgroups > max_grps) {
1950 		//todo free
1951 		grps = (unsigned char *)realloc(grps, eobj->nbgroups);
1952 		max_grps = eobj->nbgroups;
1953 	}
1954 
1955 	memset(grps, 0, eobj->nbgroups);
1956 
1957 	Cedric_AnimCalcTranslation(io, animuse, scale, ftr, update_movement);
1958 
1959 	if(Cedric_IO_Visible(io)) {
1960 
1961 		// Manage Extra Rotations in Local Space
1962 		Cedric_ManageExtraRotationsFirst(io, eobj);
1963 
1964 		// Perform animation in Local space
1965 		Cedric_AnimateObject(io, eobj, animuse);
1966 
1967 		// Check for Animation Blending in Local space
1968 		if (io)
1969 		{
1970 			if (timm > 0.f)
1971 			{
1972 				Cedric_BlendAnimation(eobj, timm);
1973 				Cedric_SaveBlendData(io);
1974 			}
1975 			else
1976 				Cedric_SaveBlendData(io);
1977 		}
1978 
1979 		// Build skeleton in Object Space
1980 		Cedric_ConcatenateTM(io, eobj->c_data, angle, pos, ftr, scale);
1981 
1982 		/* Display the object */
1983 		obj = eobj->c_data;
1984 
1985 		if (!obj)
1986 			return;
1987 
1988 
1989 		if(Cedric_TransformVerts(io, eobj, obj, pos) && render) {
1990 
1991 			INTER_DRAW++;
1992 
1993 			if(!Cedric_ApplyLighting(eobj, obj, io, pos)) {
1994 				return;
1995 			}
1996 
1997 			Cedric_RenderObject(eobj, obj, io, pos, ftr, invisibility);
1998 
1999 			if (io)
2000 			{
2001 				io->bbox1.x = (short)BBOXMIN.x;
2002 				io->bbox2.x = (short)BBOXMAX.x;
2003 				io->bbox1.y = (short)BBOXMIN.y;
2004 				io->bbox2.y = (short)BBOXMAX.y;
2005 			}
2006 
2007 			// Now we can render Linked Objects
2008 
2009 			for (long k = 0; k < eobj->nblinked; k++)
2010 			{
2011 				if ((eobj->linked[k].lgroup != -1) && eobj->linked[k].obj) {
2012 
2013 					eobj->linked[k].modinfo.rot = Anglef::ZERO;
2014 
2015 					float old = 0.f;
2016 					Entity * ioo = (Entity *)eobj->linked[k].io;
2017 					EERIE_3DOBJ * obj = (EERIE_3DOBJ *) eobj->linked[k].obj;
2018 
2019 					// Store item invisibility flag
2020 					if (io && ioo)
2021 					{
2022 						old = ioo->invisibility;
2023 
2024 						if (io == entities.player())
2025 						{
2026 							ioo->invisibility = INVISIBILITY_OVERRIDE;
2027 						}
2028 						else
2029 						{
2030 							INVISIBILITY_OVERRIDE = 0.f;
2031 							ioo->invisibility = invisibility;
2032 						}
2033 					}
2034 					else
2035 					{
2036 						if (ioo)
2037 						{
2038 							INVISIBILITY_OVERRIDE = 0.f;
2039 							ioo->invisibility = invisibility;
2040 						}
2041 						else
2042 							INVISIBILITY_OVERRIDE = invisibility;
2043 					}
2044 
2045 					if (ioo)
2046 					{
2047 						if ((ioo->ignition > 0.f) || (ioo->ioflags & IO_FIERY))
2048 							ManageIgnition(ioo);
2049 					}
2050 
2051 					MUST_DRAW = 1;
2052 
2053 					// specific check to avoid drawing player weapon on its back when in subjective view
2054 					if ((io == entities.player()) &&
2055 					        (eobj->linked[k].lidx == entities.player()->obj->fastaccess.weapon_attach)
2056 					        && (!EXTERNALVIEW))
2057 						continue;
2058 
2059 					long ll = eobj->linked[k].lidx2;
2060 					eobj->linked[k].modinfo.link_position = obj->vertexlist[ll].v - obj->vertexlist[obj->origin].v;
2061 
2062 					EERIE_QUAT quat;
2063 					ll = eobj->linked[k].lidx;
2064 					Vec3f * posi = &eobj->vertexlist3[ll].v;
2065 					Quat_Copy(&quat, &eobj->c_data->bones[eobj->linked[k].lgroup].quatanim);
2066 
2067 					EERIEMATRIX	 matrix;
2068 					MatrixFromQuat(&matrix, &quat);
2069 					DrawEERIEInterMatrix(obj, &matrix, posi, ioo, &eobj->linked[k].modinfo);
2070 					INVISIBILITY_OVERRIDE = 0.f;
2071 
2072 					// Restore item invisibility flag
2073 					if (ioo)
2074 						ioo->invisibility = old;
2075 
2076 					MUST_DRAW = 0;
2077 
2078 				}
2079 			}
2080 
2081 		}
2082 	}
2083 }
2084 
MakeCLight(Entity * io,Color3f * infra,Anglef * angle,Vec3f * pos,EERIE_3DOBJ * eobj,EERIEMATRIX * BIGMAT,EERIE_QUAT * BIGQUAT)2085 void MakeCLight(Entity * io, Color3f * infra, Anglef * angle, Vec3f * pos, EERIE_3DOBJ * eobj, EERIEMATRIX * BIGMAT, EERIE_QUAT * BIGQUAT)
2086 {
2087 	if ((Project.improve) && (!io))
2088 	{
2089 		infra->r = 0.6f;
2090 		infra->g = 0.f;
2091 		infra->b = 1.f;
2092 	}
2093 
2094 	llightsInit();
2095 	Vec3f tv = *pos;
2096 
2097 	if ((io) && (io->ioflags & IO_ITEM))
2098 		tv.y -= 60.f;
2099 	else
2100 		tv.y -= 90.f;
2101 
2102 	for (long i = 0; i < TOTIOPDL; i++)
2103 	{
2104 		if (IO_PDL[i]->fallend + 500.f < 0)
2105 			continue;
2106 
2107 		Insertllight(IO_PDL[i], fdist(IO_PDL[i]->pos, tv));
2108 	}
2109 
2110 	for (int i = 0; i < TOTPDL; i++)
2111 	{
2112 		if (PDL[i]->fallend + 500.f < 0)
2113 			continue;
2114 
2115 		Insertllight(PDL[i], fdist(PDL[i]->pos, tv));
2116 	}
2117 
2118 	Preparellights(&tv);
2119 
2120 	if ((io) && (io->ioflags & IO_ANGULAR)) return;
2121 
2122 	Vec3f		vLight;
2123 	Vec3f		vTLights[32];
2124 	EERIE_QUAT		qInvert;
2125 
2126 	if (BIGMAT != NULL)
2127 	{
2128 		QuatFromMatrix(qInvert, *BIGMAT);
2129 	}
2130 	else
2131 	{
2132 		if (BIGQUAT != NULL)
2133 		{
2134 			qInvert = *BIGQUAT;
2135 		}
2136 		else
2137 		{
2138 			//FIX LIGHT
2139 			Anglef vt1;
2140 
2141 			if (angle)
2142 			{
2143 				vt1 = *angle;
2144 			}
2145 			else
2146 			{
2147 				if (io)
2148 					vt1 = io->angle;
2149 				else
2150 					vt1 = eobj->angle;
2151 			}
2152 
2153 			vt1.a = radians(MAKEANGLE(-vt1.g));
2154 			vt1.b = radians(MAKEANGLE(vt1.b));
2155 			vt1.g = radians(MAKEANGLE(vt1.a));
2156 			QuatFromAngles(&qInvert, &vt1);
2157 		}
2158 	}
2159 
2160 
2161 
2162 		for (size_t i = 0; i < eobj->vertexlist.size(); i++)
2163 		{
2164 			float r, g, b;
2165 			long ir, ig, ib;
2166 
2167 			if ((io) && (io->ioflags & (IO_NPC | IO_ITEM)))
2168 			{
2169 				r = g = b = NPC_ITEMS_AMBIENT_VALUE_255;
2170 			}
2171 			else
2172 			{
2173 				r = ACTIVEBKG->ambient255.r;
2174 				g = ACTIVEBKG->ambient255.g;
2175 				b = ACTIVEBKG->ambient255.b;
2176 			}
2177 
2178 			Vec3f * posVert = &eobj->vertexlist3[i].v;
2179 
2180 			for (long l = 0 ; l != MAX_LLIGHTS; l++)
2181 			{
2182 				EERIE_LIGHT * Cur_llights = llights[l];
2183 
2184 				if (Cur_llights)
2185 				{
2186 					float	cosangle;
2187 
2188 					vLight = (llights[l]->pos - *posVert).getNormalized();
2189 
2190 					TransformInverseVertexQuat(&qInvert, &vLight, &vTLights[l]);
2191 					Vec3f * Cur_vLights = &vTLights[l];
2192 
2193 					// Get cos angle between light and vertex norm
2194 					cosangle = (eobj->vertexlist[i].norm.x * Cur_vLights->x +
2195 					            eobj->vertexlist[i].norm.y * Cur_vLights->y +
2196 					            eobj->vertexlist[i].norm.z * Cur_vLights->z);
2197 
2198 					// If light visible
2199 					if (cosangle > 0.f)
2200 					{
2201 						float distance = fdist(*posVert, Cur_llights->pos);
2202 
2203 						// Evaluate its intensity depending on the distance Light<->Object
2204 						if (distance <= Cur_llights->fallstart)
2205 							cosangle *= Cur_llights->precalc;
2206 						else
2207 						{
2208 							float p = ((Cur_llights->fallend - distance) * Cur_llights->falldiffmul);
2209 
2210 							if (p <= 0.f)
2211 								cosangle = 0.f;
2212 							else
2213 								cosangle *= p * Cur_llights->precalc;
2214 						}
2215 
2216 						r += Cur_llights->rgb255.r * cosangle;
2217 						g += Cur_llights->rgb255.g * cosangle;
2218 						b += Cur_llights->rgb255.b * cosangle;
2219 					}
2220 				}
2221 				else
2222 					break;
2223 			}
2224 
2225 			if (eobj->drawflags & DRAWFLAG_HIGHLIGHT)
2226 			{
2227 				r += iHighLight;
2228 				g += iHighLight;
2229 				b += iHighLight;
2230 			}
2231 
2232 			if ((Project.improve) &&  (!io))
2233 			{
2234 					r *= infra->r;
2235 					g *= infra->g;
2236 					b *= infra->b;
2237 					r += infra->r * 512.f;
2238 					g += infra->g;
2239 					b += infra->b * 400.f;
2240 			}
2241 
2242 			ir = clipByte255(r);
2243 			ig = clipByte255(g);
2244 			ib = clipByte255(b);
2245 			eobj->vertexlist3[i].vert.color = 0xff000000L | (((ir) & 255) << 16) | (((ig) & 255) << 8) | ((ib) & 255);
2246 		}
2247 }
2248 
MakeCLight2(Entity * io,Color3f * infra,Anglef * angle,Vec3f * pos,EERIE_3DOBJ * eobj,EERIEMATRIX * BIGMAT,EERIE_QUAT * BIGQUAT,long ii)2249 void MakeCLight2(Entity * io, Color3f * infra, Anglef * angle, Vec3f * pos, EERIE_3DOBJ * eobj, EERIEMATRIX * BIGMAT, EERIE_QUAT * BIGQUAT, long ii) {
2250 
2251 	Vec3f vLight;
2252 	Vec3f vTLights[32];
2253 	EERIE_QUAT qInvert;
2254 
2255 	if (BIGMAT != NULL)
2256 	{
2257 		QuatFromMatrix(qInvert, *BIGMAT);
2258 	}
2259 	else
2260 	{
2261 		if (BIGQUAT != NULL)
2262 		{
2263 			qInvert = *BIGQUAT;
2264 		}
2265 		else
2266 		{
2267 			Anglef vt1;
2268 
2269 			if (angle)
2270 			{
2271 				vt1 = *angle;
2272 			}
2273 			else
2274 			{
2275 				if (io)
2276 					vt1 = io->angle;
2277 				else
2278 					vt1 = eobj->angle;
2279 			}
2280 
2281 			vt1 = Anglef(radians(vt1.a), radians(vt1.b), radians(vt1.g));
2282 			QuatFromAngles(&qInvert, &vt1);
2283 		}
2284 	}
2285 
2286 	Vec3f tv = *pos;
2287 
2288 	if ((io) && (io->ioflags & IO_ITEM))
2289 		tv.y -= 60.f;
2290 	else
2291 		tv.y -= 90.f;
2292 
2293 	for(long l = 0; l != MAX_LLIGHTS; l++) {
2294 		if(llights[l]) {
2295 			vLight = (llights[l]->pos - tv) / dists[l];
2296 			TransformInverseVertexQuat(&qInvert, &vLight, &vTLights[l]);
2297 		} else {
2298 			break;
2299 		}
2300 	}
2301 
2302 	long paf[3];
2303 	paf[0] = eobj->facelist[ii].vid[0];
2304 	paf[1] = eobj->facelist[ii].vid[1];
2305 	paf[2] = eobj->facelist[ii].vid[2];
2306 
2307 	for (long i = 0; i < 3; i++)
2308 	{
2309 		float r, g, b;
2310 		long ir, ig, ib;
2311 
2312 		if ((io) && (io->ioflags & (IO_NPC | IO_ITEM)))
2313 		{
2314 			r = g = b = NPC_ITEMS_AMBIENT_VALUE_255;
2315 		}
2316 		else
2317 		{
2318 			r = ACTIVEBKG->ambient255.r;
2319 			g = ACTIVEBKG->ambient255.g;
2320 			b = ACTIVEBKG->ambient255.b;
2321 		}
2322 
2323 		Vec3f * posVert = &eobj->vertexlist3[paf[i]].v;
2324 
2325 		for (int l = 0 ; l != MAX_LLIGHTS; l++)
2326 		{
2327 			EERIE_LIGHT * Cur_llights = llights[l];
2328 
2329 			if (Cur_llights)
2330 			{
2331 				float	cosangle;
2332 				float		oolength = 1.f / fdist(*posVert, Cur_llights->pos);
2333 				vLight = (llights[l]->pos - *posVert) * oolength;
2334 
2335 				TransformInverseVertexQuat(&qInvert, &vLight, &vTLights[l]);
2336 				Vec3f * Cur_vLights = &vTLights[l];
2337 
2338 				cosangle = (eobj->facelist[ii].norm.x * Cur_vLights->x +
2339 				            eobj->facelist[ii].norm.y * Cur_vLights->y +
2340 				            eobj->facelist[ii].norm.z * Cur_vLights->z) * ( 1.0f / 2 );
2341 
2342 				// If light visible
2343 				if (cosangle > 0.f)
2344 				{
2345 					float distance = fdist(*posVert, Cur_llights->pos);
2346 
2347 					// Evaluate its intensity depending on the distance Light<->Object
2348 					if (distance <= Cur_llights->fallstart)
2349 						cosangle *= Cur_llights->precalc;
2350 					else
2351 					{
2352 						float p = ((Cur_llights->fallend - distance) * Cur_llights->falldiffmul);
2353 
2354 						if (p <= 0.f)
2355 							cosangle = 0.f;
2356 						else
2357 							cosangle *= p * Cur_llights->precalc;
2358 					}
2359 
2360 					r += Cur_llights->rgb255.r * cosangle;
2361 					g += Cur_llights->rgb255.g * cosangle;
2362 					b += Cur_llights->rgb255.b * cosangle;
2363 				}
2364 			}
2365 			else
2366 				break;
2367 		}
2368 
2369 		if (eobj->drawflags & DRAWFLAG_HIGHLIGHT)
2370 		{
2371 			r += iHighLight;
2372 			g += iHighLight;
2373 			b += iHighLight;
2374 		}
2375 
2376 		if (Project.improve)
2377 		{
2378 			r *= infra->r;
2379 			g *= infra->g;
2380 			b *= infra->b;
2381 		}
2382 
2383 		ir = clipByte255(r);
2384 		ig = clipByte255(g);
2385 		ib = clipByte255(b);
2386 		eobj->vertexlist3[paf[i]].vert.color = 0xff000000L | (((ir) & 255) << 16) | (((ig) & 255) << 8) | ((ib) & 255);
2387 	}
2388 }
2389 
2390 
ApplyDynLight(EERIEPOLY * ep)2391 void ApplyDynLight(EERIEPOLY * ep)
2392 {
2393 	long nbvert, i;
2394 
2395 	if (ep->type & POLY_QUAD) nbvert = 4;
2396 	else nbvert = 3;
2397 
2398 	if (TOTPDL == 0)
2399 	{
2400 		for (i = 0; i < nbvert; i++)
2401 			ep->tv[i].color = ep->v[i].color;
2402 
2403 		return;
2404 	}
2405 
2406 	Color3f rgb;
2407 	long j;
2408 
2409 	float epr[4];
2410 	float epg[4];
2411 	float epb[4];
2412 
2413 	for (i = 0; i < nbvert; i++)
2414 	{
2415 		long c = ep->v[i].color;
2416 		epr[i] = (float)((c >> 16) & 255);
2417 		epg[i] = (float)((c >> 8) & 255);
2418 		epb[i] = (float)(c & 255);
2419 	}
2420 
2421 	for (i = 0; i < TOTPDL; i++)
2422 	{
2423 		EERIE_LIGHT * el = PDL[i];
2424 
2425 		if (el->fallend + 35.f < 0)
2426 		{
2427 			TSU_TEST_NB_LIGHT ++;
2428 			continue;
2429 		}
2430 
2431 		if (distSqr(el->pos, ep->center) <= square(el->fallend + 35.f))
2432 		{
2433 			if(Project.improve) {
2434 				rgb.r = el->rgb255.r * 4.f;
2435 				rgb.g = rgb.b = 0.2f;
2436 			} else {
2437 				rgb = el->rgb255;
2438 			}
2439 
2440 			for (j = 0; j < nbvert; j++)
2441 			{
2442 				Vec3f v(ep->v[j].p.x,ep->v[j].p.y, ep->v[j].p.z);
2443 				if (el->fallend < 0)
2444 				{
2445 					TSU_TEST_NB ++;
2446 					continue;
2447 				}
2448 
2449 				float d = fdist(el->pos, ep->v[j].p);
2450 
2451 				if (d <= el->fallend)
2452 				{
2453 					float divd = 1.f / d;
2454 					float nvalue;
2455 
2456 					Vec3f v1;
2457 					v1 = (el->pos - ep->v[j].p) * divd;
2458 					nvalue = dot(v1, ep->nrml[j]) * (1.0f / 2);
2459 
2460 					if (nvalue > 1.f) nvalue = 1.f;
2461 					else if (nvalue < 0.f) nvalue = 0.f;
2462 
2463 					if (nvalue > 0.f)
2464 					{
2465 						////
2466 						if (d <= el->fallstart)
2467 						{
2468 							d = nvalue * el->precalc;
2469 						}
2470 						else
2471 						{
2472 							d -= el->fallstart;
2473 							d = (el->falldiff - d) * el->falldiffmul * nvalue * el->precalc;
2474 						}
2475 
2476 						epr[j] += rgb.r * d;
2477 						epg[j] += rgb.g * d;
2478 						epb[j] += rgb.b * d;
2479 					}
2480 				}
2481 				else if (d > el->fallend + 100.f) break;
2482 			}
2483 		}
2484 	}
2485 
2486 	long lepr, lepg, lepb;
2487 
2488 	for (j = 0; j < nbvert; j++)
2489 	{
2490 		lepr = clipByte255(epr[j]);
2491 		lepg = clipByte255(epg[j]);
2492 		lepb = clipByte255(epb[j]);
2493 		ep->tv[j].color = (0xFF000000L  |
2494 		                   (lepr << 16) |
2495 		                   (lepg << 8) |
2496 		                   (lepb));
2497 	}
2498 }
2499 
2500 //*************************************************************************************
ApplyDynLight_VertexBuffer(EERIEPOLY * ep,SMY_VERTEX * _pVertex,unsigned short _usInd0,unsigned short _usInd1,unsigned short _usInd2,unsigned short _usInd3)2501 void ApplyDynLight_VertexBuffer(EERIEPOLY * ep, SMY_VERTEX * _pVertex, unsigned short _usInd0, unsigned short _usInd1, unsigned short _usInd2, unsigned short _usInd3)
2502 {
2503 	long nbvert, i;
2504 
2505 	if (ep->type & POLY_QUAD) nbvert = 4;
2506 	else nbvert = 3;
2507 
2508 	if (TOTPDL == 0)
2509 	{
2510 
2511 		ep->tv[0].color = _pVertex[_usInd0].color = ep->v[0].color;
2512 		ep->tv[1].color = _pVertex[_usInd1].color = ep->v[1].color;
2513 		ep->tv[2].color = _pVertex[_usInd2].color = ep->v[2].color;
2514 
2515 		if (nbvert & 4)
2516 		{
2517 			ep->tv[3].color = _pVertex[_usInd3].color = ep->v[3].color;
2518 		}
2519 
2520 		return;
2521 	}
2522 
2523 	long j;
2524 	float epr[4];
2525 	float epg[4];
2526 	float epb[4];
2527 
2528 	for (i = 0; i < nbvert; i++)
2529 	{
2530 		long c = ep->v[i].color;
2531 		epr[i] = (float)(long)((c >> 16) & 255);
2532 		epg[i] = (float)(long)((c >> 8) & 255);
2533 		epb[i] = (float)(long)(c & 255);
2534 	}
2535 
2536 	for (i = 0; i < TOTPDL; i++)
2537 	{
2538 		EERIE_LIGHT * el = PDL[i];
2539 
2540 		for (j = 0; j < nbvert; j++)
2541 		{
2542 			float d = fdist(el->pos, ep->v[j].p);
2543 
2544 			if (d < el->fallend)
2545 			{
2546 				float nvalue;
2547 
2548 				nvalue =	((el->pos.x - ep->v[j].p.x) * ep->nrml[j].x
2549 				             +	(el->pos.y - ep->v[j].p.y) * ep->nrml[j].y
2550 				             +	(el->pos.z - ep->v[j].p.z) * ep->nrml[j].z
2551 				         ) * 0.5f / d;
2552 
2553 				if (nvalue > 0.f)
2554 				{
2555 					if (d <= el->fallstart)
2556 					{
2557 						d = el->precalc * nvalue;
2558 					}
2559 					else
2560 					{
2561 						d -= el->fallstart;
2562 						d = (el->falldiff - d) * el->falldiffmul * el->precalc * nvalue;
2563 					}
2564 
2565 					epr[j] += el->rgb255.r * d;
2566 
2567 					epg[j] += el->rgb255.g * d;
2568 
2569 					epb[j] += el->rgb255.b * d;
2570 				}
2571 			}
2572 			else if (d > el->fallend + 100.f)
2573 				break;
2574 		}
2575 
2576 	}
2577 
2578 	long lepr, lepg, lepb;
2579 
2580 	lepr = clipByte255(epr[0]);
2581 	lepg = clipByte255(epg[0]);
2582 	lepb = clipByte255(epb[0]);
2583 	ep->tv[0].color = _pVertex[_usInd0].color =	(0xFF000000L  |
2584 	                  (lepr << 16) |
2585 	                  (lepg << 8) |
2586 	                  (lepb));
2587 	lepr = clipByte255(epr[1]);
2588 	lepg = clipByte255(epg[1]);
2589 	lepb = clipByte255(epb[1]);
2590 	ep->tv[1].color = _pVertex[_usInd1].color =	(0xFF000000L  |
2591 	                  (lepr << 16) |
2592 	                  (lepg << 8) |
2593 	                  (lepb));
2594 
2595 	lepr = clipByte255(epr[2]);
2596 	lepg = clipByte255(epg[2]);
2597 	lepb = clipByte255(epb[2]);
2598 	ep->tv[2].color = _pVertex[_usInd2].color =	(0xFF000000L  |
2599 	                  (lepr << 16) |
2600 	                  (lepg << 8) |
2601 	                  (lepb));
2602 
2603 	if (nbvert & 4)
2604 	{
2605 		lepr = clipByte255(epr[3]);
2606 		lepg = clipByte255(epg[3]);
2607 		lepb = clipByte255(epb[3]);
2608 		ep->tv[3].color = _pVertex[_usInd3].color =	(0xFF000000L  |
2609 		                  (lepr << 16) |
2610 		                  (lepg << 8) |
2611 		                  (lepb));
2612 	}
2613 }
2614 
2615 extern TILE_LIGHTS tilelights[MAX_BKGX][MAX_BKGZ];
2616 //*************************************************************************************
2617 
ApplyDynLight_VertexBuffer_2(EERIEPOLY * ep,short _x,short _y,SMY_VERTEX * _pVertex,unsigned short _usInd0,unsigned short _usInd1,unsigned short _usInd2,unsigned short _usInd3)2618 void ApplyDynLight_VertexBuffer_2(EERIEPOLY * ep, short _x, short _y, SMY_VERTEX * _pVertex, unsigned short _usInd0, unsigned short _usInd1, unsigned short _usInd2, unsigned short _usInd3)
2619 {
2620 	// Nuky - 25/01/11 - harmless refactor to understand what is slow.
2621 	//        MASSIVE speed up thanks to "harmless refactor", wtf ?
2622 
2623 	TILE_LIGHTS * tls = &tilelights[_x][_y];
2624 	long nbvert = (ep->type & POLY_QUAD) ? 4 : 3;
2625 
2626 	if (tls->num == 0)
2627 	{
2628 		_pVertex[_usInd0].color = ep->v[0].color;
2629 		ep->tv[0].color         = ep->v[0].color;
2630 		_pVertex[_usInd1].color = ep->v[1].color;
2631 		ep->tv[1].color         = ep->v[1].color;
2632 		_pVertex[_usInd2].color = ep->v[2].color;
2633 		ep->tv[2].color         = ep->v[2].color;
2634 
2635 		if (nbvert & 4)
2636 		{
2637 			_pVertex[_usInd3].color = ep->v[3].color;
2638 			ep->tv[3].color         = ep->v[3].color;
2639 		}
2640 
2641 		return;
2642 	}
2643 
2644 	long i, j;
2645 	float epr[4];
2646 	float epg[4];
2647 	float epb[4];
2648 
2649 	for (i = 0; i < nbvert; i++)
2650 	{
2651 		long c = ep->v[i].color;
2652 		epr[i] = (float)(long)((c >> 16) & 255);
2653 		epg[i] = (float)(long)((c >> 8) & 255);
2654 		epb[i] = (float)(long)(c & 255);
2655 	}
2656 
2657 	for (i = 0; i < tls->num; i++)
2658 	{
2659 		EERIE_LIGHT * el = tls->el[i];
2660 
2661 		for (j = 0; j < nbvert; j++)
2662 		{
2663 
2664 			float d = fdist(el->pos, ep->v[j].p);
2665 
2666 			if (d < el->fallend)
2667 			{
2668 				float nvalue;
2669 
2670 				nvalue =	((el->pos.x - ep->v[j].p.x) * ep->nrml[j].x
2671 				             +	(el->pos.y - ep->v[j].p.y) * ep->nrml[j].y
2672 				             +	(el->pos.z - ep->v[j].p.z) * ep->nrml[j].z
2673 				         ) * 0.5f / d;
2674 
2675 				if (nvalue > 0.f)
2676 				{
2677 					if (d <= el->fallstart)
2678 					{
2679 
2680 						d = el->precalc * nvalue;
2681 					}
2682 					else
2683 					{
2684 						d -= el->fallstart;
2685 
2686 						d = (el->falldiff - d) * el->falldiffmul * el->precalc * nvalue;
2687 					}
2688 
2689 					epr[j] += el->rgb255.r * d;
2690 
2691 					epg[j] += el->rgb255.g * d;
2692 
2693 					epb[j] += el->rgb255.b * d;
2694 				}
2695 			}
2696 			else if (d > el->fallend + 100.f)
2697 				break;
2698 		}
2699 
2700 	}
2701 
2702 	long lepr, lepg, lepb;
2703 
2704 	lepr = clipByte255(epr[0]);
2705 	lepg = clipByte255(epg[0]);
2706 	lepb = clipByte255(epb[0]);
2707 	ep->tv[0].color = _pVertex[_usInd0].color =	(0xFF000000L  |
2708 	                  (lepr << 16) |
2709 	                  (lepg << 8) |
2710 	                  (lepb));
2711 	lepr = clipByte255(epr[1]);
2712 	lepg = clipByte255(epg[1]);
2713 	lepb = clipByte255(epb[1]);
2714 	ep->tv[1].color = _pVertex[_usInd1].color =	(0xFF000000L  |
2715 	                  (lepr << 16) |
2716 	                  (lepg << 8) |
2717 	                  (lepb));
2718 
2719 	lepr = clipByte255(epr[2]);
2720 	lepg = clipByte255(epg[2]);
2721 	lepb = clipByte255(epb[2]);
2722 	ep->tv[2].color = _pVertex[_usInd2].color =	(0xFF000000L  |
2723 	                  (lepr << 16) |
2724 	                  (lepg << 8) |
2725 	                  (lepb));
2726 
2727 	if (nbvert & 4)
2728 	{
2729 		lepr = clipByte255(epr[3]);
2730 		lepg = clipByte255(epg[3]);
2731 		lepb = clipByte255(epb[3]);
2732 		ep->tv[3].color = _pVertex[_usInd3].color =	(0xFF000000L  |
2733 		                  (lepr << 16) |
2734 		                  (lepg << 8) |
2735 		                  (lepb));
2736 	}
2737 
2738 }
2739