diff --git a/source/common/fonts/font.cpp b/source/common/fonts/font.cpp index 011a9cadb..98763724f 100644 --- a/source/common/fonts/font.cpp +++ b/source/common/fonts/font.cpp @@ -422,7 +422,7 @@ void FFont::ReadSheetFont(TArray &folderdata, int width, int height { for (int x = 0; x < numtex_x; x++) { - auto image = new FSheetTexture(sheetBitmaps.Size() - 1, x * width, y * width, width, height); + auto image = new FSheetTexture(sheetBitmaps.Size() - 1, x * width, y * height, width, height); FImageTexture *imgtex = new FImageTexture(image); auto gtex = MakeGameTexture(imgtex, nullptr, ETextureType::FontChar); gtex->SetWorldPanning(true); diff --git a/source/common/rendering/gl/gl_shader.cpp b/source/common/rendering/gl/gl_shader.cpp index c69aa79b2..2e4951f1a 100644 --- a/source/common/rendering/gl/gl_shader.cpp +++ b/source/common/rendering/gl/gl_shader.cpp @@ -235,6 +235,8 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * float uClipHeight; float uClipHeightDirection; int uShadowmapFilter; + + int uLightBlendMode; }; uniform int uTextureMode; @@ -328,6 +330,7 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * uniform sampler2D texture9; uniform sampler2D texture10; uniform sampler2D texture11; + uniform sampler2D texture12; // timer data uniform float timer; diff --git a/source/common/rendering/hwrenderer/data/hw_viewpointbuffer.cpp b/source/common/rendering/hwrenderer/data/hw_viewpointbuffer.cpp index f60cda5e1..3d67b46be 100644 --- a/source/common/rendering/hwrenderer/data/hw_viewpointbuffer.cpp +++ b/source/common/rendering/hwrenderer/data/hw_viewpointbuffer.cpp @@ -91,6 +91,7 @@ void HWViewpointBuffer::Set2D(FRenderState &di, int width, int height, int pll) matrices.mPalLightLevels = pll; matrices.mClipLine.X = -10000000.0f; matrices.mShadowmapFilter = gl_shadowmap_filter; + matrices.mLightBlendMode = 0; matrices.mProjectionMatrix.ortho(0, (float)width, (float)height, 0, -1.0f, 1.0f); matrices.CalcDependencies(); diff --git a/source/common/rendering/hwrenderer/data/hw_viewpointuniforms.h b/source/common/rendering/hwrenderer/data/hw_viewpointuniforms.h index 3d28f5c4a..def3b4808 100644 --- a/source/common/rendering/hwrenderer/data/hw_viewpointuniforms.h +++ b/source/common/rendering/hwrenderer/data/hw_viewpointuniforms.h @@ -4,6 +4,15 @@ struct HWDrawInfo; +enum class ELightBlendMode : uint8_t +{ + CLAMP = 0, + CLAMP_COLOR = 1, + NOCLAMP = 2, + + DEFAULT = CLAMP, +}; + struct HWViewpointUniforms { VSMatrix mProjectionMatrix; @@ -19,6 +28,8 @@ struct HWViewpointUniforms float mClipHeightDirection = 0.f; int mShadowmapFilter = 1; + int mLightBlendMode = 0; + void CalcDependencies() { mNormalViewMatrix.computeNormalMatrix(mViewMatrix); diff --git a/source/common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp b/source/common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp index 6a8d15af3..9cf1badb7 100644 --- a/source/common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp +++ b/source/common/rendering/hwrenderer/postprocessing/hw_postprocess.cpp @@ -570,7 +570,8 @@ void PPColormap::Render(PPRenderState *renderstate, int fixedcm, float flash) void PPTonemap::UpdateTextures() { - if (gl_tonemap == Palette && !PaletteTexture.Data) + // level.info->tonemap cannot be ETonemapMode::Palette, so it's fine to only check gl_tonemap here + if (ETonemapMode((int)gl_tonemap) == ETonemapMode::Palette && !PaletteTexture.Data) { std::shared_ptr data(new uint32_t[512 * 512], [](void *p) { delete[](uint32_t*)p; }); @@ -598,7 +599,9 @@ void PPTonemap::UpdateTextures() void PPTonemap::Render(PPRenderState *renderstate) { - if (gl_tonemap == 0) + ETonemapMode current_tonemap = (level_tonemap != ETonemapMode::None) ? level_tonemap : ETonemapMode((int)gl_tonemap); + + if (current_tonemap == ETonemapMode::None) { return; } @@ -606,14 +609,14 @@ void PPTonemap::Render(PPRenderState *renderstate) UpdateTextures(); PPShader *shader = nullptr; - switch (gl_tonemap) + switch (current_tonemap) { default: - case Linear: shader = &LinearShader; break; - case Reinhard: shader = &ReinhardShader; break; - case HejlDawson: shader = &HejlDawsonShader; break; - case Uncharted2: shader = &Uncharted2Shader; break; - case Palette: shader = &PaletteShader; break; + case ETonemapMode::Linear: shader = &LinearShader; break; + case ETonemapMode::Reinhard: shader = &ReinhardShader; break; + case ETonemapMode::HejlDawson: shader = &HejlDawsonShader; break; + case ETonemapMode::Uncharted2: shader = &Uncharted2Shader; break; + case ETonemapMode::Palette: shader = &PaletteShader; break; } renderstate->PushGroup("tonemap"); @@ -622,7 +625,7 @@ void PPTonemap::Render(PPRenderState *renderstate) renderstate->Shader = shader; renderstate->Viewport = screen->mScreenViewport; renderstate->SetInputCurrent(0); - if (gl_tonemap == Palette) + if (current_tonemap == ETonemapMode::Palette) renderstate->SetInputTexture(1, &PaletteTexture); renderstate->SetOutputNext(); renderstate->SetNoBlend(); diff --git a/source/common/rendering/hwrenderer/postprocessing/hw_postprocess.h b/source/common/rendering/hwrenderer/postprocessing/hw_postprocess.h index 71defdcae..357396da7 100644 --- a/source/common/rendering/hwrenderer/postprocessing/hw_postprocess.h +++ b/source/common/rendering/hwrenderer/postprocessing/hw_postprocess.h @@ -13,6 +13,19 @@ typedef IntRect PPViewport; class PPTexture; class PPShader; +enum class ETonemapMode : uint8_t +{ + None, + Uncharted2, + HejlDawson, + Reinhard, + Linear, + Palette, + NumTonemapModes +}; + + + enum class PPFilterMode { Nearest, Linear }; enum class PPWrapMode { Clamp, Repeat }; enum class PPTextureType { CurrentPipelineTexture, NextPipelineTexture, PPTexture, SceneColor, SceneFog, SceneNormal, SceneDepth, SwapChain, ShadowMap }; @@ -541,6 +554,7 @@ private: class PPTonemap { public: + void SetTonemapMode(ETonemapMode tm) { level_tonemap = tm; } void Render(PPRenderState *renderstate); void ClearTonemapPalette() { PaletteTexture = {}; } @@ -554,17 +568,7 @@ private: PPShader HejlDawsonShader = { "shaders/pp/tonemap.fp", "#define HEJLDAWSON\n", {} }; PPShader Uncharted2Shader = { "shaders/pp/tonemap.fp", "#define UNCHARTED2\n", {} }; PPShader PaletteShader = { "shaders/pp/tonemap.fp", "#define PALETTE\n", {} }; - - enum TonemapMode - { - None, - Uncharted2, - HejlDawson, - Reinhard, - Linear, - Palette, - NumTonemapModes - }; + ETonemapMode level_tonemap = ETonemapMode::None; }; ///////////////////////////////////////////////////////////////////////////// @@ -840,8 +844,11 @@ public: PPCustomShaders customShaders; + void SetTonemapMode(ETonemapMode tm) { tonemap.SetTonemapMode(tm); } void Pass1(PPRenderState *state, int fixedcm, int sceneWidth, int sceneHeight); void Pass2(PPRenderState* state, int fixedcm, float flash, int sceneWidth, int sceneHeight); }; + extern Postprocess hw_postprocess; + diff --git a/source/common/rendering/vulkan/shaders/vk_shader.cpp b/source/common/rendering/vulkan/shaders/vk_shader.cpp index 1c6df42f1..25b585531 100644 --- a/source/common/rendering/vulkan/shaders/vk_shader.cpp +++ b/source/common/rendering/vulkan/shaders/vk_shader.cpp @@ -175,6 +175,8 @@ static const char *shaderBindings = R"( float uClipHeight; float uClipHeightDirection; int uShadowmapFilter; + + int uLightBlendMode; }; layout(set = 1, binding = 1, std140) uniform MatricesUBO { @@ -244,6 +246,7 @@ static const char *shaderBindings = R"( layout(set = 2, binding = 8) uniform sampler2D texture9; layout(set = 2, binding = 9) uniform sampler2D texture10; layout(set = 2, binding = 10) uniform sampler2D texture11; + layout(set = 2, binding = 11) uniform sampler2D texture12; // This must match the PushConstants struct layout(push_constant) uniform PushConstants diff --git a/source/common/scripting/core/maps.cpp b/source/common/scripting/core/maps.cpp index 28fda643e..68eab6d3d 100644 --- a/source/common/scripting/core/maps.cpp +++ b/source/common/scripting/core/maps.cpp @@ -438,10 +438,12 @@ template void MapIteratorSetValue(I * self, expand_types_vm ) \ + DEFINE_ACTION_FUNCTION_NATIVE( FMapIterator_I32_Str , GetValue , MapIteratorGetValueString< FMapIterator_I32_Str > ) \ { \ PARAM_SELF_STRUCT_PROLOGUE( FMapIterator_I32_Str ); \ - ACTION_RETURN_STRING( MapIteratorGetValue(self) ); \ + FString out; \ + MapIteratorGetValueString(self , out); \ + ACTION_RETURN_STRING( out ); \ } #define DEF_MAP_IT_S_S() \ diff --git a/source/common/textures/hw_material.cpp b/source/common/textures/hw_material.cpp index c6b38e5a6..2517c098e 100644 --- a/source/common/textures/hw_material.cpp +++ b/source/common/textures/hw_material.cpp @@ -133,12 +133,15 @@ FMaterial::FMaterial(FGameTexture * tx, int scaleflags) if (index >= FIRST_USER_SHADER) { const UserShaderDesc& usershader = usershaders[index - FIRST_USER_SHADER]; - if (tx->Layers && usershader.shaderType == mShaderIndex) // Only apply user shader if it matches the expected material + if (usershader.shaderType == mShaderIndex) // Only apply user shader if it matches the expected material { - for (auto& texture : tx->Layers->CustomShaderTextures) + if (tx->Layers) { - if (texture == nullptr) continue; - mTextureLayers.Push({ texture.get(), 0 }); // scalability should be user-definable. + for (auto& texture : tx->Layers->CustomShaderTextures) + { + if (texture == nullptr) continue; + mTextureLayers.Push({ texture.get(), 0 }); // scalability should be user-definable. + } } mShaderIndex = index; } diff --git a/source/common/utility/palette.cpp b/source/common/utility/palette.cpp index c1728a3ad..e7bc61f09 100644 --- a/source/common/utility/palette.cpp +++ b/source/common/utility/palette.cpp @@ -418,19 +418,34 @@ void MakeRemap(uint32_t* BaseColors, const uint32_t* colors, uint8_t* remap, con // color, so find a duplicate pair of palette entries, make one of them a // duplicate of color 0, and remap every graphic so that it uses that entry // instead of entry 0. -void MakeGoodRemap(uint32_t* BaseColors, uint8_t* Remap) +void MakeGoodRemap(uint32_t* BaseColors, uint8_t* Remap, const uint8_t* lastcolormap) { for (int i = 0; i < 256; i++) Remap[i] = i; PalEntry color0 = BaseColors[0]; int i; + // First try for an exact match of color 0. Only Hexen does not have one. - for (i = 1; i < 256; ++i) + if (!lastcolormap) { - if (BaseColors[i] == color0) + for (i = 1; i < 256; ++i) { - Remap[0] = i; - break; + if (BaseColors[i] == color0) + { + Remap[0] = i; + break; + } + } + } + else + { + for (i = 1; i < 256; ++i) + { + if ((BaseColors[i] == color0) && (lastcolormap[i] == lastcolormap[0])) + { + Remap[0] = i; + break; + } } } @@ -448,21 +463,44 @@ void MakeGoodRemap(uint32_t* BaseColors, uint8_t* Remap) sortcopy[i] = (BaseColors[i] & 0xffffff) | (i << 24); } qsort(sortcopy, 256, 4, sortforremap); - for (i = 255; i > 0; --i) + if (!lastcolormap) { - if ((sortcopy[i] & 0xFFFFFF) == (sortcopy[i - 1] & 0xFFFFFF)) + for (i = 255; i > 0; --i) { - int new0 = sortcopy[i].a; - int dup = sortcopy[i - 1].a; - if (new0 > dup) + if ((sortcopy[i] & 0xFFFFFF) == (sortcopy[i - 1] & 0xFFFFFF)) { - // Make the lower-numbered entry a copy of color 0. (Just because.) - std::swap(new0, dup); + int new0 = sortcopy[i].a; + int dup = sortcopy[i - 1].a; + if (new0 > dup) + { + // Make the lower-numbered entry a copy of color 0. (Just because.) + std::swap(new0, dup); + } + Remap[0] = new0; + Remap[new0] = dup; + BaseColors[new0] = color0; + break; + } + } + } + else + { + for (i = 255; i > 0; --i) + { + if (((sortcopy[i] & 0xFFFFFF) == (sortcopy[i - 1] & 0xFFFFFF)) && (lastcolormap[sortcopy[i].a] == lastcolormap[sortcopy[i - 1].a])) + { + int new0 = sortcopy[i].a; + int dup = sortcopy[i - 1].a; + if (new0 > dup) + { + // Make the lower-numbered entry a copy of color 0. (Just because.) + std::swap(new0, dup); + } + Remap[0] = new0; + Remap[new0] = dup; + BaseColors[new0] = color0; + break; } - Remap[0] = new0; - Remap[new0] = dup; - BaseColors[new0] = color0; - break; } } } diff --git a/source/common/utility/palutil.h b/source/common/utility/palutil.h index bbd8f9a2d..6faa7b5df 100644 --- a/source/common/utility/palutil.h +++ b/source/common/utility/palutil.h @@ -14,7 +14,7 @@ void DoBlending(const PalEntry* from, PalEntry* to, int count, int r, int g, int // Given an array of colors, fills in remap with values to remap the // passed array of colors to BaseColors. Used for loading palette downconversions of PNGs. void MakeRemap(uint32_t* BaseColors, const uint32_t* colors, uint8_t* remap, const uint8_t* useful, int numcolors); -void MakeGoodRemap(uint32_t* BaseColors, uint8_t* Remap); +void MakeGoodRemap(uint32_t* BaseColors, uint8_t* Remap, const uint8_t* cmapdata = nullptr); // Colorspace conversion RGB <-> HSV void RGBtoHSV (float r, float g, float b, float *h, float *s, float *v); diff --git a/source/core/rendering/scene/hw_drawinfo.cpp b/source/core/rendering/scene/hw_drawinfo.cpp index 6ef9dd4fc..b2e11a414 100644 --- a/source/core/rendering/scene/hw_drawinfo.cpp +++ b/source/core/rendering/scene/hw_drawinfo.cpp @@ -250,6 +250,7 @@ void HWDrawInfo::SetupView(FRenderState &state, float vx, float vy, float vz, bo SetViewMatrix(vp.HWAngles, vx, vy, vz, mirror, planemirror); SetCameraPos(vp.Pos); VPUniforms.CalcDependencies(); + VPUniforms.mLightBlendMode = 0; vpIndex = screen->mViewpoints->SetViewpoint(state, &VPUniforms); } diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index ab1e276e1..467653329 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -325,7 +325,7 @@ float R_DoomLightingEquation(float light) // This is a lot more primitive than Doom's lighting... float numShades = float(uPalLightLevels & 255); float curshade = (1.0 - light) * (numShades - 1.0); - float visibility = max(uGlobVis * uLightFactor * abs(z), 0.0); + float visibility = max(uGlobVis * uLightFactor * z, 0.0); float shade = clamp((curshade + visibility), 0.0, numShades - 1.0); return clamp(shade * uLightDist, 0.0, 1.0); } @@ -344,10 +344,86 @@ float R_DoomLightingEquation(float light) //=========================================================================== // -// Check if light is in shadow according to its 1D shadow map +// Check if light is in shadow // //=========================================================================== +#ifdef SUPPORTS_RAYTRACING + +bool traceHit(vec3 origin, vec3 direction, float dist) +{ + rayQueryEXT rayQuery; + rayQueryInitializeEXT(rayQuery, TopLevelAS, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF, origin, 0.01f, direction, dist); + while(rayQueryProceedEXT(rayQuery)) { } + return rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT; +} + +vec2 softshadow[9 * 3] = vec2[]( + vec2( 0.0, 0.0), + vec2(-2.0,-2.0), + vec2( 2.0, 2.0), + vec2( 2.0,-2.0), + vec2(-2.0, 2.0), + vec2(-1.0,-1.0), + vec2( 1.0, 1.0), + vec2( 1.0,-1.0), + vec2(-1.0, 1.0), + + vec2( 0.0, 0.0), + vec2(-1.5,-1.5), + vec2( 1.5, 1.5), + vec2( 1.5,-1.5), + vec2(-1.5, 1.5), + vec2(-0.5,-0.5), + vec2( 0.5, 0.5), + vec2( 0.5,-0.5), + vec2(-0.5, 0.5), + + vec2( 0.0, 0.0), + vec2(-1.25,-1.75), + vec2( 1.75, 1.25), + vec2( 1.25,-1.75), + vec2(-1.75, 1.75), + vec2(-0.75,-0.25), + vec2( 0.25, 0.75), + vec2( 0.75,-0.25), + vec2(-0.25, 0.75) +); + +float shadowAttenuation(vec4 lightpos, float lightcolorA) +{ + float shadowIndex = abs(lightcolorA) - 1.0; + if (shadowIndex >= 1024.0) + return 1.0; // Don't cast rays for this light + + vec3 origin = pixelpos.xzy; + vec3 target = lightpos.xzy + 0.01; // nudge light position slightly as Doom maps tend to have their lights perfectly aligned with planes + + vec3 direction = normalize(target - origin); + float dist = distance(origin, target); + + if (uShadowmapFilter <= 0) + { + return traceHit(origin, direction, dist) ? 0.0 : 1.0; + } + else + { + vec3 v = (abs(direction.x) > abs(direction.y)) ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0); + vec3 xdir = normalize(cross(direction, v)); + vec3 ydir = cross(direction, xdir); + + float sum = 0.0; + int step_count = uShadowmapFilter * 9; + for (int i = 0; i <= step_count; i++) + { + vec3 pos = target + xdir * softshadow[i].x + ydir * softshadow[i].y; + sum += traceHit(origin, normalize(pos - origin), dist) ? 0.0 : 1.0; + } + return sum / step_count; + } +} + +#else #ifdef SUPPORTS_SHADOWMAPS float shadowDirToU(vec2 dir) @@ -491,6 +567,7 @@ float shadowAttenuation(vec4 lightpos, float lightcolorA) return 1.0; } +#endif #endif float spotLightAttenuation(vec4 lightpos, vec3 spotdir, float lightCosInnerAngle, float lightCosOuterAngle) diff --git a/wadsrc/static/shaders/glsl/main.vp b/wadsrc/static/shaders/glsl/main.vp index f6ad81e43..f718d73bc 100644 --- a/wadsrc/static/shaders/glsl/main.vp +++ b/wadsrc/static/shaders/glsl/main.vp @@ -5,11 +5,15 @@ layout(location = 2) in vec4 aColor; layout(location = 0) out vec4 vTexCoord; layout(location = 1) out vec4 vColor; +layout(location = 9) out vec3 vLightmap; #ifndef SIMPLE // we do not need these for simple shaders layout(location = 3) in vec4 aVertex2; layout(location = 4) in vec4 aNormal; layout(location = 5) in vec4 aNormal2; +layout(location = 6) in vec3 aLightmap; +layout(location = 7) in vec4 aBoneWeight; +layout(location = 8) in uvec4 aBoneSelector; layout(location = 2) out vec4 pixelpos; layout(location = 3) out vec3 glowdist; @@ -23,6 +27,14 @@ layout(location = 7) out vec4 ClipDistanceA; layout(location = 8) out vec4 ClipDistanceB; #endif +struct BonesResult +{ + vec3 Normal; + vec4 Position; +}; + +BonesResult ApplyBones(); + void main() { float ClipDistance0, ClipDistance1, ClipDistance2, ClipDistance3, ClipDistance4; @@ -30,9 +42,11 @@ void main() vec2 parmTexCoord; vec4 parmPosition; - parmTexCoord = aTexCoord; - parmPosition = aPosition; + BonesResult bones = ApplyBones(); + parmTexCoord = aTexCoord; + parmPosition = bones.Position; + #ifndef SIMPLE vec4 worldcoord = ModelMatrix * mix(parmPosition, aVertex2, uInterpolationFactor); #else @@ -51,6 +65,8 @@ void main() #endif #ifndef SIMPLE + vLightmap = aLightmap; + pixelpos.xyz = worldcoord.xyz; pixelpos.w = -eyeCoordPos.z/eyeCoordPos.w; @@ -78,14 +94,7 @@ void main() ClipDistance4 = worldcoord.y - ((uSplitBottomPlane.w + uSplitBottomPlane.x * worldcoord.x + uSplitBottomPlane.y * worldcoord.z) * uSplitBottomPlane.z); } - #ifdef HAS_UNIFORM_VERTEX_DATA - if ((useVertexData & 2) == 0) - vWorldNormal = NormalModelMatrix * vec4(normalize(uVertexNormal.xyz), 1.0); - else - vWorldNormal = NormalModelMatrix * vec4(normalize(mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor)), 1.0); - #else - vWorldNormal = NormalModelMatrix * vec4(normalize(mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor)), 1.0); - #endif + vWorldNormal = NormalModelMatrix * vec4(normalize(bones.Normal), 1.0); vEyeNormal = NormalViewMatrix * vec4(normalize(vWorldNormal.xyz), 1.0); #endif @@ -142,3 +151,66 @@ void main() gl_PointSize = 1.0; } + +#if !defined(SIMPLE) +vec3 GetAttrNormal() +{ + #ifdef HAS_UNIFORM_VERTEX_DATA + if ((useVertexData & 2) == 0) + return uVertexNormal.xyz; + else + return mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor); + #else + return mix(aNormal.xyz, aNormal2.xyz, uInterpolationFactor); + #endif +} + +void AddWeightedBone(uint boneIndex, float weight, inout vec4 position, inout vec3 normal) +{ + if (weight != 0.0) + { + mat4 transform = bones[uBoneIndexBase + int(boneIndex)]; + mat3 rotation = mat3(transform); + position += (transform * aPosition) * weight; + normal += (rotation * aNormal.xyz) * weight; + } +} + +BonesResult ApplyBones() +{ + BonesResult result; + if (uBoneIndexBase >= 0 && aBoneWeight != vec4(0.0)) + { + result.Position = vec4(0.0); + result.Normal = vec3(0.0); + + // We use low precision input for our bone weights. Rescale so the sum still is 1.0 + float totalWeight = aBoneWeight.x + aBoneWeight.y + aBoneWeight.z + aBoneWeight.w; + float weightMultiplier = 1.0 / totalWeight; + vec4 boneWeight = aBoneWeight * weightMultiplier; + + AddWeightedBone(aBoneSelector.x, boneWeight.x, result.Position, result.Normal); + AddWeightedBone(aBoneSelector.y, boneWeight.y, result.Position, result.Normal); + AddWeightedBone(aBoneSelector.z, boneWeight.z, result.Position, result.Normal); + AddWeightedBone(aBoneSelector.w, boneWeight.w, result.Position, result.Normal); + + result.Position.w = 1.0; // For numerical stability + } + else + { + result.Position = aPosition; + result.Normal = GetAttrNormal(); + } + return result; +} + +#else + +BonesResult ApplyBones() +{ + BonesResult result; + result.Position = aPosition; + return result; +} + +#endif diff --git a/wadsrc/static/shaders/glsl/material_normal.fp b/wadsrc/static/shaders/glsl/material_normal.fp index 02c905623..b9d25852c 100644 --- a/wadsrc/static/shaders/glsl/material_normal.fp +++ b/wadsrc/static/shaders/glsl/material_normal.fp @@ -59,7 +59,21 @@ vec3 ProcessMaterialLight(Material material, vec3 color) } } - vec3 frag = material.Base.rgb * clamp(color + desaturate(dynlight).rgb, 0.0, 1.4); + vec3 frag; + + if ( uLightBlendMode == 1 ) + { // COLOR_CORRECT_CLAMPING + vec3 lightcolor = color + desaturate(dynlight).rgb; + frag = material.Base.rgb * ((lightcolor / max(max(max(lightcolor.r, lightcolor.g), lightcolor.b), 1.4) * 1.4)); + } + else if ( uLightBlendMode == 2 ) + { // UNCLAMPED + frag = material.Base.rgb * (color + desaturate(dynlight).rgb); + } + else + { + frag = material.Base.rgb * clamp(color + desaturate(dynlight).rgb, 0.0, 1.4); + } if (uLightIndex >= 0) { diff --git a/wadsrc/static/shaders/glsl/material_specular.fp b/wadsrc/static/shaders/glsl/material_specular.fp index 015586f95..12eabd33e 100644 --- a/wadsrc/static/shaders/glsl/material_specular.fp +++ b/wadsrc/static/shaders/glsl/material_specular.fp @@ -66,9 +66,25 @@ vec3 ProcessMaterialLight(Material material, vec3 color) } } } + + if ( uLightBlendMode == 1 ) + { // COLOR_CORRECT_CLAMPING + dynlight.rgb = color + desaturate(dynlight).rgb; + specular.rgb = desaturate(specular).rgb; - dynlight.rgb = clamp(color + desaturate(dynlight).rgb, 0.0, 1.4); - specular.rgb = clamp(desaturate(specular).rgb, 0.0, 1.4); + dynlight.rgb = ((dynlight.rgb / max(max(max(dynlight.r, dynlight.g), dynlight.b), 1.4) * 1.4)); + specular.rgb = ((specular.rgb / max(max(max(specular.r, specular.g), specular.b), 1.4) * 1.4)); + } + else if ( uLightBlendMode == 2 ) + { // UNCLAMPED + dynlight.rgb = color + desaturate(dynlight).rgb; + specular.rgb = desaturate(specular).rgb; + } + else + { + dynlight.rgb = clamp(color + desaturate(dynlight).rgb, 0.0, 1.4); + specular.rgb = clamp(desaturate(specular).rgb, 0.0, 1.4); + } vec3 frag = material.Base.rgb * dynlight.rgb + material.Specular * specular.rgb;