Introduced a woraround for missing array support. Some major clearnups.

Now especially has a few debugging options that make it easier to
spot when texture coordinates are not calculated accurately. Use
DEBUG_SEPERATOR_TEXTURES to add nasty stripe textures that should
(in theory) never be visible. Set DEBUG_SOLID_COLOR_TEXTURES on top
of that to replace all materials with dark solid colors to make the
stripes more clearly visible.
Peter Wortmann 2011-05-28 15:18:40 +01:00
parent d672211ef5
commit 8204c8d644
3 changed files with 219 additions and 94 deletions

View File

@ -10,7 +10,9 @@ uniform sampler3D materialTex;
uniform vec2 resolution;
// Texture map
uniform float matTexMap[256];
uniform float matMap[256];
uniform sampler1D matMapTex;
uniform int materialDepth;
// Expected parameters for the scaler
const vec2 scalerStepX = vec2(1.0 / 8.0, 0.0);
@ -18,6 +20,15 @@ const vec2 scalerStepY = vec2(0.0, 1.0 / 32.0);
const vec2 scalerOffset = vec2(0.0, 0.0) + scalerStepX / 3.0 + scalerStepY / 3.0;
const vec2 scalerPixel = vec2(scalerStepX.x, scalerStepY.y) / 3.0;
float queryMatMap(int pix)
{
#ifdef BROKEN_ARRAYS_WORKAROUND
return texture1D(matMapTex, float(pix) / 256.0 + 0.5 / 256.0).r * 255.0 / float(materialDepth) + 0.5 / float(materialDepth);
#else
return matMap[pix];
#endif
}
void main()
{
// full pixel steps in the landscape texture (depends on landscape resolution)
@ -59,13 +70,13 @@ void main()
if(texture2D(landscapeTex[0], centerCoo + fullStepX + fullStepY).r == lpx.r)
scalerCoo += 16.0 * scalerStepY;
vec4 spx = texture2D(scalerTex, scalerCoo, 0.0);
vec4 spx = texture2D(scalerTex, scalerCoo);
// Material pixel
float mix = matTexMap[int(lpx.r * 255.0)];
vec4 mpx = texture3D(materialTex, vec3(gl_TexCoord[0].st * resolution / vec2(512.0, 512.0) * vec2(3.0, 3.0), mix));
float omix = matTexMap[int(lopx.r * 255.0)];
vec4 ompx = texture3D(materialTex, vec3(gl_TexCoord[0].st * resolution / vec2(512.0, 512.0) * vec2(3.0, 3.0), omix));
// Get material pixels
float mi = queryMatMap(int(lpx.r * 255.0));
vec4 mpx = texture3D(materialTex, vec3(gl_TexCoord[0].st * resolution / vec2(512.0, 512.0) * vec2(3.0, 3.0), mi));
float omi = queryMatMap(int(lopx.r * 255.0));
vec4 ompx = texture3D(materialTex, vec3(gl_TexCoord[0].st * resolution / vec2(512.0, 512.0) * vec2(3.0, 3.0), omi));
// Brightness
vec2 normal = (1.5 * rlpx.yz - vec2(1.0, 1.0));
@ -73,7 +84,8 @@ void main()
float bright = ambientBright * (1.0 + dot(normal, vec2(0.0, -1.0)));
float bright2 = ambientBright;
gl_FragColor = vec4(
bright * spx.r * mpx.rgb + bright2 * (1.0-spx.r) * ompx.rgb,
spx.r * mpx.a + (1.0-spx.r) * ompx.a);
gl_FragColor = mix(
vec4(bright2 * ompx.rgb, ompx.a),
vec4(bright * mpx.rgb, mpx.a),
spx.r);
}

View File

