forked from Mirrors/openclonk
Replace 3D texture in landscape shader by a 2D texture array
A texture array is conceptionally what should be used in this case. One advantage of this is that we don't have to generate mipmaps ourselves but can let the graphics driver take care of it. Same for selection of the mipmap level. This would even allow to choose different mipmap levels for different textures. This is a somewhat experimental change since it makes OpenGL 3.0 a hard requirement for OpenClonk. I expect that this is fine, but if this causes failures during landscape creation on common hardware/drivers we should revisit.shapetextures
parent
061305c0c7
commit
790219ac7e
|
@ -3,7 +3,7 @@
|
|||
// Input textures
|
||||
uniform sampler2D landscapeTex[2];
|
||||
uniform sampler2D scalerTex;
|
||||
uniform sampler3D materialTex;
|
||||
uniform sampler2DArray materialTex;
|
||||
|
||||
// Resolution of the landscape texture
|
||||
uniform vec2 resolution;
|
||||
|
@ -16,7 +16,7 @@ uniform sampler1D matMapTex;
|
|||
#else
|
||||
uniform float matMap[256];
|
||||
#endif
|
||||
uniform int materialDepth;
|
||||
uniform float materialDepth;
|
||||
uniform vec2 materialSize;
|
||||
|
||||
// Expected parameters for the scaler
|
||||
|
@ -35,9 +35,10 @@ float queryMatMap(int pix)
|
|||
{
|
||||
#ifndef NO_BROKEN_ARRAYS_WORKAROUND
|
||||
int idx = f2i(texture1D(matMapTex, float(pix) / 256.0 + 0.5 / 256.0).r);
|
||||
return float(idx) / 256.0 + 0.5 / float(materialDepth);
|
||||
return (float(idx) / 256.0 + 0.0 / materialDepth) * materialDepth;
|
||||
//return texture1D(matMapTex, float(pix) / 256.0 + 0.5 / 256.0).r;
|
||||
#else
|
||||
return matMap[pix];
|
||||
return matMap[pix] * materialDepth;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -70,14 +71,14 @@ slice(material)
|
|||
|
||||
// Get material pixels
|
||||
float materialIx = queryMatMap(f2i(landscapePx.r));
|
||||
vec4 materialPx = texture3D(materialTex, vec3(materialCoo, materialIx));
|
||||
vec4 normalPx = texture3D(materialTex, vec3(materialCoo, materialIx+0.5));
|
||||
vec4 materialPx = texture(materialTex, vec3(materialCoo, materialIx));
|
||||
vec4 normalPx = texture(materialTex, vec3(materialCoo, materialIx+0.5*materialDepth));
|
||||
|
||||
// Same for second pixel, but we'll simply use the first normal
|
||||
#ifdef OC_HAVE_2PX
|
||||
float materialIx2 = queryMatMap(f2i(landscapePx2.r));
|
||||
vec4 materialPx2 = texture3D(materialTex, vec3(materialCoo, materialIx2));
|
||||
vec4 normalPx2 = texture3D(materialTex, vec3(materialCoo, materialIx2+0.5));
|
||||
vec4 materialPx2 = texture(materialTex, vec3(materialCoo, materialIx2));
|
||||
vec4 normalPx2 = texture(materialTex, vec3(materialCoo, materialIx2+0.5*materialDepth));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "C4Surface.h"
|
||||
|
||||
// Shader version
|
||||
const int C4Shader_Version = 120; // GLSL 1.20 / OpenGL 2.1
|
||||
const int C4Shader_Version = 130; // GLSL 1.30 / OpenGL 3.0
|
||||
|
||||
// Maximum number of texture coordinates
|
||||
const int C4Shader_MaxTexCoords = 8;
|
||||
|
|
|
@ -54,7 +54,7 @@ const char *const SEPERATOR_TEXTURE = "--SEP--";
|
|||
C4LandscapeRenderGL::C4LandscapeRenderGL()
|
||||
{
|
||||
ZeroMem(Surfaces, sizeof(Surfaces));
|
||||
ZeroMem(hMaterialTexture, sizeof(hMaterialTexture));
|
||||
hMaterialTexture = 0;
|
||||
}
|
||||
|
||||
C4LandscapeRenderGL::~C4LandscapeRenderGL()
|
||||
|
@ -135,8 +135,8 @@ void C4LandscapeRenderGL::Clear()
|
|||
delete Surfaces[i];
|
||||
Surfaces[i] = NULL;
|
||||
}
|
||||
glDeleteTextures(C4LR_MipMapCount, hMaterialTexture);
|
||||
std::fill_n(hMaterialTexture, C4LR_MipMapCount, 0);
|
||||
if (hMaterialTexture) glDeleteTextures(1, &hMaterialTexture);
|
||||
hMaterialTexture = 0;
|
||||
}
|
||||
|
||||
bool C4LandscapeRenderGL::InitLandscapeTexture()
|
||||
|
@ -170,9 +170,7 @@ bool C4LandscapeRenderGL::InitMaterialTexture(C4TextureMap *pTexs)
|
|||
AddTexturesFromMap(pTexs);
|
||||
|
||||
// Determine depth to use
|
||||
iMaterialTextureDepth = 1;
|
||||
while(iMaterialTextureDepth < 2*int32_t(MaterialTextureMap.size()))
|
||||
iMaterialTextureDepth <<= 1;
|
||||
iMaterialTextureDepth = 2*MaterialTextureMap.size();
|
||||
int32_t iNormalDepth = iMaterialTextureDepth / 2;
|
||||
|
||||
// Find the largest texture
|
||||
|
@ -186,15 +184,16 @@ bool C4LandscapeRenderGL::InitMaterialTexture(C4TextureMap *pTexs)
|
|||
|
||||
// Get size for our textures. We might be limited by hardware
|
||||
int iTexWdt = pRefSfc->Wdt, iTexHgt = pRefSfc->Hgt;
|
||||
GLint iMaxTexSize;
|
||||
glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &iMaxTexSize);
|
||||
GLint iMaxTexSize, iMaxTexLayers;
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &iMaxTexSize);
|
||||
glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &iMaxTexLayers);
|
||||
if (iTexWdt > iMaxTexSize || iTexHgt > iMaxTexSize)
|
||||
{
|
||||
iTexWdt = Min(iTexWdt, iMaxTexSize);
|
||||
iTexHgt = Min(iTexHgt, iMaxTexSize);
|
||||
LogF(" gl: Material textures too large, GPU only supports %dx%d! Cropping might occur!", iMaxTexSize, iMaxTexSize);
|
||||
}
|
||||
if(iMaterialTextureDepth >= iMaxTexSize)
|
||||
if(iMaterialTextureDepth >= iMaxTexLayers)
|
||||
{
|
||||
LogF(" gl: Too many material textures! GPU only supports 3D texture depth of %d!", iMaxTexSize);
|
||||
return false;
|
||||
|
@ -265,70 +264,42 @@ bool C4LandscapeRenderGL::InitMaterialTexture(C4TextureMap *pTexs)
|
|||
// Clear error error(s?)
|
||||
while(glGetError()) {}
|
||||
|
||||
// Alloc 3D textures
|
||||
glEnable(GL_TEXTURE_3D);
|
||||
glGenTextures(C4LR_MipMapCount, hMaterialTexture);
|
||||
|
||||
// Generate textures (mipmaps too!)
|
||||
// Alloc 2D texture array
|
||||
//glEnable(GL_TEXTURE_2D_ARRAY);
|
||||
glGenTextures(1, &hMaterialTexture);
|
||||
|
||||
// Generate textures
|
||||
int iSizeSum = 0;
|
||||
BYTE *pLastData = new BYTE [iSize / 4];
|
||||
for(int iMMLevel = 0; iMMLevel < C4LR_MipMapCount; iMMLevel++)
|
||||
{
|
||||
|
||||
// Scale the texture down for mip-mapping
|
||||
if(iMMLevel) {
|
||||
BYTE *pOut = pData;
|
||||
BYTE *pIn[4] = {
|
||||
pLastData, pLastData + iBytesPP,
|
||||
pLastData + iBytesPP * iTexWdt, pLastData + iBytesPP * iTexWdt + iBytesPP
|
||||
};
|
||||
for (int i = 0; i < iMaterialTextureDepth; ++i)
|
||||
for (int y = 0; y < iTexHgt / 2; ++y)
|
||||
{
|
||||
for (int x = 0; x < iTexWdt / 2; ++x)
|
||||
{
|
||||
for (int j = 0; j < iBytesPP; j++)
|
||||
{
|
||||
unsigned int s = 0;
|
||||
s += *pIn[0]++; s += 3 * *pIn[1]++; s += 3 * *pIn[2]++; s += *pIn[3]++;
|
||||
*pOut++ = BYTE(s / 8);
|
||||
}
|
||||
pIn[0] += iBytesPP; pIn[1] += iBytesPP; pIn[2] += iBytesPP; pIn[3] += iBytesPP;
|
||||
}
|
||||
pIn[0] += iBytesPP * iTexWdt; pIn[1] += iBytesPP * iTexWdt;
|
||||
pIn[2] += iBytesPP * iTexWdt; pIn[3] += iBytesPP * iTexWdt;
|
||||
}
|
||||
iTexWdt /= 2; iTexHgt /= 2;
|
||||
}
|
||||
|
||||
// Select texture
|
||||
glBindTexture(GL_TEXTURE_3D, hMaterialTexture[iMMLevel]);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
// Select texture
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, hMaterialTexture);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
// We fully expect to tile these
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
// We fully expect to tile these
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_GENERATE_MIPMAP, GL_TRUE);
|
||||
|
||||
// Make it happen!
|
||||
glTexImage3D(GL_TEXTURE_3D, 0, 4, iTexWdt, iTexHgt, iMaterialTextureDepth, 0, GL_BGRA,
|
||||
iBytesPP == 2 ? GL_UNSIGNED_SHORT_4_4_4_4_REV : GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
pData);
|
||||
// Make it happen!
|
||||
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, 4, iTexWdt, iTexHgt, iMaterialTextureDepth, 0, GL_BGRA,
|
||||
iBytesPP == 2 ? GL_UNSIGNED_SHORT_4_4_4_4_REV : GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
pData);
|
||||
|
||||
// Exchange buffers
|
||||
BYTE *tmp = pLastData;
|
||||
pLastData = pData;
|
||||
pData = tmp;
|
||||
// Exchange buffers
|
||||
BYTE *tmp = pLastData;
|
||||
pLastData = pData;
|
||||
pData = tmp;
|
||||
|
||||
// Statistics
|
||||
iSizeSum += iTexWdt * iTexHgt * iMaterialTextureDepth * iBytesPP;
|
||||
}
|
||||
// Statistics
|
||||
iSizeSum += iTexWdt * iTexHgt * iMaterialTextureDepth * iBytesPP;
|
||||
|
||||
// Dispose of data
|
||||
delete [] pData;
|
||||
delete [] pLastData;
|
||||
glDisable(GL_TEXTURE_3D);
|
||||
//glDisable(GL_TEXTURE_3D);
|
||||
|
||||
// Check whether we were successful
|
||||
if(int err = glGetError())
|
||||
|
@ -338,10 +309,9 @@ bool C4LandscapeRenderGL::InitMaterialTexture(C4TextureMap *pTexs)
|
|||
}
|
||||
|
||||
// Announce the good news
|
||||
LogF(" gl: Texturing uses %d slots at %dx%d, %d levels (%d MB total)",
|
||||
LogF(" gl: Texturing uses %d slots at %dx%d (%d MB total)",
|
||||
static_cast<int>(MaterialTextureMap.size()),
|
||||
iMaterialWidth, iMaterialHeight,
|
||||
C4LR_MipMapCount,
|
||||
iSizeSum / 1000000);
|
||||
|
||||
return true;
|
||||
|
@ -852,7 +822,7 @@ void C4LandscapeRenderGL::BuildMatMap(GLfloat *pFMap, GLubyte *pIMap)
|
|||
}
|
||||
|
||||
// Assign texture
|
||||
if(pFMap) pFMap[pix] = (gTexCoo + 0.5) / iMaterialTextureDepth;
|
||||
if(pFMap) pFMap[pix] = gTexCoo / iMaterialTextureDepth;
|
||||
if(pIMap) pIMap[pix] = int((gTexCoo * 256.0 / iMaterialTextureDepth) + 0.5);
|
||||
}
|
||||
}
|
||||
|
@ -896,7 +866,9 @@ void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo, const C4FoWRegion *Ligh
|
|||
BuildMatMap(MatMap, NULL);
|
||||
ShaderCall.SetUniform1fv(C4LRU_MatMap, 256, MatMap);
|
||||
}
|
||||
ShaderCall.SetUniform1i(C4LRU_MaterialDepth, iMaterialTextureDepth);
|
||||
|
||||
float fMaterialTextureDepth = iMaterialTextureDepth;
|
||||
ShaderCall.SetUniform1f(C4LRU_MaterialDepth, fMaterialTextureDepth);
|
||||
ShaderCall.SetUniform2f(C4LRU_MaterialSize,
|
||||
float(iMaterialWidth) / ::Game.C4S.Landscape.MaterialZoom,
|
||||
float(iMaterialHeight) / ::Game.C4S.Landscape.MaterialZoom);
|
||||
|
@ -951,13 +923,7 @@ void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo, const C4FoWRegion *Ligh
|
|||
}
|
||||
if(ShaderCall.AllocTexUnit(C4LRU_MaterialTex))
|
||||
{
|
||||
// Decide which mip-map level to use
|
||||
double z = 0.5; int iMM = 0;
|
||||
while(pGL->Zoom < z * ::Game.C4S.Landscape.MaterialZoom && iMM + 1 <C4LR_MipMapCount)
|
||||
{ z /= 2; iMM++; }
|
||||
glBindTexture(GL_TEXTURE_3D, hMaterialTexture[iMM]);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, hMaterialTexture);
|
||||
}
|
||||
if(ShaderCall.AllocTexUnit(C4LRU_MatMapTex))
|
||||
{
|
||||
|
|
|
@ -62,9 +62,6 @@ const int C4LR_BytesPerPx = 3;
|
|||
const int C4LR_BytesPerSurface = 4;
|
||||
const int C4LR_SurfaceCount = (C4LR_ByteCount + C4LR_BytesPerSurface - 1) / C4LR_BytesPerSurface;
|
||||
|
||||
// How many mip-map levels should be used at maximum?
|
||||
const int C4LR_MipMapCount = 6;
|
||||
|
||||
class C4Landscape; class C4TextureMap;
|
||||
|
||||
class C4LandscapeRender
|
||||
|
@ -112,9 +109,9 @@ private:
|
|||
static const char *UniformNames[];
|
||||
GLenum hLandscapeTexCoord, hLightTexCoord;
|
||||
|
||||
// 3D texture of material textures
|
||||
GLuint hMaterialTexture[C4LR_MipMapCount];
|
||||
// material texture positions in 3D texture
|
||||
// 2D texture array of material textures
|
||||
GLuint hMaterialTexture;
|
||||
// material texture positions in texture array
|
||||
std::vector<StdCopyStrBuf> MaterialTextureMap;
|
||||
// depth of material texture in layers
|
||||
int32_t iMaterialTextureDepth;
|
||||
|
|
Loading…
Reference in New Issue