/* * Copyright 2011-2012 Arx Libertatis Team (see the AUTHORS file) * * This file is part of Arx Libertatis. * * Arx Libertatis is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Arx Libertatis is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Arx Libertatis. If not, see . */ /* Based on: =========================================================================== ARX FATALIS GPL Source Code Copyright (C) 1999-2010 Arkane Studios SA, a ZeniMax Media company. This file is part of the Arx Fatalis GPL Source Code ('Arx Fatalis Source Code'). Arx Fatalis Source Code is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Arx Fatalis Source Code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Arx Fatalis Source Code. If not, see . In addition, the Arx Fatalis Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Arx Fatalis Source Code. If not, please request a copy in writing from Arkane Studios at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing Arkane Studios, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. =========================================================================== */ #include "animation/AnimationRender.h" #include #include #include #include #include "animation/Animation.h" #include "core/Application.h" #include "core/GameTime.h" #include "core/Core.h" #include "game/Damage.h" #include "game/Equipment.h" #include "game/EntityManager.h" #include "game/NPC.h" #include "game/Player.h" #include "game/Spells.h" #include "graphics/BaseGraphicsTypes.h" #include "graphics/GraphicsTypes.h" #include "graphics/Draw.h" #include "graphics/Math.h" #include "graphics/Renderer.h" #include "graphics/Vertex.h" #include "graphics/data/Mesh.h" #include "graphics/data/MeshManipulation.h" #include "graphics/data/TextureContainer.h" #include "graphics/particle/ParticleEffects.h" #include "math/Angle.h" #include "math/Vector3.h" #include "physics/Collisions.h" #include "platform/Platform.h" #include "scene/Light.h" #include "scene/GameSound.h" #include "scene/Scene.h" #include "scene/Interactive.h" using std::min; using std::max; unsigned char * grps = NULL; static long max_grps = 0; extern long FORCE_NO_HIDE; extern long USEINTERNORM; extern long INTER_DRAW; extern float dists[]; extern long BH_MODE; extern int iHighLight; extern TextureContainer TexSpecialColor; extern long TSU_TEST_NB; extern long TSU_TEST_NB_LIGHT; //#define USE_SOFTWARE_CLIPPING #ifdef USE_SOFTWARE_CLIPPING float SOFTNEARCLIPPZ=1.f; #endif /* Init bounding box */ inline static void Cedric_ResetBoundingBox(Entity * io) { // resets 2D Bounding Box BBOXMIN.y = BBOXMIN.x = 32000; BBOXMAX.y = BBOXMAX.x = -32000; // Resets 3D Bounding Box ResetBBox3D(io); } extern float INVISIBILITY_OVERRIDE; extern long EXTERNALVIEW; static void Cedric_GetScale(float & scale, float & invisibility, Entity * io) { if (io) { invisibility = io->invisibility; if (invisibility > 1.f) invisibility -= 1.f; if ((io != entities.player()) && (invisibility > 0.f) && (!EXTERNALVIEW)) { long num = ARX_SPELLS_GetSpellOn(io, SPELL_INVISIBILITY); if (num >= 0) { if (player.Full_Skill_Intuition > spells[num].caster_level * 10) { invisibility -= (float)player.Full_Skill_Intuition * ( 1.0f / 100 ) + (float)spells[num].caster_level * ( 1.0f / 10 ); if (invisibility < 0.1f) invisibility = 0.1f; else if (invisibility > 1.f) invisibility = 1.f; } } } // Scaling Value for this object (Movements will also be scaled) scale = io->scale; } else { if (INVISIBILITY_OVERRIDE != 0.f) { invisibility = INVISIBILITY_OVERRIDE; if (invisibility > 1.f) invisibility -= 1.f; } else { invisibility = 0.f; } scale = 1.f; } } static void Cedric_GetTime(float & timm, Entity * io) { if(!io || !io->nb_lastanimvertex) { timm = 0.f; return; } timm = (arxtime.get_frame_time() - io->lastanimtime) + 0.0001f; if(timm >= 300.f) { timm = 0.f; io->nb_lastanimvertex = 0; } else { timm *= ( 1.0f / 300 ); if(timm >= 1.f) { timm = 0.f; } else if(timm < 0.f) { timm = 0.f; } } } /* Evaluate main entity translation */ static void Cedric_AnimCalcTranslation(Entity * io, ANIM_USE * animuse, float scale, Vec3f & ftr, bool update_movement) { // Resets Frame Translate ftr = Vec3f::ZERO; Vec3f ftr2 = Vec3f::ZERO; // Fill frame translate values with multi-layer translate informations... for (int count = MAX_ANIM_LAYERS - 1; count >= 0; count--) { EERIE_ANIM * eanim; if (!io) { count = -1; } else { animuse = &io->animlayer[count]; } if (!animuse) continue; if (!animuse->cur_anim) continue; eanim = animuse->cur_anim->anims[animuse->altidx_cur]; if (!eanim) continue; //Avoiding impossible cases if (animuse->fr < 0) { animuse->fr = 0; animuse->pour = 0.f; } else if (animuse->fr >= eanim->nb_key_frames - 1) { animuse->fr = eanim->nb_key_frames - 2; animuse->pour = 1.f; } else if (animuse->pour > 1.f) animuse->pour = 1.f; else if (animuse->pour < 0.f) animuse->pour = 0.f; // FRAME TRANSLATE : Gives the Virtual pos of Main Object if (((eanim->frames[animuse->fr].f_translate) && (!(animuse->flags & EA_STATICANIM)))) { EERIE_FRAME * sFrame = &eanim->frames[animuse->fr]; EERIE_FRAME * eFrame = &eanim->frames[animuse->fr+1]; // Linear interpolation of object translation (MOVE) ftr = sFrame->translate + (eFrame->translate - sFrame->translate) * animuse->pour; if(io && update_movement) { ftr *= scale; float temp = radians(MAKEANGLE(180.f - io->angle.b)); if (io == entities.player()) temp = radians(MAKEANGLE(180.f - player.angle.b)); YRotatePoint(&ftr, &ftr2, (float)EEcos(temp), (float)EEsin(temp)); // stores Translations for a later use io->move = ftr2; } } } if(io && io->animlayer[0].cur_anim && update_movement) { // Use calculated value to notify the Movement engine of the translation to do if(io->ioflags & IO_NPC) { ftr = Vec3f::ZERO; io->move -= io->lastmove; } else if (io->gameFlags & GFLAG_ELEVATOR) { // Must recover translations for NON-NPC IO PushIO_ON_Top(io, io->move.y - io->lastmove.y); } io->lastmove = ftr2; } } // Animate skeleton static void Cedric_AnimateObject(Entity * io, EERIE_3DOBJ * eobj, ANIM_USE * animuse) { int j, l; EERIE_C_DATA * obj = eobj->c_data; for (long count = MAX_ANIM_LAYERS - 1; count >= 0; count--) { EERIE_QUAT t, temp; Vec3f vect; Vec3f scale; if(!io) { count = -1; } else { animuse = &io->animlayer[count]; } if(!animuse) { continue; } if(!animuse->cur_anim) { continue; } EERIE_ANIM * eanim = animuse->cur_anim->anims[animuse->altidx_cur]; if (!eanim) continue; if (animuse->fr < 0) { animuse->fr = 0; animuse->pour = 0.f; } else if (animuse->fr >= eanim->nb_key_frames - 1) { animuse->fr = eanim->nb_key_frames - 2; animuse->pour = 1.f; } else if (animuse->pour > 1.f) animuse->pour = 1.f; else if (animuse->pour < 0.f) animuse->pour = 0.f; // Now go for groups rotation/translation/scaling, And transform Linked objects by the way l = min(eobj->nbgroups - 1, eanim->nb_groups - 1); for (j = l; j >= 0; j--) { if (grps[j]) continue; EERIE_GROUP * sGroup = &eanim->groups[j+(animuse->fr*eanim->nb_groups)]; EERIE_GROUP * eGroup = &eanim->groups[j+(animuse->fr*eanim->nb_groups)+eanim->nb_groups]; if (!eanim->voidgroups[j]) grps[j] = 1; if (eanim->nb_key_frames != 1) { Quat_Slerp(&t, &sGroup->quat, &eGroup->quat, animuse->pour); Quat_Copy(&temp, &obj->bones[j].quatinit); Quat_Multiply(&obj->bones[j].quatinit, &temp, &t); vect = sGroup->translate + (eGroup->translate - sGroup->translate) * animuse->pour; obj->bones[j].transinit = vect + obj->bones[j].transinit_global; scale = sGroup->zoom + (eGroup->zoom - sGroup->zoom) * animuse->pour; if(BH_MODE && j == eobj->fastaccess.head_group) { scale += Vec3f::ONE; } obj->bones[j].scaleinit = scale; } } } } /* Apply transformations on all bones */ static void Cedric_ConcatenateTM(Entity * io, EERIE_C_DATA * obj, Anglef * angle, Vec3f * pos, Vec3f & ftr, float g_scale) { int i; if (!obj) return; for (i = 0; i != obj->nb_bones; i++) { EERIE_QUAT qt2; if (obj->bones[i].father >= 0) // Child Bones { // Rotation Quat_Multiply(&obj->bones[i].quatanim, &obj->bones[obj->bones[i].father].quatanim, &obj->bones[i].quatinit); // Translation obj->bones[i].transanim = obj->bones[i].transinit * obj->bones[obj->bones[i].father].scaleanim; TransformVertexQuat(&obj->bones[obj->bones[i].father].quatanim, &obj->bones[i].transanim, &obj->bones[i].transanim); obj->bones[i].transanim = obj->bones[obj->bones[i].father].transanim + obj->bones[i].transanim; /* Scale */ obj->bones[i].scaleanim = (obj->bones[i].scaleinit + Vec3f::ONE) * obj->bones[obj->bones[i].father].scaleanim; } else // Root Bone { // Rotation if ((io) && !(io->ioflags & IO_NPC)) { // To correct invalid angle in Animated FIX/ITEMS Anglef ang = *angle; ang.a = (360 - ang.a); ang.b = (ang.b); ang.g = (ang.g); EERIEMATRIX mat; Vec3f vect(0, 0, 1); Vec3f up(0, 1, 0); VRotateY(&vect, ang.b); VRotateX(&vect, ang.a); VRotateZ(&vect, ang.g); VRotateY(&up, ang.b); VRotateX(&up, ang.a); VRotateZ(&up, ang.g); MatrixSetByVectors(&mat, &vect, &up); QuatFromMatrix(qt2, mat); Quat_Multiply(&obj->bones[i].quatanim, &qt2, &obj->bones[i].quatinit); } else { Anglef vt1 = Anglef(radians(angle->a), radians(angle->b), radians(angle->g)); QuatFromAngles(&qt2, &vt1); Quat_Multiply(&obj->bones[i].quatanim, &qt2, &obj->bones[i].quatinit); } // Translation Vec3f vt1 = obj->bones[i].transinit + ftr; TransformVertexQuat(&qt2, &vt1, &obj->bones[i].transanim); obj->bones[i].transanim *= g_scale; obj->bones[i].transanim = *pos + obj->bones[i].transanim; // Compute Global Object Scale AND Global Animation Scale obj->bones[i].scaleanim = (obj->bones[i].scaleinit + Vec3f::ONE) * g_scale; } } } void EE_RT(TexturedVertex * in, Vec3f * out); void EE_P(Vec3f * in, TexturedVertex * out); void EE_P2(TexturedVertex * in, TexturedVertex * out); /* Transform object vertices */ int Cedric_TransformVerts(Entity * io, EERIE_3DOBJ * eobj, EERIE_C_DATA * obj, Vec3f * pos) { int v; EERIE_3DPAD * inVert; EERIE_VERTEX * outVert; /* Transform & project all vertices */ for (long i = 0; i != obj->nb_bones; i++) { EERIEMATRIX matrix; MatrixFromQuat(&matrix, &obj->bones[i].quatanim); Vec3f vector = obj->bones[i].transanim; // Apply Scale matrix._11 *= obj->bones[i].scaleanim.x; matrix._12 *= obj->bones[i].scaleanim.x; matrix._13 *= obj->bones[i].scaleanim.x; matrix._21 *= obj->bones[i].scaleanim.y; matrix._22 *= obj->bones[i].scaleanim.y; matrix._23 *= obj->bones[i].scaleanim.y; matrix._31 *= obj->bones[i].scaleanim.z; matrix._32 *= obj->bones[i].scaleanim.z; matrix._33 *= obj->bones[i].scaleanim.z; for(v = 0; v != obj->bones[i].nb_idxvertices; v++) { inVert = &eobj->vertexlocal[obj->bones[i].idxvertices[v]]; outVert = &eobj->vertexlist3[obj->bones[i].idxvertices[v]]; TransformVertexMatrix(&matrix, inVert, &outVert->v); outVert->v += vector; outVert->vert.p = outVert->v; } } if(eobj->cdata && eobj->sdata) { for(size_t i = 0; i < eobj->vertexlist.size(); i++) { eobj->vertexlist[i].vert.p = eobj->vertexlist3[i].v - *pos; } } for (size_t i = 0; i < eobj->vertexlist.size(); i++) { outVert = &eobj->vertexlist3[i]; AddToBBox3D(io, &outVert->v); EE_RT(&outVert->vert, &outVert->vworld); EE_P(&outVert->vworld, &outVert->vert); // Updates 2D Bounding Box if (outVert->vert.rhw > 0.f) { BBOXMIN.x = min(BBOXMIN.x, outVert->vert.p.x); BBOXMAX.x = max(BBOXMAX.x, outVert->vert.p.x); BBOXMIN.y = min(BBOXMIN.y, outVert->vert.p.y); BBOXMAX.y = max(BBOXMAX.y, outVert->vert.p.y); } } if ((io) && (io->ioflags & IO_NPC) && (io->_npcdata->behavior & BEHAVIOUR_FIGHT) && (distSqr(io->pos, player.pos) < square(240.f))) return true; if ((io != entities.player()) && (!EXTERNALVIEW) && (!eobj->cdata) && ((BBOXMIN.x >= DANAESIZX - 1) || (BBOXMAX.x <= 1) || (BBOXMIN.y >= DANAESIZY - 1) || (BBOXMAX.y <= 1)) ) { return false; } if (ARX_SCENE_PORTAL_ClipIO(io, pos)) return false; return true; } extern Entity * DESTROYED_DURING_RENDERING; long special_color_flag = 0; Color3f special_color; extern long TRAP_DETECT; extern long TRAP_SECRET; extern long FRAME_COUNT; extern float GLOBAL_LIGHT_FACTOR; /* Object dynamic lighting */ static bool Cedric_ApplyLighting(EERIE_3DOBJ * eobj, EERIE_C_DATA * obj, Entity * io, Vec3f * pos) { Color3f infra = Color3f::black; int i, v, l; Vec3f tv; Vec3f vTLights[32]; /* Same as above but in bone space (for faster calculation) */ special_color_flag = 0; if (io) { float poisonpercent = 0.f; float trappercent = 0.f; float secretpercent = 0.f; if (io->ioflags & IO_NPC) { if (io->_npcdata->poisonned > 0.f) { poisonpercent = io->_npcdata->poisonned * ( 1.0f / 20 ); if (poisonpercent > 1.f) poisonpercent = 1.f; } } if ((io->ioflags & IO_ITEM) && (io->poisonous > 0.f) && (io->poisonous_count != 0)) { poisonpercent = (float)io->poisonous * ( 1.0f / 20 ); if (poisonpercent > 1.f) poisonpercent = 1.f; } if ((io->ioflags & IO_FIX) && (io->_fixdata->trapvalue > -1)) { trappercent = (float)TRAP_DETECT - (float)io->_fixdata->trapvalue; if (trappercent > 0.f) { trappercent = 0.6f + trappercent * ( 1.0f / 100 ); if (trappercent < 0.6f) trappercent = 0.6f; if (trappercent > 1.f) trappercent = 1.f; } } if ((io->ioflags & IO_FIX) && (io->secretvalue > -1)) { secretpercent = (float)TRAP_SECRET - (float)io->secretvalue; if (secretpercent > 0.f) { secretpercent = 0.6f + secretpercent * ( 1.0f / 100 ); if (secretpercent < 0.6f) secretpercent = 0.6f; else if (secretpercent > 1.f) secretpercent = 1.f; } } if (poisonpercent > 0.f) { special_color_flag = 1; special_color.r = 0.f; special_color.g = 1.f; special_color.b = 0.f; } if (trappercent > 0.f) { special_color_flag = 1; special_color.r = trappercent; special_color.g = 1.f - trappercent; special_color.b = 1.f - trappercent; } if (secretpercent > 0.f) { special_color_flag = 1; special_color.r = 1.f - secretpercent; special_color.g = 1.f - secretpercent; special_color.b = secretpercent; } if (io->ioflags & IO_FREEZESCRIPT) { special_color_flag = 1; special_color.r = 0.f; special_color.g = 0.f; special_color.b = 1.f; } if (io->sfx_flag & SFX_TYPE_YLSIDE_DEATH) { if (io->show == SHOW_FLAG_TELEPORTING) { float fTime = io->sfx_time + FrameDiff; io->sfx_time = checked_range_cast(fTime); if (io->sfx_time >= (unsigned long)(arxtime)) io->sfx_time = (unsigned long)(arxtime); } else { special_color_flag = 1; float elapsed = float(arxtime) - io->sfx_time; if (elapsed > 0.f) { if (elapsed < 3000.f) // 5 seconds to red { float ratio = elapsed * ( 1.0f / 3000 ); special_color.r = 1.f; special_color.g = 1.f - ratio; special_color.b = 1.f - ratio; AddRandomSmoke(io, 1); } else if (elapsed < 6000.f) // 5 seconds to White { float ratio = (elapsed - 3000.f) * ( 1.0f / 3000 ); special_color.r = ratio; special_color_flag = 2; AddRandomSmoke(io, 2); } else // SFX finish { special_color_flag = 0; io->sfx_time = 0; if (io->ioflags & IO_NPC) { MakePlayerAppearsFX(io); AddRandomSmoke(io, 50); Color3f rgb = io->_npcdata->blood_color.to(); EERIE_SPHERE sp; sp.origin = io->pos; sp.radius = 200.f; long count = 6; while (count--) { SpawnGroundSplat(&sp, &rgb, rnd() * 30.f + 30.f, 1); sp.origin.y -= rnd() * 150.f; ARX_PARTICLES_Spawn_Splat(sp.origin, 200.f, io->_npcdata->blood_color); sp.origin.x = io->pos.x + rnd() * 200.f - 100.f; sp.origin.y = io->pos.y + rnd() * 20.f - 10.f; sp.origin.z = io->pos.z + rnd() * 200.f - 100.f; sp.radius = rnd() * 100.f + 100.f; } long nn = GetFreeDynLight(); if (nn >= 0) { DynLight[nn].exist = 1; DynLight[nn].intensity = 0.7f + 2.f * rnd(); DynLight[nn].fallend = 600.f; DynLight[nn].fallstart = 400.f; DynLight[nn].rgb.r = 1.0f; DynLight[nn].rgb.g = 0.8f; DynLight[nn].rgb.b = .0f; DynLight[nn].pos.x = io->pos.x; DynLight[nn].pos.y = io->pos.y - 80.f; DynLight[nn].pos.z = io->pos.z; DynLight[nn].duration = 600; } if (io->sfx_flag & SFX_TYPE_INCINERATE) { io->sfx_flag &= ~SFX_TYPE_INCINERATE; io->sfx_flag &= ~SFX_TYPE_YLSIDE_DEATH; long num = ARX_SPELLS_GetSpellOn(io, SPELL_INCINERATE); if (num < 0) num = ARX_SPELLS_GetSpellOn(io, SPELL_MASS_INCINERATE); if (num >= 0) { spells[num].tolive = 0; float damages = 20 * spells[num].caster_level; damages = ARX_SPELLS_ApplyFireProtection(io, damages); if (ValidIONum(spells[num].caster)) ARX_DAMAGES_DamageNPC(io, damages, spells[num].caster, 1, &entities[spells[num].caster]->pos); else ARX_DAMAGES_DamageNPC(io, damages, spells[num].caster, 1, &io->pos); ARX_SOUND_PlaySFX(SND_SPELL_FIRE_HIT, &io->pos); } } else { io->sfx_flag &= ~SFX_TYPE_YLSIDE_DEATH; ARX_INTERACTIVE_DestroyIO(io); DESTROYED_DURING_RENDERING = io; return false; } } } } } } } if(eobj->drawflags & DRAWFLAG_HIGHLIGHT) { special_color_flag = 4; special_color = Color3f::gray(float(iHighLight)); } if(FRAME_COUNT > 0) { return true; } if(Project.improve) { infra = (io) ? io->infracolor : Color3f(0.6f, 0.f, 1.f); } /* Get nearest lights */ tv = *pos; if ((io) && (io->obj->fastaccess.view_attach >= 0) && (io->obj->fastaccess.head_group_origin != -1)) { tv.y = io->obj->vertexlist3[io->obj->fastaccess.head_group_origin].v.y + 10; } else tv.y -= 90.f; llightsInit(); for (i = 0; i < TOTIOPDL; i++) { if (IO_PDL[i]->fallend + 500.f < 0) continue; Insertllight(IO_PDL[i], dist(IO_PDL[i]->pos, tv)); } for (i = 0; i < TOTPDL; i++) { if (PDL[i]->fallend + 500.f < 0) continue; Insertllight(PDL[i], dist(PDL[i]->pos, tv)); } if (!USEINTERNORM) { /* Apply light on all vertices */ for (i = 0; i != obj->nb_bones; i++) { /* Get light value for each vertex */ for (v = 0; v != obj->bones[i].nb_idxvertices; v++) { Vec3f * posVert; float r, g, b; long ir, ig, ib; if(io) { posVert = &io->obj->vertexlist3[obj->bones[i].idxvertices[v]].v; } else { posVert = &eobj->vertexlist3[obj->bones[i].idxvertices[v]].v; } /* Ambient light */ if ((io) && (io->ioflags & (IO_NPC | IO_ITEM))) { r = g = b = NPC_ITEMS_AMBIENT_VALUE_255; } else { r = ACTIVEBKG->ambient255.r; g = ACTIVEBKG->ambient255.g; b = ACTIVEBKG->ambient255.b; } /* Dynamic lights */ for (l = 0 ; l != MAX_LLIGHTS; l++) { EERIE_LIGHT * Cur_llights = llights[l]; if (Cur_llights) { // tsu if (Cur_llights->fallend < 0) { TSU_TEST_NB_LIGHT ++; continue; } float cosangle; float distance = fdist(Cur_llights->pos, *posVert); /* Evaluate its intensity depending on the distance Light<->Object */ if (distance <= Cur_llights->fallstart) cosangle = Cur_llights->intensity * GLOBAL_LIGHT_FACTOR; else { float p = ((Cur_llights->fallend - distance) * Cur_llights->falldiffmul); if (p <= 0.f) cosangle = 0.f; else cosangle = p * Cur_llights->precalc; } r += Cur_llights->rgb255.r * cosangle; g += Cur_llights->rgb255.g * cosangle; b += Cur_llights->rgb255.b * cosangle; } else break; } if (special_color_flag) { if (special_color_flag & 1) { r *= special_color.r; g *= special_color.g; b *= special_color.b; } else if (special_color_flag & 2) { r = 1.f; g = 0.f; b = 0.f; } else if (special_color_flag & 4) // HIGHLIGHT { r += special_color.r; g += special_color.g; b += special_color.b; } } /* PACK color */ ir = clipByte255(r); ig = clipByte255(g); ib = clipByte255(b); eobj->vertexlist3[obj->bones[i].idxvertices[v]].vert.color = (0xFF000000L | ((ir) << 16) | ((ig) << 8) | (ib)); } } } else { /* Apply light on all vertices */ for (i = 0; i != obj->nb_bones; i++) { EERIE_QUAT qt1; EERIEMATRIX matrix;//,omatrix; Quat_Copy(&qt1, &obj->bones[i].quatanim); Quat_Reverse(&qt1); MatrixFromQuat(&matrix, &qt1); // FMatrixInvert(matrix,omatrix); /* Get light value for each vertex */ for (v = 0; v != obj->bones[i].nb_idxvertices; v++) { EERIE_3DPAD * inVert; float r, g, b; long ir, ig, ib; inVert = (EERIE_3DPAD *)&eobj->vertexlist[obj->bones[i].idxvertices[v]].norm; /* Ambient light */ if ((io) && (io->ioflags & (IO_NPC | IO_ITEM))) { r = g = b = NPC_ITEMS_AMBIENT_VALUE_255; } else { r = ACTIVEBKG->ambient255.r; g = ACTIVEBKG->ambient255.g; b = ACTIVEBKG->ambient255.b; } /* Dynamic lights */ for (l = 0 ; l != MAX_LLIGHTS; l++) { EERIE_LIGHT * Cur_llights = llights[l]; if (Cur_llights) { Vec3f & Cur_vTLights = vTLights[l]; Vec3f tl; tl = (Cur_llights->pos - eobj->vertexlist3[obj->bones[i].idxvertices[v]].v); float dista = ffsqrt(tl.lengthSqr()); if(dista < Cur_llights->fallend) { tl *= 1.f / dista; VectorMatrixMultiply(&Cur_vTLights, &tl, &matrix); float cosangle = dot(*inVert, Cur_vTLights); /* If light visible */ if (cosangle > 0.0f) { /* Evaluate its intensity depending on the distance Light<->Object */ if (dista <= Cur_llights->fallstart) cosangle *= Cur_llights->precalc; else { float p = ((Cur_llights->fallend - dista) * Cur_llights->falldiffmul); if (p <= 0.f) cosangle = 0.f; else cosangle *= p * Cur_llights->precalc; } r += Cur_llights->rgb255.r * cosangle; g += Cur_llights->rgb255.g * cosangle; b += Cur_llights->rgb255.b * cosangle; } } } else break; } /* Fake adjust */ if (Project.improve) { r *= infra.r; g *= infra.g; b *= infra.b; } if (special_color_flag) { if (special_color_flag & 1) { r *= special_color.r; g *= special_color.g; b *= special_color.b; } else if (special_color_flag & 2) { r = 1.f; g = 0.f; b = 0.f; } else if (special_color_flag & 4) // HIGHLIGHT { r += special_color.r; g += special_color.g; b += special_color.b; } } /* PACK color */ ir = clipByte255(r); ig = clipByte255(g); ib = clipByte255(b); eobj->vertexlist3[obj->bones[i].idxvertices[v]].vert.color = (0xFF000000L | ((ir) << 16) | ((ig) << 8) | (ib)); } } } return true; } void Cedric_PrepareHalo(EERIE_3DOBJ * eobj, EERIE_C_DATA * obj) { Vec3f cam_vector, t_vector; cam_vector.x = -EEsin(radians(ACTIVECAM->angle.b)) * EEcos(radians(ACTIVECAM->angle.a)); cam_vector.y = EEsin(radians(ACTIVECAM->angle.a)); cam_vector.z = EEcos(radians(ACTIVECAM->angle.b)) * EEcos(radians(ACTIVECAM->angle.a)); /* Apply light on all vertices */ for (long i = 0; i != obj->nb_bones; i++) { EERIE_QUAT qt1; Quat_Copy(&qt1, &obj->bones[i].quatanim); TransformInverseVertexQuat(&qt1, &cam_vector, &t_vector); /* Get light value for each vertex */ for (long v = 0; v != obj->bones[i].nb_idxvertices; v++) { EERIE_3DPAD * inVert; //inVert = &eobj->normallocal[obj->bones[i].idxvertices[v]]; inVert = (EERIE_3DPAD *)&eobj->vertexlist[obj->bones[i].idxvertices[v]].norm; /* Get cos angle between light and vertex norm */ eobj->vertexlist3[obj->bones[i].idxvertices[v]].norm.z = (inVert->x * t_vector.x + inVert->y * t_vector.y + inVert->z * t_vector.z); } } } #ifdef USE_SOFTWARE_CLIPPING //----------------------------------------------------------------------------- void ARX_ClippZ(TexturedVertex * _pA, TexturedVertex * _pB, EERIE_VERTEX * _pVertexA, EERIE_VERTEX * _pVertexB, TexturedVertex * _pOut) { Vec3f e3dTemp; float fDenom = (SOFTNEARCLIPPZ - _pVertexB->vworld.z) / (_pVertexA->vworld.z - _pVertexB->vworld.z); e3dTemp.x = (_pVertexA->vworld.x - _pVertexB->vworld.x) * fDenom + _pVertexB->vworld.x; e3dTemp.y = (_pVertexA->vworld.y - _pVertexB->vworld.y) * fDenom + _pVertexB->vworld.y; e3dTemp.z = SOFTNEARCLIPPZ ; float fRA, fGA, fBA; float fRB, fGB, fBB; fRA = checked_range_cast((_pA->color >> 16) & 255); fGA = checked_range_cast((_pA->color >> 8) & 255); fBA = checked_range_cast(_pA->color & 255); fRB = checked_range_cast((_pB->color >> 16) & 255); fGB = checked_range_cast((_pB->color >> 8) & 255); fBB = checked_range_cast(_pB->color & 255); float fRC, fGC, fBC; fRC = (fRA - fRB) * fDenom + fRB; fGC = (fGA - fGB) * fDenom + fGB; fBC = (fBA - fBB) * fDenom + fBB; _pOut->color = (((int)fRC) << 16) | (((int)fGC) << 8) | ((int)fBC); _pOut->uv = (_pA->uv - _pB->uv) * fDenom + _pB->uv; EE_P(&e3dTemp, _pOut); } //----------------------------------------------------------------------------- void ARX_DrawPrimitive_ClippZ(TexturedVertex * _pVertexA, TexturedVertex * _pVertexB, TexturedVertex * _pOut, float _fAdd = 0.f); void ARX_DrawPrimitive_ClippZ(TexturedVertex * _pVertexA, TexturedVertex * _pVertexB, TexturedVertex * _pOut, float _fAdd) { Vec3f e3dTemp; float fDenom = ((SOFTNEARCLIPPZ + _fAdd) - _pVertexB->p.z) / (_pVertexA->p.z - _pVertexB->p.z); e3dTemp.x = (_pVertexA->p.x - _pVertexB->p.x) * fDenom + _pVertexB->p.x; e3dTemp.y = (_pVertexA->p.y - _pVertexB->p.y) * fDenom + _pVertexB->p.y; e3dTemp.z = SOFTNEARCLIPPZ + _fAdd; float fRA, fGA, fBA; float fRB, fGB, fBB; fRA = checked_range_cast((_pVertexA->color >> 16) & 255); fGA = checked_range_cast((_pVertexA->color >> 8) & 255); fBA = checked_range_cast(_pVertexA->color & 255); fRB = checked_range_cast((_pVertexB->color >> 16) & 255); fGB = checked_range_cast((_pVertexB->color >> 8) & 255); fBB = checked_range_cast(_pVertexB->color & 255); float fRC, fGC, fBC; fRC = (fRA - fRB) * fDenom + fRB; fGC = (fGA - fGB) * fDenom + fGB; fBC = (fBA - fBB) * fDenom + fBB; _pOut->color = (((int) fRC) << 16) | (((int)fGC) << 8) | ((int) fBC); _pOut->uv = (_pVertexA->uv - _pVertexB->uv) * fDenom + _pVertexB->uv; EE_P(&e3dTemp, _pOut); } #endif //----------------------------------------------------------------------------- TexturedVertex * GetNewVertexList(EERIE_FACE * _pFace, float _fInvisibility, TextureContainer * _pTex) { if(!(_pFace->facetype & POLY_TRANS) && !(_fInvisibility > 0.f)) { return PushVertexInTableCull(_pTex); } float fTransp; if(_fInvisibility > 0.f) { fTransp = 2.f - _fInvisibility; } else { fTransp = _pFace->transval; } if(fTransp >= 2.f) { //MULTIPLICATIVE return PushVertexInTableCull_TMultiplicative(_pTex); } else if(fTransp >= 1.f) { //ADDITIVE return PushVertexInTableCull_TAdditive(_pTex); } else if(fTransp > 0.f) { //NORMAL TRANS return PushVertexInTableCull_TNormalTrans(_pTex); } else { //SUBTRACTIVE return PushVertexInTableCull_TSubstractive(_pTex); } } #ifdef USE_SOFTWARE_CLIPPING 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) { int iPointAdd = 3; int iClipp = 0; if ((_pVertex1->vworld.z) < SOFTNEARCLIPPZ) iClipp |= 1; if ((_pVertex2->vworld.z) < SOFTNEARCLIPPZ) iClipp |= 2; if ((_pVertex3->vworld.z) < SOFTNEARCLIPPZ) iClipp |= 4; TexturedVertex ClippZ1, ClippZ2; TexturedVertex * pPointAdd = NULL; TexturedVertex * ptV = *_ptV; switch (iClipp) { case 1: //pt1 outside ARX_ClippZ(&ptV[0], &ptV[1], _pVertex1, _pVertex2, &ClippZ1); ARX_ClippZ(&ptV[0], &ptV[2], _pVertex1, _pVertex3, &ClippZ2); pPointAdd = GetNewVertexList(_pFace, _fInvibility, _pTex); ptV = pPointAdd - 3; if (pPointAdd) { pPointAdd[0] = ClippZ1; pPointAdd[1] = ptV[1]; pPointAdd[2] = ClippZ2; } ptV[0] = ClippZ2; iPointAdd = 6; break; case 2: //pt2 outside ARX_ClippZ(&ptV[1], &ptV[2], _pVertex2, _pVertex3, &ClippZ1); ARX_ClippZ(&ptV[1], &ptV[0], _pVertex2, _pVertex1, &ClippZ2); pPointAdd = GetNewVertexList(_pFace, _fInvibility, _pTex); ptV = pPointAdd - 3; if (pPointAdd) { pPointAdd[0] = ptV[2]; pPointAdd[1] = ClippZ1; pPointAdd[2] = ClippZ2; } ptV[1] = ClippZ2; iPointAdd = 6; break; case 4: //pt3 outside ARX_ClippZ(&ptV[2], &ptV[0], _pVertex3, _pVertex1, &ClippZ1); ARX_ClippZ(&ptV[2], &ptV[1], _pVertex3, _pVertex2, &ClippZ2); pPointAdd = GetNewVertexList(_pFace, _fInvibility, _pTex); ptV = pPointAdd - 3; if (pPointAdd) { pPointAdd[0] = ptV[0]; pPointAdd[1] = ClippZ2; pPointAdd[2] = ClippZ1; } ptV[2] = ClippZ2; iPointAdd = 6; break; case 3: //pt1_2 outside ARX_ClippZ(&ptV[0], &ptV[2], _pVertex1, _pVertex3, &ClippZ1); ARX_ClippZ(&ptV[1], &ptV[2], _pVertex2, _pVertex3, &ClippZ2); ptV[0] = ClippZ1; ptV[1] = ClippZ2; break; case 5: //pt1_3 outside ARX_ClippZ(&ptV[0], &ptV[1], _pVertex1, _pVertex2, &ClippZ1); ARX_ClippZ(&ptV[2], &ptV[1], _pVertex3, _pVertex2, &ClippZ2); ptV[0] = ClippZ1; ptV[2] = ClippZ2; break; case 6: //pt2_3 outside ARX_ClippZ(&ptV[2], &ptV[0], _pVertex3, _pVertex1, &ClippZ1); ARX_ClippZ(&ptV[1], &ptV[0], _pVertex2, _pVertex1, &ClippZ2); ptV[1] = ClippZ1; ptV[2] = ClippZ2; break; case 7: return 0; } if (pPointAdd) { *_ptV = ptV; if (_bZMapp) { CalculateInterZMapp(_pObj, _iNumFace, _pInd, _pTex, pPointAdd); } } return iPointAdd; } #endif extern long IsInGroup(EERIE_3DOBJ * obj, long vert, long tw); void ARX_DrawPrimitive(TexturedVertex * _pVertex1, TexturedVertex * _pVertex2, TexturedVertex * _pVertex3, float _fAddZ) { #ifdef USE_SOFTWARE_CLIPPING int iClipp = 0; if (_pVertex1->p.z < (SOFTNEARCLIPPZ + _fAddZ)) iClipp |= 1; if (_pVertex2->p.z < (SOFTNEARCLIPPZ + _fAddZ)) iClipp |= 2; if (_pVertex3->p.z < (SOFTNEARCLIPPZ + _fAddZ)) iClipp |= 4; TexturedVertex ClippZ1, ClippZ2; TexturedVertex pPointAdd[6]; int iNbTotVertex = 3; switch (iClipp) { case 0: { EE_P(&_pVertex1->p, &pPointAdd[0]); EE_P(&_pVertex2->p, &pPointAdd[1]); EE_P(&_pVertex3->p, &pPointAdd[2]); pPointAdd[0].color = _pVertex1->color; pPointAdd[0].specular = _pVertex1->specular; pPointAdd[0].uv = _pVertex1->uv; pPointAdd[1].specular = _pVertex2->specular; pPointAdd[1].uv = _pVertex2->uv; pPointAdd[2].color = _pVertex3->color; pPointAdd[2].specular = _pVertex3->specular; pPointAdd[2].uv = _pVertex3->uv; break; } case 1: //pt1 outside ARX_DrawPrimitive_ClippZ(_pVertex1, _pVertex2, &ClippZ1, _fAddZ); ARX_DrawPrimitive_ClippZ(_pVertex1, _pVertex3, &ClippZ2, _fAddZ); pPointAdd[0] = ClippZ2; pPointAdd[1] = *_pVertex2; EE_P2(&pPointAdd[1], &pPointAdd[1]); pPointAdd[2] = *_pVertex3; EE_P2(&pPointAdd[2], &pPointAdd[2]); pPointAdd[3] = ClippZ1; pPointAdd[4] = pPointAdd[1]; pPointAdd[5] = ClippZ2; iNbTotVertex = 6; break; case 2: //pt2 outside ARX_DrawPrimitive_ClippZ(_pVertex2, _pVertex3, &ClippZ1, _fAddZ); ARX_DrawPrimitive_ClippZ(_pVertex2, _pVertex1, &ClippZ2, _fAddZ); pPointAdd[0] = *_pVertex1; EE_P2(&pPointAdd[0], &pPointAdd[0]); pPointAdd[1] = ClippZ2; pPointAdd[2] = *_pVertex3; EE_P2(&pPointAdd[2], &pPointAdd[2]); pPointAdd[3] = pPointAdd[2]; pPointAdd[4] = ClippZ1; pPointAdd[5] = ClippZ2; iNbTotVertex = 6; break; case 4: //pt3 outside ARX_DrawPrimitive_ClippZ(_pVertex3, _pVertex1, &ClippZ1, _fAddZ); ARX_DrawPrimitive_ClippZ(_pVertex3, _pVertex2, &ClippZ2, _fAddZ); pPointAdd[0] = *_pVertex1; EE_P2(&pPointAdd[0], &pPointAdd[0]); pPointAdd[1] = *_pVertex2; EE_P2(&pPointAdd[1], &pPointAdd[1]); pPointAdd[2] = ClippZ2; pPointAdd[3] = pPointAdd[0]; pPointAdd[4] = ClippZ2; pPointAdd[5] = ClippZ1; iNbTotVertex = 6; break; case 3: //pt1_2 outside ARX_DrawPrimitive_ClippZ(_pVertex1, _pVertex3, &ClippZ1, _fAddZ); ARX_DrawPrimitive_ClippZ(_pVertex2, _pVertex3, &ClippZ2, _fAddZ); pPointAdd[0] = ClippZ1; pPointAdd[1] = ClippZ2; pPointAdd[2] = *_pVertex3; EE_P2(&pPointAdd[2], &pPointAdd[2]); break; case 5: //pt1_3 outside ARX_DrawPrimitive_ClippZ(_pVertex1, _pVertex2, &ClippZ1, _fAddZ); ARX_DrawPrimitive_ClippZ(_pVertex3, _pVertex2, &ClippZ2, _fAddZ); pPointAdd[0] = ClippZ1; pPointAdd[1] = *_pVertex2; EE_P2(&pPointAdd[1], &pPointAdd[1]); pPointAdd[2] = ClippZ2; break; case 6: //pt2_3 outside ARX_DrawPrimitive_ClippZ(_pVertex3, _pVertex1, &ClippZ1, _fAddZ); ARX_DrawPrimitive_ClippZ(_pVertex2, _pVertex1, &ClippZ2, _fAddZ); pPointAdd[0] = *_pVertex1; EE_P2(&pPointAdd[0], &pPointAdd[0]); pPointAdd[1] = ClippZ1; pPointAdd[2] = ClippZ2; break; case 7: return; } #else ARX_UNUSED(_fAddZ); TexturedVertex pPointAdd[3]; EE_P(&_pVertex1->p, &pPointAdd[0]); EE_P(&_pVertex2->p, &pPointAdd[1]); EE_P(&_pVertex3->p, &pPointAdd[2]); pPointAdd[0].color = _pVertex1->color; pPointAdd[0].specular = _pVertex1->specular; pPointAdd[0].uv = _pVertex1->uv; pPointAdd[1].color = _pVertex2->color; pPointAdd[1].specular = _pVertex2->specular; pPointAdd[1].uv = _pVertex2->uv; pPointAdd[2].color = _pVertex3->color; pPointAdd[2].specular = _pVertex3->specular; pPointAdd[2].uv = _pVertex3->uv; #endif EERIEDRAWPRIM(Renderer::TriangleList, pPointAdd); } long FORCE_FRONT_DRAW = 0; //----------------------------------------------------------------------------- extern long IN_BOOK_DRAW; /* Render object */ static void Cedric_RenderObject(EERIE_3DOBJ * eobj, EERIE_C_DATA * obj, Entity * io, Vec3f * pos, Vec3f & ftr, float invisibility) { float MAX_ZEDE = 0.f; // Sets IO BBox to calculated BBox :) if (io) { io->bbox1.x = (short) BBOXMIN.x; io->bbox2.x = (short) BBOXMAX.x; io->bbox1.y = (short) BBOXMIN.y; io->bbox2.y = (short) BBOXMAX.y; } if (invisibility == 1.f) return; float ddist = 0.f; long need_halo; need_halo = 0; Entity * hio_helmet = NULL; Entity * hio_armor = NULL; Entity * hio_leggings = NULL; Entity * hio_player = NULL; Entity * use_io = io; if ((!io) && (IN_BOOK_DRAW) && (eobj == entities.player()->obj)) use_io = entities.player(); if (use_io) { if (use_io == entities.player()) { if ((player.equiped[EQUIP_SLOT_HELMET] != 0) && ValidIONum(player.equiped[EQUIP_SLOT_HELMET])) { Entity * tio = entities[player.equiped[EQUIP_SLOT_HELMET]]; if (tio->halo.flags & HALO_ACTIVE) hio_helmet = tio; } if ((player.equiped[EQUIP_SLOT_ARMOR] != 0) && ValidIONum(player.equiped[EQUIP_SLOT_ARMOR])) { Entity * tio = entities[player.equiped[EQUIP_SLOT_ARMOR]]; if (tio->halo.flags & HALO_ACTIVE) hio_armor = tio; } if ((player.equiped[EQUIP_SLOT_LEGGINGS] != 0) && ValidIONum(player.equiped[EQUIP_SLOT_LEGGINGS])) { Entity * tio = entities[player.equiped[EQUIP_SLOT_LEGGINGS]]; if (tio->halo.flags & HALO_ACTIVE) hio_leggings = tio; } if (use_io->halo.flags & HALO_ACTIVE) hio_player = use_io; } if (hio_player || hio_armor || hio_leggings || hio_helmet || (use_io->halo.flags & HALO_ACTIVE)) { float mdist = ACTIVECAM->cdepth * ( 1.0f / 2 ); ddist = mdist - fdist(*pos + ftr, ACTIVECAM->pos); ddist = (ddist / mdist); //*0.1f; ddist *= ddist * ddist * ddist * ddist * ddist; if (ddist <= 0.25f) ddist = 0.25f; else if (ddist > 0.9f) ddist = 0.9f; Cedric_PrepareHalo(eobj, obj); need_halo = 1; MAX_ZEDE = 0.f; for (size_t i = 0 ; i < eobj->vertexlist.size() ; i++) { if (eobj->vertexlist3[i].vert.rhw > 0.f) MAX_ZEDE = max(eobj->vertexlist3[i].vert.p.z, MAX_ZEDE); } } } { for (size_t i = 0 ; i < eobj->facelist.size() ; i++) { TexturedVertex * tv = NULL; EERIE_FACE * eface; long paf[3]; eface = &eobj->facelist[i]; if ((eface->facetype & POLY_HIDE) && (!FORCE_NO_HIDE)) continue; //CULL3D Vec3f nrm = eobj->vertexlist3[eface->vid[0]].v - ACTIVECAM->pos; if(!(eface->facetype & POLY_DOUBLESIDED)) { Vec3f normV10; Vec3f normV20; normV10 = eobj->vertexlist3[eface->vid[1]].v - eobj->vertexlist3[eface->vid[0]].v; normV20 = eobj->vertexlist3[eface->vid[2]].v - eobj->vertexlist3[eface->vid[0]].v; Vec3f normFace; normFace.x = (normV10.y * normV20.z) - (normV10.z * normV20.y); normFace.y = (normV10.z * normV20.x) - (normV10.x * normV20.z); normFace.z = (normV10.x * normV20.y) - (normV10.y * normV20.x); if ((dot(normFace , nrm) > 0.f)) continue; } TextureContainer * pTex; if(eobj->facelist[i].texid < 0) continue; pTex = eobj->texturecontainer[eobj->facelist[i].texid]; if(!pTex) continue; float fTransp = 0; if((eobj->facelist[i].facetype & POLY_TRANS) || invisibility > 0.f) { fTransp = (invisibility > 0.f) ? 2.f - invisibility : eobj->facelist[i].transval; if(fTransp >= 2.f) { //MULTIPLICATIVE fTransp *= (1.f/2); fTransp += .5f; tv = PushVertexInTableCull_TMultiplicative(pTex); } else if(fTransp >= 1.f) { //ADDITIVE fTransp -= 1.f; tv = PushVertexInTableCull_TAdditive(pTex); } else if(fTransp > 0.f) { //NORMAL TRANS fTransp = 1.f - fTransp; tv = PushVertexInTableCull_TNormalTrans(pTex); } else { //SUBTRACTIVE fTransp = 1.f - fTransp; tv = PushVertexInTableCull_TSubstractive(pTex); } } else { tv = PushVertexInTableCull(pTex); } for(long n = 0 ; n < 3 ; n++) { paf[n] = eface->vid[n]; tv[n].p = eobj->vertexlist3[paf[n]].vert.p; // Nuky - this code takes 20% of the whole game performance O_O // AFAIK it allows to correctly display the blue magic effects // when one's hands are inside a wall. I've only managed to do that // while in combat mode, looking straight down, and touching a wall // So, for the greater good I think it's best to simply skip this test //const float IN_FRONT_DIVIDER = 0.75f; //const float IN_FRONT_DIVIDER_FEET = 0.998f; //if (FORCE_FRONT_DRAW) //{ // if (IsInGroup(eobj, paf[n], 1) != -1) // tv[n].sz *= IN_FRONT_DIVIDER; // else // tv[n].sz *= IN_FRONT_DIVIDER_FEET; //} tv[n].rhw = eobj->vertexlist3[paf[n]].vert.rhw; tv[n].uv.x = eface->u[n]; tv[n].uv.y = eface->v[n]; tv[n].color = eobj->vertexlist3[paf[n]].vert.color; } if (special_color_flag) { if (special_color_flag & 1) { for (long j = 0 ; j < 3 ; j++) { tv[j].color = 0xFF000000L | (((long)((float)((long)((tv[j].color >> 16) & 255)) * (special_color.r)) & 255) << 16) | (((long)((float)((long)((tv[j].color >> 8) & 255)) * special_color.g) & 255) << 8) | ((long)((float)((long)(tv[j].color & 255)) * (special_color.b)) & 255); } } else if (special_color_flag & 2) { for (long j = 0 ; j < 3 ; j++) { tv[j].color = 0xFFFF0000; } } } if((eobj->facelist[i].facetype & POLY_TRANS) || invisibility > 0.f) { tv[0].color = tv[1].color = tv[2].color = Color::gray(fTransp).toBGR(); } #ifdef USE_SOFTWARE_CLIPPING if (!(ARX_SoftClippZ(&eobj->vertexlist3[paf[0]], &eobj->vertexlist3[paf[1]], &eobj->vertexlist3[paf[2]], &tv, eface, invisibility, pTex, (io) && (io->ioflags & IO_ZMAP), eobj, i, paf, NULL, true, special_color_flag, &special_color))) { continue; } #endif if ((io) && (io->ioflags & IO_ZMAP)) { CalculateInterZMapp(eobj, i, paf, pTex, tv); } //////////////////////////////////////////////////////////////////////// // HALO HANDLING START if ( need_halo && io ) { long lfr, lfg, lfb; float ffr, ffg, ffb; float tot = 0; float _ffr[3]; IO_HALO curhalo; memcpy(&curhalo, &io->halo, sizeof(IO_HALO)); int curhaloInitialized = 0; long max_c; if (use_io == entities.player()) max_c = 4; else max_c = 1; for (long cnt = 0 ; cnt < max_c ; cnt++) { switch (cnt) { case 0: if (use_io == entities.player()) { if (hio_player) { memcpy(&curhalo, &use_io->halo, sizeof(IO_HALO)); ++curhaloInitialized; } else continue; } else { memcpy(&curhalo, &io->halo, sizeof(IO_HALO)); ++curhaloInitialized; } break; case 1: if ((hio_helmet) && (IsInSelection(use_io->obj, paf[0], use_io->obj->fastaccess.sel_head) >= 0)) { memcpy(&curhalo, &hio_helmet->halo, sizeof(IO_HALO)); ++curhaloInitialized; } else continue; break; case 2: if ((hio_armor) && (IsInSelection(use_io->obj, paf[0], use_io->obj->fastaccess.sel_chest) >= 0)) { memcpy(&curhalo, &hio_armor->halo, sizeof(IO_HALO)); ++curhaloInitialized; } else continue; break; case 3: if ((hio_leggings) && (IsInSelection(use_io->obj, paf[0], use_io->obj->fastaccess.sel_leggings) >= 0)) { memcpy(&curhalo, &hio_leggings->halo, sizeof(IO_HALO)) ; ++curhaloInitialized; } else continue; break; } arx_assert(curhaloInitialized > 0); TexturedVertex * workon; workon = tv; long o; for (o = 0 ; o < 3 ; o++) { float tttz = EEfabs(eobj->vertexlist3[paf[o]].norm.z) * ( 1.0f / 2 ); float power = 255.f - (float)(255.f * tttz); power *= (1.f - invisibility); if (power > 255.f) power = 255.f; else if (power < 0.f) power = 0.f; ffr = curhalo.color.r * power; ffg = curhalo.color.g * power; ffb = curhalo.color.b * power; tot += power; _ffr[o] = power; lfr = ffr; lfg = ffg; lfb = ffb; tv[o].color = 0xFF000000L | (((lfr) & 255) << 16) | (((lfg) & 255) << 8) | ((lfb) & 255); } //GRenderer->SetCulling(Renderer::CullNone); if (tot > 260) //260.f) { long first; long second; long third; if ((_ffr[0] >= _ffr[1]) && (_ffr[1] >= _ffr[2])) { first = 0; second = 1; third = 2; } else if ((_ffr[0] >= _ffr[2]) && (_ffr[2] >= _ffr[1])) { first = 0; second = 2; third = 1; } else if ((_ffr[1] >= _ffr[0]) && (_ffr[0] >= _ffr[2])) { first = 1; second = 0; third = 2; } else if ((_ffr[1] >= _ffr[2]) && (_ffr[2] >= _ffr[0])) { first = 1; second = 2; third = 0; } else if ((_ffr[2] >= _ffr[0]) && (_ffr[0] >= _ffr[1])) { first = 2; second = 0; third = 1; } else { first = 2; second = 1; third = 0; } if ((_ffr[first] > 150.f) && (_ffr[second] > 110.f)) { Vec3f vect1, vect2; TexturedVertex * vert = &LATERDRAWHALO[(HALOCUR << 2)]; if(HALOCUR < ((long)HALOMAX) - 1) { HALOCUR++; } memcpy(&vert[0], &workon[first], sizeof(TexturedVertex)); memcpy(&vert[1], &workon[first], sizeof(TexturedVertex)); memcpy(&vert[2], &workon[second], sizeof(TexturedVertex)); memcpy(&vert[3], &workon[second], sizeof(TexturedVertex)); float siz = ddist * (curhalo.radius * (EEsin((float)(arxtime.get_frame_time() + i) * ( 1.0f / 100 )) * ( 1.0f / 10 ) + 1.f)) * 0.6f; if ((io == entities.player()) && (ddist > 0.8f) && !EXTERNALVIEW) siz *= 1.5f; vect1.x = workon[first].p.x - workon[third].p.x; vect1.y = workon[first].p.y - workon[third].p.y; float len1 = 2.f / ffsqrt(vect1.x * vect1.x + vect1.y * vect1.y); if (vect1.x < 0.f) len1 *= 1.2f; vect1.x *= len1; vect1.y *= len1; vect2.x = workon[second].p.x - workon[third].p.x; vect2.y = workon[second].p.y - workon[third].p.y; float len2 = 1.f / ffsqrt(vect2.x * vect2.x + vect2.y * vect2.y); if (vect2.x < 0.f) len2 *= 1.2f; vect2.x *= len2; vect2.y *= len2; vert[1].p.x += (vect1.x + 0.2f - rnd() * 0.1f) * siz; vert[1].p.y += (vect1.y + 0.2f - rnd() * 0.1f) * siz; vert[1].color = 0xFF000000; float valll; valll = 0.005f + (EEfabs(workon[first].p.z) - EEfabs(workon[third].p.z)) + (EEfabs(workon[second].p.z) - EEfabs(workon[third].p.z)); valll = 0.0001f + valll * ( 1.0f / 10 ); if (valll < 0.f) valll = 0.f; vert[1].p.z += valll; vert[2].p.z += valll; vert[0].p.z += 0.0001f; vert[3].p.z += 0.0001f;//*( 1.0f / 2 ); vert[1].rhw *= .98f; vert[2].rhw *= .98f; vert[0].rhw *= .98f; vert[3].rhw *= .98f; vert[2].p.x += (vect2.x + 0.2f - rnd() * 0.1f) * siz; vert[2].p.y += (vect2.y + 0.2f - rnd() * 0.1f) * siz; vert[1].p.z = (vert[1].p.z + MAX_ZEDE) * ( 1.0f / 2 ); vert[2].p.z = (vert[2].p.z + MAX_ZEDE) * ( 1.0f / 2 ); if (curhalo.flags & HALO_NEGATIVE) vert[2].color = 0x00000000; else vert[2].color = 0xFF000000; } } } for (long o = 0 ; o < 3 ; o++) { paf[o] = eface->vid[o]; tv[o].color = eobj->vertexlist3[paf[o]].vert.color; } } //////////////////////////////////////////////////////////////////////// // HALO HANDLING END //////////////////////////////////////////////////////////////////////// if (special_color_flag & 2) { TexturedVertex * tv2; { tv2 = PushVertexInTableCull(&TexSpecialColor); } memcpy(tv2, tv, sizeof(TexturedVertex) * 3); tv2[0].color = tv2[1].color = tv2[2].color = Color::gray(special_color.r).toBGR(); } } } } void Cedric_BlendAnimation(EERIE_3DOBJ * eobj, float timm) { for (long i = 0; i < eobj->c_data->nb_bones; i++) { EERIE_QUAT tquat; Quat_Copy(&tquat, &eobj->c_data->bones[i].quatinit); EERIE_QUAT q2; Quat_Copy(&q2, &eobj->c_data->bones[i].quatlast); Quat_Slerp(&eobj->c_data->bones[i].quatinit , &q2, &tquat, timm); eobj->c_data->bones[i].transinit = eobj->c_data->bones[i].translast + (eobj->c_data->bones[i].transinit - eobj->c_data->bones[i].translast) * timm; } } void Cedric_SaveBlendData(Entity * io) { if (io->obj->c_data) { for (long i = 0; i < io->obj->c_data->nb_bones; i++) { Quat_Copy(&io->obj->c_data->bones[i].quatlast, &io->obj->c_data->bones[i].quatinit); io->obj->c_data->bones[i].scalelast = io->obj->c_data->bones[i].scaleinit; io->obj->c_data->bones[i].translast = io->obj->c_data->bones[i].transinit; } } } void Cedric_ManageExtraRotationsFirst(Entity * io, EERIE_3DOBJ * obj) { for (long i = 0; i != obj->c_data->nb_bones; i++) { Quat_Init(&obj->c_data->bones[i].quatinit); obj->c_data->bones[i].transinit = obj->c_data->bones[i].transinit_global; } if ((io) && (io->ioflags & IO_NPC) && (io->_npcdata->ex_rotate)) { for (long k = 0; k < MAX_EXTRA_ROTATE; k++) { long i = io->_npcdata->ex_rotate->group_number[k]; if(i >= 0) { Anglef vt1; EERIE_QUAT quat1; vt1.a = radians(io->_npcdata->ex_rotate->group_rotate[k].g); vt1.b = radians(io->_npcdata->ex_rotate->group_rotate[k].b); vt1.g = radians(io->_npcdata->ex_rotate->group_rotate[k].a); QuatFromAngles(&quat1, &vt1); Quat_Copy(&obj->c_data->bones[i].quatinit, &quat1); } } } } static bool Cedric_IO_Visible(Entity * io) { if (io == entities.player()) return true; if(ACTIVEBKG && io) { if (distSqr(io->pos, ACTIVECAM->pos) > square(ACTIVECAM->cdepth) * square(0.6f)) return false; long xx, yy; xx = io->pos.x * ACTIVEBKG->Xmul; yy = io->pos.z * ACTIVEBKG->Zmul; if ((xx >= 1) && (yy >= 1) && (xx < ACTIVEBKG->Xsize - 1) && (yy < ACTIVEBKG->Zsize - 1)) { for (long ky = yy - 1; ky <= yy + 1; ky++) for (long kx = xx - 1; kx <= xx + 1; kx++) { FAST_BKG_DATA * feg = (FAST_BKG_DATA *)&ACTIVEBKG->fastdata[kx][ky]; if (feg->treat) return true; } return false; } } return true; } extern long MUST_DRAW; extern long EXTERNALVIEW; /* Apply animation and draw object */ void Cedric_AnimateDrawEntity(EERIE_3DOBJ * eobj, ANIM_USE * animuse, Anglef * angle, Vec3f * pos, Entity * io, bool render, bool update_movement) { float invisibility; float scale; float timm; Vec3f ftr; EERIE_C_DATA * obj; // Init some data Cedric_ResetBoundingBox(io); // Set scale and invisibility factors Cedric_GetScale(scale, invisibility, io); // Flag linked objects //Cedric_FlagLinkedObjects(eobj); ??? // Is There any Between-Animations Interpolation to make ? timm>0.f Cedric_GetTime(timm, io); // Buffer size check if(eobj->nbgroups > max_grps) { //todo free grps = (unsigned char *)realloc(grps, eobj->nbgroups); max_grps = eobj->nbgroups; } memset(grps, 0, eobj->nbgroups); Cedric_AnimCalcTranslation(io, animuse, scale, ftr, update_movement); if(Cedric_IO_Visible(io)) { // Manage Extra Rotations in Local Space Cedric_ManageExtraRotationsFirst(io, eobj); // Perform animation in Local space Cedric_AnimateObject(io, eobj, animuse); // Check for Animation Blending in Local space if (io) { if (timm > 0.f) { Cedric_BlendAnimation(eobj, timm); Cedric_SaveBlendData(io); } else Cedric_SaveBlendData(io); } // Build skeleton in Object Space Cedric_ConcatenateTM(io, eobj->c_data, angle, pos, ftr, scale); /* Display the object */ obj = eobj->c_data; if (!obj) return; if(Cedric_TransformVerts(io, eobj, obj, pos) && render) { INTER_DRAW++; if(!Cedric_ApplyLighting(eobj, obj, io, pos)) { return; } Cedric_RenderObject(eobj, obj, io, pos, ftr, invisibility); if (io) { io->bbox1.x = (short)BBOXMIN.x; io->bbox2.x = (short)BBOXMAX.x; io->bbox1.y = (short)BBOXMIN.y; io->bbox2.y = (short)BBOXMAX.y; } // Now we can render Linked Objects for (long k = 0; k < eobj->nblinked; k++) { if ((eobj->linked[k].lgroup != -1) && eobj->linked[k].obj) { eobj->linked[k].modinfo.rot = Anglef::ZERO; float old = 0.f; Entity * ioo = (Entity *)eobj->linked[k].io; EERIE_3DOBJ * obj = (EERIE_3DOBJ *) eobj->linked[k].obj; // Store item invisibility flag if (io && ioo) { old = ioo->invisibility; if (io == entities.player()) { ioo->invisibility = INVISIBILITY_OVERRIDE; } else { INVISIBILITY_OVERRIDE = 0.f; ioo->invisibility = invisibility; } } else { if (ioo) { INVISIBILITY_OVERRIDE = 0.f; ioo->invisibility = invisibility; } else INVISIBILITY_OVERRIDE = invisibility; } if (ioo) { if ((ioo->ignition > 0.f) || (ioo->ioflags & IO_FIERY)) ManageIgnition(ioo); } MUST_DRAW = 1; // specific check to avoid drawing player weapon on its back when in subjective view if ((io == entities.player()) && (eobj->linked[k].lidx == entities.player()->obj->fastaccess.weapon_attach) && (!EXTERNALVIEW)) continue; long ll = eobj->linked[k].lidx2; eobj->linked[k].modinfo.link_position = obj->vertexlist[ll].v - obj->vertexlist[obj->origin].v; EERIE_QUAT quat; ll = eobj->linked[k].lidx; Vec3f * posi = &eobj->vertexlist3[ll].v; Quat_Copy(&quat, &eobj->c_data->bones[eobj->linked[k].lgroup].quatanim); EERIEMATRIX matrix; MatrixFromQuat(&matrix, &quat); DrawEERIEInterMatrix(obj, &matrix, posi, ioo, &eobj->linked[k].modinfo); INVISIBILITY_OVERRIDE = 0.f; // Restore item invisibility flag if (ioo) ioo->invisibility = old; MUST_DRAW = 0; } } } } } void MakeCLight(Entity * io, Color3f * infra, Anglef * angle, Vec3f * pos, EERIE_3DOBJ * eobj, EERIEMATRIX * BIGMAT, EERIE_QUAT * BIGQUAT) { if ((Project.improve) && (!io)) { infra->r = 0.6f; infra->g = 0.f; infra->b = 1.f; } llightsInit(); Vec3f tv = *pos; if ((io) && (io->ioflags & IO_ITEM)) tv.y -= 60.f; else tv.y -= 90.f; for (long i = 0; i < TOTIOPDL; i++) { if (IO_PDL[i]->fallend + 500.f < 0) continue; Insertllight(IO_PDL[i], fdist(IO_PDL[i]->pos, tv)); } for (int i = 0; i < TOTPDL; i++) { if (PDL[i]->fallend + 500.f < 0) continue; Insertllight(PDL[i], fdist(PDL[i]->pos, tv)); } Preparellights(&tv); if ((io) && (io->ioflags & IO_ANGULAR)) return; Vec3f vLight; Vec3f vTLights[32]; EERIE_QUAT qInvert; if (BIGMAT != NULL) { QuatFromMatrix(qInvert, *BIGMAT); } else { if (BIGQUAT != NULL) { qInvert = *BIGQUAT; } else { //FIX LIGHT Anglef vt1; if (angle) { vt1 = *angle; } else { if (io) vt1 = io->angle; else vt1 = eobj->angle; } vt1.a = radians(MAKEANGLE(-vt1.g)); vt1.b = radians(MAKEANGLE(vt1.b)); vt1.g = radians(MAKEANGLE(vt1.a)); QuatFromAngles(&qInvert, &vt1); } } for (size_t i = 0; i < eobj->vertexlist.size(); i++) { float r, g, b; long ir, ig, ib; if ((io) && (io->ioflags & (IO_NPC | IO_ITEM))) { r = g = b = NPC_ITEMS_AMBIENT_VALUE_255; } else { r = ACTIVEBKG->ambient255.r; g = ACTIVEBKG->ambient255.g; b = ACTIVEBKG->ambient255.b; } Vec3f * posVert = &eobj->vertexlist3[i].v; for (long l = 0 ; l != MAX_LLIGHTS; l++) { EERIE_LIGHT * Cur_llights = llights[l]; if (Cur_llights) { float cosangle; vLight = (llights[l]->pos - *posVert).getNormalized(); TransformInverseVertexQuat(&qInvert, &vLight, &vTLights[l]); Vec3f * Cur_vLights = &vTLights[l]; // Get cos angle between light and vertex norm cosangle = (eobj->vertexlist[i].norm.x * Cur_vLights->x + eobj->vertexlist[i].norm.y * Cur_vLights->y + eobj->vertexlist[i].norm.z * Cur_vLights->z); // If light visible if (cosangle > 0.f) { float distance = fdist(*posVert, Cur_llights->pos); // Evaluate its intensity depending on the distance Light<->Object if (distance <= Cur_llights->fallstart) cosangle *= Cur_llights->precalc; else { float p = ((Cur_llights->fallend - distance) * Cur_llights->falldiffmul); if (p <= 0.f) cosangle = 0.f; else cosangle *= p * Cur_llights->precalc; } r += Cur_llights->rgb255.r * cosangle; g += Cur_llights->rgb255.g * cosangle; b += Cur_llights->rgb255.b * cosangle; } } else break; } if (eobj->drawflags & DRAWFLAG_HIGHLIGHT) { r += iHighLight; g += iHighLight; b += iHighLight; } if ((Project.improve) && (!io)) { r *= infra->r; g *= infra->g; b *= infra->b; r += infra->r * 512.f; g += infra->g; b += infra->b * 400.f; } ir = clipByte255(r); ig = clipByte255(g); ib = clipByte255(b); eobj->vertexlist3[i].vert.color = 0xff000000L | (((ir) & 255) << 16) | (((ig) & 255) << 8) | ((ib) & 255); } } void MakeCLight2(Entity * io, Color3f * infra, Anglef * angle, Vec3f * pos, EERIE_3DOBJ * eobj, EERIEMATRIX * BIGMAT, EERIE_QUAT * BIGQUAT, long ii) { Vec3f vLight; Vec3f vTLights[32]; EERIE_QUAT qInvert; if (BIGMAT != NULL) { QuatFromMatrix(qInvert, *BIGMAT); } else { if (BIGQUAT != NULL) { qInvert = *BIGQUAT; } else { Anglef vt1; if (angle) { vt1 = *angle; } else { if (io) vt1 = io->angle; else vt1 = eobj->angle; } vt1 = Anglef(radians(vt1.a), radians(vt1.b), radians(vt1.g)); QuatFromAngles(&qInvert, &vt1); } } Vec3f tv = *pos; if ((io) && (io->ioflags & IO_ITEM)) tv.y -= 60.f; else tv.y -= 90.f; for(long l = 0; l != MAX_LLIGHTS; l++) { if(llights[l]) { vLight = (llights[l]->pos - tv) / dists[l]; TransformInverseVertexQuat(&qInvert, &vLight, &vTLights[l]); } else { break; } } long paf[3]; paf[0] = eobj->facelist[ii].vid[0]; paf[1] = eobj->facelist[ii].vid[1]; paf[2] = eobj->facelist[ii].vid[2]; for (long i = 0; i < 3; i++) { float r, g, b; long ir, ig, ib; if ((io) && (io->ioflags & (IO_NPC | IO_ITEM))) { r = g = b = NPC_ITEMS_AMBIENT_VALUE_255; } else { r = ACTIVEBKG->ambient255.r; g = ACTIVEBKG->ambient255.g; b = ACTIVEBKG->ambient255.b; } Vec3f * posVert = &eobj->vertexlist3[paf[i]].v; for (int l = 0 ; l != MAX_LLIGHTS; l++) { EERIE_LIGHT * Cur_llights = llights[l]; if (Cur_llights) { float cosangle; float oolength = 1.f / fdist(*posVert, Cur_llights->pos); vLight = (llights[l]->pos - *posVert) * oolength; TransformInverseVertexQuat(&qInvert, &vLight, &vTLights[l]); Vec3f * Cur_vLights = &vTLights[l]; cosangle = (eobj->facelist[ii].norm.x * Cur_vLights->x + eobj->facelist[ii].norm.y * Cur_vLights->y + eobj->facelist[ii].norm.z * Cur_vLights->z) * ( 1.0f / 2 ); // If light visible if (cosangle > 0.f) { float distance = fdist(*posVert, Cur_llights->pos); // Evaluate its intensity depending on the distance Light<->Object if (distance <= Cur_llights->fallstart) cosangle *= Cur_llights->precalc; else { float p = ((Cur_llights->fallend - distance) * Cur_llights->falldiffmul); if (p <= 0.f) cosangle = 0.f; else cosangle *= p * Cur_llights->precalc; } r += Cur_llights->rgb255.r * cosangle; g += Cur_llights->rgb255.g * cosangle; b += Cur_llights->rgb255.b * cosangle; } } else break; } if (eobj->drawflags & DRAWFLAG_HIGHLIGHT) { r += iHighLight; g += iHighLight; b += iHighLight; } if (Project.improve) { r *= infra->r; g *= infra->g; b *= infra->b; } ir = clipByte255(r); ig = clipByte255(g); ib = clipByte255(b); eobj->vertexlist3[paf[i]].vert.color = 0xff000000L | (((ir) & 255) << 16) | (((ig) & 255) << 8) | ((ib) & 255); } } void ApplyDynLight(EERIEPOLY * ep) { long nbvert, i; if (ep->type & POLY_QUAD) nbvert = 4; else nbvert = 3; if (TOTPDL == 0) { for (i = 0; i < nbvert; i++) ep->tv[i].color = ep->v[i].color; return; } Color3f rgb; long j; float epr[4]; float epg[4]; float epb[4]; for (i = 0; i < nbvert; i++) { long c = ep->v[i].color; epr[i] = (float)((c >> 16) & 255); epg[i] = (float)((c >> 8) & 255); epb[i] = (float)(c & 255); } for (i = 0; i < TOTPDL; i++) { EERIE_LIGHT * el = PDL[i]; if (el->fallend + 35.f < 0) { TSU_TEST_NB_LIGHT ++; continue; } if (distSqr(el->pos, ep->center) <= square(el->fallend + 35.f)) { if(Project.improve) { rgb.r = el->rgb255.r * 4.f; rgb.g = rgb.b = 0.2f; } else { rgb = el->rgb255; } for (j = 0; j < nbvert; j++) { Vec3f v(ep->v[j].p.x,ep->v[j].p.y, ep->v[j].p.z); if (el->fallend < 0) { TSU_TEST_NB ++; continue; } float d = fdist(el->pos, ep->v[j].p); if (d <= el->fallend) { float divd = 1.f / d; float nvalue; Vec3f v1; v1 = (el->pos - ep->v[j].p) * divd; nvalue = dot(v1, ep->nrml[j]) * (1.0f / 2); if (nvalue > 1.f) nvalue = 1.f; else if (nvalue < 0.f) nvalue = 0.f; if (nvalue > 0.f) { //// if (d <= el->fallstart) { d = nvalue * el->precalc; } else { d -= el->fallstart; d = (el->falldiff - d) * el->falldiffmul * nvalue * el->precalc; } epr[j] += rgb.r * d; epg[j] += rgb.g * d; epb[j] += rgb.b * d; } } else if (d > el->fallend + 100.f) break; } } } long lepr, lepg, lepb; for (j = 0; j < nbvert; j++) { lepr = clipByte255(epr[j]); lepg = clipByte255(epg[j]); lepb = clipByte255(epb[j]); ep->tv[j].color = (0xFF000000L | (lepr << 16) | (lepg << 8) | (lepb)); } } //************************************************************************************* void ApplyDynLight_VertexBuffer(EERIEPOLY * ep, SMY_VERTEX * _pVertex, unsigned short _usInd0, unsigned short _usInd1, unsigned short _usInd2, unsigned short _usInd3) { long nbvert, i; if (ep->type & POLY_QUAD) nbvert = 4; else nbvert = 3; if (TOTPDL == 0) { ep->tv[0].color = _pVertex[_usInd0].color = ep->v[0].color; ep->tv[1].color = _pVertex[_usInd1].color = ep->v[1].color; ep->tv[2].color = _pVertex[_usInd2].color = ep->v[2].color; if (nbvert & 4) { ep->tv[3].color = _pVertex[_usInd3].color = ep->v[3].color; } return; } long j; float epr[4]; float epg[4]; float epb[4]; for (i = 0; i < nbvert; i++) { long c = ep->v[i].color; epr[i] = (float)(long)((c >> 16) & 255); epg[i] = (float)(long)((c >> 8) & 255); epb[i] = (float)(long)(c & 255); } for (i = 0; i < TOTPDL; i++) { EERIE_LIGHT * el = PDL[i]; for (j = 0; j < nbvert; j++) { float d = fdist(el->pos, ep->v[j].p); if (d < el->fallend) { float nvalue; nvalue = ((el->pos.x - ep->v[j].p.x) * ep->nrml[j].x + (el->pos.y - ep->v[j].p.y) * ep->nrml[j].y + (el->pos.z - ep->v[j].p.z) * ep->nrml[j].z ) * 0.5f / d; if (nvalue > 0.f) { if (d <= el->fallstart) { d = el->precalc * nvalue; } else { d -= el->fallstart; d = (el->falldiff - d) * el->falldiffmul * el->precalc * nvalue; } epr[j] += el->rgb255.r * d; epg[j] += el->rgb255.g * d; epb[j] += el->rgb255.b * d; } } else if (d > el->fallend + 100.f) break; } } long lepr, lepg, lepb; lepr = clipByte255(epr[0]); lepg = clipByte255(epg[0]); lepb = clipByte255(epb[0]); ep->tv[0].color = _pVertex[_usInd0].color = (0xFF000000L | (lepr << 16) | (lepg << 8) | (lepb)); lepr = clipByte255(epr[1]); lepg = clipByte255(epg[1]); lepb = clipByte255(epb[1]); ep->tv[1].color = _pVertex[_usInd1].color = (0xFF000000L | (lepr << 16) | (lepg << 8) | (lepb)); lepr = clipByte255(epr[2]); lepg = clipByte255(epg[2]); lepb = clipByte255(epb[2]); ep->tv[2].color = _pVertex[_usInd2].color = (0xFF000000L | (lepr << 16) | (lepg << 8) | (lepb)); if (nbvert & 4) { lepr = clipByte255(epr[3]); lepg = clipByte255(epg[3]); lepb = clipByte255(epb[3]); ep->tv[3].color = _pVertex[_usInd3].color = (0xFF000000L | (lepr << 16) | (lepg << 8) | (lepb)); } } extern TILE_LIGHTS tilelights[MAX_BKGX][MAX_BKGZ]; //************************************************************************************* 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) { // Nuky - 25/01/11 - harmless refactor to understand what is slow. // MASSIVE speed up thanks to "harmless refactor", wtf ? TILE_LIGHTS * tls = &tilelights[_x][_y]; long nbvert = (ep->type & POLY_QUAD) ? 4 : 3; if (tls->num == 0) { _pVertex[_usInd0].color = ep->v[0].color; ep->tv[0].color = ep->v[0].color; _pVertex[_usInd1].color = ep->v[1].color; ep->tv[1].color = ep->v[1].color; _pVertex[_usInd2].color = ep->v[2].color; ep->tv[2].color = ep->v[2].color; if (nbvert & 4) { _pVertex[_usInd3].color = ep->v[3].color; ep->tv[3].color = ep->v[3].color; } return; } long i, j; float epr[4]; float epg[4]; float epb[4]; for (i = 0; i < nbvert; i++) { long c = ep->v[i].color; epr[i] = (float)(long)((c >> 16) & 255); epg[i] = (float)(long)((c >> 8) & 255); epb[i] = (float)(long)(c & 255); } for (i = 0; i < tls->num; i++) { EERIE_LIGHT * el = tls->el[i]; for (j = 0; j < nbvert; j++) { float d = fdist(el->pos, ep->v[j].p); if (d < el->fallend) { float nvalue; nvalue = ((el->pos.x - ep->v[j].p.x) * ep->nrml[j].x + (el->pos.y - ep->v[j].p.y) * ep->nrml[j].y + (el->pos.z - ep->v[j].p.z) * ep->nrml[j].z ) * 0.5f / d; if (nvalue > 0.f) { if (d <= el->fallstart) { d = el->precalc * nvalue; } else { d -= el->fallstart; d = (el->falldiff - d) * el->falldiffmul * el->precalc * nvalue; } epr[j] += el->rgb255.r * d; epg[j] += el->rgb255.g * d; epb[j] += el->rgb255.b * d; } } else if (d > el->fallend + 100.f) break; } } long lepr, lepg, lepb; lepr = clipByte255(epr[0]); lepg = clipByte255(epg[0]); lepb = clipByte255(epb[0]); ep->tv[0].color = _pVertex[_usInd0].color = (0xFF000000L | (lepr << 16) | (lepg << 8) | (lepb)); lepr = clipByte255(epr[1]); lepg = clipByte255(epg[1]); lepb = clipByte255(epb[1]); ep->tv[1].color = _pVertex[_usInd1].color = (0xFF000000L | (lepr << 16) | (lepg << 8) | (lepb)); lepr = clipByte255(epr[2]); lepg = clipByte255(epg[2]); lepb = clipByte255(epb[2]); ep->tv[2].color = _pVertex[_usInd2].color = (0xFF000000L | (lepr << 16) | (lepg << 8) | (lepb)); if (nbvert & 4) { lepr = clipByte255(epr[3]); lepg = clipByte255(epg[3]); lepb = clipByte255(epb[3]); ep->tv[3].color = _pVertex[_usInd3].color = (0xFF000000L | (lepr << 16) | (lepg << 8) | (lepb)); } }