@ -16,20 +16,53 @@
// Automatically reload shaders when changed at runtime?
#define AUTO_RELOAD_SHADERS
// Generate seperator textures into 3D texture so we can make sure that
// we are addressing textures using the right coordinates
#define DEBUG_SEPERATOR_TEXTURES
#ifdef _DEBUG
// Replace all textures by solid colors
//#define DEBUG_SOLID_COLOR_TEXTURES
#endif
// How much to look into each direction for bias
const int C4LR_BiasDistanceX = 8;
const int C4LR_BiasDistanceY = 8;
// Workarounds to try if shader fails to compile
const char *C4LR_ShaderWorkarounds[] = {
"",
"#define BROKEN_ARRAYS_WORKAROUND\n",
};
const int C4LR_ShaderWorkaroundCount = sizeof(C4LR_ShaderWorkarounds) / sizeof(*C4LR_ShaderWorkarounds);
// Map of uniforms to names in shader
static const char *GetUniformName(int iUniform)
{
switch(iUniform)
{
case C4LRU_LandscapeTex: return "landscapeTex";
case C4LRU_ScalerTex: return "scalerTex";
case C4LRU_MaterialTex: return "materialTex";
case C4LRU_Resolution: return "resolution";
case C4LRU_MatMap: return "matMap";
case C4LRU_MatMapTex: return "matMapTex";
case C4LRU_MaterialDepth:return "materialDepth";
}
assert(false);
return "mysterious";
}
C4LandscapeRenderGL::C4LandscapeRenderGL()
: iLandscapeShaderTime(0),
hVert(0), hFrag(0), hProg(0),
hLandscapeUnit(0), hScalerUnit(0), hMaterialUnit(0),
hResolutionUniform(0), hMatTexMapUniform(0),
iTexCount(0)
{
ZeroMem(MatTexMap, sizeof(MatTexMap));
ZeroMem(Surfaces, sizeof(Surfaces));
ZeroMem(hMaterialTexture, sizeof(hMaterialTexture));
ZeroMem(hUniforms, sizeof(hUniforms));
}
C4LandscapeRenderGL::~C4LandscapeRenderGL()
@ -55,6 +88,7 @@ bool C4LandscapeRenderGL::Init(int32_t iWidth, int32_t iHeight, C4TextureMap *pT
// Safe info
this->iWidth = iWidth;
this->iHeight = iHeight;
this->pTexs = pTexs;
// Count the textures
iTexCount = 0;
@ -82,23 +116,6 @@ bool C4LandscapeRenderGL::Init(int32_t iWidth, int32_t iHeight, C4TextureMap *pT
return false;
}
// Build material-texture map (depth parameter where to find appropriate texture)
for(int pix = 0; pix < 256; pix++)
{
// Look up indexed entry
const C4TexMapEntry *pEntry = pTexs->GetEntry(PixCol2Tex(BYTE(pix)));
if(!pEntry->GetTextureName())
{
// Textures over iTexCount are transparent
MatTexMap[pix] = (float(iTexCount) + 0.5) / iMaterialTextureDepth;
continue;
}
// Assign texture
int32_t iTexIndex = pTexs->GetTextureIndex(pEntry->GetTextureName());
if(iTexIndex < 0) iTexIndex = 0;
MatTexMap[pix] = (float(iTexIndex) + 0.5) / iMaterialTextureDepth;
}
return true;
}
@ -126,12 +143,16 @@ void C4LandscapeRenderGL::Clear()
bool C4LandscapeRenderGL::InitMaterialTexture(C4TextureMap *pTexs)
{
#ifdef DEBUG_SEPERATOR_TEXTURES
int iTexCountP = 2 * iTexCount;
#else
int iTexCountP = iTexCount;
#endif
// Determine depth to use. Lowest power of 2 that can contain
// all textures plus sky (= empty). Might have more complicated
// Determine depth to use. Might have more complicated
// mappings in future.
iMaterialTextureDepth = 1;
while(iMaterialTextureDepth < iTexCount + 1)
while(iMaterialTextureDepth < iTexCountP + 1)
iMaterialTextureDepth <<= 1;
// Find first (actual) texture
@ -151,8 +172,29 @@ bool C4LandscapeRenderGL::InitMaterialTexture(C4TextureMap *pTexs)
for(int i = 0; i < iMaterialTextureDepth; i++)
{
BYTE *p = pData + i * iTexSize;
#ifdef DEBUG_SEPERATOR_TEXTURES
if (i % 2)
{
// Make every second texture ugly stripes
DWORD *texdata = reinterpret_cast<DWORD *>(p);
for (int y = 0; y < iTexHgt; ++y)
for (int x = 0; x < iTexWdt; ++x)
*texdata++ = ((x + y) % 32 < 16 ? RGBA(255, 0, 0, 255) : RGBA(0, 255, 255, 255));
continue;
}
int iTex = i / 2;
#else
int iTex = i;
#endif
#ifdef DEBUG_SOLID_COLOR_TEXTURES
DWORD *texdata = reinterpret_cast<DWORD *>(p);
for (int y = 0; y < iTexHgt; ++y)
for (int x = 0; x < iTexWdt; ++x)
*texdata++ = RGBA((iTex & 48), (iTex & 3) * 16, (i & 12) * 4, 255);
continue;
#endif
C4Texture *pTex; CSurface *pSurface;
if(!(pTex = pTexs->GetTexture(pTexs->GetTexture(i))))
if(!(pTex = pTexs->GetTexture(pTexs->GetTexture(iTex))))
{}
else if(!(pSurface = pTex->Surface32))
{}
@ -162,7 +204,7 @@ bool C4LandscapeRenderGL::InitMaterialTexture(C4TextureMap *pTexs)
{
// Size recheck
if(pSurface->Wdt != iTexWdt || pSurface->Hgt != iTexHgt)
LogF(" gl: texture %s size mismatch (%dx%d vs %dx%d)!", pTexs->GetTexture(i), pSurface->Wdt, pSurface->Hgt, iTexWdt, iTexHgt);
LogF(" gl: texture %s size mismatch (%dx%d vs %dx%d)!", pTexs->GetTexture(iTex), pSurface->Wdt, pSurface->Hgt, iTexWdt, iTexHgt);
// Copy bytes
DWORD *texdata = reinterpret_cast<DWORD *>(p);
pSurface->Lock();
@ -198,7 +240,7 @@ bool C4LandscapeRenderGL::InitMaterialTexture(C4TextureMap *pTexs)
pLastData, pLastData + iBytesPP,
pLastData + iBytesPP * iTexWdt, pLastData + iBytesPP * iTexWdt + iBytesPP
};
for (int i = 0; i <= iTexCount; ++i)
for (int i = 0; i <= iTexCountP; ++i)
for (int y = 0; y < iTexHgt / 2; ++y)
{
for (int x = 0; x < iTexWdt / 2; ++x)
@ -391,19 +433,24 @@ int C4LandscapeRenderGL::GetObjectStatus(GLhandleARB hObj, GLenum type)
GLhandleARB C4LandscapeRenderGL::CreateShader(GLenum iShaderType, const char *szWhat, const char *szCode)
{
const char *szCodes[1] = { szCode };
GLhandleARB hShader = glCreateShaderObjectARB(iShaderType);
glShaderSourceARB(hShader, 1, szCodes, 0);
glCompileShaderARB(hShader);
// Try all workarounds until one works
for(int iWorkaround = 0; iWorkaround < C4LR_ShaderWorkaroundCount; iWorkaround++)
{
// Build code
const char *szCodes[2] = { C4LR_ShaderWorkarounds[iWorkaround], szCode };
GLhandleARB hShader = glCreateShaderObjectARB(iShaderType);
glShaderSourceARB(hShader, 2, szCodes, 0);
glCompileShaderARB(hShader);
// Dump any information to log
DumpInfoLog(szWhat, hShader);
// Dump any information to log
DumpInfoLog(szWhat, hShader);
// Success?
if(GetObjectStatus(hShader, GL_OBJECT_COMPILE_STATUS_ARB) != 1)
return 0;
else
return hShader;
// Success?
if(GetObjectStatus(hShader, GL_OBJECT_COMPILE_STATUS_ARB) == 1)
return hShader;
}
// Did not work :/
return 0;
}
bool C4LandscapeRenderGL::InitShaders()
@ -439,12 +486,10 @@ bool C4LandscapeRenderGL::InitShaders()
return false;
}
// Get variable locations
hLandscapeUnit = glGetUniformLocationARB(hProg, "landscapeTex");
hScalerUnit = glGetUniformLocationARB(hProg, "scalerTex");
hMaterialUnit = glGetUniformLocationARB(hProg, "materialTex");
hResolutionUniform = glGetUniformLocationARB(hProg, "resolution");
hMatTexMapUniform = glGetUniformLocationARB(hProg, "matTexMap");
// Get uniform locations. Note this is expected to fail for a few of them
// because the respective uniforms got optimized out!
for (int i = 0; i < C4LRU_Count; i++)
hUniforms[i] = glGetUniformLocationARB(hProg, GetUniformName(i));
// Success?
if(int err = glGetError())
@ -467,8 +512,7 @@ void C4LandscapeRenderGL::ClearShaders()
glDeleteObjectARB(hProg);
hFrag = hVert = hProg = 0;
hLandscapeUnit = hScalerUnit = hMaterialUnit = 0;
hResolutionUniform = hMatTexMapUniform = 0;
ZeroMem(hUniforms, sizeof(hUniforms));
}
bool C4LandscapeRenderGL::LoadShaders(C4GroupSet *pGroups)
@ -500,16 +544,8 @@ bool C4LandscapeRenderGL::LoadScaler(C4GroupSet *pGroups)
return fctScaler.Load(*pGroup, C4CFN_LandscapeScaler);
}
void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo)
void C4LandscapeRenderGL::RefreshShaders()
{
// Must have GL and be initialized
if(!pGL && !hProg) return;
// prepare rendering to surface
CSurface *sfcTarget = cgo.Surface;
if (!pGL->PrepareRendering(sfcTarget)) return;
#ifdef AUTO_RELOAD_SHADERS
// File changed?
if(!LandscapeShaderPath.isNull() &&
FileTime(LandscapeShaderPath.getData()) != iLandscapeShaderTime)
@ -526,6 +562,46 @@ void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo)
InitShaders();
iLandscapeShaderTime = FileTime(LandscapeShaderPath.getData());
}
}
void C4LandscapeRenderGL::BuildMatMap(GLfloat *pFMap, GLubyte *pIMap)
{
// TODO: Still merely an inefficient placeholder for things to come...
// Build material-texture map (depth parameter where to find appropriate texture)
for(int pix = 0; pix < 256; pix++)
{
// Look up indexed entry
const C4TexMapEntry *pEntry = pTexs->GetEntry(PixCol2Tex(BYTE(pix)));
if(!pEntry->GetTextureName())
{
// Textures over iTexCount are transparent
if(pFMap) pFMap[pix] = (float(iMaterialTextureDepth) - 1.5) / iMaterialTextureDepth;
if(pIMap) pIMap[pix] = iMaterialTextureDepth - 2;
continue;
}
// Assign texture
int32_t iTexIndex = pTexs->GetTextureIndex(pEntry->GetTextureName());
if(iTexIndex < 0) iTexIndex = 0;
#ifdef DEBUG_SEPERATOR_TEXTURES
iTexIndex *= 2;
#endif
if(pFMap) pFMap[pix] = (float(iTexIndex) + 0.5) / iMaterialTextureDepth;
if(pIMap) pIMap[pix] = iTexIndex;
}
}
void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo)
{
// Must have GL and be initialized
if(!pGL && !hProg) return;
// prepare rendering to surface
CSurface *sfcTarget = cgo.Surface;
if (!pGL->PrepareRendering(sfcTarget)) return;
#ifdef AUTO_RELOAD_SHADERS
RefreshShaders();
#endif // AUTO_RELOAD_SHADERS
// Clear error(s?)
@ -535,42 +611,55 @@ void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo)
glUseProgramObjectARB(hProg);
// Bind data
glUniform1fvARB(hMatTexMapUniform, 256, MatTexMap);
glUniform2fARB(hResolutionUniform, iWidth, iHeight);
// Bind textures
int iUnit = 0; int iMaterialUnit = -1;
if(hScalerUnit >= 0)
if (hUniforms[C4LRU_Resolution] != -1)
glUniform2fARB(hUniforms[C4LRU_Resolution], iWidth, iHeight);
if (hUniforms[C4LRU_MatMap] != -1)
{
glUniform1iARB(hScalerUnit, iUnit);
glActiveTexture(GL_TEXTURE0 + iUnit);
iUnit++;
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, fctScaler.Surface->ppTex[0]->texName);
GLfloat MatMap[256];
BuildMatMap(MatMap, NULL);
glUniform1fvARB(hUniforms[C4LRU_MatMap], 256, MatMap);
}
if(hMaterialUnit >= 0)
if (hUniforms[C4LRU_MaterialDepth] != -1)
glUniform1iARB(hUniforms[C4LRU_MaterialDepth], iMaterialTextureDepth);
// Setup facilities for texture unit allocation (gimme local functions...)
int iUnit = 0; int iUnitMap[32]; ZeroMem(iUnitMap, sizeof(iUnitMap));
#define ALLOC_UNIT(hUniform, iType) do { \
if(hUniform != -1) glUniform1iARB(hUniform, iUnit); \
glActiveTexture(GL_TEXTURE0 + iUnit); \
iUnitMap[iUnit] = iType; \
glEnable(iType); \
iUnit++; \
assert(iUnit < 32); \
} while(false)
// Start binding textures
if(hUniforms[C4LRU_ScalerTex] != -1)
{
iMaterialUnit = iUnit;
glUniform1iARB(hMaterialUnit, iUnit);
glActiveTexture(GL_TEXTURE0 + iUnit);
iUnit++;
glEnable(GL_TEXTURE_3D);
ALLOC_UNIT(hUniforms[C4LRU_ScalerTex], GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, fctScaler.Surface->ppTex[0]->texName);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
if(hUniforms[C4LRU_MaterialTex] != -1)
{
ALLOC_UNIT(hUniforms[C4LRU_MaterialTex], GL_TEXTURE_3D);
// Decide which mip-map level to use
double z = 2.0; int iMM = 0;
double z = 1.5; int iMM = 0;
while(pGL->Zoom < z && 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);
}
if(hLandscapeUnit >= 0)
if(hUniforms[C4LRU_LandscapeTex] != -1)
{
GLint iLandscapeUnits[C4LR_SurfaceCount];
for(int i = 0; i < C4LR_SurfaceCount; i++)
{
iLandscapeUnits[i] = iUnit;
glActiveTexture(GL_TEXTURE0 + iUnit);
iUnit++;
glEnable(GL_TEXTURE_2D);
ALLOC_UNIT(-1, GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, Surfaces[i]->ppTex[0]->texName);
if (pGL->Zoom != 1.0)
{
@ -583,7 +672,15 @@ void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
}
glUniform1ivARB(hLandscapeUnit, C4LR_SurfaceCount, iLandscapeUnits);
glUniform1ivARB(hUniforms[C4LRU_LandscapeTex], C4LR_SurfaceCount, iLandscapeUnits);
}
if(hUniforms[C4LRU_MatMapTex] != -1)
{
ALLOC_UNIT(hUniforms[C4LRU_MatMapTex], GL_TEXTURE_1D);
GLubyte MatMap[256];
BuildMatMap(NULL, MatMap);
glTexImage1D(GL_TEXTURE_1D, 0, 1, 256, 0, GL_RED, GL_UNSIGNED_BYTE, MatMap);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
// set up blit data as rect
@ -631,7 +728,6 @@ void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo)
// Blend it
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND); // FIXME: needed?
// Blit
glInterleavedArrays(GL_T2F_C4UB_V3F, sizeof(CBltVertex), Vtx);
@ -645,13 +741,13 @@ void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo)
{
iUnit--;
glActiveTexture(GL_TEXTURE0 + iUnit);
glDisable(iUnit == iMaterialUnit ? GL_TEXTURE_3D : GL_TEXTURE_2D);
glDisable(iUnitMap[iUnit]);
}
// Got an error?
if(int err = glGetError())
{
LogF("GL error: %d", err);
LogF("GL error: %d", err /*, gluErrorString(err)*/);
}
}

