diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7cafad330..af5ff990e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -825,7 +825,6 @@ set( FASTMATH_SOURCES gl/scene/gl_swscene.cpp gl/scene/gl_portal.cpp gl/scene/gl_walls_draw.cpp - gl/scene/gl_spritelight.cpp gl_load/gl_load.c hwrenderer/dynlights/hw_dynlightdata.cpp hwrenderer/scene/hw_fakeflat.cpp @@ -835,6 +834,7 @@ set( FASTMATH_SOURCES hwrenderer/scene/hw_renderhacks.cpp hwrenderer/scene/hw_sky.cpp hwrenderer/scene/hw_sprites.cpp + hwrenderer/scene/hw_spritelight.cpp hwrenderer/scene/hw_walls.cpp hwrenderer/scene/hw_walls_vertex.cpp r_data/models/models.cpp @@ -1059,6 +1059,7 @@ set (PCH_SOURCES gl/textures/gl_samplers.cpp hwrenderer/data/flatvertices.cpp hwrenderer/dynlights/hw_aabbtree.cpp + hwrenderer/dynlights/hw_shadowmap.cpp hwrenderer/scene/hw_skydome.cpp hwrenderer/textures/hw_material.cpp hwrenderer/textures/hw_precache.cpp diff --git a/src/gl/dynlights/gl_shadowmap.cpp b/src/gl/dynlights/gl_shadowmap.cpp index 4def5ebbe..26bb32a7c 100644 --- a/src/gl/dynlights/gl_shadowmap.cpp +++ b/src/gl/dynlights/gl_shadowmap.cpp @@ -1,6 +1,6 @@ // //--------------------------------------------------------------------------- -// 1D dynamic shadow maps +// 1D dynamic shadow maps (OpenGL dependent part) // Copyright(C) 2017 Magnus Norddahl // All rights reserved. // @@ -32,77 +32,6 @@ #include "hwrenderer/dynlights/hw_dynlightdata.h" #include "stats.h" -/* - The 1D shadow maps are stored in a 1024x1024 texture as float depth values (R32F). - - Each line in the texture is assigned to a single light. For example, to grab depth values for light 20 - the fragment shader (main.fp) needs to sample from row 20. That is, the V texture coordinate needs - to be 20.5/1024. - - The texel row for each light is split into four parts. One for each direction, like a cube texture, - but then only in 2D where this reduces itself to a square. When main.fp samples from the shadow map - it first decides in which direction the fragment is (relative to the light), like cubemap sampling does - for 3D, but once again just for the 2D case. - - Texels 0-255 is Y positive, 256-511 is X positive, 512-767 is Y negative and 768-1023 is X negative. - - Generating the shadow map itself is done by FShadowMap::Update(). The shadow map texture's FBO is - bound and then a screen quad is drawn to make a fragment shader cover all texels. For each fragment - it shoots a ray and collects the distance to what it hit. - - The shadowmap.fp shader knows which light and texel it is processing by mapping gl_FragCoord.y back - to the light index, and it knows which direction to ray trace by looking at gl_FragCoord.x. For - example, if gl_FragCoord.y is 20.5, then it knows its processing light 20, and if gl_FragCoord.x is - 127.5, then it knows we are shooting straight ahead for the Y positive direction. - - Ray testing is done by uploading two GPU storage buffers - one holding AABB tree nodes, and one with - the line segments at the leaf nodes of the tree. The fragment shader then performs a test same way - as on the CPU, except everything uses indexes as pointers are not allowed in GLSL. -*/ - -namespace -{ - cycle_t UpdateCycles; - int LightsProcessed; - int LightsShadowmapped; -} - -ADD_STAT(shadowmap) -{ - FString out; - out.Format("upload=%04.2f ms lights=%d shadowmapped=%d", UpdateCycles.TimeMS(), LightsProcessed, LightsShadowmapped); - return out; -} - -CUSTOM_CVAR(Int, gl_shadowmap_quality, 512, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -{ - switch (self) - { - case 128: - case 256: - case 512: - case 1024: - break; - default: - self = 128; - break; - } -} - -CUSTOM_CVAR (Bool, gl_light_shadowmap, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) -{ - if (!self) - { - // Unset any residual shadow map indices in the light actors. - TThinkerIterator it(STAT_DLIGHT); - while (auto light = it.Next()) - { - light->mShadowmapIndex = 1024; - } - } -} - - void FShadowMap::Update() { UpdateCycles.Reset(); @@ -145,53 +74,10 @@ void FShadowMap::Update() UpdateCycles.Unclock(); } -bool FShadowMap::ShadowTest(ADynamicLight *light, const DVector3 &pos) -{ - if (light->shadowmapped && light->radius > 0.0 && IsEnabled() && mAABBTree) - return mAABBTree->RayTest(light->Pos(), pos) >= 1.0f; - else - return true; -} - -bool FShadowMap::IsEnabled() const -{ - return gl_light_shadowmap && !!(gl.flags & RFL_SHADER_STORAGE_BUFFER); -} - void FShadowMap::UploadLights() { - if (mLights.Size() != 1024 * 4) mLights.Resize(1024 * 4); - int lightindex = 0; - - // Todo: this should go through the blockmap in a spiral pattern around the player so that closer lights are preferred. - TThinkerIterator it(STAT_DLIGHT); - while (auto light = it.Next()) - { - LightsProcessed++; - if (light->shadowmapped && lightindex < 1024 * 4) - { - LightsShadowmapped++; - - light->mShadowmapIndex = lightindex >> 2; - - mLights[lightindex] = light->X(); - mLights[lightindex+1] = light->Y(); - mLights[lightindex+2] = light->Z(); - mLights[lightindex+3] = light->GetRadius(); - lightindex += 4; - } - else - { - light->mShadowmapIndex = 1024; - } - - } - - for (; lightindex < 1024 * 4; lightindex++) - { - mLights[lightindex] = 0; - } - + CollectLights(); + if (mLightList == 0) glGenBuffers(1, (GLuint*)&mLightList); @@ -204,28 +90,21 @@ void FShadowMap::UploadLights() void FShadowMap::UploadAABBTree() { - // Just comparing the level info is not enough. If two MAPINFO-less levels get played after each other, - // they can both refer to the same default level info. - if (level.info != mLastLevel && (level.nodes.Size() != mLastNumNodes || level.segs.Size() != mLastNumSegs)) - Clear(); + if (!ValidateAABBTree()) + { + int oldBinding = 0; + glGetIntegerv(GL_SHADER_STORAGE_BUFFER_BINDING, &oldBinding); - if (mAABBTree) - return; + glGenBuffers(1, (GLuint*)&mNodesBuffer); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, mNodesBuffer); + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(hwrenderer::AABBTreeNode) * mAABBTree->nodes.Size(), &mAABBTree->nodes[0], GL_STATIC_DRAW); - mAABBTree.reset(new hwrenderer::LevelAABBTree()); + glGenBuffers(1, (GLuint*)&mLinesBuffer); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, mLinesBuffer); + glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(hwrenderer::AABBTreeLine) * mAABBTree->lines.Size(), &mAABBTree->lines[0], GL_STATIC_DRAW); - int oldBinding = 0; - glGetIntegerv(GL_SHADER_STORAGE_BUFFER_BINDING, &oldBinding); - - glGenBuffers(1, (GLuint*)&mNodesBuffer); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, mNodesBuffer); - glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(hwrenderer::AABBTreeNode) * mAABBTree->nodes.Size(), &mAABBTree->nodes[0], GL_STATIC_DRAW); - - glGenBuffers(1, (GLuint*)&mLinesBuffer); - glBindBuffer(GL_SHADER_STORAGE_BUFFER, mLinesBuffer); - glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(hwrenderer::AABBTreeLine) * mAABBTree->lines.Size(), &mAABBTree->lines[0], GL_STATIC_DRAW); - - glBindBuffer(GL_SHADER_STORAGE_BUFFER, oldBinding); + glBindBuffer(GL_SHADER_STORAGE_BUFFER, oldBinding); + } } void FShadowMap::Clear() @@ -247,10 +126,4 @@ void FShadowMap::Clear() glDeleteBuffers(1, (GLuint*)&mLinesBuffer); mLinesBuffer = 0; } - - mAABBTree.reset(); - - mLastLevel = level.info; - mLastNumNodes = level.nodes.Size(); - mLastNumSegs = level.segs.Size(); } diff --git a/src/gl/dynlights/gl_shadowmap.h b/src/gl/dynlights/gl_shadowmap.h index d2081ff2a..ee43abef8 100644 --- a/src/gl/dynlights/gl_shadowmap.h +++ b/src/gl/dynlights/gl_shadowmap.h @@ -1,30 +1,18 @@ #pragma once -#include "hwrenderer/dynlights/hw_aabbtree.h" -#include "tarray.h" -#include +#include "hwrenderer/dynlights/hw_shadowmap.h" -class ADynamicLight; -struct level_info_t; - -class FShadowMap +class FShadowMap : public IShadowMap { public: - FShadowMap() { } ~FShadowMap() { Clear(); } // Release resources - void Clear(); + void Clear() override; // Update shadow map texture - void Update(); - - // Test if a world position is in shadow relative to the specified light and returns false if it is - bool ShadowTest(ADynamicLight *light, const DVector3 &pos); - - // Returns true if gl_light_shadowmap is enabled and supported by the hardware - bool IsEnabled() const; + void Update() override; private: // Upload the AABB-tree to the GPU @@ -36,21 +24,7 @@ private: // OpenGL storage buffer with the list of lights in the shadow map texture int mLightList = 0; - // Working buffer for creating the list of lights. Stored here to avoid allocating memory each frame - TArray mLights; - // OpenGL storage buffers for the AABB tree int mNodesBuffer = 0; int mLinesBuffer = 0; - - // Used to detect when a level change requires the AABB tree to be regenerated - level_info_t *mLastLevel = nullptr; - unsigned mLastNumNodes = 0; - unsigned mLastNumSegs = 0; - - // AABB-tree of the level, used for ray tests - std::unique_ptr mAABBTree; - - FShadowMap(const FShadowMap &) = delete; - FShadowMap &operator=(FShadowMap &) = delete; }; diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 15c034975..601dfb24c 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -256,6 +256,7 @@ void GLSceneDrawer::CreateScene() gl_drawinfo->mAngles = GLRenderer->mAngles; gl_drawinfo->mViewVector = GLRenderer->mViewVector; gl_drawinfo->mViewActor = GLRenderer->mViewActor; + gl_drawinfo->mShadowMap = &GLRenderer->mShadowMap; RenderBSPNode (level.HeadNode()); if (GLRenderer->mCurrentPortal != NULL) GLRenderer->mCurrentPortal->RenderAttached(); @@ -581,7 +582,6 @@ void GLSceneDrawer::DrawEndScene2D(sector_t * viewsector) void GLSceneDrawer::ProcessScene(bool toscreen) { - FDrawInfo::StartDrawInfo(this); iter_dlightf = iter_dlight = draw_dlight = draw_dlightf = 0; GLPortal::BeginScene(); @@ -590,7 +590,6 @@ void GLSceneDrawer::ProcessScene(bool toscreen) CurrentMapSections.Zero(); CurrentMapSections.Set(mapsection); DrawScene(toscreen ? DM_MAINVIEW : DM_OFFSCREEN); - FDrawInfo::EndDrawInfo(); } @@ -714,8 +713,11 @@ sector_t * GLSceneDrawer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, f SetViewMatrix(r_viewpoint.Pos.X, r_viewpoint.Pos.Y, r_viewpoint.Pos.Z, false, false); gl_RenderState.ApplyMatrices(); + FDrawInfo::StartDrawInfo(this); ProcessScene(toscreen); if (mainview && toscreen) EndDrawScene(lviewsector); // do not call this for camera textures. + FDrawInfo::EndDrawInfo(); + if (mainview && FGLRenderBuffers::IsEnabled()) { GLRenderer->PostProcessScene(FixedColormap, [&]() { if (gl_bloom && FixedColormap == CM_DEFAULT) DrawEndScene2D(lviewsector); }); diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index 042f4817b..910b90978 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -69,7 +69,7 @@ int gl_SetDynModelLight(AActor *self, int dynlightindex) if (gl.legacyMode) { float out[3]; - hw_GetDynSpriteLight(self, nullptr, out); + gl_drawinfo->GetDynSpriteLight(self, nullptr, out); gl_RenderState.SetDynLight(out[0], out[1], out[2]); return -1; } @@ -198,7 +198,7 @@ void FDrawInfo::DrawSprite(GLSprite *sprite, int pass) else { float out[3]; - hw_GetDynSpriteLight(gl_light_sprites ? sprite->actor : nullptr, gl_light_particles ? sprite->particle : nullptr, out); + GetDynSpriteLight(gl_light_sprites ? sprite->actor : nullptr, gl_light_particles ? sprite->particle : nullptr, out); gl_RenderState.SetDynLight(out[0], out[1], out[2]); } } diff --git a/src/gl/scene/gl_walls_draw.cpp b/src/gl/scene/gl_walls_draw.cpp index ebec1bab9..d7cb215dd 100644 --- a/src/gl/scene/gl_walls_draw.cpp +++ b/src/gl/scene/gl_walls_draw.cpp @@ -491,7 +491,7 @@ void FDrawInfo::DrawDecal(GLDecal *gldecal) double x, y; float out[3]; decal->GetXY(seg->sidedef, x, y); - hw_GetDynSpriteLight(nullptr, x, y, gldecal->zcenter, wall->sub, out); + GetDynSpriteLight(nullptr, x, y, gldecal->zcenter, wall->sub, out); gl_RenderState.SetDynLight(out[0], out[1], out[2]); } diff --git a/src/gl/scene/gl_weapon.cpp b/src/gl/scene/gl_weapon.cpp index 11fcd2734..6df86170d 100644 --- a/src/gl/scene/gl_weapon.cpp +++ b/src/gl/scene/gl_weapon.cpp @@ -457,7 +457,7 @@ void GLSceneDrawer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep) else { float out[3]; - hw_GetDynSpriteLight(playermo, nullptr, out); + gl_drawinfo->GetDynSpriteLight(playermo, nullptr, out); gl_RenderState.SetDynLight(out[0], out[1], out[2]); } } diff --git a/src/hwrenderer/dynlights/hw_shadowmap.cpp b/src/hwrenderer/dynlights/hw_shadowmap.cpp new file mode 100644 index 000000000..027942f46 --- /dev/null +++ b/src/hwrenderer/dynlights/hw_shadowmap.cpp @@ -0,0 +1,162 @@ +// +//--------------------------------------------------------------------------- +// 1D dynamic shadow maps (API independent part) +// Copyright(C) 2017 Magnus Norddahl +// All rights reserved. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see http://www.gnu.org/licenses/ +// +//-------------------------------------------------------------------------- +// + +#include "hwrenderer/dynlights/hw_shadowmap.h" +#include "hwrenderer/utility/hw_cvars.h" +#include "hwrenderer/dynlights/hw_dynlightdata.h" +#include "stats.h" +#include "g_levellocals.h" + +/* + The 1D shadow maps are stored in a 1024x1024 texture as float depth values (R32F). + + Each line in the texture is assigned to a single light. For example, to grab depth values for light 20 + the fragment shader (main.fp) needs to sample from row 20. That is, the V texture coordinate needs + to be 20.5/1024. + + The texel row for each light is split into four parts. One for each direction, like a cube texture, + but then only in 2D where this reduces itself to a square. When main.fp samples from the shadow map + it first decides in which direction the fragment is (relative to the light), like cubemap sampling does + for 3D, but once again just for the 2D case. + + Texels 0-255 is Y positive, 256-511 is X positive, 512-767 is Y negative and 768-1023 is X negative. + + Generating the shadow map itself is done by FShadowMap::Update(). The shadow map texture's FBO is + bound and then a screen quad is drawn to make a fragment shader cover all texels. For each fragment + it shoots a ray and collects the distance to what it hit. + + The shadowmap.fp shader knows which light and texel it is processing by mapping gl_FragCoord.y back + to the light index, and it knows which direction to ray trace by looking at gl_FragCoord.x. For + example, if gl_FragCoord.y is 20.5, then it knows its processing light 20, and if gl_FragCoord.x is + 127.5, then it knows we are shooting straight ahead for the Y positive direction. + + Ray testing is done by uploading two GPU storage buffers - one holding AABB tree nodes, and one with + the line segments at the leaf nodes of the tree. The fragment shader then performs a test same way + as on the CPU, except everything uses indexes as pointers are not allowed in GLSL. +*/ + +cycle_t IShadowMap::UpdateCycles; +int IShadowMap::LightsProcessed; +int IShadowMap::LightsShadowmapped; + +ADD_STAT(shadowmap) +{ + FString out; + out.Format("upload=%04.2f ms lights=%d shadowmapped=%d", IShadowMap::UpdateCycles.TimeMS(), IShadowMap::LightsProcessed, IShadowMap::LightsShadowmapped); + return out; +} + +CUSTOM_CVAR(Int, gl_shadowmap_quality, 512, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + switch (self) + { + case 128: + case 256: + case 512: + case 1024: + break; + default: + self = 128; + break; + } +} + +CUSTOM_CVAR (Bool, gl_light_shadowmap, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (!self) + { + // Unset any residual shadow map indices in the light actors. + TThinkerIterator it(STAT_DLIGHT); + while (auto light = it.Next()) + { + light->mShadowmapIndex = 1024; + } + } +} + +bool IShadowMap::ShadowTest(ADynamicLight *light, const DVector3 &pos) +{ + if (light->shadowmapped && light->radius > 0.0 && IsEnabled() && mAABBTree) + return mAABBTree->RayTest(light->Pos(), pos) >= 1.0f; + else + return true; +} + +bool IShadowMap::IsEnabled() const +{ + return gl_light_shadowmap && (screen->hwcaps & RFL_SHADER_STORAGE_BUFFER); +} + +void IShadowMap::CollectLights() +{ + if (mLights.Size() != 1024 * 4) mLights.Resize(1024 * 4); + int lightindex = 0; + + // Todo: this should go through the blockmap in a spiral pattern around the player so that closer lights are preferred. + TThinkerIterator it(STAT_DLIGHT); + while (auto light = it.Next()) + { + LightsProcessed++; + if (light->shadowmapped && light->IsActive() && lightindex < 1024 * 4) + { + LightsShadowmapped++; + + light->mShadowmapIndex = lightindex >> 2; + + mLights[lightindex] = (float)light->X(); + mLights[lightindex+1] = (float)light->Y(); + mLights[lightindex+2] = (float)light->Z(); + mLights[lightindex+3] = light->GetRadius(); + lightindex += 4; + } + else + { + light->mShadowmapIndex = 1024; + } + + } + + for (; lightindex < 1024 * 4; lightindex++) + { + mLights[lightindex] = 0; + } +} + +bool IShadowMap::ValidateAABBTree() +{ + // Just comparing the level info is not enough. If two MAPINFO-less levels get played after each other, + // they can both refer to the same default level info. + if (level.info != mLastLevel && (level.nodes.Size() != mLastNumNodes || level.segs.Size() != mLastNumSegs)) + { + mAABBTree.reset(); + + mLastLevel = level.info; + mLastNumNodes = level.nodes.Size(); + mLastNumSegs = level.segs.Size(); + } + + if (mAABBTree) + return true; + + mAABBTree.reset(new hwrenderer::LevelAABBTree()); + return false; +} diff --git a/src/hwrenderer/dynlights/hw_shadowmap.h b/src/hwrenderer/dynlights/hw_shadowmap.h new file mode 100644 index 000000000..6b26db8a3 --- /dev/null +++ b/src/hwrenderer/dynlights/hw_shadowmap.h @@ -0,0 +1,51 @@ + +#pragma once + +#include "hw_aabbtree.h" +#include "tarray.h" +#include "stats.h" +#include + +class ADynamicLight; +struct level_info_t; + +class IShadowMap +{ +public: + IShadowMap() { } + virtual ~IShadowMap() { } + + // Release resources + virtual void Clear() = 0; + + // Update shadow map texture + virtual void Update() = 0; + + // Test if a world position is in shadow relative to the specified light and returns false if it is + bool ShadowTest(ADynamicLight *light, const DVector3 &pos); + + // Returns true if gl_light_shadowmap is enabled and supported by the hardware + bool IsEnabled() const; + + static cycle_t UpdateCycles; + static int LightsProcessed; + static int LightsShadowmapped; + +protected: + void CollectLights(); + bool ValidateAABBTree(); + + // Working buffer for creating the list of lights. Stored here to avoid allocating memory each frame + TArray mLights; + + // Used to detect when a level change requires the AABB tree to be regenerated + level_info_t *mLastLevel = nullptr; + unsigned mLastNumNodes = 0; + unsigned mLastNumSegs = 0; + + // AABB-tree of the level, used for ray tests + std::unique_ptr mAABBTree; + + IShadowMap(const IShadowMap &) = delete; + IShadowMap &operator=(IShadowMap &) = delete; +}; diff --git a/src/hwrenderer/scene/hw_drawinfo.h b/src/hwrenderer/scene/hw_drawinfo.h index 5e8297a45..a1fc623f6 100644 --- a/src/hwrenderer/scene/hw_drawinfo.h +++ b/src/hwrenderer/scene/hw_drawinfo.h @@ -10,6 +10,8 @@ class GLWall; class GLFlat; class GLSprite; struct GLDecal; +class IShadowMap; +struct particle_t; //========================================================================== // @@ -78,6 +80,7 @@ struct HWDrawInfo FRotator mAngles; FVector2 mViewVector; AActor *mViewActor; + IShadowMap *mShadowMap; TArray MissingUpperTextures; TArray MissingLowerTextures; @@ -137,6 +140,10 @@ public: void AddOtherFloorPlane(int sector, gl_subsectorrendernode * node); void AddOtherCeilingPlane(int sector, gl_subsectorrendernode * node); + void GetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t * subsec, float *out); + void GetDynSpriteLight(AActor *thing, particle_t *particle, float *out); + + virtual void FloodUpperGap(seg_t * seg) = 0; virtual void FloodLowerGap(seg_t * seg) = 0; virtual void ProcessLowerMinisegs(TArray &lowersegs) = 0; diff --git a/src/hwrenderer/scene/hw_drawstructs.h b/src/hwrenderer/scene/hw_drawstructs.h index 1452bc430..fdaabf249 100644 --- a/src/hwrenderer/scene/hw_drawstructs.h +++ b/src/hwrenderer/scene/hw_drawstructs.h @@ -432,8 +432,6 @@ inline float Dist2(float x1,float y1,float x2,float y2) } bool hw_SetPlaneTextureRotation(const GLSectorPlane * secplane, FMaterial * gltexture, VSMatrix &mat); -void hw_GetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t *subsec, float *out); -void hw_GetDynSpriteLight(AActor *actor, particle_t *particle, float *out); void hw_GetDynModelLight(AActor *self, FDynLightData &modellightdata); extern const float LARGE_VALUE; diff --git a/src/gl/scene/gl_spritelight.cpp b/src/hwrenderer/scene/hw_spritelight.cpp similarity index 91% rename from src/gl/scene/gl_spritelight.cpp rename to src/hwrenderer/scene/hw_spritelight.cpp index 864e74a99..21037adfc 100644 --- a/src/gl/scene/gl_spritelight.cpp +++ b/src/hwrenderer/scene/hw_spritelight.cpp @@ -33,13 +33,8 @@ #include "g_levellocals.h" #include "actorinlines.h" #include "hwrenderer/dynlights/hw_dynlightdata.h" - -#include "gl/renderer/gl_renderer.h" -#include "gl/renderer/gl_lightdata.h" -#include "gl/scene/gl_drawinfo.h" -#include "gl/shaders/gl_shader.h" -#include "gl/dynlights/gl_lightbuffer.h" - +#include "hwrenderer/dynlights/hw_shadowmap.h" +#include "hwrenderer/scene/hw_drawinfo.h" template T smoothstep(const T edge0, const T edge1, const T x) @@ -54,7 +49,7 @@ T smoothstep(const T edge0, const T edge1, const T x) // //========================================================================== -void hw_GetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t * subsec, float *out) +void HWDrawInfo::GetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t * subsec, float *out) { ADynamicLight *light; float frac, lr, lg, lb; @@ -109,7 +104,7 @@ void hw_GetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t * frac *= (float)smoothstep(light->SpotOuterAngle.Cos(), light->SpotInnerAngle.Cos(), cosDir); } - if (frac > 0 && GLRenderer->mShadowMap.ShadowTest(light, { x, y, z })) + if (frac > 0 && (!light->shadowmapped || mShadowMap->ShadowTest(light, { x, y, z }))) { lr = light->GetRed() / 255.0f; lg = light->GetGreen() / 255.0f; @@ -133,15 +128,15 @@ void hw_GetDynSpriteLight(AActor *self, float x, float y, float z, subsector_t * } } -void hw_GetDynSpriteLight(AActor *thing, particle_t *particle, float *out) +void HWDrawInfo::GetDynSpriteLight(AActor *thing, particle_t *particle, float *out) { if (thing != NULL) { - hw_GetDynSpriteLight(thing, thing->X(), thing->Y(), thing->Center(), thing->subsector, out); + GetDynSpriteLight(thing, thing->X(), thing->Y(), thing->Center(), thing->subsector, out); } else if (particle != NULL) { - hw_GetDynSpriteLight(NULL, particle->Pos.X, particle->Pos.Y, particle->Pos.Z, particle->subsector, out); + GetDynSpriteLight(NULL, particle->Pos.X, particle->Pos.Y, particle->Pos.Z, particle->subsector, out); } }