Index: binaries/data/mods/public/shaders/arb/los_interp.fp
===================================================================
--- binaries/data/mods/public/shaders/arb/los_interp.fp
+++ binaries/data/mods/public/shaders/arb/los_interp.fp
@@ -12,6 +12,6 @@
TEMP smoothing;
MOV_SAT smoothing, delta.x;
-LRP result.color.a, smoothing, los1_tex.a, los2_tex.a;
+LRP result.color.r, smoothing, los1_tex.r, los2_tex.r;
END
Index: binaries/data/mods/public/shaders/arb/minimap.fp
===================================================================
--- binaries/data/mods/public/shaders/arb/minimap.fp
+++ binaries/data/mods/public/shaders/arb/minimap.fp
@@ -21,12 +21,11 @@
TEMP tex;
TEX tex, fragment.texcoord[0], texture[0], 2D;
- SUB tex.a, 1.0, tex.a;
- MOV result.color.r, 0.0;
- MOV result.color.g, 0.0;
- MOV result.color.b, 0.0;
- MOV result.color.a, tex.a;
+ MOV result.color.r, tex.r;
+ MOV result.color.g, tex.r;
+ MOV result.color.b, tex.r;
+ MOV result.color.a, tex.r;
#endif
#if MINIMAP_POINT
Index: binaries/data/mods/public/shaders/arb/model_common.fp
===================================================================
--- binaries/data/mods/public/shaders/arb/model_common.fp
+++ binaries/data/mods/public/shaders/arb/model_common.fp
@@ -148,8 +148,8 @@
#if !IGNORE_LOS
// Multiply everything by the LOS texture
- TEX tex.a, v_los, texture[2], 2D;
- MUL color.rgb, color, tex.a;
+ TEX tex.r, v_los, texture[2], 2D;
+ MUL color.rgb, color, tex.r;
#endif
MUL result.color.rgb, color, shadingColor;
Index: binaries/data/mods/public/shaders/arb/overlayline.fp
===================================================================
--- binaries/data/mods/public/shaders/arb/overlayline.fp
+++ binaries/data/mods/public/shaders/arb/overlayline.fp
@@ -16,10 +16,10 @@
#if IGNORE_LOS
MOV result.color.rgb, color;
#else
- // Multiply RGB by LOS texture (alpha channel)
+ // Multiply RGB by LOS texture (red channel)
TEMP los;
TEX los, fragment.texcoord[1], texture[2], 2D;
- MUL result.color.rgb, color, los.a;
+ MUL result.color.rgb, color, los.r;
#endif
// Use alpha from base texture, combined with the object color/fragment alpha.
Index: binaries/data/mods/public/shaders/arb/particle.fp
===================================================================
--- binaries/data/mods/public/shaders/arb/particle.fp
+++ binaries/data/mods/public/shaders/arb/particle.fp
@@ -17,7 +17,7 @@
// Multiply everything by the LOS texture
TEX losTex, v_los, texture[1], 2D;
-MUL result.color.rgb, color, losTex.a;
+MUL result.color.rgb, color, losTex.r;
MUL result.color.a, tex, fragment.color;
END
Index: binaries/data/mods/public/shaders/arb/terrain_common.fp
===================================================================
--- binaries/data/mods/public/shaders/arb/terrain_common.fp
+++ binaries/data/mods/public/shaders/arb/terrain_common.fp
@@ -87,8 +87,8 @@
#endif
// Multiply everything by the LOS texture
-TEX tex.a, fragment.texcoord[3], texture[3], 2D;
-MUL color.rgb, color, tex.a;
+TEX tex.r, fragment.texcoord[3], texture[3], 2D;
+MUL color.rgb, color, tex.r;
#if DECAL
MUL result.color.rgb, color, shadingColor;
Index: binaries/data/mods/public/shaders/arb/water_simple.fp
===================================================================
--- binaries/data/mods/public/shaders/arb/water_simple.fp
+++ binaries/data/mods/public/shaders/arb/water_simple.fp
@@ -11,7 +11,7 @@
TEMP los;
TEX los, v_losCoords, texture[1], 2D;
-MUL diffuse, diffuse, los.a;
+MUL diffuse, diffuse, los.r;
MOV result.color, diffuse;
END
Index: binaries/data/mods/public/shaders/effects/minimap_los.xml
===================================================================
--- binaries/data/mods/public/shaders/effects/minimap_los.xml
+++ binaries/data/mods/public/shaders/effects/minimap_los.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: binaries/data/mods/public/shaders/glsl/common/los_fragment.h
===================================================================
--- binaries/data/mods/public/shaders/glsl/common/los_fragment.h
+++ binaries/data/mods/public/shaders/glsl/common/los_fragment.h
@@ -10,7 +10,7 @@
float getLOS()
{
#if !IGNORE_LOS
- float los = texture2D(losTex, v_los).a;
+ float los = texture2D(losTex, v_los).r;
float threshold = 0.03;
return (los - threshold) / (1.0 - threshold);
#else
Index: binaries/data/mods/public/shaders/glsl/los_interp.fs
===================================================================
--- binaries/data/mods/public/shaders/glsl/los_interp.fs
+++ binaries/data/mods/public/shaders/glsl/los_interp.fs
@@ -9,9 +9,9 @@
void main(void)
{
- float los2 = texture2D(losTex1, v_tex).a;
- float los1 = texture2D(losTex2, v_tex).a;
+ float los2 = texture2D(losTex1, v_tex).r;
+ float los1 = texture2D(losTex2, v_tex).r;
- gl_FragColor.a = mix(los1, los2, clamp(delta, 0.0, 1.0));
+ gl_FragColor.r = mix(los1, los2, clamp(delta, 0.0, 1.0));
}
Index: binaries/data/mods/public/shaders/glsl/minimap.fs
===================================================================
--- binaries/data/mods/public/shaders/glsl/minimap.fs
+++ binaries/data/mods/public/shaders/glsl/minimap.fs
@@ -35,7 +35,7 @@
#endif
#if MINIMAP_LOS
- gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0 - texture2D(baseTex, v_tex).a);
+ gl_FragColor = texture2D(baseTex, v_tex).rrrr;
#endif
#if MINIMAP_POINT
Index: source/graphics/LOSTexture.h
===================================================================
--- source/graphics/LOSTexture.h
+++ source/graphics/LOSTexture.h
@@ -20,6 +20,7 @@
#include "graphics/ShaderTechniquePtr.h"
#include "maths/Matrix3D.h"
+#include "renderer/backend/Format.h"
#include "renderer/backend/IDeviceCommandContext.h"
#include "renderer/backend/IFramebuffer.h"
#include "renderer/backend/ITexture.h"
@@ -87,6 +88,12 @@
bool m_ShaderInitialized = false;
+ // We need to choose the smallest format. We always use the red channel but
+ // R8_UNORM might be unavailable on some platforms. So we fallback to
+ // R8G8B8A8_UNORM.
+ Renderer::Backend::Format m_TextureFormat =
+ Renderer::Backend::Format::UNDEFINED;
+ size_t m_TextureFormatStride = 0;
std::unique_ptr
m_Texture, m_SmoothTextures[2];
Index: source/graphics/LOSTexture.cpp
===================================================================
--- source/graphics/LOSTexture.cpp
+++ source/graphics/LOSTexture.cpp
@@ -244,25 +244,37 @@
Renderer::Backend::Sampler::Filter::LINEAR,
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE);
+ if (backendDevice->IsFramebufferFormatSupported(Renderer::Backend::Format::R8_UNORM))
+ {
+ m_TextureFormat = Renderer::Backend::Format::R8_UNORM;
+ m_TextureFormatStride = 1;
+ }
+ else
+ {
+ m_TextureFormat = Renderer::Backend::Format::R8G8B8A8_UNORM;
+ m_TextureFormatStride = 4;
+ }
+
m_Texture = backendDevice->CreateTexture2D("LOSTexture",
- Renderer::Backend::Format::A8_UNORM, textureSize, textureSize, defaultSamplerDesc);
+ m_TextureFormat, textureSize, textureSize, defaultSamplerDesc);
// Initialise texture with SoD color, for the areas we don't
// overwrite with uploading later.
- std::unique_ptr texData = std::make_unique(textureSize * textureSize);
- memset(texData.get(), 0x00, textureSize * textureSize);
+ const size_t textureDataSize = textureSize * textureSize * m_TextureFormatStride;
+ std::unique_ptr texData = std::make_unique(textureDataSize);
+ memset(texData.get(), 0x00, textureDataSize);
if (CRenderer::IsInitialised() && g_RenderingOptions.GetSmoothLOS())
{
m_SmoothTextures[0] = backendDevice->CreateTexture2D("LOSSmoothTexture0",
- Renderer::Backend::Format::A8_UNORM, textureSize, textureSize, defaultSamplerDesc);
+ m_TextureFormat, textureSize, textureSize, defaultSamplerDesc);
m_SmoothTextures[1] = backendDevice->CreateTexture2D("LOSSmoothTexture1",
- Renderer::Backend::Format::A8_UNORM, textureSize, textureSize, defaultSamplerDesc);
+ m_TextureFormat, textureSize, textureSize, defaultSamplerDesc);
- m_SmoothFramebuffers[0] = backendDevice->CreateFramebuffer("LOSSmoothFramebuffer0",
- m_SmoothTextures[0].get(), nullptr);
- m_SmoothFramebuffers[1] = backendDevice->CreateFramebuffer("LOSSmoothFramebuffer1",
- m_SmoothTextures[1].get(), nullptr);
+ m_SmoothFramebuffers[0] = backendDevice->CreateFramebuffer(
+ "LOSSmoothFramebuffer0", m_SmoothTextures[0].get(), nullptr);
+ m_SmoothFramebuffers[1] = backendDevice->CreateFramebuffer(
+ "LOSSmoothFramebuffer1", m_SmoothTextures[1].get(), nullptr);
if (!m_SmoothFramebuffers[0] || !m_SmoothFramebuffers[1])
{
LOGERROR("Failed to create LOS framebuffers");
@@ -270,16 +282,13 @@
}
deviceCommandContext->UploadTexture(
- m_SmoothTextures[0].get(), Renderer::Backend::Format::A8_UNORM,
- texData.get(), textureSize * textureSize);
+ m_SmoothTextures[0].get(), m_TextureFormat, texData.get(), textureDataSize);
deviceCommandContext->UploadTexture(
- m_SmoothTextures[1].get(), Renderer::Backend::Format::A8_UNORM,
- texData.get(), textureSize * textureSize);
+ m_SmoothTextures[1].get(), m_TextureFormat, texData.get(), textureDataSize);
}
deviceCommandContext->UploadTexture(
- m_Texture.get(), Renderer::Backend::Format::A8_UNORM,
- texData.get(), textureSize * textureSize);
+ m_Texture.get(), m_TextureFormat, texData.get(), textureDataSize);
texData.reset();
@@ -330,32 +339,49 @@
PROFILE("recompute LOS texture");
- size_t pitch;
- const size_t dataSize = GetBitmapSize(m_MapSize, m_MapSize, &pitch);
- ENSURE(pitch * m_MapSize <= dataSize);
- std::unique_ptr losData = std::make_unique(dataSize);
-
CmpPtr cmpRangeManager(m_Simulation, SYSTEM_ENTITY);
if (!cmpRangeManager)
return;
+ size_t pitch;
+ const size_t dataSize = GetBitmapSize(m_MapSize, m_MapSize, &pitch);
+ ENSURE(pitch * m_MapSize <= dataSize);
+ std::unique_ptr losData = std::make_unique(
+ dataSize * m_TextureFormatStride);
+
CLosQuerier los(cmpRangeManager->GetLosQuerier(g_Game->GetSimulation2()->GetSimContext().GetCurrentDisplayedPlayer()));
GenerateBitmap(los, &losData[0], m_MapSize, m_MapSize, pitch);
+ // GenerateBitmap writes data tightly packed and we need to offset it to fit
+ // into the texture format properly.
+ const size_t textureDataPitch = pitch * m_TextureFormatStride;
+ if (m_TextureFormatStride > 1)
+ {
+ // We skip the last byte because it will be first in our order and we
+ // don't need to move it.
+ for (size_t index = 0; index + 1 < dataSize; ++index)
+ {
+ const size_t oldAddress = dataSize - 1 - index;
+ const size_t newAddress = oldAddress * m_TextureFormatStride;
+ losData[newAddress] = losData[oldAddress];
+ losData[oldAddress] = 0;
+ }
+ }
+
if (CRenderer::IsInitialised() && g_RenderingOptions.GetSmoothLOS() && recreated)
{
deviceCommandContext->UploadTextureRegion(
- m_SmoothTextures[0].get(), Renderer::Backend::Format::A8_UNORM, losData.get(),
- pitch * m_MapSize, 0, 0, pitch, m_MapSize);
+ m_SmoothTextures[0].get(), m_TextureFormat, losData.get(),
+ textureDataPitch * m_MapSize, 0, 0, pitch, m_MapSize);
deviceCommandContext->UploadTextureRegion(
- m_SmoothTextures[1].get(), Renderer::Backend::Format::A8_UNORM, losData.get(),
- pitch * m_MapSize, 0, 0, pitch, m_MapSize);
+ m_SmoothTextures[1].get(), m_TextureFormat, losData.get(),
+ textureDataPitch * m_MapSize, 0, 0, pitch, m_MapSize);
}
deviceCommandContext->UploadTextureRegion(
- m_Texture.get(), Renderer::Backend::Format::A8_UNORM, losData.get(),
- pitch * m_MapSize, 0, 0, pitch, m_MapSize);
+ m_Texture.get(), m_TextureFormat, losData.get(),
+ textureDataPitch * m_MapSize, 0, 0, pitch, m_MapSize);
}
size_t CLOSTexture::GetBitmapSize(size_t w, size_t h, size_t* pitch)
Index: source/graphics/MiniMapTexture.cpp
===================================================================
--- source/graphics/MiniMapTexture.cpp
+++ source/graphics/MiniMapTexture.cpp
@@ -430,11 +430,11 @@
DrawTexture(deviceCommandContext);
deviceCommandContext->EndPass();
- pipelineStateDesc.blendState.enabled = false;
- pipelineStateDesc.blendState.colorWriteMask =
- Renderer::Backend::ColorWriteMask::ALPHA;
- deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc);
+ tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap_los, CShaderDefines());
+ deviceCommandContext->SetGraphicsPipelineState(
+ tech->GetGraphicsPipelineStateDesc());
deviceCommandContext->BeginPass();
+ shader = tech->GetShader();
deviceCommandContext->SetTexture(
shader->GetBindingSlot(str_baseTex), losTexture.GetTexture());
Index: source/gui/ObjectTypes/CMiniMap.cpp
===================================================================
--- source/gui/ObjectTypes/CMiniMap.cpp
+++ source/gui/ObjectTypes/CMiniMap.cpp
@@ -21,7 +21,6 @@
#include "graphics/Canvas2D.h"
#include "graphics/GameView.h"
-#include "graphics/LOSTexture.h"
#include "graphics/MiniMapTexture.h"
#include "graphics/MiniPatch.h"
#include "graphics/ShaderManager.h"
Index: source/ps/CStrInternStatic.h
===================================================================
--- source/ps/CStrInternStatic.h
+++ source/ps/CStrInternStatic.h
@@ -126,6 +126,7 @@
X(maskTex)
X(maskTextureTransform)
X(minimap)
+X(minimap_los)
X(modelViewMatrix)
X(murkiness)
X(normalMap)
Index: source/renderer/backend/Format.h
===================================================================
--- source/renderer/backend/Format.h
+++ source/renderer/backend/Format.h
@@ -27,12 +27,15 @@
enum class Format
{
UNDEFINED,
+ R8_UNORM,
R8G8_UNORM,
R8G8_UINT,
R8G8B8_UNORM,
R8G8B8A8_UNORM,
R8G8B8A8_UINT,
+ // TODO: we need to drop legacy A8 and L8 formats as soon as we have proper
+ // channel swizzling.
A8_UNORM,
L8_UNORM,
Index: source/renderer/backend/IDevice.h
===================================================================
--- source/renderer/backend/IDevice.h
+++ source/renderer/backend/IDevice.h
@@ -98,6 +98,8 @@
virtual bool IsTextureFormatSupported(const Format format) const = 0;
+ virtual bool IsFramebufferFormatSupported(const Format format) const = 0;
+
virtual const Capabilities& GetCapabilities() const = 0;
};
Index: source/renderer/backend/dummy/Device.h
===================================================================
--- source/renderer/backend/dummy/Device.h
+++ source/renderer/backend/dummy/Device.h
@@ -76,6 +76,8 @@
bool IsTextureFormatSupported(const Format format) const override;
+ bool IsFramebufferFormatSupported(const Format format) const override;
+
const Capabilities& GetCapabilities() const override { return m_Capabilities; }
private:
Index: source/renderer/backend/dummy/Device.cpp
===================================================================
--- source/renderer/backend/dummy/Device.cpp
+++ source/renderer/backend/dummy/Device.cpp
@@ -121,6 +121,11 @@
return true;
}
+bool CDevice::IsFramebufferFormatSupported(const Format format) const
+{
+ return true;
+}
+
} // namespace Dummy
} // namespace Backend
Index: source/renderer/backend/gl/Device.h
===================================================================
--- source/renderer/backend/gl/Device.h
+++ source/renderer/backend/gl/Device.h
@@ -93,6 +93,8 @@
bool IsTextureFormatSupported(const Format format) const override;
+ bool IsFramebufferFormatSupported(const Format format) const override;
+
const Capabilities& GetCapabilities() const override { return m_Capabilities; }
private:
Index: source/renderer/backend/gl/Device.cpp
===================================================================
--- source/renderer/backend/gl/Device.cpp
+++ source/renderer/backend/gl/Device.cpp
@@ -902,6 +902,27 @@
return supported;
}
+bool CDevice::IsFramebufferFormatSupported(const Format format) const
+{
+ bool supported = false;
+ switch (format)
+ {
+ case Format::UNDEFINED:
+ break;
+#if !CONFIG2_GLES
+ case Format::R8_UNORM:
+ supported = ogl_HaveVersion(3, 0);
+ break;
+#endif
+ case Format::R8G8B8A8_UNORM:
+ supported = true;
+ break;
+ default:
+ break;
+ }
+ return supported;
+}
+
} // namespace GL
} // namespace Backend
Index: source/renderer/backend/gl/DeviceCommandContext.cpp
===================================================================
--- source/renderer/backend/gl/DeviceCommandContext.cpp
+++ source/renderer/backend/gl/DeviceCommandContext.cpp
@@ -228,6 +228,7 @@
ENSURE(layer == 0);
if (texture->GetFormat() == Format::R8G8B8A8_UNORM ||
texture->GetFormat() == Format::R8G8B8_UNORM ||
+ texture->GetFormat() == Format::R8_UNORM ||
texture->GetFormat() == Format::A8_UNORM)
{
ENSURE(texture->GetFormat() == dataFormat);
@@ -240,6 +241,10 @@
case Format::R8G8B8_UNORM:
pixelFormat = GL_RGB;
bytesPerPixel = 3;
+ break;
+ case Format::R8_UNORM:
+ pixelFormat = GL_RED;
+ bytesPerPixel = 1;
break;
case Format::A8_UNORM:
pixelFormat = GL_ALPHA;
Index: source/renderer/backend/gl/Framebuffer.cpp
===================================================================
--- source/renderer/backend/gl/Framebuffer.cpp
+++ source/renderer/backend/gl/Framebuffer.cpp
@@ -57,6 +57,8 @@
if (colorAttachment)
{
+ ENSURE(device->IsFramebufferFormatSupported(colorAttachment->GetFormat()));
+
framebuffer->m_AttachmentMask |= GL_COLOR_BUFFER_BIT;
#if CONFIG2_GLES
Index: source/renderer/backend/gl/Texture.cpp
===================================================================
--- source/renderer/backend/gl/Texture.cpp
+++ source/renderer/backend/gl/Texture.cpp
@@ -178,6 +178,13 @@
pixelFormat = GL_RGB;
pixelType = GL_UNSIGNED_BYTE;
break;
+#if !CONFIG2_GLES
+ case Format::R8_UNORM:
+ internalFormat = GL_RED;
+ pixelFormat = GL_RED;
+ pixelType = GL_UNSIGNED_BYTE;
+ break;
+#endif
case Format::A8_UNORM:
internalFormat = GL_ALPHA;
pixelFormat = GL_ALPHA;
Index: source/renderer/backend/vulkan/Device.h
===================================================================
--- source/renderer/backend/vulkan/Device.h
+++ source/renderer/backend/vulkan/Device.h
@@ -81,6 +81,8 @@
bool IsTextureFormatSupported(const Format format) const override;
+ bool IsFramebufferFormatSupported(const Format format) const override;
+
const Capabilities& GetCapabilities() const override { return m_Capabilities; }
private:
Index: source/renderer/backend/vulkan/Device.cpp
===================================================================
--- source/renderer/backend/vulkan/Device.cpp
+++ source/renderer/backend/vulkan/Device.cpp
@@ -162,6 +162,12 @@
return false;
}
+bool CDevice::IsFramebufferFormatSupported(const Format format) const
+{
+ UNUSED2(format);
+ return false;
+}
+
} // namespace Vulkan
} // namespace Backend