View File

@ -14,6 +14,22 @@ enum C4LR_Byte {
C4LR_ByteCount
};
// Uniform data we give the shader (constants from its viewpoint)
// Don't forget to update GetUniformName when introducing new uniforms!
enum C4LR_Uniforms
{
C4LRU_LandscapeTex,
C4LRU_ScalerTex,
C4LRU_MaterialTex,
C4LRU_Resolution,
C4LRU_MatMap,
C4LRU_MatMapTex,
C4LRU_MaterialDepth,
C4LRU_Count
};
// How much data we want to store per landscape pixel
const int C4LR_BytesPerPx = 3;
@ -71,8 +87,7 @@ private:
// shaders
GLhandleARB hVert, hFrag, hProg;
// shader variables
GLhandleARB hLandscapeUnit, hScalerUnit, hMaterialUnit;
GLhandleARB hResolutionUniform, hMatTexMapUniform;
GLhandleARB hUniforms[C4LRU_Count];
// Texture count
int32_t iTexCount;
@ -80,8 +95,6 @@ private:
GLuint hMaterialTexture[C4LR_MipMapCount];
// depth of material texture in layers
int32_t iMaterialTextureDepth;
// material map
GLfloat MatTexMap[256];
// scaler image
C4FacetSurface fctScaler;
@ -95,6 +108,8 @@ public:
virtual void Draw(const C4TargetFacet &cgo);
void RefreshShaders();
private:
bool InitMaterialTexture(C4TextureMap *pMap);
bool LoadShaders(C4GroupSet *pGraphics);
@ -106,6 +121,8 @@ private:
bool InitShaders();
void ClearShaders();
void BuildMatMap(GLfloat *pFMap, GLubyte *pIMap);
};
#endif