diff --git a/src/gl/dynlights/gl_dynlight.h b/src/gl/dynlights/gl_dynlight.h index 74e49baba..a85814b6b 100644 --- a/src/gl/dynlights/gl_dynlight.h +++ b/src/gl/dynlights/gl_dynlight.h @@ -59,6 +59,7 @@ struct FDynLightData bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, FDynLightData &data); +void gl_AddLightToList(int group, ADynamicLight * light, FDynLightData &ldata, bool hudmodel); void gl_UploadLights(FDynLightData &data); diff --git a/src/gl/dynlights/gl_dynlight1.cpp b/src/gl/dynlights/gl_dynlight1.cpp index 4000554c8..92a503c8d 100644 --- a/src/gl/dynlights/gl_dynlight1.cpp +++ b/src/gl/dynlights/gl_dynlight1.cpp @@ -65,13 +65,11 @@ CVAR(Int, gl_attenuate, -1, 0); // This is mainly a debug option. //========================================================================== bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, FDynLightData &ldata) { - int i = 0; - DVector3 pos = light->PosRelative(group); - - float dist = fabsf(p.DistToPoint(pos.X, pos.Z, pos.Y)); float radius = (light->GetRadius()); - + + float dist = fabsf(p.DistToPoint(pos.X, pos.Z, pos.Y)); + if (radius <= 0.f) return false; if (dist > radius) return false; if (checkside && gl_lights_checkside && p.PointOnSide(pos.X, pos.Z, pos.Y)) @@ -79,6 +77,46 @@ bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, FD return false; } + gl_AddLightToList(group, light, ldata, false); + return true; +} + +//========================================================================== +// +// Add one dynamic light to the light data list +// +//========================================================================== +void gl_AddLightToList(int group, ADynamicLight * light, FDynLightData &ldata, bool hudmodel) +{ + int i = 0; + + DVector3 pos = light->PosRelative(group); + float radius = light->GetRadius(); + + if (hudmodel) + { + // HUD model is already translated and rotated. We must rotate the lights into that view space. + + DVector3 rotation; + DVector3 localpos = pos - r_viewpoint.Pos; + + rotation.X = localpos.X * r_viewpoint.Angles.Yaw.Sin() - localpos.Y * r_viewpoint.Angles.Yaw.Cos(); + rotation.Y = localpos.X * r_viewpoint.Angles.Yaw.Cos() + localpos.Y * r_viewpoint.Angles.Yaw.Sin(); + rotation.Z = localpos.Z; + localpos = rotation; + + rotation.X = localpos.X; + rotation.Y = localpos.Y * r_viewpoint.Angles.Pitch.Sin() - localpos.Z * r_viewpoint.Angles.Pitch.Cos(); + rotation.Z = localpos.Y * r_viewpoint.Angles.Pitch.Cos() + localpos.Z * r_viewpoint.Angles.Pitch.Sin(); + localpos = rotation; + + rotation.Y = localpos.Y; + rotation.Z = localpos.Z * r_viewpoint.Angles.Roll.Sin() - localpos.X * r_viewpoint.Angles.Roll.Cos(); + rotation.X = localpos.Z * r_viewpoint.Angles.Roll.Cos() + localpos.X * r_viewpoint.Angles.Roll.Sin(); + localpos = rotation; + + pos = localpos; + } float cs; if (light->IsAdditive()) @@ -124,6 +162,5 @@ bool gl_GetLight(int group, Plane & p, ADynamicLight * light, bool checkside, FD data[5] = g; data[6] = b; data[7] = shadowIndex; - return true; } diff --git a/src/gl/models/gl_models.cpp b/src/gl/models/gl_models.cpp index a118e20f2..45b955b56 100644 --- a/src/gl/models/gl_models.cpp +++ b/src/gl/models/gl_models.cpp @@ -1099,6 +1099,9 @@ void gl_RenderHUDModel(DPSprite *psp, float ofsX, float ofsY) // so we have to reset the view matrix. gl_RenderState.mViewMatrix.loadIdentity(); + // Need to reset the normal matrix too + gl_RenderState.mNormalViewMatrix.loadIdentity(); + // Scaling model (y scale for a sprite means height, i.e. z in the world!). gl_RenderState.mViewMatrix.scale(smf->xscale, smf->zscale, smf->yscale); diff --git a/src/gl/models/gl_models_md2.cpp b/src/gl/models/gl_models_md2.cpp index 507e5977a..7f7930ac9 100644 --- a/src/gl/models/gl_models_md2.cpp +++ b/src/gl/models/gl_models_md2.cpp @@ -40,6 +40,8 @@ #include "gl/shaders/gl_shader.h" #include "gl/data/gl_vertexbuffer.h" +extern int modellightindex; + static float avertexnormals[NUMVERTEXNORMALS][3] = { #include "tab_anorms.h" }; @@ -379,6 +381,7 @@ void FDMDModel::RenderFrame(FTexture * skin, int frameno, int frameno2, double i gl_RenderState.SetInterpolationFactor((float)inter); gl_RenderState.Apply(); + if (modellightindex != -1) gl_RenderState.ApplyLightIndex(modellightindex); mVBuf->SetupFrame(frames[frameno].vindex, frames[frameno2].vindex, lodInfo[0].numTriangles * 3); glDrawArrays(GL_TRIANGLES, 0, lodInfo[0].numTriangles * 3); gl_RenderState.SetInterpolationFactor(0.f); diff --git a/src/gl/models/gl_models_md3.cpp b/src/gl/models/gl_models_md3.cpp index 6336ce277..9573b83c1 100644 --- a/src/gl/models/gl_models_md3.cpp +++ b/src/gl/models/gl_models_md3.cpp @@ -35,6 +35,8 @@ #define MAX_QPATH 64 +extern int modellightindex; + //=========================================================================== // // decode the lat/lng normal to a 3 float normal @@ -372,6 +374,7 @@ void FMD3Model::RenderFrame(FTexture * skin, int frameno, int frameno2, double i gl_RenderState.SetMaterial(tex, CLAMP_NONE, translation, -1, false); gl_RenderState.Apply(); + if (modellightindex != -1) gl_RenderState.ApplyLightIndex(modellightindex); mVBuf->SetupFrame(surf->vindex + frameno * surf->numVertices, surf->vindex + frameno2 * surf->numVertices, surf->numVertices); glDrawElements(GL_TRIANGLES, surf->numTriangles * 3, GL_UNSIGNED_INT, (void*)(intptr_t)(surf->iindex * sizeof(unsigned int))); } diff --git a/src/gl/models/gl_voxels.cpp b/src/gl/models/gl_voxels.cpp index 48b6da442..0b97e87f8 100644 --- a/src/gl/models/gl_voxels.cpp +++ b/src/gl/models/gl_voxels.cpp @@ -50,6 +50,7 @@ #include "gl/utility/gl_convert.h" #include "gl/renderer/gl_renderstate.h" +extern int modellightindex; //=========================================================================== // @@ -445,6 +446,7 @@ void FVoxelModel::RenderFrame(FTexture * skin, int frame, int frame2, double int gl_RenderState.SetMaterial(tex, CLAMP_NOFILTER, translation, -1, false); gl_RenderState.Apply(); + if (modellightindex != -1) gl_RenderState.ApplyLightIndex(modellightindex); mVBuf->SetupFrame(0, 0, 0); glDrawElements(GL_TRIANGLES, mNumIndices, GL_UNSIGNED_INT, (void*)(intptr_t)0); } diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index f3b698360..b29053383 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -328,7 +328,10 @@ void GLSprite::Draw(int pass) { if (gl_lights && GLRenderer->mLightCount && mDrawer->FixedColormap == CM_DEFAULT && !fullbright) { - gl_SetDynSpriteLight(gl_light_sprites ? actor : NULL, gl_light_particles ? particle : NULL); + if (modelframe && !particle) + gl_SetDynModelLight(gl_light_sprites ? actor : NULL, false); + else + gl_SetDynSpriteLight(gl_light_sprites ? actor : NULL, gl_light_particles ? particle : NULL); } sector_t *cursec = actor ? actor->Sector : particle ? particle->subsector->sector : nullptr; if (cursec != nullptr) diff --git a/src/gl/scene/gl_spritelight.cpp b/src/gl/scene/gl_spritelight.cpp index bb9de17b3..4bc2588e8 100644 --- a/src/gl/scene/gl_spritelight.cpp +++ b/src/gl/scene/gl_spritelight.cpp @@ -32,6 +32,8 @@ #include "vectors.h" #include "gl/gl_functions.h" #include "g_level.h" +#include "g_levellocals.h" +#include "actorinlines.h" #include "gl/system/gl_cvars.h" #include "gl/renderer/gl_renderer.h" @@ -42,7 +44,10 @@ #include "gl/scene/gl_portal.h" #include "gl/shaders/gl_shader.h" #include "gl/textures/gl_material.h" +#include "gl/dynlights/gl_lightbuffer.h" +FDynLightData modellightdata; +int modellightindex = -1; //========================================================================== // @@ -114,6 +119,7 @@ void gl_SetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t * node = node->nextLight; } gl_RenderState.SetDynLight(out[0], out[1], out[2]); + modellightindex = -1; } void gl_SetDynSpriteLight(AActor *thing, particle_t *particle) @@ -127,3 +133,94 @@ void gl_SetDynSpriteLight(AActor *thing, particle_t *particle) gl_SetDynSpriteLight(NULL, particle->Pos.X, particle->Pos.Y, particle->Pos.Z, particle->subsector); } } + +// Check if circle potentially intersects with node AABB +static bool CheckBBoxCircle(float *bbox, float x, float y, float radiusSquared) +{ + float centerX = (bbox[BOXRIGHT] + bbox[BOXLEFT]) * 0.5f; + float centerY = (bbox[BOXBOTTOM] + bbox[BOXTOP]) * 0.5f; + float extentX = (bbox[BOXRIGHT] - bbox[BOXLEFT]) * 0.5f; + float extentY = (bbox[BOXBOTTOM] - bbox[BOXTOP]) * 0.5f; + float aabbRadiusSquared = extentX * extentX + extentY * extentY; + x -= centerX; + y -= centerY; + float dist = x * x + y * y; + return dist <= radiusSquared + aabbRadiusSquared; +} + +template +void BSPNodeWalkCircle(void *node, float x, float y, float radiusSquared, const Callback &callback) +{ + while (!((size_t)node & 1)) + { + node_t *bsp = (node_t *)node; + + if (CheckBBoxCircle(bsp->bbox[0], x, y, radiusSquared)) + BSPNodeWalkCircle(bsp->children[0], x, y, radiusSquared, callback); + + if (!CheckBBoxCircle(bsp->bbox[1], x, y, radiusSquared)) + return; + + node = bsp->children[1]; + } + + subsector_t *sub = (subsector_t *)((uint8_t *)node - 1); + callback(sub); +} + +template +void BSPWalkCircle(float x, float y, float radiusSquared, const Callback &callback) +{ + if (level.nodes.Size() == 0) + callback(&level.subsectors[0]); + else + BSPNodeWalkCircle(level.HeadNode(), x, y, radiusSquared, callback); +} + +void gl_SetDynModelLight(AActor *self, bool hudmodel) +{ + modellightdata.Clear(); + + if (self) + { + static std::vector addedLights; // static so that we build up a reserve (memory allocations stop) + + addedLights.clear(); + + float x = self->X(); + float y = self->Y(); + float z = self->Center(); + float radiusSquared = self->renderradius * self->renderradius; + + BSPWalkCircle(x, y, radiusSquared, [&](subsector_t *subsector) // Iterate through all subsectors potentially touched by actor + { + FLightNode * node = subsector->lighthead; + while (node) // check all lights touching a subsector + { + ADynamicLight *light = node->lightsource; + if (light->visibletoplayer && !(light->flags2&MF2_DORMANT) && (!(light->lightflags&LF_DONTLIGHTSELF) || light->target != self) && !(light->lightflags&LF_DONTLIGHTACTORS)) + { + int group = subsector->sector->PortalGroup; + DVector3 pos = light->PosRelative(group); + float radius = light->GetRadius(); + double dx = pos.X - x; + double dy = pos.Y - y; + double dz = pos.Z - z; + double distSquared = dx * dx + dy * dy + dz * dz; + if (distSquared < radiusSquared + radius * radius) // Light and actor touches + { + if (std::find(addedLights.begin(), addedLights.end(), light) == addedLights.end()) // Check if we already added this light from a different subsector + { + gl_AddLightToList(group, light, modellightdata, hudmodel); + addedLights.push_back(light); + } + } + } + node = node->nextLight; + } + }); + } + + gl_RenderState.SetDynLight(0, 0, 0); + modellightindex = GLRenderer->mLights->UploadLights(modellightdata); +} diff --git a/src/gl/scene/gl_wall.h b/src/gl/scene/gl_wall.h index 1c52e3c30..47cf5654c 100644 --- a/src/gl/scene/gl_wall.h +++ b/src/gl/scene/gl_wall.h @@ -422,5 +422,6 @@ inline float Dist2(float x1,float y1,float x2,float y2) void gl_SetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t *subsec); void gl_SetDynSpriteLight(AActor *actor, particle_t *particle); +void gl_SetDynModelLight(AActor *self, bool hudmodel); #endif diff --git a/src/gl/scene/gl_weapon.cpp b/src/gl/scene/gl_weapon.cpp index ff2321da5..551f34cbd 100644 --- a/src/gl/scene/gl_weapon.cpp +++ b/src/gl/scene/gl_weapon.cpp @@ -420,7 +420,11 @@ void GLSceneDrawer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep) { if (gl_lights && GLRenderer->mLightCount && FixedColormap == CM_DEFAULT && gl_light_sprites) { - gl_SetDynSpriteLight(playermo, NULL); + FSpriteModelFrame *smf = playermo->player->ReadyWeapon ? gl_FindModelFrame(playermo->player->ReadyWeapon->GetClass(), psp->GetState()->sprite, psp->GetState()->GetFrame(), false) : nullptr; + if (smf) + gl_SetDynModelLight(playermo, true); + else + gl_SetDynSpriteLight(playermo, NULL); } SetColor(ll, 0, cmc, trans, true); } diff --git a/wadsrc/static/shaders/glsl/main.vp b/wadsrc/static/shaders/glsl/main.vp index 9901fba3f..a6055c2b5 100644 --- a/wadsrc/static/shaders/glsl/main.vp +++ b/wadsrc/static/shaders/glsl/main.vp @@ -62,7 +62,7 @@ void main() gl_ClipDistance[4] = worldcoord.y + ((uSplitBottomPlane.w + uSplitBottomPlane.x * worldcoord.x + uSplitBottomPlane.y * worldcoord.z) * uSplitBottomPlane.z); } - vWorldNormal = NormalModelMatrix * normalize(aNormal); + vWorldNormal = NormalModelMatrix * vec4(normalize(aNormal.xyz), 1.0); vEyeNormal = NormalViewMatrix * vWorldNormal; #endif