Permalink
Browse files

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.
  • Loading branch information...
aburgm committed Sep 17, 2015
1 parent 061305c commit 790219ac7eeb0be340c5063dff6944abcf520f7a
@@ -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
}
View
@@ -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);
-
- // 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);
-
- // 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);
+ // Select texture
+ glBindTexture(GL_TEXTURE_2D_ARRAY, hMaterialTexture);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ // 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_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 @@ class C4LandscapeRenderGL : public C4LandscapeRender
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;

0 comments on commit 790219a

Please sign in to comment.