Moves texture management to CDeviceCommandContext, adds quality options.
Comments By: nwtour, Stan Tested By: nwtour, Stan Differential Revision: https://code.wildfiregames.com/D4488 This was SVN commit r26365.
This commit is contained in:
parent
451dc24a7e
commit
4de89c3db1
@ -122,6 +122,12 @@ rendererbackend = "gl"
|
||||
; Should not be edited. It's used only for preventing of running fixed pipeline.
|
||||
renderpath = default
|
||||
|
||||
; (0 - low, 1 - medium, 2 - high), higher quality means worse performance.
|
||||
textures.quality = 2
|
||||
|
||||
; (1, 2, 4, 8 and 16)
|
||||
textures.maxanisotropy = 2
|
||||
|
||||
;;;;; EXPERIMENTAL ;;;;;
|
||||
; Experimental probably-non-working GPU skinning support; requires GLSL; use at own risk
|
||||
gpuskinning = false
|
||||
|
@ -343,6 +343,30 @@
|
||||
"tooltip": "Use actual water depth in rendering calculations.",
|
||||
"dependencies": ["watereffects", "waterrefraction"],
|
||||
"config": "waterrealdepth"
|
||||
},
|
||||
{
|
||||
"type": "dropdown",
|
||||
"label": "Texture quality",
|
||||
"tooltip": "Decrease texture quality making them blurrier but increases game performance.",
|
||||
"config": "textures.quality",
|
||||
"list": [
|
||||
{ "value": 0, "label": "Low", "tooltip": "Low" },
|
||||
{ "value": 1, "label": "Medium", "tooltip": "Medium" },
|
||||
{ "value": 2, "label": "High", "tooltip": "High" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "dropdown",
|
||||
"label": "Texture anisotropic filter",
|
||||
"tooltip": "Makes textures look better, especially terrain. If the anisotropic filter value is unsupported it will be set to the max supported value.",
|
||||
"config": "textures.maxanisotropy",
|
||||
"list": [
|
||||
{ "value": 1, "label": "1x", "tooltip": "Disabled" },
|
||||
{ "value": 2, "label": "2x", "tooltip": "2x" },
|
||||
{ "value": 4, "label": "4x", "tooltip": "4x" },
|
||||
{ "value": 8, "label": "8x", "tooltip": "8x" },
|
||||
{ "value": 16, "label": "16x", "tooltip": "16x" }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -38,11 +38,14 @@ namespace
|
||||
// Array of 2D elements unrolled into 1D array.
|
||||
using PlaneArray2D = std::array<float, 8>;
|
||||
|
||||
inline void DrawTextureImpl(const CShaderProgramPtr& shader, CTexturePtr texture,
|
||||
inline void DrawTextureImpl(
|
||||
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderProgramPtr& shader, const CTexturePtr& texture,
|
||||
const PlaneArray2D& vertices, PlaneArray2D uvs,
|
||||
const CColor& multiply, const CColor& add, const float grayscaleFactor)
|
||||
{
|
||||
shader->BindTexture(str_tex, texture);
|
||||
texture->UploadBackendTextureIfNeeded(deviceCommandContext);
|
||||
shader->BindTexture(str_tex, texture->GetBackendTexture());
|
||||
for (size_t idx = 0; idx < uvs.size(); idx += 2)
|
||||
{
|
||||
if (texture->GetWidth() > 0.0f)
|
||||
@ -67,6 +70,12 @@ inline void DrawTextureImpl(const CShaderProgramPtr& shader, CTexturePtr texture
|
||||
class CCanvas2D::Impl
|
||||
{
|
||||
public:
|
||||
Impl()
|
||||
// TODO: remove global renderer access as pass as an argument.
|
||||
: DeviceCommandContext(g_Renderer.GetDeviceCommandContext())
|
||||
{
|
||||
}
|
||||
|
||||
void BindTechIfNeeded()
|
||||
{
|
||||
if (Tech)
|
||||
@ -76,8 +85,7 @@ public:
|
||||
Tech = g_Renderer.GetShaderManager().LoadEffect(str_canvas2d, defines);
|
||||
ENSURE(Tech);
|
||||
Tech->BeginPass();
|
||||
// TODO: remove global renderer access.
|
||||
g_Renderer.GetDeviceCommandContext()->SetGraphicsPipelineState(
|
||||
DeviceCommandContext->SetGraphicsPipelineState(
|
||||
Tech->GetGraphicsPipelineStateDesc());
|
||||
}
|
||||
|
||||
@ -90,6 +98,7 @@ public:
|
||||
Tech.reset();
|
||||
}
|
||||
|
||||
Renderer::Backend::GL::CDeviceCommandContext* DeviceCommandContext;
|
||||
CShaderTechniquePtr Tech;
|
||||
};
|
||||
|
||||
@ -117,7 +126,7 @@ void CCanvas2D::DrawLine(const std::vector<CVector2D>& points, const float width
|
||||
}
|
||||
|
||||
CShaderProgramPtr shader = m->Tech->GetShader();
|
||||
shader->BindTexture(str_tex, g_Renderer.GetTextureManager().GetTransparentTexture());
|
||||
shader->BindTexture(str_tex, g_Renderer.GetTextureManager().GetTransparentTexture()->GetBackendTexture());
|
||||
shader->Uniform(str_transform, GetDefaultGuiMatrix());
|
||||
shader->Uniform(str_colorAdd, color);
|
||||
shader->Uniform(str_colorMul, CColor(0.0f, 0.0f, 0.0f, 0.0f));
|
||||
@ -151,7 +160,8 @@ void CCanvas2D::DrawRect(const CRect& rect, const CColor& color)
|
||||
|
||||
m->BindTechIfNeeded();
|
||||
DrawTextureImpl(
|
||||
m->Tech->GetShader(), g_Renderer.GetTextureManager().GetTransparentTexture(),
|
||||
m->DeviceCommandContext, m->Tech->GetShader(),
|
||||
g_Renderer.GetTextureManager().GetTransparentTexture(),
|
||||
vertices, uvs, CColor(0.0f, 0.0f, 0.0f, 0.0f), color, 0.0f);
|
||||
}
|
||||
|
||||
@ -180,7 +190,8 @@ void CCanvas2D::DrawTexture(
|
||||
};
|
||||
|
||||
m->BindTechIfNeeded();
|
||||
DrawTextureImpl(m->Tech->GetShader(), texture, vertices, uvs, multiply, add, grayscaleFactor);
|
||||
DrawTextureImpl(m->DeviceCommandContext, m->Tech->GetShader(),
|
||||
texture, vertices, uvs, multiply, add, grayscaleFactor);
|
||||
}
|
||||
|
||||
void CCanvas2D::DrawText(CTextRenderer& textRenderer)
|
||||
@ -190,7 +201,7 @@ void CCanvas2D::DrawText(CTextRenderer& textRenderer)
|
||||
CShaderProgramPtr shader = m->Tech->GetShader();
|
||||
shader->Uniform(str_grayscaleFactor, 0.0f);
|
||||
|
||||
textRenderer.Render(shader, GetDefaultGuiMatrix());
|
||||
textRenderer.Render(m->DeviceCommandContext, shader, GetDefaultGuiMatrix());
|
||||
}
|
||||
|
||||
void CCanvas2D::Flush()
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -139,10 +139,9 @@ bool CFontManager::ReadFont(CFont* font, CStrIntern fontName)
|
||||
|
||||
// Load glyph texture
|
||||
const VfsPath imageName(fontName.string() + ".png");
|
||||
CTextureProperties textureProps(path / imageName);
|
||||
textureProps.SetFilter(GL_LINEAR);
|
||||
if (!font->m_HasRGB)
|
||||
textureProps.SetFormatOverride(GL_ALPHA);
|
||||
CTextureProperties textureProps(path / imageName,
|
||||
font->m_HasRGB ? Renderer::Backend::Format::R8G8B8A8 : Renderer::Backend::Format::A8);
|
||||
textureProps.SetIgnoreQuality(true);
|
||||
font->m_Texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
|
||||
|
||||
return true;
|
||||
|
@ -229,7 +229,7 @@ void CLOSTexture::ConstructTexture(Renderer::Backend::GL::CDeviceCommandContext*
|
||||
Renderer::Backend::Sampler::Filter::LINEAR,
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE);
|
||||
|
||||
m_Texture = Renderer::Backend::GL::CTexture::Create2D(
|
||||
m_Texture = deviceCommandContext->GetDevice()->CreateTexture2D("LOSTexture",
|
||||
Renderer::Backend::Format::A8, textureSize, textureSize, defaultSamplerDesc);
|
||||
|
||||
// Initialise texture with SoD color, for the areas we don't
|
||||
@ -239,9 +239,9 @@ void CLOSTexture::ConstructTexture(Renderer::Backend::GL::CDeviceCommandContext*
|
||||
|
||||
if (CRenderer::IsInitialised() && g_RenderingOptions.GetSmoothLOS())
|
||||
{
|
||||
m_SmoothTextures[0] = Renderer::Backend::GL::CTexture::Create2D(
|
||||
m_SmoothTextures[0] = deviceCommandContext->GetDevice()->CreateTexture2D("LOSSmoothTexture0",
|
||||
Renderer::Backend::Format::A8, textureSize, textureSize, defaultSamplerDesc);
|
||||
m_SmoothTextures[1] = Renderer::Backend::GL::CTexture::Create2D(
|
||||
m_SmoothTextures[1] = deviceCommandContext->GetDevice()->CreateTexture2D("LOSSmoothTexture1",
|
||||
Renderer::Backend::Format::A8, textureSize, textureSize, defaultSamplerDesc);
|
||||
|
||||
m_SmoothFramebuffers[0] = Renderer::Backend::GL::CFramebuffer::Create(
|
||||
@ -254,11 +254,17 @@ void CLOSTexture::ConstructTexture(Renderer::Backend::GL::CDeviceCommandContext*
|
||||
g_RenderingOptions.SetSmoothLOS(false);
|
||||
}
|
||||
|
||||
deviceCommandContext->UploadTexture(m_SmoothTextures[0].get(), Renderer::Backend::Format::A8, texData.get(), textureSize * textureSize);
|
||||
deviceCommandContext->UploadTexture(m_SmoothTextures[1].get(), Renderer::Backend::Format::A8, texData.get(), textureSize * textureSize);
|
||||
deviceCommandContext->UploadTexture(
|
||||
m_SmoothTextures[0].get(), Renderer::Backend::Format::A8,
|
||||
texData.get(), textureSize * textureSize);
|
||||
deviceCommandContext->UploadTexture(
|
||||
m_SmoothTextures[1].get(), Renderer::Backend::Format::A8,
|
||||
texData.get(), textureSize * textureSize);
|
||||
}
|
||||
|
||||
deviceCommandContext->UploadTexture(m_Texture.get(), Renderer::Backend::Format::A8, texData.get(), textureSize * textureSize);
|
||||
deviceCommandContext->UploadTexture(
|
||||
m_Texture.get(), Renderer::Backend::Format::A8,
|
||||
texData.get(), textureSize * textureSize);
|
||||
|
||||
texData.reset();
|
||||
|
||||
|
@ -219,7 +219,7 @@ void CMiniMapTexture::CreateTextures(
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE);
|
||||
|
||||
// Create terrain texture
|
||||
m_TerrainTexture = Renderer::Backend::GL::CTexture::Create2D(
|
||||
m_TerrainTexture = deviceCommandContext->GetDevice()->CreateTexture2D("MiniMapTerrainTexture",
|
||||
Renderer::Backend::Format::R8G8B8A8, textureSize, textureSize, defaultSamplerDesc);
|
||||
|
||||
// Initialise texture with solid black, for the areas we don't
|
||||
@ -234,7 +234,7 @@ void CMiniMapTexture::CreateTextures(
|
||||
|
||||
m_TerrainData = std::make_unique<u32[]>((m_MapSize - 1) * (m_MapSize - 1));
|
||||
|
||||
m_FinalTexture = Renderer::Backend::GL::CTexture::Create2D(
|
||||
m_FinalTexture = deviceCommandContext->GetDevice()->CreateTexture2D("MiniMapFinalTexture",
|
||||
Renderer::Backend::Format::R8G8B8A8, FINAL_TEXTURE_SIZE, FINAL_TEXTURE_SIZE, defaultSamplerDesc);
|
||||
|
||||
m_FinalTextureFramebuffer = Renderer::Backend::GL::CFramebuffer::Create(
|
||||
|
@ -84,7 +84,7 @@ bool CObjectEntry::BuildVariation(const std::vector<const std::set<CStr>*>& comp
|
||||
for (const CObjectBase::Samp& samp : m_Samplers)
|
||||
{
|
||||
CTextureProperties textureProps(samp.m_SamplerFile);
|
||||
textureProps.SetWrap(GL_CLAMP_TO_BORDER);
|
||||
textureProps.SetAddressMode(Renderer::Backend::Sampler::AddressMode::CLAMP_TO_BORDER);
|
||||
CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
|
||||
// TODO: Should check which renderpath is selected and only preload the necessary textures.
|
||||
texture->Prefetch();
|
||||
@ -141,7 +141,7 @@ bool CObjectEntry::BuildVariation(const std::vector<const std::set<CStr>*>& comp
|
||||
for (const CObjectBase::Samp& samp : m_Samplers)
|
||||
{
|
||||
CTextureProperties textureProps(samp.m_SamplerFile);
|
||||
textureProps.SetWrap(GL_CLAMP_TO_EDGE);
|
||||
textureProps.SetAddressMode(Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE);
|
||||
CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
|
||||
// if we've loaded this model we're probably going to render it soon, so prefetch its texture.
|
||||
// All textures are prefetched even in the fixed pipeline, including the normal maps etc.
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -43,12 +43,16 @@ SOverlayTexturedLine::LineCapType SOverlayTexturedLine::StrToLineCapType(const s
|
||||
void SOverlayTexturedLine::CreateOverlayTexture(const SOverlayDescriptor* overlayDescriptor)
|
||||
{
|
||||
CTextureProperties texturePropsBase(overlayDescriptor->m_LineTexture.c_str());
|
||||
texturePropsBase.SetWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE);
|
||||
texturePropsBase.SetMaxAnisotropy(4.f);
|
||||
texturePropsBase.SetAddressMode(
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_BORDER,
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE);
|
||||
texturePropsBase.SetAnisotropicFilter(true);
|
||||
|
||||
CTextureProperties texturePropsMask(overlayDescriptor->m_LineTextureMask.c_str());
|
||||
texturePropsMask.SetWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE);
|
||||
texturePropsMask.SetMaxAnisotropy(4.f);
|
||||
texturePropsMask.SetAddressMode(
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_BORDER,
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE);
|
||||
texturePropsMask.SetAnisotropicFilter(true);
|
||||
|
||||
m_AlwaysVisible = false;
|
||||
m_Closed = true;
|
||||
|
@ -178,8 +178,12 @@ void CParticleEmitter::PrepareForRendering()
|
||||
m_VertexArray.PrepareForRendering();
|
||||
}
|
||||
|
||||
void CParticleEmitter::Bind(const CShaderProgramPtr& shader)
|
||||
void CParticleEmitter::Bind(
|
||||
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderProgramPtr& shader)
|
||||
{
|
||||
m_Type->m_Texture->UploadBackendTextureIfNeeded(deviceCommandContext);
|
||||
|
||||
CLOSTexture& los = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture();
|
||||
shader->BindTexture(str_losTex, los.GetTextureSmooth());
|
||||
shader->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f);
|
||||
@ -189,7 +193,7 @@ void CParticleEmitter::Bind(const CShaderProgramPtr& shader)
|
||||
shader->Uniform(str_fogColor, lightEnv.m_FogColor);
|
||||
shader->Uniform(str_fogParams, lightEnv.m_FogFactor, lightEnv.m_FogMax, 0.f, 0.f);
|
||||
|
||||
shader->BindTexture(str_baseTex, m_Type->m_Texture);
|
||||
shader->BindTexture(str_baseTex, m_Type->m_Texture->GetBackendTexture());
|
||||
}
|
||||
|
||||
void CParticleEmitter::RenderArray(const CShaderProgramPtr& shader)
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "graphics/ModelAbstract.h"
|
||||
#include "graphics/ParticleEmitterType.h"
|
||||
#include "maths/Quaternion.h"
|
||||
#include "renderer/backend/gl/DeviceCommandContext.h"
|
||||
#include "renderer/VertexArray.h"
|
||||
|
||||
#include <map>
|
||||
@ -120,7 +121,9 @@ public:
|
||||
/**
|
||||
* Bind rendering state (textures and blend modes).
|
||||
*/
|
||||
void Bind(const CShaderProgramPtr& shader);
|
||||
void Bind(
|
||||
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderProgramPtr& shader);
|
||||
|
||||
/**
|
||||
* Draw the vertex array.
|
||||
|
@ -394,7 +394,8 @@ bool CParticleEmitterType::LoadXML(const VfsPath& path)
|
||||
if (Child.GetNodeName() == el_texture)
|
||||
{
|
||||
CTextureProperties textureProps(Child.GetText().FromUTF8());
|
||||
textureProps.SetWrap(GL_CLAMP_TO_EDGE);
|
||||
textureProps.SetAddressMode(
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE);
|
||||
m_Texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
|
||||
}
|
||||
else if (Child.GetNodeName() == el_blend)
|
||||
|
@ -24,11 +24,12 @@
|
||||
#include "graphics/ShaderManager.h"
|
||||
#include "graphics/TextureManager.h"
|
||||
#include "lib/timer.h"
|
||||
#include "lib/res/graphics/ogl_tex.h"
|
||||
#include "maths/Matrix3D.h"
|
||||
#include "maths/Vector3D.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "renderer/backend/gl/DeviceCommandContext.h"
|
||||
#include "renderer/Renderer.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@ -171,8 +172,7 @@ public:
|
||||
int index = fPair.first;
|
||||
if (index != -1)
|
||||
{
|
||||
glActiveTextureARB(GL_TEXTURE0 + index);
|
||||
glBindTexture(fPair.second, tex);
|
||||
g_Renderer.GetDeviceCommandContext()->BindTexture(index, fPair.second, tex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,8 +181,7 @@ public:
|
||||
int index = id.second;
|
||||
if (index != -1)
|
||||
{
|
||||
glActiveTextureARB(GL_TEXTURE0 + index);
|
||||
glBindTexture(id.first, tex);
|
||||
g_Renderer.GetDeviceCommandContext()->BindTexture(index, id.first, tex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -533,8 +532,7 @@ public:
|
||||
if (it == m_Samplers.end())
|
||||
return;
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + it->second.second);
|
||||
glBindTexture(it->second.first, tex);
|
||||
g_Renderer.GetDeviceCommandContext()->BindTexture(it->second.second, it->second.first, tex);
|
||||
}
|
||||
|
||||
void BindTexture(Binding id, GLuint tex) override
|
||||
@ -542,8 +540,7 @@ public:
|
||||
if (id.second == -1)
|
||||
return;
|
||||
|
||||
glActiveTexture(GL_TEXTURE0 + id.second);
|
||||
glBindTexture(id.first, tex);
|
||||
g_Renderer.GetDeviceCommandContext()->BindTexture(id.second, id.first, tex);
|
||||
}
|
||||
|
||||
Binding GetUniformBinding(uniform_id_t id) override
|
||||
@ -720,20 +717,6 @@ int CShaderProgram::GetStreamFlags() const
|
||||
return m_StreamFlags;
|
||||
}
|
||||
|
||||
void CShaderProgram::BindTexture(texture_id_t id, const CTexturePtr& tex)
|
||||
{
|
||||
GLuint h;
|
||||
ogl_tex_get_texture_id(tex->GetHandle(), &h);
|
||||
BindTexture(id, h);
|
||||
}
|
||||
|
||||
void CShaderProgram::BindTexture(Binding id, const CTexturePtr& tex)
|
||||
{
|
||||
GLuint h;
|
||||
ogl_tex_get_texture_id(tex->GetHandle(), &h);
|
||||
BindTexture(id, h);
|
||||
}
|
||||
|
||||
void CShaderProgram::BindTexture(texture_id_t id, const Renderer::Backend::GL::CTexture* tex)
|
||||
{
|
||||
BindTexture(id, tex->GetHandle());
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -19,7 +19,6 @@
|
||||
#define INCLUDED_SHADERPROGRAM
|
||||
|
||||
#include "graphics/ShaderProgramPtr.h"
|
||||
#include "graphics/Texture.h"
|
||||
#include "lib/ogl.h"
|
||||
#include "lib/file/vfs/vfs_path.h"
|
||||
#include "renderer/backend/gl/Texture.h"
|
||||
@ -143,8 +142,6 @@ public:
|
||||
virtual Binding GetTextureBinding(texture_id_t id) = 0;
|
||||
|
||||
// Variants of texture binding:
|
||||
void BindTexture(texture_id_t id, const CTexturePtr& tex);
|
||||
void BindTexture(Binding id, const CTexturePtr& tex);
|
||||
void BindTexture(texture_id_t id, const Renderer::Backend::GL::CTexture* tex);
|
||||
void BindTexture(Binding id, const Renderer::Backend::GL::CTexture* tex);
|
||||
|
||||
|
@ -125,12 +125,8 @@ CTerrainTextureEntry::CTerrainTextureEntry(CTerrainPropertiesPtr properties, con
|
||||
for (size_t i = 0; i < samplers.size(); ++i)
|
||||
{
|
||||
CTextureProperties texture(samplers[i].second);
|
||||
texture.SetWrap(GL_REPEAT);
|
||||
|
||||
// TODO: anisotropy should probably be user-configurable, but we want it to be
|
||||
// at least 2 for terrain else the ground looks very blurry when you tilt the
|
||||
// camera upwards
|
||||
texture.SetMaxAnisotropy(2.0f);
|
||||
texture.SetAddressMode(Renderer::Backend::Sampler::AddressMode::REPEAT);
|
||||
texture.SetAnisotropicFilter(true);
|
||||
|
||||
if (CRenderer::IsInitialised())
|
||||
{
|
||||
|
@ -29,7 +29,9 @@
|
||||
#include "lib/timer.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/VideoMode.h"
|
||||
#include "ps/XML/Xeromyces.h"
|
||||
#include "renderer/backend/gl/Device.h"
|
||||
#include "renderer/Renderer.h"
|
||||
|
||||
#include <algorithm>
|
||||
@ -291,7 +293,7 @@ CTerrainTextureManager::LoadAlphaMap(const VfsPath& alphaMapType)
|
||||
ignore_result(da_free(&da));
|
||||
#endif
|
||||
|
||||
result.m_CompositeAlphaMap = Renderer::Backend::GL::CTexture::Create2D(
|
||||
result.m_CompositeAlphaMap = g_VideoMode.GetBackendDevice()->CreateTexture2D("CompositeAlphaMap",
|
||||
Renderer::Backend::Format::A8, totalWidth, totalHeight,
|
||||
Renderer::Backend::Sampler::MakeDefaultSampler(
|
||||
Renderer::Backend::Sampler::Filter::LINEAR,
|
||||
@ -313,9 +315,10 @@ void CTerrainTextureManager::UploadResourcesIfNeeded(
|
||||
if (!alphaMap.m_CompositeDataToUpload)
|
||||
continue;
|
||||
// Upload the composite texture.
|
||||
deviceCommandContext->UploadTexture(alphaMap.m_CompositeAlphaMap.get(),
|
||||
Renderer::Backend::Format::A8, alphaMap.m_CompositeDataToUpload.get(),
|
||||
alphaMap.m_CompositeAlphaMap->GetWidth() * alphaMap.m_CompositeAlphaMap->GetHeight());
|
||||
Renderer::Backend::GL::CTexture* texture = alphaMap.m_CompositeAlphaMap.get();
|
||||
deviceCommandContext->UploadTexture(
|
||||
texture, Renderer::Backend::Format::A8, alphaMap.m_CompositeDataToUpload.get(),
|
||||
texture->GetWidth() * texture->GetHeight());
|
||||
alphaMap.m_CompositeDataToUpload.reset();
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,8 @@
|
||||
#include "graphics/Terrain.h"
|
||||
#include "lib/bits.h"
|
||||
#include "ps/Profile.h"
|
||||
#include "renderer/backend/gl/Device.h"
|
||||
#include "renderer/backend/gl/DeviceCommandContext.h"
|
||||
#include "renderer/Renderer.h"
|
||||
#include "simulation2/Simulation2.h"
|
||||
#include "simulation2/helpers/Grid.h"
|
||||
@ -84,7 +86,7 @@ void CTerritoryTexture::ConstructTexture(Renderer::Backend::GL::CDeviceCommandCo
|
||||
|
||||
const uint32_t textureSize = round_up_to_pow2(static_cast<uint32_t>(m_MapSize));
|
||||
|
||||
m_Texture = Renderer::Backend::GL::CTexture::Create2D(
|
||||
m_Texture = deviceCommandContext->GetDevice()->CreateTexture2D("TerritoryTexture",
|
||||
Renderer::Backend::Format::R8G8B8A8, textureSize, textureSize,
|
||||
Renderer::Backend::Sampler::MakeDefaultSampler(
|
||||
Renderer::Backend::Sampler::Filter::LINEAR,
|
||||
@ -95,7 +97,8 @@ void CTerritoryTexture::ConstructTexture(Renderer::Backend::GL::CDeviceCommandCo
|
||||
std::unique_ptr<u8[]> texData = std::make_unique<u8[]>(textureSize * textureSize * 4);
|
||||
memset(texData.get(), 0x00, textureSize * textureSize * 4);
|
||||
deviceCommandContext->UploadTexture(
|
||||
m_Texture.get(), Renderer::Backend::Format::R8G8B8A8, texData.get(), textureSize * textureSize * 4);
|
||||
m_Texture.get(), Renderer::Backend::Format::R8G8B8A8,
|
||||
texData.get(), textureSize * textureSize * 4);
|
||||
texData.reset();
|
||||
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -22,6 +22,7 @@
|
||||
#include "graphics/Font.h"
|
||||
#include "graphics/FontManager.h"
|
||||
#include "graphics/ShaderProgram.h"
|
||||
#include "graphics/TextureManager.h"
|
||||
#include "lib/ogl.h"
|
||||
#include "maths/Matrix3D.h"
|
||||
#include "ps/CStrIntern.h"
|
||||
@ -201,7 +202,9 @@ struct SBatchCompare
|
||||
}
|
||||
};
|
||||
|
||||
void CTextRenderer::Render(const CShaderProgramPtr& shader, const CMatrix3D& transform)
|
||||
void CTextRenderer::Render(
|
||||
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderProgramPtr& shader, const CMatrix3D& transform)
|
||||
{
|
||||
std::vector<u16> indexes;
|
||||
std::vector<t2f_v2i> vertexes;
|
||||
@ -232,7 +235,8 @@ void CTextRenderer::Render(const CShaderProgramPtr& shader, const CMatrix3D& tra
|
||||
if (lastTexture != batch.font->GetTexture().get())
|
||||
{
|
||||
lastTexture = batch.font->GetTexture().get();
|
||||
shader->BindTexture(str_tex, batch.font->GetTexture());
|
||||
lastTexture->UploadBackendTextureIfNeeded(deviceCommandContext);
|
||||
shader->BindTexture(str_tex, lastTexture->GetBackendTexture());
|
||||
}
|
||||
|
||||
CMatrix3D translation;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "maths/Rect.h"
|
||||
#include "maths/Vector2D.h"
|
||||
#include "ps/CStrIntern.h"
|
||||
#include "renderer/backend/gl/DeviceCommandContext.h"
|
||||
|
||||
#include <list>
|
||||
|
||||
@ -102,7 +103,9 @@ public:
|
||||
/**
|
||||
* Render all of the previously printed text calls.
|
||||
*/
|
||||
void Render(const CShaderProgramPtr& shader, const CMatrix3D& transform);
|
||||
void Render(
|
||||
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderProgramPtr& shader, const CMatrix3D& transform);
|
||||
|
||||
private:
|
||||
friend struct SBatchCompare;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -24,89 +24,163 @@
|
||||
#include "lib/allocators/shared_ptr.h"
|
||||
#include "lib/file/vfs/vfs_tree.h"
|
||||
#include "lib/hash.h"
|
||||
#include "lib/res/graphics/ogl_tex.h"
|
||||
#include "lib/res/h_mgr.h"
|
||||
#include "lib/timer.h"
|
||||
#include "maths/MD5.h"
|
||||
#include "ps/CacheLoader.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/ConfigDB.h"
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/Profile.h"
|
||||
#include "ps/VideoMode.h"
|
||||
#include "renderer/backend/gl/Device.h"
|
||||
#include "renderer/Renderer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <iomanip>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
Renderer::Backend::Format ChooseFormatAndTransformTextureDataIfNeeded(Tex& textureData, const bool hasS3TC)
|
||||
{
|
||||
const bool alpha = (textureData.m_Flags & TEX_ALPHA) != 0;
|
||||
const bool grey = (textureData.m_Flags & TEX_GREY) != 0;
|
||||
const size_t dxt = textureData.m_Flags & TEX_DXT;
|
||||
|
||||
// Some backends don't support BGR as an internal format (like GLES).
|
||||
// TODO: add a check that the format is internally supported.
|
||||
if ((textureData.m_Flags & TEX_BGR) != 0)
|
||||
{
|
||||
LOGWARNING("Using slow path to convert BGR texture.");
|
||||
textureData.transform_to(textureData.m_Flags & ~TEX_BGR);
|
||||
}
|
||||
|
||||
if (dxt)
|
||||
{
|
||||
if (hasS3TC)
|
||||
{
|
||||
switch (dxt)
|
||||
{
|
||||
case DXT1A:
|
||||
return Renderer::Backend::Format::BC1_RGBA;
|
||||
case 1:
|
||||
return Renderer::Backend::Format::BC1_RGB;
|
||||
case 3:
|
||||
return Renderer::Backend::Format::BC2;
|
||||
case 5:
|
||||
return Renderer::Backend::Format::BC3;
|
||||
default:
|
||||
LOGERROR("Unknown DXT compression.");
|
||||
return Renderer::Backend::Format::UNDEFINED;
|
||||
}
|
||||
}
|
||||
else
|
||||
textureData.transform_to(textureData.m_Flags & ~TEX_DXT);
|
||||
}
|
||||
|
||||
switch (textureData.m_Bpp)
|
||||
{
|
||||
case 8:
|
||||
ENSURE(grey);
|
||||
return Renderer::Backend::Format::L8;
|
||||
case 24:
|
||||
ENSURE(!alpha);
|
||||
return Renderer::Backend::Format::R8G8B8;
|
||||
case 32:
|
||||
ENSURE(alpha);
|
||||
return Renderer::Backend::Format::R8G8B8A8;
|
||||
default:
|
||||
LOGERROR("Unsupported BPP: %zu", textureData.m_Bpp);
|
||||
}
|
||||
|
||||
return Renderer::Backend::Format::UNDEFINED;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class SingleColorTexture
|
||||
{
|
||||
public:
|
||||
SingleColorTexture(const CColor& color, PIVFS vfs, const VfsPath& pathPlaceholder, const bool disableGL, CTextureManagerImpl* textureManager)
|
||||
: m_Handle(0)
|
||||
SingleColorTexture(const CColor& color, const VfsPath& pathPlaceholder,
|
||||
const bool disableGL, CTextureManagerImpl* textureManager)
|
||||
: m_Color(color)
|
||||
{
|
||||
if (disableGL)
|
||||
return;
|
||||
|
||||
const SColor4ub color32 = color.AsSColor4ub();
|
||||
// Construct 1x1 32-bit texture
|
||||
std::shared_ptr<u8> data(new u8[4], ArrayDeleter());
|
||||
data.get()[0] = color32.R;
|
||||
data.get()[1] = color32.G;
|
||||
data.get()[2] = color32.B;
|
||||
data.get()[3] = color32.A;
|
||||
std::stringstream textureName;
|
||||
textureName << "SingleColorTexture (";
|
||||
textureName << "R: " << m_Color.r << ",";
|
||||
textureName << "G: " << m_Color.g << ",";
|
||||
textureName << "B: " << m_Color.b << ",";
|
||||
textureName << "A: " << m_Color.a << ")";
|
||||
|
||||
Tex t;
|
||||
ignore_result(t.wrap(1, 1, 32, TEX_ALPHA, data, 0));
|
||||
|
||||
m_Handle = ogl_tex_wrap(&t, vfs, pathPlaceholder);
|
||||
ignore_result(ogl_tex_set_filter(m_Handle, GL_LINEAR));
|
||||
if (!disableGL)
|
||||
ignore_result(ogl_tex_upload(m_Handle));
|
||||
std::unique_ptr<Renderer::Backend::GL::CTexture> backendTexture =
|
||||
g_VideoMode.GetBackendDevice()->CreateTexture2D(
|
||||
textureName.str().c_str(),
|
||||
Renderer::Backend::Format::R8G8B8A8,
|
||||
1, 1, Renderer::Backend::Sampler::MakeDefaultSampler(
|
||||
Renderer::Backend::Sampler::Filter::LINEAR,
|
||||
Renderer::Backend::Sampler::AddressMode::REPEAT));
|
||||
Renderer::Backend::GL::CTexture* fallback = backendTexture.get();
|
||||
|
||||
CTextureProperties props(pathPlaceholder);
|
||||
m_Texture = CTexturePtr(new CTexture(m_Handle, props, textureManager));
|
||||
m_Texture->m_State = CTexture::LOADED;
|
||||
m_Texture = CTexturePtr(new CTexture(
|
||||
std::move(backendTexture), fallback, props, textureManager));
|
||||
m_Texture->m_State = CTexture::UPLOADED;
|
||||
m_Texture->m_Self = m_Texture;
|
||||
}
|
||||
|
||||
~SingleColorTexture()
|
||||
{
|
||||
ignore_result(ogl_tex_free(m_Handle));
|
||||
}
|
||||
|
||||
CTexturePtr GetTexture()
|
||||
const CTexturePtr& GetTexture()
|
||||
{
|
||||
return m_Texture;
|
||||
}
|
||||
|
||||
Handle GetHandle()
|
||||
void Upload(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext)
|
||||
{
|
||||
return m_Handle;
|
||||
if (!m_Texture || !m_Texture->GetBackendTexture())
|
||||
return;
|
||||
|
||||
const SColor4ub color32 = m_Color.AsSColor4ub();
|
||||
// Construct 1x1 32-bit texture
|
||||
const u8 data[4] =
|
||||
{
|
||||
color32.R,
|
||||
color32.G,
|
||||
color32.B,
|
||||
color32.A
|
||||
};
|
||||
deviceCommandContext->UploadTexture(m_Texture->GetBackendTexture(),
|
||||
Renderer::Backend::Format::R8G8B8A8, data, std::size(data));
|
||||
}
|
||||
|
||||
private:
|
||||
Handle m_Handle;
|
||||
CTexturePtr m_Texture;
|
||||
CColor m_Color;
|
||||
};
|
||||
|
||||
struct TPhash
|
||||
{
|
||||
std::size_t operator()(CTextureProperties const& a) const
|
||||
std::size_t operator()(const CTextureProperties& textureProperties) const
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
hash_combine(seed, m_PathHash(a.m_Path));
|
||||
hash_combine(seed, a.m_Filter);
|
||||
hash_combine(seed, a.m_WrapS);
|
||||
hash_combine(seed, a.m_WrapT);
|
||||
hash_combine(seed, a.m_Aniso);
|
||||
hash_combine(seed, a.m_Format);
|
||||
hash_combine(seed, m_PathHash(textureProperties.m_Path));
|
||||
hash_combine(seed, textureProperties.m_AddressModeU);
|
||||
hash_combine(seed, textureProperties.m_AddressModeV);
|
||||
hash_combine(seed, textureProperties.m_AnisotropicFilterEnabled);
|
||||
hash_combine(seed, textureProperties.m_FormatOverride);
|
||||
hash_combine(seed, textureProperties.m_IgnoreQuality);
|
||||
return seed;
|
||||
}
|
||||
|
||||
std::size_t operator()(CTexturePtr const& a) const
|
||||
std::size_t operator()(const CTexturePtr& texture) const
|
||||
{
|
||||
return (*this)(a->m_Properties);
|
||||
return this->operator()(texture->m_Properties);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -115,15 +189,20 @@ private:
|
||||
|
||||
struct TPequal_to
|
||||
{
|
||||
bool operator()(CTextureProperties const& a, CTextureProperties const& b) const
|
||||
bool operator()(const CTextureProperties& lhs, const CTextureProperties& rhs) const
|
||||
{
|
||||
return a.m_Path == b.m_Path && a.m_Filter == b.m_Filter
|
||||
&& a.m_WrapS == b.m_WrapS && a.m_WrapT == b.m_WrapT
|
||||
&& a.m_Aniso == b.m_Aniso && a.m_Format == b.m_Format;
|
||||
return
|
||||
lhs.m_Path == rhs.m_Path &&
|
||||
lhs.m_AddressModeU == rhs.m_AddressModeU &&
|
||||
lhs.m_AddressModeV == rhs.m_AddressModeV &&
|
||||
lhs.m_AnisotropicFilterEnabled == rhs.m_AnisotropicFilterEnabled &&
|
||||
lhs.m_FormatOverride == rhs.m_FormatOverride &&
|
||||
lhs.m_IgnoreQuality == rhs.m_IgnoreQuality;
|
||||
}
|
||||
bool operator()(CTexturePtr const& a, CTexturePtr const& b) const
|
||||
|
||||
bool operator()(const CTexturePtr& lhs, const CTexturePtr& rhs) const
|
||||
{
|
||||
return (*this)(a->m_Properties, b->m_Properties);
|
||||
return this->operator()(lhs->m_Properties, rhs->m_Properties);
|
||||
}
|
||||
};
|
||||
|
||||
@ -134,13 +213,23 @@ public:
|
||||
CTextureManagerImpl(PIVFS vfs, bool highQuality, bool disableGL) :
|
||||
m_VFS(vfs), m_CacheLoader(vfs, L".dds"), m_DisableGL(disableGL),
|
||||
m_TextureConverter(vfs, highQuality),
|
||||
m_DefaultTexture(CColor(0.25f, 0.25f, 0.25f, 1.0f), vfs, L"(default texture)", disableGL, this),
|
||||
m_ErrorTexture(CColor(1.0f, 0.0f, 1.0f, 1.0f), vfs, L"(error texture)", disableGL, this),
|
||||
m_WhiteTexture(CColor(1.0f, 1.0f, 1.0f, 1.0f), vfs, L"(white texture)", disableGL, this),
|
||||
m_TransparentTexture(CColor(0.0f, 0.0f, 0.0f, 0.0f), vfs, L"(transparent texture)", disableGL, this)
|
||||
m_DefaultTexture(CColor(0.25f, 0.25f, 0.25f, 1.0f), L"(default texture)", disableGL, this),
|
||||
m_ErrorTexture(CColor(1.0f, 0.0f, 1.0f, 1.0f), L"(error texture)", disableGL, this),
|
||||
m_WhiteTexture(CColor(1.0f, 1.0f, 1.0f, 1.0f), L"(white texture)", disableGL, this),
|
||||
m_TransparentTexture(CColor(0.0f, 0.0f, 0.0f, 0.0f), L"(transparent texture)", disableGL, this)
|
||||
{
|
||||
// Allow hotloading of textures
|
||||
RegisterFileReloadFunc(ReloadChangedFileCB, this);
|
||||
|
||||
if (disableGL)
|
||||
return;
|
||||
|
||||
Renderer::Backend::GL::CDevice* backendDevice = g_VideoMode.GetBackendDevice();
|
||||
m_HasS3TC =
|
||||
backendDevice->IsFormatSupported(Renderer::Backend::Format::BC1_RGB) &&
|
||||
backendDevice->IsFormatSupported(Renderer::Backend::Format::BC1_RGBA) &&
|
||||
backendDevice->IsFormatSupported(Renderer::Backend::Format::BC2) &&
|
||||
backendDevice->IsFormatSupported(Renderer::Backend::Format::BC3);
|
||||
}
|
||||
|
||||
~CTextureManagerImpl()
|
||||
@ -148,17 +237,17 @@ public:
|
||||
UnregisterFileReloadFunc(ReloadChangedFileCB, this);
|
||||
}
|
||||
|
||||
CTexturePtr GetErrorTexture()
|
||||
const CTexturePtr& GetErrorTexture()
|
||||
{
|
||||
return m_ErrorTexture.GetTexture();
|
||||
}
|
||||
|
||||
CTexturePtr GetWhiteTexture()
|
||||
const CTexturePtr& GetWhiteTexture()
|
||||
{
|
||||
return m_WhiteTexture.GetTexture();
|
||||
}
|
||||
|
||||
CTexturePtr GetTransparentTexture()
|
||||
const CTexturePtr& GetTransparentTexture()
|
||||
{
|
||||
return m_TransparentTexture.GetTexture();
|
||||
}
|
||||
@ -169,7 +258,9 @@ public:
|
||||
CTexturePtr CreateTexture(const CTextureProperties& props)
|
||||
{
|
||||
// Construct a new default texture with the given properties to use as the search key
|
||||
CTexturePtr texture(new CTexture(m_DefaultTexture.GetHandle(), props, this));
|
||||
CTexturePtr texture(new CTexture(
|
||||
nullptr, m_DisableGL ? nullptr : m_DefaultTexture.GetTexture()->GetBackendTexture(),
|
||||
props, this));
|
||||
|
||||
// Try to find an existing texture with the given properties
|
||||
TextureCache::iterator it = m_TextureCache.find(texture);
|
||||
@ -196,60 +287,104 @@ public:
|
||||
PROFILE2("load texture");
|
||||
PROFILE2_ATTR("name: %ls", path.string().c_str());
|
||||
|
||||
Handle h = ogl_tex_load(m_VFS, path, RES_UNIQUE);
|
||||
if (h <= 0)
|
||||
std::shared_ptr<u8> fileData;
|
||||
size_t fileSize;
|
||||
texture->m_TextureData = std::make_unique<Tex>();
|
||||
Tex& textureData = *texture->m_TextureData;
|
||||
if (g_VFS->LoadFile(path, fileData, fileSize) != INFO::OK ||
|
||||
textureData.decode(fileData, fileSize) != INFO::OK)
|
||||
{
|
||||
LOGERROR("Texture failed to load; \"%s\"", texture->m_Properties.m_Path.string8());
|
||||
|
||||
// Replace with error texture to make it obvious
|
||||
texture->SetHandle(m_ErrorTexture.GetHandle());
|
||||
texture->ResetBackendTexture(
|
||||
nullptr, m_ErrorTexture.GetTexture()->GetBackendTexture());
|
||||
return;
|
||||
}
|
||||
|
||||
// Get some flags for later use
|
||||
size_t flags = 0;
|
||||
ignore_result(ogl_tex_get_format(h, &flags, NULL));
|
||||
|
||||
// Initialise base color from the texture
|
||||
ignore_result(ogl_tex_get_average_color(h, &texture->m_BaseColor));
|
||||
texture->m_BaseColor = textureData.get_average_color();
|
||||
|
||||
// Set GL upload properties
|
||||
ignore_result(ogl_tex_set_wrap(h, texture->m_Properties.m_WrapS, texture->m_Properties.m_WrapT));
|
||||
ignore_result(ogl_tex_set_anisotropy(h, texture->m_Properties.m_Aniso));
|
||||
|
||||
// Prevent ogl_tex automatically generating mipmaps (which is slow and unwanted),
|
||||
// by avoiding mipmapped filters unless the source texture already has mipmaps
|
||||
GLint filter = texture->m_Properties.m_Filter;
|
||||
if (!(flags & TEX_MIPMAPS))
|
||||
Renderer::Backend::Format format = Renderer::Backend::Format::UNDEFINED;
|
||||
if (texture->m_Properties.m_FormatOverride != Renderer::Backend::Format::UNDEFINED)
|
||||
{
|
||||
switch (filter)
|
||||
format = texture->m_Properties.m_FormatOverride;
|
||||
// TODO: it'd be good to remove the override hack and provide information
|
||||
// via XML.
|
||||
ENSURE((textureData.m_Flags & TEX_DXT) == 0);
|
||||
if (format == Renderer::Backend::Format::A8)
|
||||
{
|
||||
case GL_NEAREST_MIPMAP_NEAREST:
|
||||
case GL_NEAREST_MIPMAP_LINEAR:
|
||||
filter = GL_NEAREST;
|
||||
break;
|
||||
case GL_LINEAR_MIPMAP_NEAREST:
|
||||
case GL_LINEAR_MIPMAP_LINEAR:
|
||||
filter = GL_LINEAR;
|
||||
break;
|
||||
ENSURE(textureData.m_Bpp == 8 && (textureData.m_Flags & TEX_GREY));
|
||||
}
|
||||
else if (format == Renderer::Backend::Format::R8G8B8A8)
|
||||
{
|
||||
ENSURE(textureData.m_Bpp == 32 && (textureData.m_Flags & TEX_ALPHA));
|
||||
}
|
||||
else
|
||||
debug_warn("Unsupported format override.");
|
||||
}
|
||||
ignore_result(ogl_tex_set_filter(h, filter));
|
||||
|
||||
// Upload to GL
|
||||
if (!m_DisableGL && ogl_tex_upload(h, texture->m_Properties.m_Format) < 0)
|
||||
else
|
||||
{
|
||||
LOGERROR("Texture failed to upload: \"%s\"", texture->m_Properties.m_Path.string8());
|
||||
format = ChooseFormatAndTransformTextureDataIfNeeded(textureData, m_HasS3TC);
|
||||
}
|
||||
|
||||
ogl_tex_free(h);
|
||||
|
||||
// Replace with error texture to make it obvious
|
||||
texture->SetHandle(m_ErrorTexture.GetHandle());
|
||||
if (format == Renderer::Backend::Format::UNDEFINED)
|
||||
{
|
||||
LOGERROR("Texture failed to choose format; \"%s\"", texture->m_Properties.m_Path.string8());
|
||||
texture->ResetBackendTexture(
|
||||
nullptr, m_ErrorTexture.GetTexture()->GetBackendTexture());
|
||||
return;
|
||||
}
|
||||
|
||||
// Let the texture object take ownership of this handle
|
||||
texture->SetHandle(h, true);
|
||||
const uint32_t width = texture->m_TextureData->m_Width;
|
||||
const uint32_t height = texture->m_TextureData->m_Height ;
|
||||
const uint32_t MIPLevelCount = texture->m_TextureData->GetMIPLevels().size();
|
||||
texture->m_BaseLevelOffset = 0;
|
||||
|
||||
Renderer::Backend::Sampler::Desc defaultSamplerDesc =
|
||||
Renderer::Backend::Sampler::MakeDefaultSampler(
|
||||
Renderer::Backend::Sampler::Filter::LINEAR,
|
||||
Renderer::Backend::Sampler::AddressMode::REPEAT);
|
||||
|
||||
defaultSamplerDesc.addressModeU = texture->m_Properties.m_AddressModeU;
|
||||
defaultSamplerDesc.addressModeV = texture->m_Properties.m_AddressModeV;
|
||||
if (texture->m_Properties.m_AnisotropicFilterEnabled)
|
||||
{
|
||||
int maxAnisotropy = 1;
|
||||
CFG_GET_VAL("textures.maxanisotropy", maxAnisotropy);
|
||||
const int allowedValues[] = {2, 4, 8, 16};
|
||||
if (std::find(std::begin(allowedValues), std::end(allowedValues), maxAnisotropy) != std::end(allowedValues))
|
||||
{
|
||||
defaultSamplerDesc.anisotropyEnabled = true;
|
||||
defaultSamplerDesc.maxAnisotropy = maxAnisotropy;
|
||||
}
|
||||
}
|
||||
|
||||
if (!texture->m_Properties.m_IgnoreQuality)
|
||||
{
|
||||
int quality = 2;
|
||||
CFG_GET_VAL("textures.quality", quality);
|
||||
if (quality == 1)
|
||||
{
|
||||
if (MIPLevelCount > 1 && std::min(width, height) > 8)
|
||||
texture->m_BaseLevelOffset += 1;
|
||||
}
|
||||
else if (quality == 0)
|
||||
{
|
||||
if (MIPLevelCount > 2 && std::min(width, height) > 16)
|
||||
texture->m_BaseLevelOffset += 2;
|
||||
while (std::min(width >> texture->m_BaseLevelOffset, height >> texture->m_BaseLevelOffset) > 256 &&
|
||||
MIPLevelCount > texture->m_BaseLevelOffset + 1)
|
||||
{
|
||||
texture->m_BaseLevelOffset += 1;
|
||||
}
|
||||
defaultSamplerDesc.mipFilter = Renderer::Backend::Sampler::Filter::NEAREST;
|
||||
defaultSamplerDesc.anisotropyEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
texture->m_BackendTexture = g_VideoMode.GetBackendDevice()->CreateTexture2D(
|
||||
texture->m_Properties.m_Path.string8().c_str(),
|
||||
format, (width >> texture->m_BaseLevelOffset), (height >> texture->m_BaseLevelOffset),
|
||||
defaultSamplerDesc, MIPLevelCount - texture->m_BaseLevelOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -299,7 +434,8 @@ public:
|
||||
// No source file or archive cache was found, so we can't load the
|
||||
// real texture at all - return the error texture instead
|
||||
LOGERROR("CCacheLoader failed to find archived or source file for: \"%s\"", texture->m_Properties.m_Path.string8());
|
||||
texture->SetHandle(m_ErrorTexture.GetHandle());
|
||||
texture->ResetBackendTexture(
|
||||
nullptr, m_ErrorTexture.GetTexture()->GetBackendTexture());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -372,7 +508,8 @@ public:
|
||||
else
|
||||
{
|
||||
LOGERROR("Texture failed to convert: \"%s\"", texture->m_Properties.m_Path.string8());
|
||||
texture->SetHandle(m_ErrorTexture.GetHandle());
|
||||
texture->ResetBackendTexture(
|
||||
nullptr, m_ErrorTexture.GetTexture()->GetBackendTexture());
|
||||
}
|
||||
texture->m_State = CTexture::LOADED;
|
||||
return true;
|
||||
@ -434,6 +571,21 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MakeUploadProgress(
|
||||
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext)
|
||||
{
|
||||
if (!m_SingleColorTexturesUploaded)
|
||||
{
|
||||
m_DefaultTexture.Upload(deviceCommandContext);
|
||||
m_ErrorTexture.Upload(deviceCommandContext);
|
||||
m_WhiteTexture.Upload(deviceCommandContext);
|
||||
m_TransparentTexture.Upload(deviceCommandContext);
|
||||
m_SingleColorTexturesUploaded = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the conversion settings that apply to a given texture, by combining
|
||||
* the textures.xml files from its directory and all parent directories
|
||||
@ -495,12 +647,14 @@ public:
|
||||
if (files != m_HotloadFiles.end())
|
||||
{
|
||||
// Flag all textures using this file as needing reloading
|
||||
for (std::set<std::weak_ptr<CTexture> >::iterator it = files->second.begin(); it != files->second.end(); ++it)
|
||||
for (std::set<std::weak_ptr<CTexture>>::iterator it = files->second.begin(); it != files->second.end(); ++it)
|
||||
{
|
||||
if (std::shared_ptr<CTexture> texture = it->lock())
|
||||
{
|
||||
texture->m_State = CTexture::UNLOADED;
|
||||
texture->SetHandle(m_DefaultTexture.GetHandle());
|
||||
texture->ResetBackendTexture(
|
||||
nullptr, m_DefaultTexture.GetTexture()->GetBackendTexture());
|
||||
texture->m_TextureData.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -508,6 +662,17 @@ public:
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
void ReloadAllTextures()
|
||||
{
|
||||
for (const CTexturePtr& texture : m_TextureCache)
|
||||
{
|
||||
texture->m_State = CTexture::UNLOADED;
|
||||
texture->ResetBackendTexture(
|
||||
nullptr, m_DefaultTexture.GetTexture()->GetBackendTexture());
|
||||
texture->m_TextureData.reset();
|
||||
}
|
||||
}
|
||||
|
||||
size_t GetBytesUploaded() const
|
||||
{
|
||||
size_t size = 0;
|
||||
@ -516,6 +681,11 @@ public:
|
||||
return size;
|
||||
}
|
||||
|
||||
void OnQualityChanged()
|
||||
{
|
||||
ReloadAllTextures();
|
||||
}
|
||||
|
||||
private:
|
||||
PIVFS m_VFS;
|
||||
CCacheLoader m_CacheLoader;
|
||||
@ -526,6 +696,7 @@ private:
|
||||
SingleColorTexture m_ErrorTexture;
|
||||
SingleColorTexture m_WhiteTexture;
|
||||
SingleColorTexture m_TransparentTexture;
|
||||
bool m_SingleColorTexturesUploaded = false;
|
||||
|
||||
// Cache of all loaded textures
|
||||
using TextureCache =
|
||||
@ -536,44 +707,68 @@ private:
|
||||
// Store the set of textures that need to be reloaded when the given file
|
||||
// (a source file or settings.xml) is modified
|
||||
using HotloadFilesMap =
|
||||
std::unordered_map<VfsPath, std::set<std::weak_ptr<CTexture>, std::owner_less<std::weak_ptr<CTexture> > > >;
|
||||
std::unordered_map<VfsPath, std::set<std::weak_ptr<CTexture>, std::owner_less<std::weak_ptr<CTexture>>>>;
|
||||
HotloadFilesMap m_HotloadFiles;
|
||||
|
||||
// Cache for the conversion settings files
|
||||
using SettingsFilesMap =
|
||||
std::unordered_map<VfsPath, std::shared_ptr<CTextureConverter::SettingsFile>>;
|
||||
SettingsFilesMap m_SettingsFiles;
|
||||
|
||||
bool m_HasS3TC = false;
|
||||
};
|
||||
|
||||
CTexture::CTexture(Handle handle, const CTextureProperties& props, CTextureManagerImpl* textureManager) :
|
||||
m_Handle(handle), m_BaseColor(0), m_State(UNLOADED), m_Properties(props), m_TextureManager(textureManager)
|
||||
CTexture::CTexture(
|
||||
std::unique_ptr<Renderer::Backend::GL::CTexture> texture,
|
||||
Renderer::Backend::GL::CTexture* fallback,
|
||||
const CTextureProperties& props, CTextureManagerImpl* textureManager) :
|
||||
m_BackendTexture(std::move(texture)), m_FallbackBackendTexture(fallback),
|
||||
m_BaseColor(0), m_State(UNLOADED), m_Properties(props),
|
||||
m_TextureManager(textureManager)
|
||||
{
|
||||
// Add a reference to the handle (it might be shared by multiple CTextures
|
||||
// so we can't take ownership of it)
|
||||
if (m_Handle)
|
||||
h_add_ref(m_Handle);
|
||||
}
|
||||
|
||||
CTexture::~CTexture()
|
||||
CTexture::~CTexture() = default;
|
||||
|
||||
void CTexture::UploadBackendTextureIfNeeded(
|
||||
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext)
|
||||
{
|
||||
if (m_Handle)
|
||||
ogl_tex_free(m_Handle);
|
||||
if (IsUploaded())
|
||||
return;
|
||||
|
||||
if (!IsLoaded())
|
||||
TryLoad();
|
||||
|
||||
if (!IsLoaded())
|
||||
return;
|
||||
else if (!m_TextureData)
|
||||
{
|
||||
ResetBackendTexture(nullptr, m_TextureManager->GetErrorTexture()->GetBackendTexture());
|
||||
m_State = UPLOADED;
|
||||
return;
|
||||
}
|
||||
|
||||
m_UploadedSize = 0;
|
||||
for (uint32_t textureDataLevel = m_BaseLevelOffset, level = 0; textureDataLevel < m_TextureData->GetMIPLevels().size(); ++textureDataLevel)
|
||||
{
|
||||
const Tex::MIPLevel& levelData = m_TextureData->GetMIPLevels()[textureDataLevel];
|
||||
deviceCommandContext->UploadTexture(m_BackendTexture.get(), m_BackendTexture->GetFormat(),
|
||||
levelData.data, levelData.dataSize, level++);
|
||||
m_UploadedSize += levelData.dataSize;
|
||||
}
|
||||
m_TextureData.reset();
|
||||
|
||||
m_State = UPLOADED;
|
||||
}
|
||||
|
||||
void CTexture::Bind(size_t unit)
|
||||
Renderer::Backend::GL::CTexture* CTexture::GetBackendTexture()
|
||||
{
|
||||
ogl_tex_bind(GetHandle(), unit);
|
||||
return m_BackendTexture && IsUploaded() ? m_BackendTexture.get() : m_FallbackBackendTexture;
|
||||
}
|
||||
|
||||
Handle CTexture::GetHandle()
|
||||
const Renderer::Backend::GL::CTexture* CTexture::GetBackendTexture() const
|
||||
{
|
||||
// TODO: TryLoad might call ogl_tex_upload which enables GL_TEXTURE_2D
|
||||
// on texture unit 0, regardless of 'unit', which callers might
|
||||
// not be expecting. Ideally that wouldn't happen.
|
||||
|
||||
TryLoad();
|
||||
|
||||
return m_Handle;
|
||||
return m_BackendTexture && IsUploaded() ? m_BackendTexture.get() : m_FallbackBackendTexture;
|
||||
}
|
||||
|
||||
bool CTexture::TryLoad()
|
||||
@ -591,7 +786,7 @@ bool CTexture::TryLoad()
|
||||
}
|
||||
}
|
||||
|
||||
return (m_State == LOADED);
|
||||
return IsLoaded();
|
||||
}
|
||||
|
||||
void CTexture::Prefetch()
|
||||
@ -605,42 +800,33 @@ void CTexture::Prefetch()
|
||||
}
|
||||
}
|
||||
|
||||
bool CTexture::IsLoaded()
|
||||
void CTexture::ResetBackendTexture(
|
||||
std::unique_ptr<Renderer::Backend::GL::CTexture> backendTexture,
|
||||
Renderer::Backend::GL::CTexture* fallbackBackendTexture)
|
||||
{
|
||||
return (m_State == LOADED);
|
||||
}
|
||||
|
||||
void CTexture::SetHandle(Handle handle, bool takeOwnership)
|
||||
{
|
||||
if (handle == m_Handle)
|
||||
return;
|
||||
|
||||
if (!takeOwnership)
|
||||
h_add_ref(handle);
|
||||
|
||||
ogl_tex_free(m_Handle);
|
||||
m_Handle = handle;
|
||||
m_BackendTexture = std::move(backendTexture);
|
||||
m_FallbackBackendTexture = fallbackBackendTexture;
|
||||
}
|
||||
|
||||
size_t CTexture::GetWidth() const
|
||||
{
|
||||
size_t w = 0;
|
||||
ignore_result(ogl_tex_get_size(m_Handle, &w, 0, 0));
|
||||
return w;
|
||||
return GetBackendTexture()->GetWidth();
|
||||
}
|
||||
|
||||
size_t CTexture::GetHeight() const
|
||||
{
|
||||
size_t h = 0;
|
||||
ignore_result(ogl_tex_get_size(m_Handle, 0, &h, 0));
|
||||
return h;
|
||||
return GetBackendTexture()->GetHeight();
|
||||
}
|
||||
|
||||
bool CTexture::HasAlpha() const
|
||||
{
|
||||
size_t flags = 0;
|
||||
ignore_result(ogl_tex_get_format(m_Handle, &flags, 0));
|
||||
return (flags & TEX_ALPHA) != 0;
|
||||
const Renderer::Backend::Format format = GetBackendTexture()->GetFormat();
|
||||
return
|
||||
format == Renderer::Backend::Format::A8 ||
|
||||
format == Renderer::Backend::Format::R8G8B8A8 ||
|
||||
format == Renderer::Backend::Format::BC1_RGBA ||
|
||||
format == Renderer::Backend::Format::BC2 ||
|
||||
format == Renderer::Backend::Format::BC3;
|
||||
}
|
||||
|
||||
u32 CTexture::GetBaseColor() const
|
||||
@ -650,12 +836,9 @@ u32 CTexture::GetBaseColor() const
|
||||
|
||||
size_t CTexture::GetUploadedSize() const
|
||||
{
|
||||
size_t size = 0;
|
||||
ignore_result(ogl_tex_get_uploaded_size(m_Handle, &size));
|
||||
return size;
|
||||
return m_UploadedSize;
|
||||
}
|
||||
|
||||
|
||||
// CTextureManager: forward all calls to impl:
|
||||
|
||||
CTextureManager::CTextureManager(PIVFS vfs, bool highQuality, bool disableGL) :
|
||||
@ -678,17 +861,17 @@ bool CTextureManager::TextureExists(const VfsPath& path) const
|
||||
return m->TextureExists(path);
|
||||
}
|
||||
|
||||
CTexturePtr CTextureManager::GetErrorTexture()
|
||||
const CTexturePtr& CTextureManager::GetErrorTexture()
|
||||
{
|
||||
return m->GetErrorTexture();
|
||||
}
|
||||
|
||||
CTexturePtr CTextureManager::GetWhiteTexture()
|
||||
const CTexturePtr& CTextureManager::GetWhiteTexture()
|
||||
{
|
||||
return m->GetWhiteTexture();
|
||||
}
|
||||
|
||||
CTexturePtr CTextureManager::GetTransparentTexture()
|
||||
const CTexturePtr& CTextureManager::GetTransparentTexture()
|
||||
{
|
||||
return m->GetTransparentTexture();
|
||||
}
|
||||
@ -698,6 +881,12 @@ bool CTextureManager::MakeProgress()
|
||||
return m->MakeProgress();
|
||||
}
|
||||
|
||||
bool CTextureManager::MakeUploadProgress(
|
||||
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext)
|
||||
{
|
||||
return m->MakeUploadProgress(deviceCommandContext);
|
||||
}
|
||||
|
||||
bool CTextureManager::GenerateCachedTexture(const VfsPath& path, VfsPath& outputPath)
|
||||
{
|
||||
return m->GenerateCachedTexture(path, outputPath);
|
||||
@ -707,3 +896,8 @@ size_t CTextureManager::GetBytesUploaded() const
|
||||
{
|
||||
return m->GetBytesUploaded();
|
||||
}
|
||||
|
||||
void CTextureManager::OnQualityChanged()
|
||||
{
|
||||
m->OnQualityChanged();
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -20,8 +20,9 @@
|
||||
|
||||
#include "graphics/Texture.h"
|
||||
#include "lib/file/vfs/vfs.h"
|
||||
#include "lib/ogl.h"
|
||||
#include "lib/res/handle.h"
|
||||
#include "lib/tex/tex.h"
|
||||
#include "renderer/backend/gl/DeviceCommandContext.h"
|
||||
#include "renderer/backend/gl/Texture.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
@ -92,17 +93,17 @@ public:
|
||||
* Returns a magenta texture. Use this for highlighting errors
|
||||
* (e.g. missing terrain textures).
|
||||
*/
|
||||
CTexturePtr GetErrorTexture();
|
||||
const CTexturePtr& GetErrorTexture();
|
||||
|
||||
/**
|
||||
* Returns a single color RGBA texture with CColor(1.0f, 1.0f, 1.0f, 1.0f).
|
||||
*/
|
||||
CTexturePtr GetWhiteTexture();
|
||||
const CTexturePtr& GetWhiteTexture();
|
||||
|
||||
/**
|
||||
* Returns a single color RGBA texture with CColor(0.0f, 0.0f, 0.0f, 0.0f).
|
||||
*/
|
||||
CTexturePtr GetTransparentTexture();
|
||||
const CTexturePtr& GetTransparentTexture();
|
||||
|
||||
/**
|
||||
* Work on asynchronous texture loading operations, if any.
|
||||
@ -112,6 +113,12 @@ public:
|
||||
*/
|
||||
bool MakeProgress();
|
||||
|
||||
/**
|
||||
* Work on asynchronous texture uploading operations, if any.
|
||||
* Returns true if it did any work. Mostly the same as MakeProgress.
|
||||
*/
|
||||
bool MakeUploadProgress(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext);
|
||||
|
||||
/**
|
||||
* Synchronously converts and compresses and saves the texture,
|
||||
* and returns the output path (minus a "cache/" prefix). This
|
||||
@ -131,6 +138,11 @@ public:
|
||||
*/
|
||||
size_t GetBytesUploaded() const;
|
||||
|
||||
/**
|
||||
* Should be called on any quality or anisotropic change.
|
||||
*/
|
||||
void OnQualityChanged();
|
||||
|
||||
private:
|
||||
CTextureManagerImpl* m;
|
||||
};
|
||||
@ -150,38 +162,41 @@ public:
|
||||
/**
|
||||
* Use the given texture name, and default GL parameters.
|
||||
*/
|
||||
explicit CTextureProperties(const VfsPath& path) :
|
||||
m_Path(path), m_Filter(GL_LINEAR_MIPMAP_LINEAR),
|
||||
m_WrapS(GL_REPEAT), m_WrapT(GL_REPEAT), m_Aniso(1.0f), m_Format(0)
|
||||
explicit CTextureProperties(const VfsPath& path)
|
||||
: m_Path(path)
|
||||
{
|
||||
}
|
||||
|
||||
CTextureProperties(
|
||||
const VfsPath& path, const Renderer::Backend::Format formatOverride)
|
||||
: m_Path(path), m_FormatOverride(formatOverride)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Set min/mag filter mode (typically GL_LINEAR_MIPMAP_LINEAR, GL_NEAREST, etc).
|
||||
* Set sampler address mode.
|
||||
*/
|
||||
void SetFilter(GLint filter) { m_Filter = filter; }
|
||||
void SetAddressMode(const Renderer::Backend::Sampler::AddressMode addressMode)
|
||||
{
|
||||
m_AddressModeU = m_AddressModeV = addressMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set wrapping mode (typically GL_REPEAT, GL_CLAMP_TO_EDGE, etc).
|
||||
* Set sampler address mode separately for different coordinates.
|
||||
*/
|
||||
void SetWrap(GLint wrap) { m_WrapS = wrap; m_WrapT = wrap; }
|
||||
void SetAddressMode(
|
||||
const Renderer::Backend::Sampler::AddressMode addressModeU,
|
||||
const Renderer::Backend::Sampler::AddressMode addressModeV)
|
||||
{
|
||||
m_AddressModeU = addressModeU;
|
||||
m_AddressModeV = addressModeV;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set wrapping mode (typically GL_REPEAT, GL_CLAMP_TO_EDGE, etc),
|
||||
* separately for S and T.
|
||||
* The value of max anisotropy is set by options. Though it might make sense
|
||||
* to add an override.
|
||||
*/
|
||||
void SetWrap(GLint wrap_s, GLint wrap_t) { m_WrapS = wrap_s; m_WrapT = wrap_t; }
|
||||
|
||||
/**
|
||||
* Set maximum anisotropy value. Must be >= 1.0. Should be a power of 2.
|
||||
*/
|
||||
void SetMaxAnisotropy(float aniso) { m_Aniso = aniso; }
|
||||
|
||||
/**
|
||||
* Set GL texture upload format, to override the default.
|
||||
* Typically GL_ALPHA or GL_LUMINANCE for 8-bit textures.
|
||||
*/
|
||||
void SetFormatOverride(GLenum format) { m_Format = format; }
|
||||
void SetAnisotropicFilter(const bool enabled) { m_AnisotropicFilterEnabled = enabled; }
|
||||
|
||||
// TODO: rather than this static definition of texture properties
|
||||
// (especially anisotropy), maybe we want something that can be more
|
||||
@ -200,14 +215,20 @@ public:
|
||||
//
|
||||
// or something a bit like that.
|
||||
|
||||
void SetIgnoreQuality(bool ignore) { m_IgnoreQuality = ignore; }
|
||||
|
||||
private:
|
||||
// Must update TPhash, TPequal_to when changing these fields
|
||||
VfsPath m_Path;
|
||||
GLint m_Filter;
|
||||
GLint m_WrapS;
|
||||
GLint m_WrapT;
|
||||
float m_Aniso;
|
||||
GLenum m_Format;
|
||||
|
||||
Renderer::Backend::Sampler::AddressMode m_AddressModeU =
|
||||
Renderer::Backend::Sampler::AddressMode::REPEAT;
|
||||
Renderer::Backend::Sampler::AddressMode m_AddressModeV =
|
||||
Renderer::Backend::Sampler::AddressMode::REPEAT;
|
||||
bool m_AnisotropicFilterEnabled = false;
|
||||
Renderer::Backend::Format m_FormatOverride =
|
||||
Renderer::Backend::Format::UNDEFINED;
|
||||
bool m_IgnoreQuality = false;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -218,19 +239,8 @@ private:
|
||||
*/
|
||||
class CTexture
|
||||
{
|
||||
friend class CTextureManagerImpl;
|
||||
friend class SingleColorTexture;
|
||||
friend struct TextureCacheCmp;
|
||||
friend struct TPequal_to;
|
||||
friend struct TPhash;
|
||||
|
||||
// Only the texture manager can create these
|
||||
explicit CTexture(Handle handle, const CTextureProperties& props, CTextureManagerImpl* textureManager);
|
||||
|
||||
NONCOPYABLE(CTexture);
|
||||
|
||||
public:
|
||||
|
||||
~CTexture();
|
||||
|
||||
/**
|
||||
@ -261,29 +271,37 @@ public:
|
||||
size_t GetUploadedSize() const;
|
||||
|
||||
/**
|
||||
* Bind the texture to the given GL texture unit.
|
||||
* Uploads a texture data to a backend texture if successfully loaded.
|
||||
* If the texture data hasn't been loaded yet, this may wait a short while to
|
||||
* load it. If loading takes too long then it will return sooner and the data will
|
||||
* be loaded in a background thread, so this does not guarantee the texture really
|
||||
* will be loaded.
|
||||
* will be uploaded.
|
||||
*/
|
||||
void Bind(size_t unit = 0);
|
||||
void UploadBackendTextureIfNeeded(
|
||||
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext);
|
||||
|
||||
/**
|
||||
* Returns a ogl_tex handle, for later binding. See comments from Bind().
|
||||
* Returns a backend texture if successfully uploaded, else fallback.
|
||||
*/
|
||||
Handle GetHandle();
|
||||
Renderer::Backend::GL::CTexture* GetBackendTexture();
|
||||
const Renderer::Backend::GL::CTexture* GetBackendTexture() const;
|
||||
|
||||
/**
|
||||
* Attempt to load the texture data quickly, as with Bind().
|
||||
* Returns whether the texture data is currently loaded.
|
||||
* Attempt to load the texture data quickly, as with
|
||||
* GetUploadedBackendTextureIfNeeded(). Returns whether the texture data is
|
||||
* currently loaded (but not uploaded).
|
||||
*/
|
||||
bool TryLoad();
|
||||
|
||||
/**
|
||||
* Returns whether the texture data is currently loaded.
|
||||
*/
|
||||
bool IsLoaded();
|
||||
bool IsLoaded() const { return m_State == LOADED; }
|
||||
|
||||
/**
|
||||
* Returns whether the texture data is currently uploaded.
|
||||
*/
|
||||
bool IsUploaded() const { return m_State == UPLOADED; }
|
||||
|
||||
/**
|
||||
* Activate the prefetching optimisation for this texture.
|
||||
@ -294,25 +312,42 @@ public:
|
||||
void Prefetch();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Replace the Handle stored by this object.
|
||||
* If takeOwnership is true, it will not increment the Handle's reference count.
|
||||
*/
|
||||
void SetHandle(Handle handle, bool takeOwnership = false);
|
||||
friend class CTextureManagerImpl;
|
||||
friend class SingleColorTexture;
|
||||
friend struct TextureCacheCmp;
|
||||
friend struct TPequal_to;
|
||||
friend struct TPhash;
|
||||
|
||||
// Only the texture manager can create these
|
||||
explicit CTexture(
|
||||
std::unique_ptr<Renderer::Backend::GL::CTexture> texture,
|
||||
Renderer::Backend::GL::CTexture* fallback,
|
||||
const CTextureProperties& props, CTextureManagerImpl* textureManager);
|
||||
|
||||
void ResetBackendTexture(
|
||||
std::unique_ptr<Renderer::Backend::GL::CTexture> backendTexture,
|
||||
Renderer::Backend::GL::CTexture* fallbackBackendTexture);
|
||||
|
||||
const CTextureProperties m_Properties;
|
||||
|
||||
Handle m_Handle;
|
||||
std::unique_ptr<Renderer::Backend::GL::CTexture> m_BackendTexture;
|
||||
// It's possible to m_FallbackBackendTexture references m_BackendTexture.
|
||||
Renderer::Backend::GL::CTexture* m_FallbackBackendTexture = nullptr;
|
||||
u32 m_BaseColor;
|
||||
std::unique_ptr<Tex> m_TextureData;
|
||||
size_t m_UploadedSize = 0;
|
||||
uint32_t m_BaseLevelOffset = 0;
|
||||
|
||||
enum {
|
||||
enum
|
||||
{
|
||||
UNLOADED, // loading has not started
|
||||
PREFETCH_NEEDS_LOADING, // was prefetched; currently waiting to try loading from cache
|
||||
PREFETCH_NEEDS_CONVERTING, // was prefetched; currently waiting to be sent to the texture converter
|
||||
PREFETCH_IS_CONVERTING, // was prefetched; currently being processed by the texture converter
|
||||
HIGH_NEEDS_CONVERTING, // high-priority; currently waiting to be sent to the texture converter
|
||||
HIGH_IS_CONVERTING, // high-priority; currently being processed by the texture converter
|
||||
LOADED // loading has completed (successfully or not)
|
||||
LOADED, // loading texture data has completed (successfully or not)
|
||||
UPLOADED // uploading to backend has completed (successfully or not)
|
||||
} m_State;
|
||||
|
||||
CTextureManagerImpl* m_TextureManager;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -1083,11 +1083,11 @@ void CGUI::Xeromyces_ReadImage(const XMBData& xmb, XMBElement element, CGUISprit
|
||||
else if (attr_name == "wrap_mode")
|
||||
{
|
||||
if (attr_value == L"repeat")
|
||||
image->m_WrapMode = GL_REPEAT;
|
||||
image->m_AddressMode = Renderer::Backend::Sampler::AddressMode::REPEAT;
|
||||
else if (attr_value == L"mirrored_repeat")
|
||||
image->m_WrapMode = GL_MIRRORED_REPEAT;
|
||||
image->m_AddressMode = Renderer::Backend::Sampler::AddressMode::MIRRORED_REPEAT;
|
||||
else if (attr_value == L"clamp_to_edge")
|
||||
image->m_WrapMode = GL_CLAMP_TO_EDGE;
|
||||
image->m_AddressMode = Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE;
|
||||
else
|
||||
LOGERROR("GUI: Error parsing '%s' (\"%s\")", attr_name, utf8_from_wstring(attr_value));
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -26,9 +26,9 @@
|
||||
#include "gui/GUIRenderer.h"
|
||||
#include "gui/SettingTypes/CGUISize.h"
|
||||
#include "gui/SettingTypes/CGUIColor.h"
|
||||
#include "lib/ogl.h"
|
||||
#include "lib/file/vfs/vfs_path.h"
|
||||
#include "ps/CStr.h"
|
||||
#include "renderer/backend/Sampler.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@ -55,7 +55,7 @@ public:
|
||||
SGUIImage() :
|
||||
m_FixedHAspectRatio(0.f),
|
||||
m_RoundCoordinates(true),
|
||||
m_WrapMode(GL_REPEAT),
|
||||
m_AddressMode(Renderer::Backend::Sampler::AddressMode::REPEAT),
|
||||
m_Effects(),
|
||||
m_Size(CGUISize::Full()),
|
||||
m_TextureSize(CGUISize::Full())
|
||||
@ -89,9 +89,9 @@ public:
|
||||
bool m_RoundCoordinates;
|
||||
|
||||
/**
|
||||
* Texture wrapping mode (GL_REPEAT, GL_CLAMP_TO_EDGE, etc)
|
||||
* Texture address mode (REPEAT, CLAMP_TO_EDGE, etc).
|
||||
*/
|
||||
GLint m_WrapMode;
|
||||
Renderer::Backend::Sampler::AddressMode m_AddressMode;
|
||||
|
||||
// Visual effects (e.g. color modulation)
|
||||
std::shared_ptr<SGUIImageEffects> m_Effects;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -26,8 +26,6 @@
|
||||
#include "gui/GUIMatrix.h"
|
||||
#include "gui/SettingTypes/CGUIColor.h"
|
||||
#include "i18n/L10n.h"
|
||||
#include "lib/ogl.h"
|
||||
#include "lib/res/graphics/ogl_tex.h"
|
||||
#include "lib/tex/tex.h"
|
||||
#include "lib/utf8.h"
|
||||
#include "ps/CLogger.h"
|
||||
@ -204,7 +202,8 @@ void GUIRenderer::UpdateDrawCallCache(const CGUI& pGUI, DrawCalls& Calls, const
|
||||
if (!(*cit)->m_TextureName.empty())
|
||||
{
|
||||
CTextureProperties textureProps(g_L10n.LocalizePath((*cit)->m_TextureName));
|
||||
textureProps.SetWrap((*cit)->m_WrapMode);
|
||||
textureProps.SetAddressMode((*cit)->m_AddressMode);
|
||||
textureProps.SetIgnoreQuality(true);
|
||||
CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
|
||||
texture->Prefetch();
|
||||
hasTexture = true;
|
||||
@ -323,9 +322,8 @@ void GUIRenderer::Draw(DrawCalls& Calls, CCanvas2D& canvas)
|
||||
// Iterate through each DrawCall, and execute whatever drawing code is being called
|
||||
for (DrawCalls::const_iterator cit = Calls.begin(); cit != Calls.end(); ++cit)
|
||||
{
|
||||
// A hack to preload the handle to get a correct texture size.
|
||||
GLuint h;
|
||||
ogl_tex_get_texture_id(cit->m_Texture->GetHandle(), &h);
|
||||
// A hack to get a correct backend texture size.
|
||||
cit->m_Texture->UploadBackendTextureIfNeeded(g_Renderer.GetDeviceCommandContext());
|
||||
|
||||
CRect texCoords = cit->ComputeTexCoords().Scale(
|
||||
cit->m_Texture->GetWidth(), cit->m_Texture->GetHeight());
|
||||
|
@ -220,7 +220,8 @@ void CMiniMap::RecreateFlareTextures()
|
||||
m_FlareTextures.reserve(m_FlareTextureCount);
|
||||
for (u32 i = 0; i < m_FlareTextureCount; ++i)
|
||||
{
|
||||
const CTextureProperties textureProps(fmt::sprintf(textureNumberingFormat, i).c_str());
|
||||
CTextureProperties textureProps(fmt::sprintf(textureNumberingFormat, i).c_str());
|
||||
textureProps.SetIgnoreQuality(true);
|
||||
m_FlareTextures.emplace_back(g_Renderer.GetTextureManager().CreateTexture(textureProps));
|
||||
}
|
||||
}
|
||||
|
@ -474,12 +474,14 @@ Status Tex::transform(size_t transforms)
|
||||
return INFO::OK;
|
||||
|
||||
Status ret = tex_codec_transform(this, remaining_transforms);
|
||||
UpdateMIPLevels();
|
||||
if(ret != INFO::OK)
|
||||
break;
|
||||
}
|
||||
|
||||
// last chance
|
||||
RETURN_STATUS_IF_ERR(plain_transform(this, remaining_transforms));
|
||||
UpdateMIPLevels();
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
@ -596,6 +598,9 @@ Status Tex::wrap(size_t w, size_t h, size_t bpp, size_t flags, const std::shared
|
||||
m_Ofs = ofs;
|
||||
|
||||
CHECK_TEX(this);
|
||||
|
||||
UpdateMIPLevels();
|
||||
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
@ -632,31 +637,6 @@ u8* Tex::get_data()
|
||||
return p + m_Ofs;
|
||||
}
|
||||
|
||||
u8* Tex::GetMipLevelData(const u32 level)
|
||||
{
|
||||
// (can't use normal CHECK_TEX due to u8* return value)
|
||||
WARN_IF_ERR(validate());
|
||||
|
||||
u8* levelData = m_Data.get();
|
||||
if (!levelData)
|
||||
return nullptr;
|
||||
levelData += m_Ofs;
|
||||
const size_t dataPadding = (m_Flags & TEX_DXT) != 0 ? 4 : 1;
|
||||
size_t levelWidth = m_Width, levelHeight = m_Height;
|
||||
for (u32 currentLevel = 0; levelWidth > 1 || levelHeight > 1; ++currentLevel)
|
||||
{
|
||||
if (currentLevel == level)
|
||||
return levelData;
|
||||
|
||||
const size_t levelDataSize = round_up(levelWidth, dataPadding) * round_up(levelHeight, dataPadding) * m_Bpp / 8;
|
||||
levelData += levelDataSize;
|
||||
|
||||
levelWidth = std::max<u32>(levelWidth / 2, 1);
|
||||
levelHeight = std::max<u32>(levelHeight / 2, 1);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// returns color of 1x1 mipmap level
|
||||
u32 Tex::get_average_color() const
|
||||
{
|
||||
@ -765,6 +745,8 @@ Status Tex::decode(const std::shared_ptr<u8>& Data, size_t DataSize)
|
||||
|
||||
CHECK_TEX(this);
|
||||
|
||||
UpdateMIPLevels();
|
||||
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
@ -795,3 +777,39 @@ Status Tex::encode(const OsPath& extension, DynArray* da)
|
||||
|
||||
return INFO::OK;
|
||||
}
|
||||
|
||||
void Tex::UpdateMIPLevels()
|
||||
{
|
||||
m_MIPLevels.clear();
|
||||
|
||||
if (m_Flags & TEX_MIPMAPS)
|
||||
{
|
||||
// We add one because we need to account the smallest 1x1 level.
|
||||
m_MIPLevels.reserve(ceil_log2(std::max(m_Width, m_Height)) + 1);
|
||||
}
|
||||
|
||||
u8* levelData = m_Data.get();
|
||||
levelData += m_Ofs;
|
||||
|
||||
const u32 dataPadding = (m_Flags & TEX_DXT) != 0 ? 4 : 1;
|
||||
u32 levelWidth = m_Width, levelHeight = m_Height;
|
||||
for (u32 level = 0; ; ++level)
|
||||
{
|
||||
const u32 levelDataSize = round_up(levelWidth, dataPadding) * round_up(levelHeight, dataPadding) * m_Bpp / 8;
|
||||
m_MIPLevels.emplace_back();
|
||||
m_MIPLevels.back().data = levelData;
|
||||
m_MIPLevels.back().dataSize = levelDataSize;
|
||||
m_MIPLevels.back().width = levelWidth;
|
||||
m_MIPLevels.back().height = levelHeight;
|
||||
|
||||
if (!(m_Flags & TEX_MIPMAPS))
|
||||
break;
|
||||
|
||||
if (levelWidth == 1 && levelHeight == 1)
|
||||
break;
|
||||
|
||||
levelData += levelDataSize;
|
||||
levelWidth = std::max<u32>(levelWidth / 2, 1);
|
||||
levelHeight = std::max<u32>(levelHeight / 2, 1);
|
||||
}
|
||||
}
|
||||
|
@ -109,6 +109,7 @@ library and IO layer. Read and write are zero-copy.
|
||||
#include "lib/file/vfs/vfs_path.h"
|
||||
#include "lib/allocators/dynarray.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace ERR
|
||||
{
|
||||
@ -202,12 +203,21 @@ enum TexFlags
|
||||
};
|
||||
|
||||
/**
|
||||
* stores all data describing an image.
|
||||
* we try to minimize size, since this is stored in OglTex resources
|
||||
* (which are big and pushing the h_mgr limit).
|
||||
* Stores all data describing an image.
|
||||
* TODO: rename to TextureData.
|
||||
**/
|
||||
struct Tex
|
||||
class Tex
|
||||
{
|
||||
public:
|
||||
struct MIPLevel
|
||||
{
|
||||
// A pointer to the mip level image data (pixels).
|
||||
u8* data;
|
||||
u32 dataSize;
|
||||
u32 width;
|
||||
u32 height;
|
||||
};
|
||||
|
||||
/**
|
||||
* file buffer or image data. note: during the course of transforms
|
||||
* (which may occur when being loaded), this may be replaced with
|
||||
@ -332,13 +342,7 @@ struct Tex
|
||||
**/
|
||||
u8* get_data();
|
||||
|
||||
/**
|
||||
* return a pointer to the mip level image data (pixels).
|
||||
*
|
||||
* @param level which level's data should be returned.
|
||||
* @return pointer to the data.
|
||||
**/
|
||||
u8* GetMipLevelData(const u32 level);
|
||||
const std::vector<MIPLevel>& GetMIPLevels() const { return m_MIPLevels; }
|
||||
|
||||
/**
|
||||
* return the ARGB value of the 1x1 mipmap level of the texture.
|
||||
@ -356,6 +360,10 @@ struct Tex
|
||||
**/
|
||||
size_t img_size() const;
|
||||
|
||||
private:
|
||||
void UpdateMIPLevels();
|
||||
|
||||
std::vector<MIPLevel> m_MIPLevels;
|
||||
};
|
||||
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "lib/os_path.h"
|
||||
#include "lib/file/vfs/vfs_path.h"
|
||||
|
||||
struct Tex;
|
||||
class Tex;
|
||||
|
||||
void WriteSystemInfo();
|
||||
|
||||
|
@ -177,7 +177,9 @@ void CDecalRData::RenderDecals(
|
||||
|
||||
const CMaterial::SamplersVector& samplers = material.GetSamplers();
|
||||
for (const CMaterial::TextureSampler& sampler : samplers)
|
||||
shader->BindTexture(sampler.Name, sampler.Sampler);
|
||||
sampler.Sampler->UploadBackendTextureIfNeeded(deviceCommandContext);
|
||||
for (const CMaterial::TextureSampler& sampler : samplers)
|
||||
shader->BindTexture(sampler.Name, sampler.Sampler->GetBackendTexture());
|
||||
|
||||
material.GetStaticUniforms().BindUniforms(shader);
|
||||
|
||||
|
@ -693,7 +693,8 @@ void ShaderModelRenderer::Render(
|
||||
CTexture* newTex = samp.Sampler.get();
|
||||
if (texBindings[s].Active() && newTex != currentTexs[s])
|
||||
{
|
||||
shader->BindTexture(texBindings[s], samp.Sampler);
|
||||
newTex->UploadBackendTextureIfNeeded(deviceCommandContext);
|
||||
shader->BindTexture(texBindings[s], newTex->GetBackendTexture());
|
||||
currentTexs[s] = newTex;
|
||||
}
|
||||
}
|
||||
@ -733,9 +734,13 @@ void ShaderModelRenderer::Render(
|
||||
const double period = 1.6;
|
||||
const WaterManager& waterManager = g_Renderer.GetSceneRenderer().GetWaterManager();
|
||||
if (waterManager.m_RenderWater && waterManager.WillRenderFancyWater())
|
||||
shader->BindTexture(str_waterTex, waterManager.m_NormalMap[waterManager.GetCurrentTextureIndex(period)]);
|
||||
{
|
||||
const CTexturePtr& waterTexture = waterManager.m_NormalMap[waterManager.GetCurrentTextureIndex(period)];
|
||||
waterTexture->UploadBackendTextureIfNeeded(deviceCommandContext);
|
||||
shader->BindTexture(str_waterTex, waterTexture->GetBackendTexture());
|
||||
}
|
||||
else
|
||||
shader->BindTexture(str_waterTex, g_Renderer.GetTextureManager().GetErrorTexture());
|
||||
shader->BindTexture(str_waterTex, g_Renderer.GetTextureManager().GetErrorTexture()->GetBackendTexture());
|
||||
}
|
||||
else if (rq.first == RQUERY_SKY_CUBE)
|
||||
{
|
||||
|
@ -409,8 +409,6 @@ void OverlayRenderer::RenderTexturedOverlayLines(Renderer::Backend::GL::CDeviceC
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
glActiveTextureARB(GL_TEXTURE0);
|
||||
|
||||
CLOSTexture& los = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture();
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
@ -439,7 +437,7 @@ void OverlayRenderer::RenderTexturedOverlayLines(Renderer::Backend::GL::CDeviceC
|
||||
shaderTexLineNormal->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection());
|
||||
|
||||
// batch render only the non-always-visible overlay lines using the normal shader
|
||||
RenderTexturedOverlayLines(shaderTexLineNormal, false);
|
||||
RenderTexturedOverlayLines(deviceCommandContext, shaderTexLineNormal, false);
|
||||
|
||||
shaderTechTexLineNormal->EndPass();
|
||||
}
|
||||
@ -471,7 +469,7 @@ void OverlayRenderer::RenderTexturedOverlayLines(Renderer::Backend::GL::CDeviceC
|
||||
shaderTexLineAlwaysVisible->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection());
|
||||
|
||||
// batch render only the always-visible overlay lines using the LoS-ignored shader
|
||||
RenderTexturedOverlayLines(shaderTexLineAlwaysVisible, true);
|
||||
RenderTexturedOverlayLines(deviceCommandContext, shaderTexLineAlwaysVisible, true);
|
||||
|
||||
shaderTechTexLineAlwaysVisible->EndPass();
|
||||
}
|
||||
@ -479,13 +477,15 @@ void OverlayRenderer::RenderTexturedOverlayLines(Renderer::Backend::GL::CDeviceC
|
||||
// ----------------------------------------------------------------------------------------
|
||||
|
||||
// TODO: the shaders should probably be responsible for unbinding their textures
|
||||
g_Renderer.BindTexture(1, 0);
|
||||
g_Renderer.BindTexture(0, 0);
|
||||
deviceCommandContext->BindTexture(1, GL_TEXTURE_2D, 0);
|
||||
deviceCommandContext->BindTexture(0, GL_TEXTURE_2D, 0);
|
||||
|
||||
CVertexBuffer::Unbind();
|
||||
}
|
||||
|
||||
void OverlayRenderer::RenderTexturedOverlayLines(const CShaderProgramPtr& shader, bool alwaysVisible)
|
||||
void OverlayRenderer::RenderTexturedOverlayLines(
|
||||
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderProgramPtr& shader, bool alwaysVisible)
|
||||
{
|
||||
#if !CONFIG2_GLES
|
||||
if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME)
|
||||
@ -500,7 +500,7 @@ void OverlayRenderer::RenderTexturedOverlayLines(const CShaderProgramPtr& shader
|
||||
continue;
|
||||
|
||||
ENSURE(line->m_RenderData);
|
||||
line->m_RenderData->Render(*line, shader);
|
||||
line->m_RenderData->Render(deviceCommandContext, *line, shader);
|
||||
}
|
||||
#if !CONFIG2_GLES
|
||||
if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME)
|
||||
@ -543,8 +543,6 @@ void OverlayRenderer::RenderQuadOverlays(
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
#endif
|
||||
|
||||
glActiveTextureARB(GL_TEXTURE0);
|
||||
|
||||
CLOSTexture& los = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture();
|
||||
|
||||
shader->BindTexture(str_losTex, los.GetTexture());
|
||||
@ -569,8 +567,10 @@ void OverlayRenderer::RenderQuadOverlays(
|
||||
|
||||
const QuadBatchKey& maskPair = it->first;
|
||||
|
||||
shader->BindTexture(str_baseTex, maskPair.m_Texture);
|
||||
shader->BindTexture(str_maskTex, maskPair.m_TextureMask);
|
||||
maskPair.m_Texture->UploadBackendTextureIfNeeded(deviceCommandContext);
|
||||
maskPair.m_TextureMask->UploadBackendTextureIfNeeded(deviceCommandContext);
|
||||
shader->BindTexture(str_baseTex, maskPair.m_Texture->GetBackendTexture());
|
||||
shader->BindTexture(str_maskTex, maskPair.m_TextureMask->GetBackendTexture());
|
||||
|
||||
int streamflags = shader->GetStreamFlags();
|
||||
|
||||
@ -596,8 +596,8 @@ void OverlayRenderer::RenderQuadOverlays(
|
||||
shaderTech->EndPass();
|
||||
|
||||
// TODO: the shader should probably be responsible for unbinding its textures
|
||||
g_Renderer.BindTexture(1, 0);
|
||||
g_Renderer.BindTexture(0, 0);
|
||||
deviceCommandContext->BindTexture(1, GL_TEXTURE_2D, 0);
|
||||
deviceCommandContext->BindTexture(0, GL_TEXTURE_2D, 0);
|
||||
|
||||
CVertexBuffer::Unbind();
|
||||
|
||||
@ -621,8 +621,6 @@ void OverlayRenderer::RenderForegroundOverlays(
|
||||
if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME)
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
|
||||
glActiveTextureARB(GL_TEXTURE0);
|
||||
|
||||
CVector3D right = -viewCamera.GetOrientation().GetLeft();
|
||||
CVector3D up = viewCamera.GetOrientation().GetUp();
|
||||
|
||||
@ -652,7 +650,10 @@ void OverlayRenderer::RenderForegroundOverlays(
|
||||
{
|
||||
SOverlaySprite* sprite = m->sprites[i];
|
||||
if (!i || sprite->m_Texture != m->sprites[i - 1]->m_Texture)
|
||||
shader->BindTexture(str_baseTex, sprite->m_Texture);
|
||||
{
|
||||
sprite->m_Texture->UploadBackendTextureIfNeeded(deviceCommandContext);
|
||||
shader->BindTexture(str_baseTex, sprite->m_Texture->GetBackendTexture());
|
||||
}
|
||||
|
||||
shader->Uniform(str_colorMul, sprite->m_Color);
|
||||
|
||||
|
@ -107,7 +107,8 @@ public:
|
||||
* (i.e. rendered behind other objects in the normal 3D way)
|
||||
* and should be drawn after water (i.e. may be visible on top of the water)
|
||||
*/
|
||||
void RenderOverlaysAfterWater(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext);
|
||||
void RenderOverlaysAfterWater(
|
||||
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext);
|
||||
|
||||
/**
|
||||
* Render all the submitted overlays that should appear on top of everything
|
||||
@ -136,7 +137,9 @@ private:
|
||||
* batch rendering the overlay lines according to their alwaysVisible status, as this
|
||||
* requires a separate shader to be used.
|
||||
*/
|
||||
void RenderTexturedOverlayLines(const CShaderProgramPtr& shader, bool alwaysVisible);
|
||||
void RenderTexturedOverlayLines(
|
||||
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
|
||||
const CShaderProgramPtr& shader, bool alwaysVisible);
|
||||
|
||||
/**
|
||||
* Helper method; batch-renders all registered quad overlays, batched by their texture for effiency.
|
||||
|
@ -157,7 +157,7 @@ void ParticleRenderer::RenderParticles(
|
||||
shader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection());
|
||||
shader->Uniform(str_modelViewMatrix, g_Renderer.GetSceneRenderer().GetViewCamera().GetOrientation().GetInverse());
|
||||
}
|
||||
emitter->Bind(lastTech->GetShader());
|
||||
emitter->Bind(deviceCommandContext, lastTech->GetShader());
|
||||
emitter->RenderArray(lastTech->GetShader());
|
||||
}
|
||||
|
||||
|
@ -757,11 +757,13 @@ void CPatchRData::RenderBases(
|
||||
TextureBatches& textureBatches = itTech->second;
|
||||
for (TextureBatches::iterator itt = textureBatches.begin(); itt != textureBatches.end(); ++itt)
|
||||
{
|
||||
if (itt->first->GetMaterial().GetSamplers().size() != 0)
|
||||
if (!itt->first->GetMaterial().GetSamplers().empty())
|
||||
{
|
||||
const CMaterial::SamplersVector& samplers = itt->first->GetMaterial().GetSamplers();
|
||||
for(const CMaterial::TextureSampler& samp : samplers)
|
||||
shader->BindTexture(samp.Name, samp.Sampler);
|
||||
samp.Sampler->UploadBackendTextureIfNeeded(deviceCommandContext);
|
||||
for(const CMaterial::TextureSampler& samp : samplers)
|
||||
shader->BindTexture(samp.Name, samp.Sampler->GetBackendTexture());
|
||||
|
||||
itt->first->GetMaterial().GetStaticUniforms().BindUniforms(shader);
|
||||
|
||||
@ -771,7 +773,7 @@ void CPatchRData::RenderBases(
|
||||
}
|
||||
else
|
||||
{
|
||||
shader->BindTexture(str_baseTex, g_Renderer.GetTextureManager().GetErrorTexture());
|
||||
shader->BindTexture(str_baseTex, g_Renderer.GetTextureManager().GetErrorTexture()->GetBackendTexture());
|
||||
}
|
||||
|
||||
for (VertexBufferBatches::iterator itv = itt->second.begin(); itv != itt->second.end(); ++itv)
|
||||
@ -974,7 +976,9 @@ void CPatchRData::RenderBlends(
|
||||
{
|
||||
const CMaterial::SamplersVector& samplers = itt->m_Texture->GetMaterial().GetSamplers();
|
||||
for (const CMaterial::TextureSampler& samp : samplers)
|
||||
shader->BindTexture(samp.Name, samp.Sampler);
|
||||
samp.Sampler->UploadBackendTextureIfNeeded(deviceCommandContext);
|
||||
for (const CMaterial::TextureSampler& samp : samplers)
|
||||
shader->BindTexture(samp.Name, samp.Sampler->GetBackendTexture());
|
||||
|
||||
Renderer::Backend::GL::CTexture* currentBlendTex = itt->m_Texture->m_TerrainAlpha->second.m_CompositeAlphaMap.get();
|
||||
if (currentBlendTex != lastBlendTex)
|
||||
@ -991,7 +995,7 @@ void CPatchRData::RenderBlends(
|
||||
}
|
||||
else
|
||||
{
|
||||
shader->BindTexture(str_baseTex, g_Renderer.GetTextureManager().GetErrorTexture());
|
||||
shader->BindTexture(str_baseTex, g_Renderer.GetTextureManager().GetErrorTexture()->GetBackendTexture());
|
||||
}
|
||||
|
||||
for (VertexBufferBatches::iterator itv = itt->m_Batches.begin(); itv != itt->m_Batches.end(); ++itv)
|
||||
|
@ -124,8 +124,8 @@ void CPostprocManager::RecreateBuffers()
|
||||
Cleanup();
|
||||
|
||||
#define GEN_BUFFER_RGBA(name, w, h) \
|
||||
name = Renderer::Backend::GL::CTexture::Create2D( \
|
||||
Renderer::Backend::Format::R8G8B8A8, w, h, \
|
||||
name = g_VideoMode.GetBackendDevice()->CreateTexture2D( \
|
||||
"PostProc" #name, Renderer::Backend::Format::R8G8B8A8, w, h, \
|
||||
Renderer::Backend::Sampler::MakeDefaultSampler( \
|
||||
Renderer::Backend::Sampler::Filter::LINEAR, \
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE));
|
||||
@ -154,15 +154,15 @@ void CPostprocManager::RecreateBuffers()
|
||||
#undef GEN_BUFFER_RGBA
|
||||
|
||||
// Allocate the Depth/Stencil texture.
|
||||
m_DepthTex = Renderer::Backend::GL::CTexture::Create2D(
|
||||
m_DepthTex = g_VideoMode.GetBackendDevice()->CreateTexture2D("PostPRocDepthTexture",
|
||||
Renderer::Backend::Format::D24_S8, m_Width, m_Height,
|
||||
Renderer::Backend::Sampler::MakeDefaultSampler(
|
||||
Renderer::Backend::Sampler::Filter::LINEAR,
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE));
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, m_DepthTex->GetHandle());
|
||||
g_Renderer.GetDeviceCommandContext()->BindTexture(0, GL_TEXTURE_2D, m_DepthTex->GetHandle());
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
g_Renderer.GetDeviceCommandContext()->BindTexture(0, GL_TEXTURE_2D, 0);
|
||||
|
||||
// Set up the framebuffers with some initial textures.
|
||||
m_CaptureFramebuffer = Renderer::Backend::GL::CFramebuffer::Create(
|
||||
@ -605,7 +605,7 @@ void CPostprocManager::CreateMultisampleBuffer()
|
||||
{
|
||||
glEnable(GL_MULTISAMPLE);
|
||||
|
||||
m_MultisampleColorTex = Renderer::Backend::GL::CTexture::Create(
|
||||
m_MultisampleColorTex = g_VideoMode.GetBackendDevice()->CreateTexture("PostProcColorMS",
|
||||
Renderer::Backend::GL::CTexture::Type::TEXTURE_2D_MULTISAMPLE,
|
||||
Renderer::Backend::Format::R8G8B8A8, m_Width, m_Height,
|
||||
Renderer::Backend::Sampler::MakeDefaultSampler(
|
||||
@ -613,7 +613,7 @@ void CPostprocManager::CreateMultisampleBuffer()
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE), 1, m_MultisampleCount);
|
||||
|
||||
// Allocate the Depth/Stencil texture.
|
||||
m_MultisampleDepthTex = Renderer::Backend::GL::CTexture::Create(
|
||||
m_MultisampleDepthTex = g_VideoMode.GetBackendDevice()->CreateTexture("PostProcDepthMS",
|
||||
Renderer::Backend::GL::CTexture::Type::TEXTURE_2D_MULTISAMPLE,
|
||||
Renderer::Backend::Format::D24_S8, m_Width, m_Height,
|
||||
Renderer::Backend::Sampler::MakeDefaultSampler(
|
||||
|
@ -243,6 +243,8 @@ class CRenderer::Internals
|
||||
{
|
||||
NONCOPYABLE(Internals);
|
||||
public:
|
||||
std::unique_ptr<Renderer::Backend::GL::CDeviceCommandContext> deviceCommandContext;
|
||||
|
||||
/// true if CRenderer::Open has been called
|
||||
bool IsOpen;
|
||||
|
||||
@ -270,10 +272,10 @@ public:
|
||||
|
||||
CFontManager fontManager;
|
||||
|
||||
std::unique_ptr<Renderer::Backend::GL::CDeviceCommandContext> deviceCommandContext;
|
||||
|
||||
Internals() :
|
||||
IsOpen(false), ShadersDirty(true), profileTable(g_Renderer.m_Stats), textureManager(g_VFS, false, false)
|
||||
IsOpen(false), ShadersDirty(true), profileTable(g_Renderer.m_Stats),
|
||||
deviceCommandContext(g_VideoMode.GetBackendDevice()->CreateCommandContext()),
|
||||
textureManager(g_VFS, false, false)
|
||||
{
|
||||
}
|
||||
};
|
||||
@ -387,8 +389,6 @@ bool CRenderer::Open(int width, int height)
|
||||
// Validate the currently selected render path
|
||||
SetRenderPath(g_RenderingOptions.GetRenderPath());
|
||||
|
||||
m->deviceCommandContext = g_VideoMode.GetBackendDevice()->CreateCommandContext();
|
||||
|
||||
if (m->postprocManager.IsEnabled())
|
||||
m->postprocManager.Initialize();
|
||||
|
||||
@ -484,6 +484,8 @@ void CRenderer::RenderFrameImpl(const bool renderGUI, const bool renderLogger)
|
||||
|
||||
g_TexMan.UploadResourcesIfNeeded(m->deviceCommandContext.get());
|
||||
|
||||
m->textureManager.MakeUploadProgress(m->deviceCommandContext.get());
|
||||
|
||||
// prepare before starting the renderer frame
|
||||
if (g_Game && g_Game->IsGameStarted())
|
||||
g_Game->GetView()->BeginFrame();
|
||||
@ -756,8 +758,6 @@ void CRenderer::EndFrame()
|
||||
PROFILE3("end frame");
|
||||
|
||||
m->sceneRenderer.EndFrame();
|
||||
|
||||
BindTexture(0, 0);
|
||||
}
|
||||
|
||||
void CRenderer::SetViewport(const SViewPort &vp)
|
||||
@ -771,13 +771,6 @@ SViewPort CRenderer::GetViewport()
|
||||
return m_Viewport;
|
||||
}
|
||||
|
||||
void CRenderer::BindTexture(int unit, GLuint tex)
|
||||
{
|
||||
glActiveTextureARB(GL_TEXTURE0+unit);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, tex);
|
||||
}
|
||||
|
||||
void CRenderer::MakeShadersDirty()
|
||||
{
|
||||
m->ShadersDirty = true;
|
||||
|
@ -115,9 +115,6 @@ public:
|
||||
// get the last viewport
|
||||
SViewPort GetViewport();
|
||||
|
||||
// bind a GL texture object to active unit
|
||||
void BindTexture(int unit, unsigned int tex);
|
||||
|
||||
// return stats accumulated for current frame
|
||||
Stats& GetStats() { return m_Stats; }
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "RenderingOptions.h"
|
||||
|
||||
#include "graphics/TextureManager.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/ConfigDB.h"
|
||||
#include "ps/CStr.h"
|
||||
@ -221,6 +222,15 @@ void CRenderingOptions::ReadConfigAndSetupHooks()
|
||||
});
|
||||
|
||||
m_ConfigHooks->Setup("renderactors", m_RenderActors);
|
||||
|
||||
m_ConfigHooks->Setup("textures.quality", []() {
|
||||
if (CRenderer::IsInitialised())
|
||||
g_Renderer.GetTextureManager().OnQualityChanged();
|
||||
});
|
||||
m_ConfigHooks->Setup("textures.maxanisotropy", []() {
|
||||
if (CRenderer::IsInitialised())
|
||||
g_Renderer.GetTextureManager().OnQualityChanged();
|
||||
});
|
||||
}
|
||||
|
||||
void CRenderingOptions::ClearHooks()
|
||||
|
@ -368,7 +368,6 @@ void CSceneRenderer::RenderPatches(
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
|
||||
// setup some renderstate ..
|
||||
glActiveTextureARB(GL_TEXTURE0);
|
||||
glLineWidth(2.0f);
|
||||
|
||||
// render tiles edges
|
||||
|
@ -527,14 +527,14 @@ void ShadowMapInternals::CreateTexture()
|
||||
|
||||
if (g_RenderingOptions.GetShadowAlphaFix())
|
||||
{
|
||||
DummyTexture = Renderer::Backend::GL::CTexture::Create2D(
|
||||
DummyTexture = g_VideoMode.GetBackendDevice()->CreateTexture2D("ShadowMapDummy",
|
||||
Renderer::Backend::Format::R8G8B8A8, Width, Height,
|
||||
Renderer::Backend::Sampler::MakeDefaultSampler(
|
||||
Renderer::Backend::Sampler::Filter::NEAREST,
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE));
|
||||
}
|
||||
|
||||
Texture = Renderer::Backend::GL::CTexture::Create2D(
|
||||
Texture = g_VideoMode.GetBackendDevice()->CreateTexture2D("ShadowMapDepth",
|
||||
backendFormat, Width, Height,
|
||||
Renderer::Backend::Sampler::MakeDefaultSampler(
|
||||
#if CONFIG2_GLES
|
||||
@ -549,12 +549,12 @@ void ShadowMapInternals::CreateTexture()
|
||||
|
||||
|
||||
#if !CONFIG2_GLES
|
||||
g_Renderer.BindTexture(0, Texture->GetHandle());
|
||||
g_Renderer.GetDeviceCommandContext()->BindTexture(0, GL_TEXTURE_2D, Texture->GetHandle());
|
||||
// Enable automatic depth comparisons
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
g_Renderer.GetDeviceCommandContext()->BindTexture(0, GL_TEXTURE_2D, 0);
|
||||
#endif
|
||||
|
||||
ogl_WarnIfError();
|
||||
@ -579,7 +579,6 @@ void ShadowMap::BeginRender()
|
||||
|
||||
{
|
||||
PROFILE("bind framebuffer");
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
deviceCommandContext->SetFramebuffer(m->Framebuffer.get());
|
||||
}
|
||||
|
||||
@ -719,7 +718,7 @@ void ShadowMap::RenderDebugTexture(
|
||||
return;
|
||||
|
||||
#if !CONFIG2_GLES
|
||||
g_Renderer.BindTexture(0, m->Texture->GetHandle());
|
||||
deviceCommandContext->BindTexture(0, GL_TEXTURE_2D, m->Texture->GetHandle());
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
|
||||
#endif
|
||||
|
||||
@ -756,7 +755,7 @@ void ShadowMap::RenderDebugTexture(
|
||||
texTech->EndPass();
|
||||
|
||||
#if !CONFIG2_GLES
|
||||
g_Renderer.BindTexture(0, m->Texture->GetHandle());
|
||||
deviceCommandContext->BindTexture(0, GL_TEXTURE_2D, m->Texture->GetHandle());
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
|
||||
#endif
|
||||
|
||||
|
@ -34,7 +34,9 @@
|
||||
#include "ps/Filesystem.h"
|
||||
#include "ps/Game.h"
|
||||
#include "ps/Loader.h"
|
||||
#include "ps/VideoMode.h"
|
||||
#include "ps/World.h"
|
||||
#include "renderer/backend/gl/Device.h"
|
||||
#include "renderer/Renderer.h"
|
||||
#include "renderer/SceneRenderer.h"
|
||||
#include "renderer/RenderingOptions.h"
|
||||
@ -111,7 +113,7 @@ void SkyManager::LoadAndUploadSkyTexturesIfNeeded(
|
||||
}
|
||||
}
|
||||
|
||||
m_SkyCubeMap = Renderer::Backend::GL::CTexture::Create(
|
||||
m_SkyCubeMap = g_VideoMode.GetBackendDevice()->CreateTexture("SkyCubeMap",
|
||||
Renderer::Backend::GL::CTexture::Type::TEXTURE_CUBE,
|
||||
Renderer::Backend::Format::R8G8B8A8, textures[0].m_Width, textures[0].m_Height,
|
||||
Renderer::Backend::Sampler::MakeDefaultSampler(
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "ps/Game.h"
|
||||
#include "ps/Profile.h"
|
||||
#include "ps/World.h"
|
||||
#include "renderer/backend/gl/Device.h"
|
||||
#include "renderer/Renderer.h"
|
||||
#include "renderer/SceneRenderer.h"
|
||||
#include "renderer/TerrainRenderer.h"
|
||||
@ -129,8 +130,6 @@ void TerrainOverlay::RenderBeforeWater(
|
||||
//glEnable(GL_POLYGON_OFFSET_LINE);
|
||||
glEnable(GL_POLYGON_OFFSET_FILL);
|
||||
|
||||
glActiveTextureARB(GL_TEXTURE0);
|
||||
|
||||
StartRender();
|
||||
|
||||
ssize_t min_i, min_j, max_i, max_j;
|
||||
@ -338,12 +337,10 @@ void TerrainTextureOverlay::RenderAfterWater(
|
||||
const uint32_t requiredWidth = round_up_to_pow2(w);
|
||||
const uint32_t requiredHeight = round_up_to_pow2(h);
|
||||
|
||||
glActiveTextureARB(GL_TEXTURE0);
|
||||
|
||||
// Recreate the texture with new size if necessary
|
||||
if (!m_Texture || m_Texture->GetWidth() != requiredWidth || m_Texture->GetHeight() != requiredHeight)
|
||||
{
|
||||
m_Texture = Renderer::Backend::GL::CTexture::Create2D(
|
||||
m_Texture = deviceCommandContext->GetDevice()->CreateTexture2D("TerrainOverlayTexture",
|
||||
Renderer::Backend::Format::R8G8B8A8, requiredWidth, requiredHeight,
|
||||
Renderer::Backend::Sampler::MakeDefaultSampler(
|
||||
Renderer::Backend::Sampler::Filter::NEAREST,
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "graphics/ShaderManager.h"
|
||||
#include "graphics/TerritoryTexture.h"
|
||||
#include "graphics/TextRenderer.h"
|
||||
#include "graphics/TextureManager.h"
|
||||
#include "maths/MathUtil.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/CStrInternStatic.h"
|
||||
@ -280,9 +281,9 @@ void TerrainRenderer::RenderTerrainShader(
|
||||
CDecalRData::RenderDecals(deviceCommandContext, visibleDecals, context, shadow);
|
||||
|
||||
// restore OpenGL state
|
||||
g_Renderer.BindTexture(1, 0);
|
||||
g_Renderer.BindTexture(2, 0);
|
||||
g_Renderer.BindTexture(3, 0);
|
||||
deviceCommandContext->BindTexture(3, GL_TEXTURE_2D, 0);
|
||||
deviceCommandContext->BindTexture(2, GL_TEXTURE_2D, 0);
|
||||
deviceCommandContext->BindTexture(1, GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -417,8 +418,13 @@ bool TerrainRenderer::RenderFancyWater(
|
||||
const CCamera& camera = g_Renderer.GetSceneRenderer().GetViewCamera();
|
||||
|
||||
const double period = 8.0;
|
||||
fancyWaterShader->BindTexture(str_normalMap, waterManager.m_NormalMap[waterManager.GetCurrentTextureIndex(period)]);
|
||||
fancyWaterShader->BindTexture(str_normalMap2, waterManager.m_NormalMap[waterManager.GetNextTextureIndex(period)]);
|
||||
// TODO: move uploading to a prepare function during loading.
|
||||
const CTexturePtr& currentNormalTexture = waterManager.m_NormalMap[waterManager.GetCurrentTextureIndex(period)];
|
||||
const CTexturePtr& nextNormalTexture = waterManager.m_NormalMap[waterManager.GetNextTextureIndex(period)];
|
||||
currentNormalTexture->UploadBackendTextureIfNeeded(deviceCommandContext);
|
||||
nextNormalTexture->UploadBackendTextureIfNeeded(deviceCommandContext);
|
||||
fancyWaterShader->BindTexture(str_normalMap, currentNormalTexture->GetBackendTexture());
|
||||
fancyWaterShader->BindTexture(str_normalMap2, nextNormalTexture->GetBackendTexture());
|
||||
|
||||
if (waterManager.m_WaterFancyEffects)
|
||||
{
|
||||
@ -533,7 +539,9 @@ void TerrainRenderer::RenderSimpleWater(
|
||||
waterSimpleTech->GetGraphicsPipelineStateDesc());
|
||||
const CShaderProgramPtr& waterSimpleShader = waterSimpleTech->GetShader();
|
||||
|
||||
waterSimpleShader->BindTexture(str_baseTex, waterManager.m_WaterTexture[waterManager.GetCurrentTextureIndex(1.6)]);
|
||||
const CTexturePtr& waterTexture = waterManager.m_WaterTexture[waterManager.GetCurrentTextureIndex(1.6)];
|
||||
waterTexture->UploadBackendTextureIfNeeded(deviceCommandContext);
|
||||
waterSimpleShader->BindTexture(str_baseTex, waterTexture->GetBackendTexture());
|
||||
waterSimpleShader->BindTexture(str_losTex, losTexture.GetTextureSmooth());
|
||||
waterSimpleShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection());
|
||||
waterSimpleShader->Uniform(str_losTransform, losTexture.GetTextureMatrix()[0], losTexture.GetTextureMatrix()[12], 0.f, 0.f);
|
||||
@ -547,9 +555,7 @@ void TerrainRenderer::RenderSimpleWater(
|
||||
data->RenderWaterSurface(waterSimpleShader, false);
|
||||
}
|
||||
|
||||
g_Renderer.BindTexture(1, 0);
|
||||
|
||||
glActiveTextureARB(GL_TEXTURE0_ARB);
|
||||
deviceCommandContext->BindTexture(1, GL_TEXTURE_2D, 0);
|
||||
|
||||
waterSimpleTech->EndPass();
|
||||
|
||||
|
@ -35,7 +35,9 @@
|
||||
* because it allows you to work with variable amounts of vertices and indices more easily. New code should prefer
|
||||
* to use VertexArray where possible, though. */
|
||||
|
||||
void CTexturedLineRData::Render(const SOverlayTexturedLine& line, const CShaderProgramPtr& shader)
|
||||
void CTexturedLineRData::Render(
|
||||
Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
|
||||
const SOverlayTexturedLine& line, const CShaderProgramPtr& shader)
|
||||
{
|
||||
if (!m_VB || !m_VBIndices)
|
||||
return; // might have failed to allocate
|
||||
@ -44,8 +46,10 @@ void CTexturedLineRData::Render(const SOverlayTexturedLine& line, const CShaderP
|
||||
|
||||
const int streamFlags = shader->GetStreamFlags();
|
||||
|
||||
shader->BindTexture(str_baseTex, line.m_TextureBase);
|
||||
shader->BindTexture(str_maskTex, line.m_TextureMask);
|
||||
line.m_TextureBase->UploadBackendTextureIfNeeded(deviceCommandContext);
|
||||
line.m_TextureMask->UploadBackendTextureIfNeeded(deviceCommandContext);
|
||||
shader->BindTexture(str_baseTex, line.m_TextureBase->GetBackendTexture());
|
||||
shader->BindTexture(str_maskTex, line.m_TextureMask->GetBackendTexture());
|
||||
shader->Uniform(str_objectColor, line.m_Color);
|
||||
|
||||
GLsizei stride = sizeof(CTexturedLineRData::SVertex);
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "graphics/ShaderProgramPtr.h"
|
||||
#include "graphics/TextureManager.h"
|
||||
#include "maths/BoundingBoxAligned.h"
|
||||
#include "renderer/backend/gl/DeviceCommandContext.h"
|
||||
#include "renderer/VertexBufferManager.h"
|
||||
|
||||
class CFrustum;
|
||||
@ -51,7 +52,8 @@ public:
|
||||
~CTexturedLineRData() = default;
|
||||
|
||||
void Update(const SOverlayTexturedLine& line);
|
||||
void Render(const SOverlayTexturedLine& line, const CShaderProgramPtr& shader);
|
||||
void Render(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext,
|
||||
const SOverlayTexturedLine& line, const CShaderProgramPtr& shader);
|
||||
|
||||
bool IsVisibleInFrustum(const CFrustum& frustum) const;
|
||||
|
||||
|
@ -145,7 +145,8 @@ int WaterManager::LoadWaterTextures()
|
||||
{
|
||||
swprintf_s(pathname, ARRAY_SIZE(pathname), L"art/textures/animated/water/default/diffuse%02d.dds", (int)i+1);
|
||||
CTextureProperties textureProps(pathname);
|
||||
textureProps.SetWrap(GL_REPEAT);
|
||||
textureProps.SetAddressMode(
|
||||
Renderer::Backend::Sampler::AddressMode::REPEAT);
|
||||
|
||||
CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
|
||||
texture->Prefetch();
|
||||
@ -168,7 +169,8 @@ int WaterManager::LoadWaterTextures()
|
||||
// Load CoastalWaves
|
||||
{
|
||||
CTextureProperties textureProps(L"art/textures/terrain/types/water/coastalWave.png");
|
||||
textureProps.SetWrap(GL_REPEAT);
|
||||
textureProps.SetAddressMode(
|
||||
Renderer::Backend::Sampler::AddressMode::REPEAT);
|
||||
CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
|
||||
texture->Prefetch();
|
||||
m_WaveTex = texture;
|
||||
@ -177,7 +179,8 @@ int WaterManager::LoadWaterTextures()
|
||||
// Load Foam
|
||||
{
|
||||
CTextureProperties textureProps(L"art/textures/terrain/types/water/foam.png");
|
||||
textureProps.SetWrap(GL_REPEAT);
|
||||
textureProps.SetAddressMode(
|
||||
Renderer::Backend::Sampler::AddressMode::REPEAT);
|
||||
CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
|
||||
texture->Prefetch();
|
||||
m_FoamTex = texture;
|
||||
@ -186,28 +189,30 @@ int WaterManager::LoadWaterTextures()
|
||||
// Use screen-sized textures for minimum artifacts.
|
||||
m_RefTextureSize = round_up_to_pow2(g_Renderer.GetHeight());
|
||||
|
||||
Renderer::Backend::GL::CDevice* backendDevice = g_VideoMode.GetBackendDevice();
|
||||
|
||||
// Create reflection texture
|
||||
m_ReflectionTexture = Renderer::Backend::GL::CTexture::Create2D(
|
||||
m_ReflectionTexture = backendDevice->CreateTexture2D("WaterReflectionTexture",
|
||||
Renderer::Backend::Format::R8G8B8A8, m_RefTextureSize, m_RefTextureSize,
|
||||
Renderer::Backend::Sampler::MakeDefaultSampler(
|
||||
Renderer::Backend::Sampler::Filter::LINEAR,
|
||||
Renderer::Backend::Sampler::AddressMode::MIRRORED_REPEAT));
|
||||
|
||||
// Create refraction texture
|
||||
m_RefractionTexture = Renderer::Backend::GL::CTexture::Create2D(
|
||||
m_RefractionTexture = backendDevice->CreateTexture2D("WaterRefractionTexture",
|
||||
Renderer::Backend::Format::R8G8B8A8, m_RefTextureSize, m_RefTextureSize,
|
||||
Renderer::Backend::Sampler::MakeDefaultSampler(
|
||||
Renderer::Backend::Sampler::Filter::LINEAR,
|
||||
Renderer::Backend::Sampler::AddressMode::MIRRORED_REPEAT));
|
||||
|
||||
// Create depth textures
|
||||
m_ReflFboDepthTexture = Renderer::Backend::GL::CTexture::Create2D(
|
||||
m_ReflFboDepthTexture = backendDevice->CreateTexture2D("WaterReflectionDepthTexture",
|
||||
Renderer::Backend::Format::D32, m_RefTextureSize, m_RefTextureSize,
|
||||
Renderer::Backend::Sampler::MakeDefaultSampler(
|
||||
Renderer::Backend::Sampler::Filter::NEAREST,
|
||||
Renderer::Backend::Sampler::AddressMode::REPEAT));
|
||||
|
||||
m_RefrFboDepthTexture = Renderer::Backend::GL::CTexture::Create2D(
|
||||
m_RefrFboDepthTexture = backendDevice->CreateTexture2D("WaterRefractionDepthTexture",
|
||||
Renderer::Backend::Format::D32, m_RefTextureSize, m_RefTextureSize,
|
||||
Renderer::Backend::Sampler::MakeDefaultSampler(
|
||||
Renderer::Backend::Sampler::Filter::NEAREST,
|
||||
@ -252,14 +257,16 @@ int WaterManager::LoadWaterTextures()
|
||||
// Resize: Updates the fancy water textures.
|
||||
void WaterManager::Resize()
|
||||
{
|
||||
Renderer::Backend::GL::CDevice* backendDevice = g_VideoMode.GetBackendDevice();
|
||||
|
||||
// Create the Fancy Effects texture
|
||||
m_FancyTexture = Renderer::Backend::GL::CTexture::Create2D(
|
||||
m_FancyTexture = backendDevice->CreateTexture2D("WaterFancyTexture",
|
||||
Renderer::Backend::Format::R8G8B8A8, g_Renderer.GetWidth(), g_Renderer.GetHeight(),
|
||||
Renderer::Backend::Sampler::MakeDefaultSampler(
|
||||
Renderer::Backend::Sampler::Filter::LINEAR,
|
||||
Renderer::Backend::Sampler::AddressMode::REPEAT));
|
||||
|
||||
m_FancyTextureDepth = Renderer::Backend::GL::CTexture::Create2D(
|
||||
m_FancyTextureDepth = backendDevice->CreateTexture2D("WaterFancyDepthTexture",
|
||||
Renderer::Backend::Format::D32, g_Renderer.GetWidth(), g_Renderer.GetHeight(),
|
||||
Renderer::Backend::Sampler::MakeDefaultSampler(
|
||||
Renderer::Backend::Sampler::Filter::LINEAR,
|
||||
@ -273,8 +280,9 @@ void WaterManager::ReloadWaterNormalTextures()
|
||||
{
|
||||
swprintf_s(pathname, ARRAY_SIZE(pathname), L"art/textures/animated/water/%ls/normal00%02d.png", m_WaterType.c_str(), static_cast<int>(i) + 1);
|
||||
CTextureProperties textureProps(pathname);
|
||||
textureProps.SetWrap(GL_REPEAT);
|
||||
textureProps.SetMaxAnisotropy(4);
|
||||
textureProps.SetAddressMode(
|
||||
Renderer::Backend::Sampler::AddressMode::REPEAT);
|
||||
textureProps.SetAnisotropicFilter(true);
|
||||
|
||||
CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
|
||||
texture->Prefetch();
|
||||
@ -784,8 +792,10 @@ void WaterManager::RenderWaves(
|
||||
tech->GetGraphicsPipelineStateDesc());
|
||||
const CShaderProgramPtr& shader = tech->GetShader();
|
||||
|
||||
shader->BindTexture(str_waveTex, m_WaveTex);
|
||||
shader->BindTexture(str_foamTex, m_FoamTex);
|
||||
m_WaveTex->UploadBackendTextureIfNeeded(deviceCommandContext);
|
||||
m_FoamTex->UploadBackendTextureIfNeeded(deviceCommandContext);
|
||||
shader->BindTexture(str_waveTex, m_WaveTex->GetBackendTexture());
|
||||
shader->BindTexture(str_foamTex, m_FoamTex->GetBackendTexture());
|
||||
|
||||
shader->Uniform(str_time, (float)m_WaterTexTimer);
|
||||
shader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection());
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -27,12 +27,21 @@ namespace Backend
|
||||
enum class Format
|
||||
{
|
||||
UNDEFINED,
|
||||
R8G8B8,
|
||||
R8G8B8A8,
|
||||
|
||||
A8,
|
||||
L8,
|
||||
|
||||
D16,
|
||||
D24,
|
||||
D24_S8,
|
||||
D32
|
||||
D32,
|
||||
|
||||
BC1_RGB,
|
||||
BC1_RGBA,
|
||||
BC2,
|
||||
BC3
|
||||
};
|
||||
|
||||
} // namespace Backend
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -39,6 +39,7 @@ Desc MakeDefaultSampler(Filter filter, AddressMode addressMode)
|
||||
desc.addressModeW = addressMode;
|
||||
desc.anisotropyEnabled = false;
|
||||
desc.mipLODBias = 0.0f;
|
||||
desc.borderColor = CColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
return desc;
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "ps/ConfigDB.h"
|
||||
#include "ps/Profile.h"
|
||||
#include "renderer/backend/gl/DeviceCommandContext.h"
|
||||
#include "renderer/backend/gl/Texture.h"
|
||||
#include "scriptinterface/JSON.h"
|
||||
#include "scriptinterface/Object.h"
|
||||
#include "scriptinterface/ScriptInterface.h"
|
||||
@ -199,6 +200,16 @@ std::unique_ptr<CDevice> CDevice::Create(SDL_Window* window, const bool arb)
|
||||
|
||||
device->m_Backbuffer = CFramebuffer::CreateBackbuffer();
|
||||
|
||||
#if CONFIG2_GLES
|
||||
// Some GLES implementations have GL_EXT_texture_compression_dxt1
|
||||
// but that only supports DXT1 so we can't use it.
|
||||
device->m_HasS3TC = ogl_HaveExtensions(0, "GL_EXT_texture_compression_s3tc", nullptr) == 0;
|
||||
#else
|
||||
// Note: we don't bother checking for GL_S3_s3tc - it is incompatible
|
||||
// and irrelevant (was never widespread).
|
||||
device->m_HasS3TC = ogl_HaveExtensions(0, "GL_ARB_texture_compression", "GL_EXT_texture_compression_s3tc", nullptr) == 0;
|
||||
#endif
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
@ -599,7 +610,25 @@ void CDevice::Report(const ScriptRequest& rq, JS::HandleValue settings)
|
||||
|
||||
std::unique_ptr<CDeviceCommandContext> CDevice::CreateCommandContext()
|
||||
{
|
||||
return CDeviceCommandContext::Create(this);
|
||||
std::unique_ptr<CDeviceCommandContext> commandContet = CDeviceCommandContext::Create(this);
|
||||
m_ActiveCommandContext = commandContet.get();
|
||||
return commandContet;
|
||||
}
|
||||
|
||||
std::unique_ptr<CTexture> CDevice::CreateTexture(const char* name, const CTexture::Type type,
|
||||
const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount)
|
||||
{
|
||||
return CTexture::Create(this, name, type,
|
||||
format, width, height, defaultSamplerDesc, MIPLevelCount, sampleCount);
|
||||
}
|
||||
|
||||
std::unique_ptr<CTexture> CDevice::CreateTexture2D(const char* name,
|
||||
const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount)
|
||||
{
|
||||
return CreateTexture(name, CTexture::Type::TEXTURE_2D,
|
||||
format, width, height, defaultSamplerDesc, MIPLevelCount, sampleCount);
|
||||
}
|
||||
|
||||
void CDevice::Present()
|
||||
@ -624,6 +653,42 @@ void CDevice::Present()
|
||||
ONCE(LOGERROR("GL error %s (0x%04x) occurred", ogl_GetErrorName(err), err));
|
||||
}
|
||||
|
||||
bool CDevice::IsFormatSupported(const Format format) const
|
||||
{
|
||||
bool supported = false;
|
||||
switch (format)
|
||||
{
|
||||
case Format::UNDEFINED:
|
||||
break;
|
||||
|
||||
case Format::R8G8B8: FALLTHROUGH;
|
||||
case Format::R8G8B8A8: FALLTHROUGH;
|
||||
case Format::A8: FALLTHROUGH;
|
||||
case Format::L8:
|
||||
supported = true;
|
||||
break;
|
||||
|
||||
case Format::D16: FALLTHROUGH;
|
||||
case Format::D24: FALLTHROUGH;
|
||||
case Format::D32:
|
||||
supported = true;
|
||||
break;
|
||||
case Format::D24_S8:
|
||||
#if !CONFIG2_GLES
|
||||
supported = true;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case Format::BC1_RGB: FALLTHROUGH;
|
||||
case Format::BC1_RGBA: FALLTHROUGH;
|
||||
case Format::BC2: FALLTHROUGH;
|
||||
case Format::BC3:
|
||||
supported = m_HasS3TC;
|
||||
break;
|
||||
}
|
||||
return supported;
|
||||
}
|
||||
|
||||
} // namespace GL
|
||||
|
||||
} // namespace Backend
|
||||
|
@ -18,6 +18,7 @@
|
||||
#ifndef INCLUDED_RENDERER_BACKEND_GL_DEVICE
|
||||
#define INCLUDED_RENDERER_BACKEND_GL_DEVICE
|
||||
|
||||
#include "renderer/backend/Format.h"
|
||||
#include "renderer/backend/gl/Framebuffer.h"
|
||||
#include "scriptinterface/ScriptForward.h"
|
||||
|
||||
@ -38,6 +39,7 @@ namespace GL
|
||||
{
|
||||
|
||||
class CDeviceCommandContext;
|
||||
class CTexture;
|
||||
|
||||
class CDevice
|
||||
{
|
||||
@ -60,8 +62,20 @@ public:
|
||||
|
||||
std::unique_ptr<CDeviceCommandContext> CreateCommandContext();
|
||||
|
||||
CDeviceCommandContext* GetActiveCommandContext() { return m_ActiveCommandContext; }
|
||||
|
||||
std::unique_ptr<CTexture> CreateTexture(const char* name, const CTexture::Type type,
|
||||
const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount);
|
||||
|
||||
std::unique_ptr<CTexture> CreateTexture2D(const char* name,
|
||||
const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount = 1, const uint32_t sampleCount = 1);
|
||||
|
||||
void Present();
|
||||
|
||||
bool IsFormatSupported(const Format format) const;
|
||||
|
||||
private:
|
||||
CDevice();
|
||||
|
||||
@ -73,7 +87,14 @@ private:
|
||||
std::string m_DriverInformation;
|
||||
std::vector<std::string> m_Extensions;
|
||||
|
||||
// GL can have the only one command context at once.
|
||||
// TODO: remove as soon as we have no GL code outside backend, currently
|
||||
// it's used only as a helper for transition.
|
||||
CDeviceCommandContext* m_ActiveCommandContext = nullptr;
|
||||
|
||||
std::unique_ptr<CFramebuffer> m_Backbuffer;
|
||||
|
||||
bool m_HasS3TC = false;
|
||||
};
|
||||
|
||||
} // namespace GL
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "renderer/backend/gl/Mapping.h"
|
||||
#include "renderer/backend/gl/Texture.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
namespace Renderer
|
||||
@ -100,6 +101,10 @@ std::unique_ptr<CDeviceCommandContext> CDeviceCommandContext::Create(CDevice* de
|
||||
CDeviceCommandContext::CDeviceCommandContext(CDevice* device)
|
||||
: m_Device(device)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
for (std::pair<GLenum, GLuint>& unit : m_BoundTextures)
|
||||
unit.first = unit.second = 0;
|
||||
}
|
||||
|
||||
CDeviceCommandContext::~CDeviceCommandContext() = default;
|
||||
@ -116,7 +121,10 @@ void CDeviceCommandContext::UploadTexture(
|
||||
const uint32_t level, const uint32_t layer)
|
||||
{
|
||||
UploadTextureRegion(texture, format, data, dataSize,
|
||||
0, 0, texture->GetWidth(), texture->GetHeight(), level, layer);
|
||||
0, 0,
|
||||
std::max(1u, texture->GetWidth() >> level),
|
||||
std::max(1u, texture->GetHeight() >> level),
|
||||
level, layer);
|
||||
}
|
||||
|
||||
void CDeviceCommandContext::UploadTextureRegion(
|
||||
@ -127,24 +135,73 @@ void CDeviceCommandContext::UploadTextureRegion(
|
||||
const uint32_t level, const uint32_t layer)
|
||||
{
|
||||
ENSURE(texture);
|
||||
ENSURE(width > 0 && height > 0);
|
||||
if (texture->GetType() == CTexture::Type::TEXTURE_2D)
|
||||
{
|
||||
ENSURE(level == 0 && layer == 0);
|
||||
if (texture->GetFormat() == Format::R8G8B8A8 || texture->GetFormat() == Format::A8)
|
||||
ENSURE(layer == 0);
|
||||
if (texture->GetFormat() == Format::R8G8B8A8 ||
|
||||
texture->GetFormat() == Format::R8G8B8 ||
|
||||
texture->GetFormat() == Format::A8)
|
||||
{
|
||||
ENSURE(width > 0 && height > 0);
|
||||
ENSURE(texture->GetFormat() == dataFormat);
|
||||
const size_t bpp = dataFormat == Format::R8G8B8A8 ? 4 : 1;
|
||||
ENSURE(dataSize == width * height * bpp);
|
||||
ENSURE(xOffset + width <= texture->GetWidth());
|
||||
ENSURE(yOffset + height <= texture->GetHeight());
|
||||
size_t bytesPerPixel = 4;
|
||||
GLenum pixelFormat = GL_RGBA;
|
||||
switch (dataFormat)
|
||||
{
|
||||
case Format::R8G8B8A8:
|
||||
break;
|
||||
case Format::R8G8B8:
|
||||
pixelFormat = GL_RGB;
|
||||
bytesPerPixel = 3;
|
||||
break;
|
||||
case Format::A8:
|
||||
pixelFormat = GL_ALPHA;
|
||||
bytesPerPixel = 1;
|
||||
break;
|
||||
case Format::L8:
|
||||
pixelFormat = GL_LUMINANCE;
|
||||
bytesPerPixel = 1;
|
||||
break;
|
||||
default:
|
||||
debug_warn("Unexpected format.");
|
||||
break;
|
||||
}
|
||||
ENSURE(dataSize == width * height * bytesPerPixel);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture->GetHandle());
|
||||
ScopedBind scopedBind(this, GL_TEXTURE_2D, texture->GetHandle());
|
||||
glTexSubImage2D(GL_TEXTURE_2D, level,
|
||||
xOffset, yOffset, width, height,
|
||||
dataFormat == Format::R8G8B8A8 ? GL_RGBA : GL_ALPHA, GL_UNSIGNED_BYTE, data);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
pixelFormat, GL_UNSIGNED_BYTE, data);
|
||||
ogl_WarnIfError();
|
||||
}
|
||||
else if (
|
||||
texture->GetFormat() == Format::BC1_RGB ||
|
||||
texture->GetFormat() == Format::BC1_RGBA ||
|
||||
texture->GetFormat() == Format::BC2 ||
|
||||
texture->GetFormat() == Format::BC3)
|
||||
{
|
||||
ENSURE(xOffset == 0 && yOffset == 0);
|
||||
ENSURE(texture->GetFormat() == dataFormat);
|
||||
// TODO: add data size check.
|
||||
|
||||
GLenum internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
|
||||
switch (texture->GetFormat())
|
||||
{
|
||||
case Format::BC1_RGBA:
|
||||
internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
|
||||
break;
|
||||
case Format::BC2:
|
||||
internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
||||
break;
|
||||
case Format::BC3:
|
||||
internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ScopedBind scopedBind(this, GL_TEXTURE_2D, texture->GetHandle());
|
||||
glCompressedTexImage2DARB(GL_TEXTURE_2D, level, internalFormat, width, height, 0, dataSize, data);
|
||||
ogl_WarnIfError();
|
||||
}
|
||||
else
|
||||
@ -172,10 +229,8 @@ void CDeviceCommandContext::UploadTextureRegion(
|
||||
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
|
||||
};
|
||||
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, texture->GetHandle());
|
||||
ScopedBind scopedBind(this, GL_TEXTURE_CUBE_MAP, texture->GetHandle());
|
||||
glTexImage2D(targets[layer], level, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
||||
|
||||
ogl_WarnIfError();
|
||||
}
|
||||
else
|
||||
@ -185,9 +240,33 @@ void CDeviceCommandContext::UploadTextureRegion(
|
||||
debug_warn("Unsupported type");
|
||||
}
|
||||
|
||||
void CDeviceCommandContext::BindTexture(const uint32_t unit, const GLenum target, const GLuint handle)
|
||||
{
|
||||
ENSURE(unit < m_BoundTextures.size());
|
||||
#if CONFIG2_GLES
|
||||
ENSURE(target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP);
|
||||
#else
|
||||
ENSURE(target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP || target == GL_TEXTURE_2D_MULTISAMPLE);
|
||||
#endif
|
||||
if (m_BoundTextures[unit].first == target && m_BoundTextures[unit].second == handle)
|
||||
return;
|
||||
if (m_ActiveTextureUnit != unit)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + unit);
|
||||
m_ActiveTextureUnit = unit;
|
||||
}
|
||||
if (m_BoundTextures[unit].first != target && m_BoundTextures[unit].first && m_BoundTextures[unit].second)
|
||||
glBindTexture(m_BoundTextures[unit].first, 0);
|
||||
if (m_BoundTextures[unit].second != handle)
|
||||
glBindTexture(target, handle);
|
||||
m_BoundTextures[unit] = {target, handle};
|
||||
}
|
||||
|
||||
void CDeviceCommandContext::Flush()
|
||||
{
|
||||
ResetStates();
|
||||
|
||||
BindTexture(0, GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
void CDeviceCommandContext::ResetStates()
|
||||
@ -472,6 +551,22 @@ void CDeviceCommandContext::SetScissors(const uint32_t scissorCount, const Sciss
|
||||
m_ScissorCount = scissorCount;
|
||||
}
|
||||
|
||||
CDeviceCommandContext::ScopedBind::ScopedBind(
|
||||
CDeviceCommandContext* deviceCommandContext,
|
||||
const GLenum target, const GLuint handle)
|
||||
: m_DeviceCommandContext(deviceCommandContext),
|
||||
m_OldBindUnit(deviceCommandContext->m_BoundTextures[deviceCommandContext->m_ActiveTextureUnit])
|
||||
{
|
||||
m_DeviceCommandContext->BindTexture(
|
||||
m_DeviceCommandContext->m_ActiveTextureUnit, target, handle);
|
||||
}
|
||||
|
||||
CDeviceCommandContext::ScopedBind::~ScopedBind()
|
||||
{
|
||||
m_DeviceCommandContext->BindTexture(
|
||||
m_DeviceCommandContext->m_ActiveTextureUnit, m_OldBindUnit.first, m_OldBindUnit.second);
|
||||
}
|
||||
|
||||
} // namespace GL
|
||||
|
||||
} // namespace Backend
|
||||
|
@ -18,12 +18,15 @@
|
||||
#ifndef INCLUDED_RENDERER_GL_DEVICECOMMANDCONTEXT
|
||||
#define INCLUDED_RENDERER_GL_DEVICECOMMANDCONTEXT
|
||||
|
||||
#include "lib/ogl.h"
|
||||
#include "renderer/backend/Format.h"
|
||||
#include "renderer/backend/PipelineState.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
namespace Renderer
|
||||
{
|
||||
@ -70,6 +73,9 @@ public:
|
||||
};
|
||||
void SetScissors(const uint32_t scissorCount, const ScissorRect* scissors);
|
||||
|
||||
// TODO: remove direct binding after moving shaders.
|
||||
void BindTexture(const uint32_t unit, const GLenum target, const GLuint handle);
|
||||
|
||||
void Flush();
|
||||
|
||||
private:
|
||||
@ -91,6 +97,21 @@ private:
|
||||
uint32_t m_ScissorCount = 0;
|
||||
// GL2.1 doesn't support more than 1 scissor.
|
||||
std::array<ScissorRect, 1> m_Scissors;
|
||||
|
||||
uint32_t m_ActiveTextureUnit = 0;
|
||||
using BindUnit = std::pair<GLenum, GLuint>;
|
||||
std::array<BindUnit, 16> m_BoundTextures;
|
||||
class ScopedBind
|
||||
{
|
||||
public:
|
||||
ScopedBind(CDeviceCommandContext* deviceCommandContext,
|
||||
const GLenum target, const GLuint handle);
|
||||
|
||||
~ScopedBind();
|
||||
private:
|
||||
CDeviceCommandContext* m_DeviceCommandContext = nullptr;
|
||||
BindUnit m_OldBindUnit;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace GL
|
||||
|
@ -21,7 +21,6 @@
|
||||
|
||||
#include "lib/code_annotation.h"
|
||||
#include "lib/config2.h"
|
||||
#include "lib/res/graphics/ogl_tex.h"
|
||||
#include "ps/CLogger.h"
|
||||
#include "ps/ConfigDB.h"
|
||||
#include "renderer/backend/gl/Device.h"
|
||||
|
@ -21,8 +21,10 @@
|
||||
|
||||
#include "lib/code_annotation.h"
|
||||
#include "lib/config2.h"
|
||||
#include "lib/res/graphics/ogl_tex.h"
|
||||
#include "renderer/backend/gl/Device.h"
|
||||
#include "renderer/backend/gl/DeviceCommandContext.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace Renderer
|
||||
{
|
||||
@ -84,16 +86,8 @@ GLenum TypeToGLEnum(CTexture::Type type)
|
||||
} // anonymous namespace
|
||||
|
||||
// static
|
||||
std::unique_ptr<CTexture> CTexture::Create2D(const Format format,
|
||||
const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount)
|
||||
{
|
||||
return Create(Type::TEXTURE_2D, format, width, height, defaultSamplerDesc, MIPLevelCount, sampleCount);
|
||||
}
|
||||
|
||||
// static
|
||||
std::unique_ptr<CTexture> CTexture::Create(const Type type, const Format format,
|
||||
const uint32_t width, const uint32_t height,
|
||||
std::unique_ptr<CTexture> CTexture::Create(CDevice* device, const char* name,
|
||||
const Type type, const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount)
|
||||
{
|
||||
std::unique_ptr<CTexture> texture(new CTexture());
|
||||
@ -102,6 +96,7 @@ std::unique_ptr<CTexture> CTexture::Create(const Type type, const Format format,
|
||||
ENSURE(width > 0 && height > 0 && MIPLevelCount > 0);
|
||||
ENSURE((type == Type::TEXTURE_2D_MULTISAMPLE && sampleCount > 1) || sampleCount == 1);
|
||||
|
||||
texture->m_Device = device;
|
||||
texture->m_Format = format;
|
||||
texture->m_Type = type;
|
||||
texture->m_Width = width;
|
||||
@ -112,11 +107,9 @@ std::unique_ptr<CTexture> CTexture::Create(const Type type, const Format format,
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
glActiveTextureARB(GL_TEXTURE0);
|
||||
|
||||
const GLenum target = TypeToGLEnum(type);
|
||||
|
||||
glBindTexture(target, texture->m_Handle);
|
||||
texture->m_Device->GetActiveCommandContext()->BindTexture(0, target, texture->m_Handle);
|
||||
|
||||
// It's forbidden to set sampler state for multisample textures.
|
||||
if (type != Type::TEXTURE_2D_MULTISAMPLE)
|
||||
@ -145,7 +138,8 @@ std::unique_ptr<CTexture> CTexture::Create(const Type type, const Format format,
|
||||
glTexParameteri(target, GL_TEXTURE_LOD_BIAS, defaultSamplerDesc.mipLODBias);
|
||||
#endif // !CONFIG2_GLES
|
||||
|
||||
if (type == Type::TEXTURE_2D && defaultSamplerDesc.anisotropyEnabled && ogl_tex_has_anisotropy())
|
||||
// TODO: ask anisotropy feature from Device.
|
||||
if (type == Type::TEXTURE_2D && defaultSamplerDesc.anisotropyEnabled && ogl_HaveExtension("GL_EXT_texture_filter_anisotropic"))
|
||||
glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, defaultSamplerDesc.maxAnisotropy);
|
||||
|
||||
if (defaultSamplerDesc.addressModeU == Sampler::AddressMode::CLAMP_TO_BORDER ||
|
||||
@ -157,10 +151,9 @@ std::unique_ptr<CTexture> CTexture::Create(const Type type, const Format format,
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
ENSURE(MIPLevelCount == 1);
|
||||
|
||||
if (type == CTexture::Type::TEXTURE_2D)
|
||||
{
|
||||
bool compressedFormat = false;
|
||||
GLint internalFormat = GL_RGBA;
|
||||
// Actually pixel data is nullptr so it doesn't make sense to account
|
||||
// it, but in theory some buggy drivers might complain about invalid
|
||||
@ -174,11 +167,21 @@ std::unique_ptr<CTexture> CTexture::Create(const Type type, const Format format,
|
||||
break;
|
||||
case Format::R8G8B8A8:
|
||||
break;
|
||||
case Format::R8G8B8:
|
||||
internalFormat = GL_RGB;
|
||||
pixelFormat = GL_RGB;
|
||||
pixelType = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case Format::A8:
|
||||
internalFormat = GL_ALPHA;
|
||||
pixelFormat = GL_ALPHA;
|
||||
pixelType = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case Format::L8:
|
||||
internalFormat = GL_LUMINANCE;
|
||||
pixelFormat = GL_LUMINANCE;
|
||||
pixelType = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
#if CONFIG2_GLES
|
||||
// GLES requires pixel type == UNSIGNED_SHORT or UNSIGNED_INT for depth.
|
||||
case Format::D16: FALLTHROUGH;
|
||||
@ -213,11 +216,27 @@ std::unique_ptr<CTexture> CTexture::Create(const Type type, const Format format,
|
||||
pixelType = GL_UNSIGNED_INT_24_8_EXT;
|
||||
break;
|
||||
#endif
|
||||
case Format::BC1_RGB: FALLTHROUGH;
|
||||
case Format::BC1_RGBA: FALLTHROUGH;
|
||||
case Format::BC2: FALLTHROUGH;
|
||||
case Format::BC3:
|
||||
compressedFormat = true;
|
||||
break;
|
||||
}
|
||||
// glCompressedTexImage2D can't accept a null data, so we will initialize it during uploading.
|
||||
if (!compressedFormat)
|
||||
{
|
||||
for (uint32_t level = 0; level < MIPLevelCount; ++level)
|
||||
{
|
||||
glTexImage2D(target, level, internalFormat,
|
||||
std::max(1u, width >> level), std::max(1u, height >> level),
|
||||
0, pixelFormat, pixelType, nullptr);
|
||||
}
|
||||
}
|
||||
glTexImage2D(target, 0, internalFormat, width, height, 0, pixelFormat, pixelType, nullptr);
|
||||
}
|
||||
else if (type == CTexture::Type::TEXTURE_2D_MULTISAMPLE)
|
||||
{
|
||||
ENSURE(MIPLevelCount == 1);
|
||||
#if !CONFIG2_GLES
|
||||
if (format == Format::R8G8B8A8)
|
||||
{
|
||||
@ -236,7 +255,13 @@ std::unique_ptr<CTexture> CTexture::Create(const Type type, const Format format,
|
||||
|
||||
ogl_WarnIfError();
|
||||
|
||||
glBindTexture(target, 0);
|
||||
#if KHR_DEBUG_ENABLED
|
||||
glObjectLabel(GL_TEXTURE, texture->m_Handle, -1, name);
|
||||
#else
|
||||
UNUSED2(name);
|
||||
#endif
|
||||
|
||||
texture->m_Device->GetActiveCommandContext()->BindTexture(0, target, 0);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "renderer/backend/Sampler.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace Renderer
|
||||
{
|
||||
@ -33,6 +34,8 @@ namespace Backend
|
||||
namespace GL
|
||||
{
|
||||
|
||||
class CDevice;
|
||||
|
||||
/**
|
||||
* Represents a low-level GL texture, encapsulates all properties initialization.
|
||||
*/
|
||||
@ -48,17 +51,6 @@ public:
|
||||
|
||||
~CTexture();
|
||||
|
||||
// GL before 3.3 doesn't support sampler objects, so each texture should have
|
||||
// an own default sampler.
|
||||
static std::unique_ptr<CTexture> Create(const Type type, const Format format,
|
||||
const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount);
|
||||
|
||||
// Shorthands for particular types.
|
||||
static std::unique_ptr<CTexture> Create2D(const Format format,
|
||||
const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount = 1, const uint32_t sampleCount = 1);
|
||||
|
||||
GLuint GetHandle() const { return m_Handle; }
|
||||
|
||||
Type GetType() const { return m_Type; }
|
||||
@ -68,8 +60,18 @@ public:
|
||||
uint32_t GetMIPLevelCount() const { return m_MIPLevelCount; }
|
||||
|
||||
private:
|
||||
friend class CDevice;
|
||||
|
||||
CTexture();
|
||||
|
||||
CDevice* m_Device = nullptr;
|
||||
|
||||
// GL before 3.3 doesn't support sampler objects, so each texture should have
|
||||
// an own default sampler.
|
||||
static std::unique_ptr<CTexture> Create(CDevice* device, const char* name,
|
||||
const Type type, const Format format, const uint32_t width, const uint32_t height,
|
||||
const Sampler::Desc& defaultSamplerDesc, const uint32_t MIPLevelCount, const uint32_t sampleCount);
|
||||
|
||||
GLuint m_Handle = 0;
|
||||
|
||||
Type m_Type = Type::TEXTURE_2D;
|
||||
|
@ -112,13 +112,17 @@ void CCmpRallyPointRenderer::Init(const CParamNode& paramNode)
|
||||
if (CRenderer::IsInitialised())
|
||||
{
|
||||
CTextureProperties texturePropsBase(m_LineTexturePath);
|
||||
texturePropsBase.SetWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE);
|
||||
texturePropsBase.SetMaxAnisotropy(4.f);
|
||||
texturePropsBase.SetAddressMode(
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_BORDER,
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE);
|
||||
texturePropsBase.SetAnisotropicFilter(true);
|
||||
m_Texture = g_Renderer.GetTextureManager().CreateTexture(texturePropsBase);
|
||||
|
||||
CTextureProperties texturePropsMask(m_LineTextureMaskPath);
|
||||
texturePropsMask.SetWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE);
|
||||
texturePropsMask.SetMaxAnisotropy(4.f);
|
||||
texturePropsMask.SetAddressMode(
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_BORDER,
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE);
|
||||
texturePropsMask.SetAnisotropicFilter(true);
|
||||
m_TextureMask = g_Renderer.GetTextureManager().CreateTexture(texturePropsMask);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -563,12 +563,16 @@ void CCmpSelectable::UpdateDynamicOverlay(float frameOffset)
|
||||
|
||||
// Assuming we don't need the capability of swapping textures on-demand.
|
||||
CTextureProperties texturePropsBase(m_OverlayDescriptor.m_QuadTexture.c_str());
|
||||
texturePropsBase.SetWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE);
|
||||
texturePropsBase.SetMaxAnisotropy(4.f);
|
||||
texturePropsBase.SetAddressMode(
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_BORDER,
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE);
|
||||
texturePropsBase.SetAnisotropicFilter(true);
|
||||
|
||||
CTextureProperties texturePropsMask(m_OverlayDescriptor.m_QuadTextureMask.c_str());
|
||||
texturePropsMask.SetWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE);
|
||||
texturePropsMask.SetMaxAnisotropy(4.f);
|
||||
texturePropsMask.SetAddressMode(
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_BORDER,
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE);
|
||||
texturePropsMask.SetAnisotropicFilter(true);
|
||||
|
||||
m_UnitOverlay->m_Texture = g_Renderer.GetTextureManager().CreateTexture(texturePropsBase);
|
||||
m_UnitOverlay->m_TextureMask = g_Renderer.GetTextureManager().CreateTexture(texturePropsMask);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2021 Wildfire Games.
|
||||
/* Copyright (C) 2022 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -607,13 +607,17 @@ void CCmpTerritoryManager::UpdateBoundaryLines()
|
||||
std::vector<STerritoryBoundary> boundaries = ComputeBoundaries();
|
||||
|
||||
CTextureProperties texturePropsBase("art/textures/misc/territory_border.png");
|
||||
texturePropsBase.SetWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE);
|
||||
texturePropsBase.SetMaxAnisotropy(2.f);
|
||||
texturePropsBase.SetAddressMode(
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_BORDER,
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE);
|
||||
texturePropsBase.SetAnisotropicFilter(true);
|
||||
CTexturePtr textureBase = g_Renderer.GetTextureManager().CreateTexture(texturePropsBase);
|
||||
|
||||
CTextureProperties texturePropsMask("art/textures/misc/territory_border_mask.png");
|
||||
texturePropsMask.SetWrap(GL_CLAMP_TO_BORDER, GL_CLAMP_TO_EDGE);
|
||||
texturePropsMask.SetMaxAnisotropy(2.f);
|
||||
texturePropsMask.SetAddressMode(
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_BORDER,
|
||||
Renderer::Backend::Sampler::AddressMode::CLAMP_TO_EDGE);
|
||||
texturePropsMask.SetAnisotropicFilter(true);
|
||||
CTexturePtr textureMask = g_Renderer.GetTextureManager().CreateTexture(texturePropsMask);
|
||||
|
||||
CmpPtr<ICmpPlayerManager> cmpPlayerManager(GetSystemEntity());
|
||||
|
@ -91,11 +91,11 @@ sTerrainTexturePreview GetPreview(CTerrainTextureEntry* tex, size_t width, size_
|
||||
if (canUsePreview)
|
||||
{
|
||||
size_t level = 0;
|
||||
while ((texture.m_Width >> (level + 1)) >= width && (texture.m_Height >> (level + 1)) >= height)
|
||||
while ((texture.m_Width >> (level + 1)) >= width && (texture.m_Height >> (level + 1)) >= height && level < texture.GetMIPLevels().size())
|
||||
++level;
|
||||
// Extract the middle section (as a representative preview),
|
||||
// and copy into buffer.
|
||||
u8* data = texture.GetMipLevelData(level);
|
||||
u8* data = texture.GetMIPLevels()[level].data;
|
||||
ENSURE(data);
|
||||
const size_t levelWidth = texture.m_Width >> level;
|
||||
const size_t levelHeight = texture.m_Height >> level;
|
||||
|
Loading…
Reference in New Issue
Block a user