forked from Mirrors/openclonk
Modular shader system
The idea here is that we compose shaders out of "slices", which can come from the engine ("built-in"), from files or possibly even from models. This should allow us to more easily share the code between different rendering shaders (e.g. for lights / normals). TODO: Workarounds not yet implemented, so this might degrade less gracefully.issue1247
parent
b43e1a9369
commit
72289713f9
|
@ -216,6 +216,8 @@ set(OC_CLONK_SOURCES
|
|||
src/graphics/C4FontLoader.h
|
||||
src/graphics/C4GraphicsResource.cpp
|
||||
src/graphics/C4GraphicsResource.h
|
||||
src/graphics/C4Shader.cpp
|
||||
src/graphics/C4Shader.h
|
||||
src/graphics/C4Surface.cpp
|
||||
src/graphics/C4Surface.h
|
||||
src/graphics/C4SurfaceLoaders.cpp
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
// Ambient light calculation
|
||||
|
||||
uniform sampler2D ambientTex;
|
||||
|
||||
// Factor between landscape coordinates and ambient map coordinates
|
||||
uniform vec2 ambientScale;
|
||||
|
||||
slice texture+6
|
||||
{
|
||||
// Ambient light
|
||||
float ambient = texture2D(ambientTex, ambientScale * texCoo).r;
|
||||
}
|
||||
|
||||
slice light+1
|
||||
{
|
||||
// Add ambience to brightness
|
||||
vec3 ambientDir = vec3(0.0, -1.0, 0.0);
|
||||
light = mix(light, 1.0 + 1.0 * dot(normal, ambientDir), ambient);
|
||||
#ifdef HAVE_2PX
|
||||
light2 = mix(light2, 1.0 + 1.0 * dot(normal2, ambientDir), ambient);
|
||||
#endif
|
||||
}
|
|
@ -1,10 +1,7 @@
|
|||
|
||||
#version 110
|
||||
|
||||
// Input textures
|
||||
uniform sampler2D landscapeTex[2];
|
||||
uniform sampler2D lightTex;
|
||||
uniform sampler2D ambientTex;
|
||||
uniform sampler2D scalerTex;
|
||||
uniform sampler3D materialTex;
|
||||
|
||||
|
@ -22,25 +19,12 @@ uniform float matMap[256];
|
|||
uniform int materialDepth;
|
||||
uniform vec2 materialSize;
|
||||
|
||||
// Factor between landscape coordinates and ambient map coordinates
|
||||
uniform vec2 ambientScale;
|
||||
|
||||
// Expected parameters for the scaler
|
||||
const vec2 scalerStepX = vec2(1.0 / 8.0, 0.0);
|
||||
const vec2 scalerStepY = vec2(0.0, 1.0 / 32.0);
|
||||
const vec2 scalerOffset = scalerStepX / 3.0 + scalerStepY / 3.0;
|
||||
const vec2 scalerPixel = vec2(scalerStepX.x, scalerStepY.y) / 3.0;
|
||||
|
||||
#ifdef NO_TEXTURE_LOD_IN_FRAGMENT
|
||||
#define texture1DLod(t,c,l) texture1D(t,c)
|
||||
#define texture2DLod(t,c,l) texture2D(t,c)
|
||||
#endif
|
||||
|
||||
// Converts the pixel range 0.0..1.0 into the integer range 0..255
|
||||
int f2i(float x) {
|
||||
return int(x * 255.9);
|
||||
}
|
||||
|
||||
float queryMatMap(int pix)
|
||||
{
|
||||
#ifndef NO_BROKEN_ARRAYS_WORKAROUND
|
||||
|
@ -51,111 +35,64 @@ float queryMatMap(int pix)
|
|||
#endif
|
||||
}
|
||||
|
||||
vec3 extend_normal(vec2 v)
|
||||
slice coordinate
|
||||
{
|
||||
return normalize(vec3(v, 0.3));
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
|
||||
// full pixel steps in the landscape texture (depends on landscape resolution)
|
||||
vec2 fullStep = vec2(1.0, 1.0) / resolution;
|
||||
vec2 fullStepX = vec2(fullStep.x, 0.0);
|
||||
vec2 fullStepY = vec2(0.0, fullStep.y);
|
||||
|
||||
vec2 texCoo = gl_TexCoord[0].st;
|
||||
|
||||
|
||||
// calculate pixel position in landscape, find center of current pixel
|
||||
vec2 pixelCoo = texCoo * resolution;
|
||||
vec2 centerCoo = (floor(pixelCoo) + vec2(0.5, 0.5)) / resolution;
|
||||
|
||||
// Texture coordinate for material
|
||||
vec2 materialCoo = texCoo * resolution / materialSize;
|
||||
}
|
||||
|
||||
slice texture
|
||||
{
|
||||
// our pixel color (without/with interpolation)
|
||||
vec4 landscapePx = texture2D(landscapeTex[0], centerCoo);
|
||||
vec4 realLandscapePx = texture2D(landscapeTex[0], texCoo);
|
||||
}
|
||||
|
||||
// find scaler coordinate
|
||||
vec2 scalerCoo = scalerOffset + mod(pixelCoo, vec2(1.0, 1.0)) * scalerPixel;
|
||||
|
||||
#ifdef SCALER_IN_GPU
|
||||
if(texture2D(landscapeTex[0], centerCoo - fullStepX - fullStepY).r == landscapePx.r)
|
||||
scalerCoo += scalerStepX;
|
||||
if(texture2D(landscapeTex[0], centerCoo - fullStepY).r == landscapePx.r)
|
||||
scalerCoo += 2.0 * scalerStepX;
|
||||
if(texture2D(landscapeTex[0], centerCoo + fullStepX - fullStepY).r == landscapePx.r)
|
||||
scalerCoo += 4.0 * scalerStepX;
|
||||
|
||||
if(texture2D(landscapeTex[0], centerCoo - fullStepX ).r == landscapePx.r)
|
||||
scalerCoo += scalerStepY;
|
||||
if(texture2D(landscapeTex[0], centerCoo + fullStepX ).r == landscapePx.r)
|
||||
scalerCoo += 2.0 * scalerStepY;
|
||||
|
||||
if(texture2D(landscapeTex[0], centerCoo - fullStepX + fullStepY).r == landscapePx.r)
|
||||
scalerCoo += 4.0 * scalerStepY;
|
||||
if(texture2D(landscapeTex[0], centerCoo + fullStepY).r == landscapePx.r)
|
||||
scalerCoo += 8.0 * scalerStepY;
|
||||
if(texture2D(landscapeTex[0], centerCoo + fullStepX + fullStepY).r == landscapePx.r)
|
||||
scalerCoo += 16.0 * scalerStepY;
|
||||
|
||||
#else
|
||||
|
||||
int iScaler = f2i(landscapePx.a), iRow = iScaler / 8;
|
||||
scalerCoo.x += float(iScaler - iRow * 8) / 8.0;
|
||||
scalerCoo.y += float(iScaler / 8) / 32.0;
|
||||
|
||||
#endif
|
||||
|
||||
// Note: scalerCoo will jump around a lot, causing some GPUs to apparantly get confused with
|
||||
// the level-of-detail calculation. We therefore try to disable LOD.
|
||||
vec4 scalerPx = texture2DLod(scalerTex, scalerCoo, 0.0);
|
||||
|
||||
// gen3 other coordinate calculation. Still struggles a bit with 3-ways
|
||||
vec2 otherCoo = centerCoo + fullStep * floor(vec2(-0.5, -0.5) + scalerPx.gb * 255.0 / 64.0);
|
||||
vec4 otherLandscapePx = texture2D(landscapeTex[0], otherCoo);
|
||||
slice material
|
||||
{
|
||||
|
||||
// Get material pixels
|
||||
float materialIx = queryMatMap(f2i(landscapePx.r));
|
||||
vec2 tcoo = texCoo * resolution / materialSize;
|
||||
vec4 materialPx = texture3D(materialTex, vec3(tcoo, materialIx));
|
||||
vec4 normalPx = texture3D(materialTex, vec3(tcoo, materialIx+0.5));
|
||||
float otherMaterialIx = queryMatMap(f2i(otherLandscapePx.r));
|
||||
vec4 otherMaterialPx = texture3D(materialTex, vec3(tcoo, otherMaterialIx));
|
||||
vec4 materialPx = texture3D(materialTex, vec3(materialCoo, materialIx));
|
||||
vec4 normalPx = texture3D(materialTex, vec3(materialCoo, materialIx+0.5));
|
||||
|
||||
// Brightness
|
||||
vec4 lightPx = texture2D(lightTex, gl_TexCoord[1].st);
|
||||
float shadeBright = lightPx.r;
|
||||
|
||||
// Normal calculation
|
||||
vec3 landscapeNormal = extend_normal(mix(realLandscapePx.yz, landscapePx.yz, scalerPx.a) - vec2(0.5, 0.5));
|
||||
vec3 landscapeNormal2 = extend_normal(otherLandscapePx.yz - vec2(0.5, 0.5));
|
||||
vec3 textureNormal = normalPx.xyz - vec3(0.5,0.5,0.5);
|
||||
vec3 normal = landscapeNormal + textureNormal;
|
||||
vec3 normal2 = landscapeNormal2 + textureNormal;
|
||||
|
||||
// Ambient light
|
||||
float ambient = texture2D(ambientTex, ambientScale * texCoo).r;
|
||||
float ambient2 = texture2D(ambientTex, ambientScale * otherCoo).r;
|
||||
|
||||
// Light calculation; the ambient part actually uses some shading with
|
||||
// a light direction of (0.0, -1.0, 0.0) so that it does not look utterly
|
||||
// boring at the sky/material edges.
|
||||
vec3 lightDir = extend_normal(vec2(1.0, 1.0) - lightPx.yz * 3.0);
|
||||
float bright = ambient * (1.0 + 1.0 * dot(normal, vec3(0.0, -1.0, 0.0))) + (1.0 - ambient) * 2.0 * shadeBright * dot(normal, lightDir);
|
||||
float bright2 = ambient2 * (1.0 + 1.0 * dot(normal2, vec3(0.0, -1.0, 0.0))) + (1.0 - ambient2) * 2.0 * shadeBright * dot(normal2, lightDir);
|
||||
|
||||
gl_FragColor = mix(
|
||||
vec4(bright2 * otherMaterialPx.rgb, otherMaterialPx.a),
|
||||
vec4(bright * materialPx.rgb, materialPx.a),
|
||||
scalerPx.r);
|
||||
|
||||
// uncomment the following lines for debugging light directions:
|
||||
// yellow: light up, blue: light down, turqoise: light right, pink: light left, opacity: light strength
|
||||
//float lightYDir = lightPx.b - 1.0/3.0;
|
||||
//float lightXDir = lightPx.g - 1.0/3.0;
|
||||
//float lightStrength = lightPx.r;
|
||||
//gl_FragColor = vec4(
|
||||
// 1.0-1.5*(max(0.0, lightYDir) + max(0.0,lightXDir)),
|
||||
// 1.0-1.5*(max(0.0, lightYDir) + max(0.0,-lightXDir)),
|
||||
// 1.0-1.5*max(0.0, -lightYDir),
|
||||
// lightStrength);
|
||||
// Same for second pixel, but we'll simply use the first normal
|
||||
#ifdef HAVE_2PX
|
||||
float materialIx2 = queryMatMap(f2i(landscapePx2.r));
|
||||
vec4 materialPx2 = texture3D(materialTex, vec3(materialCoo, materialIx2));
|
||||
#endif
|
||||
}
|
||||
|
||||
slice normal
|
||||
{
|
||||
// Normal calculation
|
||||
vec3 normal = extend_normal(mix(realLandscapePx.yz, landscapePx.yz, scalerPx.a)
|
||||
- vec2(0.5, 0.5));
|
||||
vec3 textureNormal = normalPx.xyz - vec3(0.5,0.5,0.5);
|
||||
normal = normal + textureNormal;
|
||||
|
||||
#ifdef HAVE_2PX
|
||||
vec3 normal2 = extend_normal(landscapePx2.yz - vec2(0.5, 0.5));
|
||||
normal2 = normal2 + textureNormal;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
slice color {
|
||||
#define color gl_FragColor
|
||||
color = materialPx;
|
||||
#ifdef HAVE_2PX
|
||||
vec4 color2 = materialPx2;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
|
||||
// Base light calculations
|
||||
|
||||
uniform sampler2D lightTex;
|
||||
|
||||
// uncomment the following lines for debugging light directions:
|
||||
// yellow: light up, blue: light down, turqoise: light right, pink: light left
|
||||
// brightness: light strength
|
||||
//#define LIGHT_DEBUG
|
||||
|
||||
slice texture+5
|
||||
{
|
||||
// Query light texture
|
||||
vec4 lightPx = texture2D(lightTex, lightCoord.st);
|
||||
float lightBright = lightPx.x;
|
||||
vec3 lightDir = extend_normal(vec2(1.0, 1.0) - lightPx.yz * 3.0);
|
||||
}
|
||||
|
||||
slice light
|
||||
{
|
||||
// Light direction
|
||||
float light = 2.0 * lightBright * dot(normal, lightDir);
|
||||
#ifdef HAVE_2PX
|
||||
float light2 = 2.0 * lightBright * dot(normal2, lightDir);
|
||||
#endif
|
||||
}
|
||||
|
||||
slice color+5
|
||||
{
|
||||
// Add light
|
||||
color = vec4(light * color.rgb, color.a);
|
||||
#ifdef HAVE_2PX
|
||||
color2 = vec4(light2 * color2.rgb, color2.a);
|
||||
#endif
|
||||
}
|
||||
|
||||
slice finish+5
|
||||
{
|
||||
|
||||
#ifdef LIGHT_DEBUG
|
||||
float lightYDir = lightPx.b - 1.0/3.0;
|
||||
float lightXDir = lightPx.g - 1.0/3.0;
|
||||
float lightStrength = lightPx.r;
|
||||
gl_FragColor =
|
||||
vec4(lightStrength * vec3(1.0-1.5*(max(0.0, lightYDir) + max(0.0,lightXDir)),
|
||||
1.0-1.5*(max(0.0, lightYDir) + max(0.0,-lightXDir)),
|
||||
1.0-1.5*max(0.0, -lightYDir)),
|
||||
1.0);
|
||||
#endif
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
|
||||
#define HAVE_2PX
|
||||
|
||||
slice texture+5
|
||||
{
|
||||
// find scaler coordinate
|
||||
vec2 scalerCoo = scalerOffset + mod(pixelCoo, vec2(1.0, 1.0)) * scalerPixel;
|
||||
|
||||
#ifdef SCALER_IN_GPU
|
||||
if(texture2D(landscapeTex[0], centerCoo - fullStepX - fullStepY).r == landscapePx.r)
|
||||
scalerCoo += scalerStepX;
|
||||
if(texture2D(landscapeTex[0], centerCoo - fullStepY).r == landscapePx.r)
|
||||
scalerCoo += 2.0 * scalerStepX;
|
||||
if(texture2D(landscapeTex[0], centerCoo + fullStepX - fullStepY).r == landscapePx.r)
|
||||
scalerCoo += 4.0 * scalerStepX;
|
||||
|
||||
if(texture2D(landscapeTex[0], centerCoo - fullStepX ).r == landscapePx.r)
|
||||
scalerCoo += scalerStepY;
|
||||
if(texture2D(landscapeTex[0], centerCoo + fullStepX ).r == landscapePx.r)
|
||||
scalerCoo += 2.0 * scalerStepY;
|
||||
|
||||
if(texture2D(landscapeTex[0], centerCoo - fullStepX + fullStepY).r == landscapePx.r)
|
||||
scalerCoo += 4.0 * scalerStepY;
|
||||
if(texture2D(landscapeTex[0], centerCoo + fullStepY).r == landscapePx.r)
|
||||
scalerCoo += 8.0 * scalerStepY;
|
||||
if(texture2D(landscapeTex[0], centerCoo + fullStepX + fullStepY).r == landscapePx.r)
|
||||
scalerCoo += 16.0 * scalerStepY;
|
||||
#else
|
||||
int iScaler = f2i(landscapePx.a), iRow = iScaler / 8;
|
||||
scalerCoo.x += float(iScaler - iRow * 8) / 8.0;
|
||||
scalerCoo.y += float(iScaler / 8) / 32.0;
|
||||
#endif
|
||||
|
||||
// Note: scalerCoo will jump around a lot, causing some GPUs to
|
||||
// apparantly get confused with the level-of-detail
|
||||
// calculation. We therefore try to disable LOD.
|
||||
vec4 scalerPx = texture2DLod(scalerTex, scalerCoo, 0.0);
|
||||
|
||||
// gen3 other coordinate calculation. Still struggles a bit with 3-ways
|
||||
vec2 centerCoo2 = centerCoo + fullStep * floor(vec2(-0.5, -0.5) +
|
||||
scalerPx.gb * 255.0 / 64.0);
|
||||
vec4 landscapePx2 = texture2D(landscapeTex[0], centerCoo2);
|
||||
|
||||
}
|
||||
|
||||
slice color+5 {
|
||||
// Mix second color into main color according to scaler
|
||||
color = mix(color2, color, scalerPx.r);
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
// #ifdef NO_TEXTURE_LOD_IN_FRAGMENT
|
||||
#define texture1DLod(t,c,l) texture1D(t,c)
|
||||
#define texture2DLod(t,c,l) texture2D(t,c)
|
||||
// #endif
|
||||
|
||||
vec3 extend_normal(vec2 v)
|
||||
{
|
||||
return normalize(vec3(v, 0.3));
|
||||
}
|
||||
|
||||
// Converts the pixel range 0.0..1.0 into the integer range 0..255
|
||||
int f2i(float x) {
|
||||
return int(x * 255.9);
|
||||
}
|
||||
|
|
@ -0,0 +1,521 @@
|
|||
|
||||
#include "C4Include.h"
|
||||
#include "C4Shader.h"
|
||||
|
||||
struct C4ShaderPosName {
|
||||
int Position; const char *Name;
|
||||
};
|
||||
|
||||
C4ShaderPosName C4SH_PosNames[] = {
|
||||
{ C4Shader_PositionInit, "init" },
|
||||
{ C4Shader_PositionCoordinate, "coordinate" },
|
||||
{ C4Shader_PositionTexture, "texture" },
|
||||
{ C4Shader_PositionMaterial, "material" },
|
||||
{ C4Shader_PositionNormal, "normal" },
|
||||
{ C4Shader_PositionLight, "light" },
|
||||
{ C4Shader_PositionColor, "color" },
|
||||
{ C4Shader_PositionFinish, "finish" },
|
||||
};
|
||||
|
||||
C4Shader::C4Shader()
|
||||
: iTexCoords(0)
|
||||
, hVert(0), hFrag(0), hProg(0)
|
||||
, pUniforms(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
C4Shader::~C4Shader()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void C4Shader::AddVertexSlice(int iPos, const char *szText)
|
||||
{
|
||||
ShaderSlice Slice;
|
||||
Slice.Position = iPos;
|
||||
Slice.Text.Copy(szText);
|
||||
Slice.SourceTime = 0;
|
||||
VertexSlices.push_back(Slice);
|
||||
}
|
||||
|
||||
void C4Shader::AddFragmentSlice(int iPos, const char *szText, const char *szSource, int iSourceTime)
|
||||
{
|
||||
ShaderSlice Slice;
|
||||
Slice.Position = iPos;
|
||||
Slice.Text.Copy(szText);
|
||||
Slice.Source = szSource;
|
||||
Slice.SourceTime = iSourceTime;
|
||||
FragmentSlices.push_back(Slice);
|
||||
}
|
||||
|
||||
void C4Shader::AddSlices(const char *szWhat, const char *szText, const char *szSource, int iSourceTime)
|
||||
{
|
||||
const char *pStart = szText, *pPos = szText;
|
||||
int iDepth = -1;
|
||||
int iPosition = -1;
|
||||
bool fGotContent = false; // Anything in the slice apart from comments and white-space?
|
||||
|
||||
// Find slices
|
||||
while(*pPos) {
|
||||
|
||||
// Comment? Might seem silly, but we don't want to get confused by braces in comments...
|
||||
if (*pPos == '/' && *(pPos + 1) == '/') {
|
||||
pPos += 2;
|
||||
while (*pPos && *pPos != '\n') pPos++;
|
||||
continue;
|
||||
}
|
||||
if (*pPos == '/' && *(pPos + 1) == '*') {
|
||||
pPos += 2;
|
||||
while (*pPos && (*pPos != '*' || *(pPos+1) != '/')) pPos++;
|
||||
if (*pPos) pPos += 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Opening brace?
|
||||
if (*pPos == '{') {
|
||||
iDepth++; pPos++;
|
||||
continue;
|
||||
}
|
||||
if (*pPos == '}') {
|
||||
// End of slice?
|
||||
if (iPosition != -1 && !iDepth) {
|
||||
|
||||
// Have a new slice!
|
||||
if (fGotContent)
|
||||
{
|
||||
StdStrBuf Str; Str.Copy(pStart, pPos - pStart);
|
||||
AddFragmentSlice(iPosition, Str.getData(), szSource, iSourceTime);
|
||||
}
|
||||
|
||||
iPosition = -1;
|
||||
pStart = pPos+1;
|
||||
fGotContent = false;
|
||||
}
|
||||
if (iDepth >= 0)
|
||||
iDepth--;
|
||||
pPos++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// New slice? We need a newline followed by "slice"
|
||||
if (iDepth < 0 && isspace(*pPos)) {
|
||||
if (SEqual2(pPos+1, "slice") && isspace(*(pPos+6))) {
|
||||
const char *pSliceEnd = pPos; pPos += 6;
|
||||
|
||||
// Now let's parse the position
|
||||
iPosition = ParsePosition(szWhat, &pPos);
|
||||
if (iPosition != -1) {
|
||||
|
||||
// Make sure an opening brace follows
|
||||
while(isspace(*pPos)) pPos++;
|
||||
if (*pPos == '{') {
|
||||
|
||||
// Add code before "slice" as new slice
|
||||
if (fGotContent)
|
||||
{
|
||||
StdStrBuf Str; Str.Copy(pStart, pSliceEnd - pStart);
|
||||
AddFragmentSlice(-1, Str.getData(), szSource, iSourceTime);
|
||||
}
|
||||
|
||||
iDepth = 0;
|
||||
pStart = pPos+1;
|
||||
fGotContent = false;
|
||||
} else {
|
||||
LogF(" gl: Missing opening brace in %s!", szWhat);
|
||||
}
|
||||
pPos++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise: Continue
|
||||
if (!isspace(*pPos)) fGotContent = true;
|
||||
pPos++;
|
||||
}
|
||||
|
||||
// Add final slice
|
||||
if (fGotContent)
|
||||
{
|
||||
StdStrBuf Str; Str.Copy(pStart, pPos - pStart);
|
||||
AddFragmentSlice(iPosition, Str.getData(), szSource, iSourceTime);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int C4Shader::ParsePosition(const char *szWhat, const char **ppPos)
|
||||
{
|
||||
const char *pPos = *ppPos;
|
||||
while (isspace(*pPos)) pPos++;
|
||||
|
||||
// Expect a name
|
||||
const char *pStart = pPos;
|
||||
while (isalnum(*pPos)) pPos++;
|
||||
StdStrBuf Name; Name.Copy(pStart, pPos - pStart);
|
||||
|
||||
// Lookup name
|
||||
int iPosition = -1;
|
||||
for (int i = 0; i < sizeof(C4SH_PosNames) / sizeof(*C4SH_PosNames); i++) {
|
||||
if (SEqual(Name.getData(), C4SH_PosNames[i].Name)) {
|
||||
iPosition = C4SH_PosNames[i].Position;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (iPosition == -1) {
|
||||
LogF(" gl: Unknown slice position in %s: %s", szWhat, Name.getData());
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Add modifier
|
||||
while (isspace(*pPos)) pPos++;
|
||||
if (*pPos == '+') {
|
||||
int iMod, iModLen;
|
||||
if (!sscanf(pPos+1, "%d%n", &iMod, &iModLen)) {
|
||||
LogF(" gl: Invalid slice modifier in %s", szWhat);
|
||||
return -1;
|
||||
}
|
||||
iPosition += iMod;
|
||||
pPos += 1+iModLen;
|
||||
}
|
||||
if (*pPos == '-') {
|
||||
int iMod, iModLen;
|
||||
if (!sscanf(pPos+1, "%d%n", &iMod, &iModLen)) {
|
||||
LogF(" gl: Invalid slice modifier in %s", szWhat);
|
||||
return -1;
|
||||
}
|
||||
iPosition -= iMod;
|
||||
pPos += 1+iModLen;
|
||||
}
|
||||
|
||||
// Everything okay!
|
||||
*ppPos = pPos;
|
||||
return iPosition;
|
||||
}
|
||||
|
||||
bool C4Shader::LoadSlices(C4GroupSet *pGroups, const char *szFile)
|
||||
{
|
||||
// Search for our shaders
|
||||
C4Group *pGroup = pGroups->FindEntry(szFile);
|
||||
if(!pGroup) return false;
|
||||
// Load it, save the path for later reloading
|
||||
StdStrBuf Shader;
|
||||
if(!pGroup->LoadEntryString(szFile, &Shader))
|
||||
return false;
|
||||
// If it physically exists, save back creation time so we
|
||||
// can automatically reload it if it changes
|
||||
StdStrBuf Source = FormatString("%s" DirSep "%s", pGroup->GetFullName().getData(), szFile);
|
||||
int iSourceTime = 0;
|
||||
if(FileExists(Source.getData()))
|
||||
iSourceTime = FileTime(Source.getData());
|
||||
// Load
|
||||
StdStrBuf What = FormatString("file %s", Config.AtRelativePath(Source.getData()));
|
||||
AddSlices(What.getData(), Shader.getData(), Source.getData(), iSourceTime);
|
||||
return true;
|
||||
}
|
||||
void C4Shader::AddVertexDefaults()
|
||||
{
|
||||
AddVertexSlice(C4Shader_Vertex_PositionPos, "gl_Position = ftransform();\n");
|
||||
}
|
||||
|
||||
GLenum C4Shader::AddTexCoord(const char *szName)
|
||||
{
|
||||
// Make sure we have enough space
|
||||
assert(iTexCoords < C4Shader_MaxTexCoords);
|
||||
if(iTexCoords >= C4Shader_MaxTexCoords)
|
||||
return -1;
|
||||
|
||||
// Add slices
|
||||
StdStrBuf Code = FormatString("gl_TexCoord[%d] = gl_MultiTexCoord%d;\n", iTexCoords, iTexCoords);
|
||||
AddVertexSlice(C4Shader_Vertex_TexCoordPos, Code.getData());
|
||||
Code.Format("#define %s gl_TexCoord[%d]\n", szName, iTexCoords);
|
||||
AddFragmentSlice(-1, Code.getData());
|
||||
|
||||
return GL_TEXTURE0 + iTexCoords++;
|
||||
}
|
||||
|
||||
void C4Shader::ClearSlices()
|
||||
{
|
||||
VertexSlices.clear();
|
||||
FragmentSlices.clear();
|
||||
iTexCoords = 0;
|
||||
}
|
||||
|
||||
void C4Shader::Clear()
|
||||
{
|
||||
if (!hProg) return;
|
||||
// Need to be detached, then deleted
|
||||
glDetachObjectARB(hProg, hFrag);
|
||||
glDetachObjectARB(hProg, hVert);
|
||||
glDeleteObjectARB(hFrag);
|
||||
glDeleteObjectARB(hVert);
|
||||
glDeleteObjectARB(hProg);
|
||||
hFrag = hVert = hProg = 0;
|
||||
// Clear uniform data
|
||||
delete[] pUniforms; pUniforms = NULL;
|
||||
iUniformCount = 0;
|
||||
}
|
||||
|
||||
bool C4Shader::Init(const char *szWhat, const char **szUniforms)
|
||||
{
|
||||
|
||||
// No support?
|
||||
if(!GLEW_ARB_fragment_program)
|
||||
{
|
||||
Log(" gl: no shader support!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clear old shader first
|
||||
if (hProg) Clear();
|
||||
|
||||
// Dump
|
||||
LogSilent(Build(VertexSlices, true).getData());
|
||||
LogSilent(Build(FragmentSlices, true).getData());
|
||||
|
||||
// Attempt to create shaders
|
||||
StdStrBuf VertexShader = Build(VertexSlices),
|
||||
FragmentShader = Build(FragmentSlices);
|
||||
hVert = Create(GL_VERTEX_SHADER_ARB,
|
||||
FormatString("%s vertex shader", szWhat).getData(),
|
||||
VertexShader.getData());
|
||||
hFrag = Create(GL_FRAGMENT_SHADER_ARB,
|
||||
FormatString("%s fragment shader", szWhat).getData(),
|
||||
FragmentShader.getData());
|
||||
if(!hFrag || !hVert)
|
||||
return false;
|
||||
|
||||
// Link program
|
||||
hProg = glCreateProgramObjectARB();
|
||||
glAttachObjectARB(hProg, hVert);
|
||||
glAttachObjectARB(hProg, hFrag);
|
||||
glLinkProgramARB(hProg);
|
||||
|
||||
// Link successful?
|
||||
DumpInfoLog(FormatString("%s shader program", szWhat).getData(), hProg);
|
||||
if(GetObjectStatus(hProg, GL_OBJECT_LINK_STATUS_ARB) != 1) {
|
||||
Clear();
|
||||
LogF(" gl: Failed to link %s shader!", szWhat);
|
||||
return false;
|
||||
}
|
||||
LogF(" gl: %s shader linked successfully", szWhat);
|
||||
|
||||
// Okay, allocate uniform array
|
||||
iUniformCount = 0;
|
||||
while (szUniforms[iUniformCount])
|
||||
iUniformCount++;
|
||||
pUniforms = new GLint[iUniformCount];
|
||||
|
||||
// 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 < iUniformCount; i++)
|
||||
pUniforms[i] = glGetUniformLocationARB(hProg, szUniforms[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool C4Shader::Refresh(const char *szWhat, const char **szUniforms)
|
||||
{
|
||||
// Find a slice where the source file has updated
|
||||
ShaderSliceList::iterator pSlice;
|
||||
for (pSlice = FragmentSlices.begin(); pSlice != FragmentSlices.end(); pSlice++)
|
||||
if (pSlice->Source.getLength() &&
|
||||
FileExists(pSlice->Source.getData()) &&
|
||||
FileTime(pSlice->Source.getData()) > pSlice->SourceTime)
|
||||
break;
|
||||
if (pSlice == FragmentSlices.end()) return true;
|
||||
StdCopyStrBuf Source = pSlice->Source;
|
||||
|
||||
// Okay, remove all slices that came from this file
|
||||
ShaderSliceList::iterator pNext;
|
||||
for (; pSlice != FragmentSlices.end(); pSlice = pNext)
|
||||
{
|
||||
pNext = pSlice; pNext++;
|
||||
if (SEqual(pSlice->Source.getData(), Source.getData()))
|
||||
FragmentSlices.erase(pSlice);
|
||||
}
|
||||
|
||||
// Load new shader
|
||||
char szParentPath[_MAX_PATH+1]; C4Group Group;
|
||||
StdStrBuf Shader;
|
||||
GetParentPath(Source.getData(),szParentPath);
|
||||
if(!Group.Open(szParentPath) ||
|
||||
!Group.LoadEntryString(GetFilename(Source.getData()),&Shader) ||
|
||||
!Group.Close())
|
||||
{
|
||||
LogF(" gl: Failed to refresh %s shader from %s!", szWhat, Source.getData());
|
||||
return Refresh(szWhat, szUniforms);
|
||||
}
|
||||
|
||||
// Load slices
|
||||
int iSourceTime = FileTime(Source.getData());
|
||||
StdStrBuf WhatSrc = FormatString("file %s", Config.AtRelativePath(Source.getData()));
|
||||
AddSlices(WhatSrc.getData(), Shader.getData(), Source.getData(), iSourceTime);
|
||||
|
||||
// Reinitialise
|
||||
if (!Init(szWhat, szUniforms))
|
||||
return false;
|
||||
|
||||
// Retry
|
||||
return Refresh(szWhat, szUniforms);
|
||||
}
|
||||
|
||||
StdStrBuf C4Shader::Build(const ShaderSliceList &Slices, bool fDebug)
|
||||
{
|
||||
|
||||
// At the start of the shader set the #version and number of
|
||||
// available uniforms
|
||||
StdStrBuf Buf;
|
||||
GLint iMaxFrags = 0, iMaxVerts = 0;
|
||||
glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, &iMaxFrags);
|
||||
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &iMaxVerts);
|
||||
Buf.Format("#version %d\n"
|
||||
"#define MAX_FRAGMENT_UNIFORM_COMPONENTS %d\n"
|
||||
"#define MAX_VERTEX_UNIFORM_COMPONENTS %d\n",
|
||||
C4Shader_Version, iMaxFrags, iMaxVerts);
|
||||
|
||||
// Put slices
|
||||
int iPos = -1, iNextPos = -1;
|
||||
do
|
||||
{
|
||||
iPos = iNextPos; iNextPos = C4Shader_LastPosition+1;
|
||||
// Add all slices at the current level
|
||||
if (fDebug && iPos > 0)
|
||||
Buf.AppendFormat("\t// Position %d:\n", iPos);
|
||||
for (ShaderSliceList::const_iterator pSlice = Slices.begin(); pSlice != Slices.end(); pSlice++)
|
||||
{
|
||||
if (pSlice->Position < iPos) continue;
|
||||
if (pSlice->Position > iPos)
|
||||
{
|
||||
iNextPos = Min(iNextPos, pSlice->Position);
|
||||
continue;
|
||||
}
|
||||
// Same position - add slice!
|
||||
if (fDebug)
|
||||
{
|
||||
if (pSlice->Source.getLength())
|
||||
Buf.AppendFormat("\t// Slice from %s:\n", pSlice->Source.getData());
|
||||
else
|
||||
Buf.Append("\t// Built-in slice:\n");
|
||||
}
|
||||
Buf.Append(pSlice->Text);
|
||||
if (Buf[Buf.getLength()-1] != '\n')
|
||||
Buf.AppendChar('\n');
|
||||
}
|
||||
// Add seperator - only priority (-1) is top-level
|
||||
if (iPos == -1) {
|
||||
Buf.Append("void main() {\n");
|
||||
}
|
||||
}
|
||||
while (iNextPos <= C4Shader_LastPosition);
|
||||
|
||||
// Terminate
|
||||
Buf.Append("}\n");
|
||||
return Buf;
|
||||
}
|
||||
|
||||
GLhandleARB C4Shader::Create(GLenum iShaderType, const char *szWhat, const char *szShader)
|
||||
{
|
||||
// Create shader
|
||||
GLhandleARB hShader = glCreateShaderObjectARB(iShaderType);
|
||||
|
||||
// Compile
|
||||
glShaderSourceARB(hShader, 1, &szShader, 0);
|
||||
glCompileShaderARB(hShader);
|
||||
|
||||
// Dump any information to log
|
||||
DumpInfoLog(szWhat, hShader);
|
||||
|
||||
// Success?
|
||||
if(GetObjectStatus(hShader, GL_OBJECT_COMPILE_STATUS_ARB) == 1)
|
||||
return hShader;
|
||||
|
||||
// Did not work :/
|
||||
glDeleteObjectARB(hShader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void C4Shader::DumpInfoLog(const char *szWhat, GLhandleARB hShader)
|
||||
{
|
||||
// Get length of info line
|
||||
int iLength = 0;
|
||||
glGetObjectParameterivARB(hShader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &iLength);
|
||||
if(iLength <= 1) return;
|
||||
|
||||
// Allocate buffer, get data
|
||||
char *pBuf = new char [iLength + 1];
|
||||
int iActualLength = 0;
|
||||
glGetInfoLogARB(hShader, iLength, &iActualLength, pBuf);
|
||||
if(iActualLength > iLength || iActualLength <= 0) return;
|
||||
|
||||
// Terminate, log
|
||||
pBuf[iActualLength] = '\0';
|
||||
LogSilentF(" gl: Compiling %s:", szWhat);
|
||||
LogSilent(pBuf);
|
||||
delete[] pBuf;
|
||||
}
|
||||
|
||||
int C4Shader::GetObjectStatus(GLhandleARB hObj, GLenum type)
|
||||
{
|
||||
int iStatus = 0;
|
||||
glGetObjectParameterivARB(hObj, type, &iStatus);
|
||||
return iStatus;
|
||||
}
|
||||
|
||||
GLint C4ShaderCall::AllocTexUnit(int iUniform, GLenum iType)
|
||||
{
|
||||
// Want to bind uniform automatically? If not, the caller will take
|
||||
// care of it.
|
||||
if (iUniform >= 0) {
|
||||
|
||||
// If uniform isn't used, we should skip this. Also check texunit range.
|
||||
if (!pShader->HaveUniform(iUniform)) return 0;
|
||||
assert(iUnits < C4ShaderCall_MaxUnits);
|
||||
if (iUnits >= C4ShaderCall_MaxUnits) return 0;
|
||||
|
||||
// Set the uniform
|
||||
SetUniform1i(iUniform, iUnits);
|
||||
}
|
||||
|
||||
// Activate the texture
|
||||
GLint hTex = GL_TEXTURE0 + iUnits;
|
||||
glActiveTexture(hTex);
|
||||
hUnit[iUnits] = iType;
|
||||
glEnable(iType);
|
||||
iUnits++;
|
||||
return hTex;
|
||||
}
|
||||
|
||||
void C4ShaderCall::Start()
|
||||
{
|
||||
assert(!fStarted);
|
||||
|
||||
// Activate shader
|
||||
glUseProgramObjectARB(pShader->hProg);
|
||||
fStarted = true;
|
||||
|
||||
}
|
||||
|
||||
void C4ShaderCall::Finish()
|
||||
{
|
||||
// Remove shader
|
||||
if (fStarted) {
|
||||
glUseProgramObjectARB(0);
|
||||
}
|
||||
|
||||
// Deactivate all texture units
|
||||
for (int i = 0; i < iUnits; i++)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + i);
|
||||
glDisable(hUnit[i]);
|
||||
}
|
||||
iUnits = 0;
|
||||
fStarted = false;
|
||||
|
||||
// Got an error?
|
||||
if(int err = glGetError())
|
||||
{
|
||||
LogF("GL error: %d", err /*, gluErrorString(err)*/);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
|
||||
// Shader implementation somewhere in the middle between easy and extensible.
|
||||
|
||||
#ifndef INC_C4Shader
|
||||
#define INC_C4Shader
|
||||
|
||||
#include "StdBuf.h"
|
||||
#include "C4Surface.h"
|
||||
|
||||
// Shader version
|
||||
const int C4Shader_Version = 110; // GLSL 1.10
|
||||
|
||||
// Maximum number of texture coordinates
|
||||
const int C4Shader_MaxTexCoords = 8;
|
||||
|
||||
// Maximum number of texture units per shader call
|
||||
const int C4ShaderCall_MaxUnits = 32;
|
||||
|
||||
// Positions in fragment shader
|
||||
const int C4Shader_PositionInit = 0;
|
||||
const int C4Shader_PositionCoordinate = 20;
|
||||
const int C4Shader_PositionTexture = 40;
|
||||
const int C4Shader_PositionMaterial = 60;
|
||||
const int C4Shader_PositionNormal = 80;
|
||||
const int C4Shader_PositionLight = 100;
|
||||
const int C4Shader_PositionColor = 120;
|
||||
const int C4Shader_PositionFinish = 140;
|
||||
const int C4Shader_LastPosition = 256;
|
||||
|
||||
// Positions in vertex shader
|
||||
const int C4Shader_Vertex_TexCoordPos = 50;
|
||||
const int C4Shader_Vertex_PositionPos = 80;
|
||||
|
||||
class C4Shader
|
||||
{
|
||||
friend class C4ShaderCall;
|
||||
public:
|
||||
C4Shader();
|
||||
~C4Shader();
|
||||
|
||||
private:
|
||||
|
||||
// Program texts
|
||||
struct ShaderSlice {
|
||||
int Position;
|
||||
StdCopyStrBuf Text;
|
||||
StdCopyStrBuf Source;
|
||||
int SourceTime;
|
||||
};
|
||||
typedef std::list<ShaderSlice> ShaderSliceList;
|
||||
ShaderSliceList VertexSlices, FragmentSlices;
|
||||
|
||||
// Used texture coordinates
|
||||
int iTexCoords;
|
||||
|
||||
// shaders
|
||||
GLhandleARB hVert, hFrag, hProg;
|
||||
// shader variables
|
||||
int iUniformCount;
|
||||
GLint *pUniforms;
|
||||
|
||||
public:
|
||||
|
||||
bool Initialised() const { return hVert != 0; }
|
||||
|
||||
// Uniform getters
|
||||
GLint GetUniform(int iUniform) const {
|
||||
return iUniform >= 0 && iUniform < iUniformCount ? pUniforms[iUniform] : -1;
|
||||
}
|
||||
bool HaveUniform(int iUniform) const {
|
||||
return GetUniform(iUniform) != GLint(-1);
|
||||
}
|
||||
|
||||
// Shader is composed from various slices
|
||||
void AddVertexSlice(int iPos, const char *szText);
|
||||
void AddFragmentSlice(int iPos, const char *szText, const char *szSource = "", int iFileTime = 0);
|
||||
void AddSlices(const char *szWhat, const char *szText, const char *szSource = "", int iFileTime = 0);
|
||||
bool LoadSlices(C4GroupSet *pGroupSet, const char *szFile);
|
||||
|
||||
// Add default vertex code (2D - no transformation)
|
||||
void AddVertexDefaults();
|
||||
|
||||
// Allocate a texture coordinate, returning its ID to be used with glMultiTexCoord.
|
||||
// The texture coordinate will be visible to both shaders under the given name.
|
||||
// Note that in contrast to uniforms, these will not disappear if not used!
|
||||
GLenum AddTexCoord(const char *szName);
|
||||
|
||||
// Assemble and link the shader. Should be called again after new slices are added.
|
||||
bool Init(const char *szWhat, const char **szUniforms);
|
||||
bool Refresh(const char *szWhat, const char **szUniforms);
|
||||
|
||||
void ClearSlices();
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
int ParsePosition(const char *szWhat, const char **ppPos);
|
||||
|
||||
StdStrBuf Build(const ShaderSliceList &Slices, bool fDebug = false);
|
||||
GLhandleARB Create(GLenum iShaderType, const char *szWhat, const char *szShader);
|
||||
void DumpInfoLog(const char *szWhat, GLhandleARB hShader);
|
||||
int GetObjectStatus(GLhandleARB hObj, GLenum type);
|
||||
};
|
||||
|
||||
class C4ShaderCall
|
||||
{
|
||||
public:
|
||||
C4ShaderCall(C4Shader *pShader)
|
||||
: fStarted(false), pShader(pShader), iUnits(0)
|
||||
{ }
|
||||
~C4ShaderCall() { Finish(); }
|
||||
|
||||
private:
|
||||
bool fStarted;
|
||||
C4Shader *pShader;
|
||||
int iUnits;
|
||||
GLenum hUnit[C4ShaderCall_MaxUnits];
|
||||
|
||||
public:
|
||||
GLint AllocTexUnit(int iUniform, GLenum iType);
|
||||
|
||||
// Setting uniforms... Lots of code duplication here, not quite sure whether
|
||||
// something could be done about it.
|
||||
void SetUniform1i(int iUniform, int iX) const {
|
||||
if (pShader->HaveUniform(iUniform))
|
||||
glUniform1iARB(pShader->GetUniform(iUniform), iX);
|
||||
}
|
||||
void SetUniform2f(int iUniform, float gX, float gY) const {
|
||||
if (pShader->HaveUniform(iUniform))
|
||||
glUniform2fARB(pShader->GetUniform(iUniform), gX, gY);
|
||||
}
|
||||
void SetUniform1iv(int iUniform, int iLength, int *pVals) const {
|
||||
if (pShader->HaveUniform(iUniform))
|
||||
glUniform1ivARB(pShader->GetUniform(iUniform), iLength, pVals);
|
||||
}
|
||||
void SetUniform1fv(int iUniform, int iLength, float *pVals) const {
|
||||
if (pShader->HaveUniform(iUniform))
|
||||
glUniform1fvARB(pShader->GetUniform(iUniform), iLength, pVals);
|
||||
}
|
||||
|
||||
void Start();
|
||||
void Finish();
|
||||
};
|
||||
|
||||
#endif // INC_C4Shader
|
|
@ -32,46 +32,13 @@
|
|||
const int C4LR_BiasDistanceX = 8;
|
||||
const int C4LR_BiasDistanceY = 8;
|
||||
|
||||
// Workarounds to try if shader fails to compile
|
||||
const char *C4LR_ShaderWorkarounds[] = {
|
||||
"#define NO_TEXTURE_LOD_IN_FRAGMENT\n",
|
||||
"#define NO_BROKEN_ARRAYS_WORKAROUND\n",
|
||||
"#define SCALER_IN_GPU\n",
|
||||
};
|
||||
const int C4LR_ShaderWorkaroundCount = sizeof(C4LR_ShaderWorkarounds) / sizeof(*C4LR_ShaderWorkarounds);
|
||||
|
||||
// Name used for the seperator texture
|
||||
const char *const SEPERATOR_TEXTURE = "--SEP--";
|
||||
|
||||
// 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_LightTex: return "lightTex";
|
||||
case C4LRU_AmbientTex: return "ambientTex";
|
||||
case C4LRU_Resolution: return "resolution";
|
||||
case C4LRU_Center: return "center";
|
||||
case C4LRU_MatMap: return "matMap";
|
||||
case C4LRU_MatMapTex: return "matMapTex";
|
||||
case C4LRU_MaterialDepth:return "materialDepth";
|
||||
case C4LRU_MaterialSize: return "materialSize";
|
||||
case C4LRU_AmbientScale: return "ambientScale";
|
||||
}
|
||||
assert(false);
|
||||
return "mysterious";
|
||||
}
|
||||
|
||||
C4LandscapeRenderGL::C4LandscapeRenderGL()
|
||||
: iLandscapeShaderTime(0),
|
||||
hVert(0), hFrag(0), hProg(0)
|
||||
: iLandscapeShaderTime(0)
|
||||
{
|
||||
ZeroMem(Surfaces, sizeof(Surfaces));
|
||||
ZeroMem(hMaterialTexture, sizeof(hMaterialTexture));
|
||||
ZeroMem(hUniforms, sizeof(hUniforms));
|
||||
}
|
||||
|
||||
C4LandscapeRenderGL::~C4LandscapeRenderGL()
|
||||
|
@ -158,7 +125,7 @@ void C4LandscapeRenderGL::Clear()
|
|||
hMaterialTexture[i] = 0;
|
||||
}
|
||||
|
||||
LandscapeShader.Clear();
|
||||
Shader.Clear(); Shader.ClearSlices();
|
||||
LandscapeShaderPath.Clear();
|
||||
iLandscapeShaderTime = 0;
|
||||
}
|
||||
|
@ -201,7 +168,7 @@ bool C4LandscapeRenderGL::InitMaterialTexture(C4TextureMap *pTexs)
|
|||
|
||||
// Find the largest texture
|
||||
C4Texture *pTex, *pRefTex; C4Surface *pRefSfc = NULL;
|
||||
for(int iTexIx = 0; pTex = pTexs->GetTexture(pTexs->GetTexture(iTexIx)); iTexIx++)
|
||||
for(int iTexIx = 0; (pTex = pTexs->GetTexture(pTexs->GetTexture(iTexIx))); iTexIx++)
|
||||
if(C4Surface *pSfc = pTex->Surface32)
|
||||
if (!pRefSfc || pRefSfc->Wdt < pSfc->Wdt || pRefSfc->Hgt < pSfc->Hgt)
|
||||
{ pRefTex = pTex; pRefSfc = pSfc; }
|
||||
|
@ -431,7 +398,6 @@ void C4LandscapeRenderGL::Update(C4Rect To, C4Landscape *pSource)
|
|||
// Biases
|
||||
int iPix = pSource->_GetPix(To.x+x, To.y+y);
|
||||
int iPlac = pSource->_GetPlacement(To.x+x, To.y+y);
|
||||
int iMat = pSource->_GetMat(To.x+x, To.y+y);
|
||||
int iHBias = Max(0, iPlac * (C4LR_BiasDistanceY-1) - iRight) -
|
||||
Max(0, iPlac * (C4LR_BiasDistanceY-1) - iLeft);
|
||||
int iVBias = Max(0, iPlac * (C4LR_BiasDistanceY-1) - pDown[x]) -
|
||||
|
@ -532,145 +498,50 @@ void C4LandscapeRenderGL::Update(C4Rect To, C4Landscape *pSource)
|
|||
|
||||
}
|
||||
|
||||
void C4LandscapeRenderGL::DumpInfoLog(const char *szWhat, GLhandleARB hShader, int32_t iWorkaround)
|
||||
const char *C4LandscapeRenderGL::UniformNames[C4LRU_Count+1];
|
||||
|
||||
bool C4LandscapeRenderGL::LoadShaders(C4GroupSet *pGroups)
|
||||
{
|
||||
// Get length of info line
|
||||
int iLength = 0;
|
||||
glGetObjectParameterivARB(hShader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &iLength);
|
||||
if(iLength <= 1) return;
|
||||
|
||||
// Allocate buffer, get data
|
||||
char *pBuf = new char [iLength + 1];
|
||||
int iActualLength = 0;
|
||||
glGetInfoLogARB(hShader, iLength, &iActualLength, pBuf);
|
||||
if(iActualLength > iLength || iActualLength <= 0) return;
|
||||
|
||||
// Terminate, log
|
||||
pBuf[iActualLength] = '\0';
|
||||
LogSilentF(" gl: Compiling %s %d:", szWhat, iWorkaround);
|
||||
LogSilent(pBuf);
|
||||
delete[] pBuf;
|
||||
}
|
||||
|
||||
int C4LandscapeRenderGL::GetObjectStatus(GLhandleARB hObj, GLenum type)
|
||||
{
|
||||
int iStatus = 0;
|
||||
glGetObjectParameterivARB(hObj, type, &iStatus);
|
||||
return iStatus;
|
||||
}
|
||||
|
||||
GLhandleARB C4LandscapeRenderGL::CreateShader(GLenum iShaderType, const char *szWhat, const char *szCode, int32_t iWorkaround)
|
||||
{
|
||||
// Create shader
|
||||
GLhandleARB hShader = glCreateShaderObjectARB(iShaderType);
|
||||
|
||||
// Find #version
|
||||
StdStrBuf Version("");
|
||||
const char *szCodeRest = szCode;
|
||||
if (const char *szVersion = SSearch(szCode, "#version"))
|
||||
{
|
||||
while (*szVersion && *szVersion != '\n')
|
||||
szVersion++;
|
||||
if (*szVersion == '\n')
|
||||
szVersion++;
|
||||
Version.Copy(szCode, szVersion - szCode);
|
||||
szCodeRest = szVersion;
|
||||
}
|
||||
|
||||
// Get number of available uniforms from driver
|
||||
GLint max_uniforms = 0;
|
||||
glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, &max_uniforms);
|
||||
Version.AppendFormat("#define MAX_FRAGMENT_UNIFORM_COMPONENTS %d\n", max_uniforms);
|
||||
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &max_uniforms);
|
||||
Version.AppendFormat("#define MAX_VERTEX_UNIFORM_COMPONENTS %d\n", max_uniforms);
|
||||
|
||||
// Build code
|
||||
const char *szCodes[C4LR_ShaderWorkaroundCount + 2];
|
||||
szCodes[0] = Version.getData();
|
||||
for(int i = 0; i < C4LR_ShaderWorkaroundCount; i++)
|
||||
if(iWorkaround & (1 << i))
|
||||
szCodes[i+1] = C4LR_ShaderWorkarounds[i];
|
||||
else
|
||||
szCodes[i+1] = "";
|
||||
szCodes[C4LR_ShaderWorkaroundCount+1] = szCodeRest;
|
||||
|
||||
// Compile
|
||||
glShaderSourceARB(hShader, C4LR_ShaderWorkaroundCount + 2, szCodes, 0);
|
||||
glCompileShaderARB(hShader);
|
||||
|
||||
// Dump any information to log
|
||||
DumpInfoLog(szWhat, hShader, iWorkaround);
|
||||
|
||||
// Success?
|
||||
if(GetObjectStatus(hShader, GL_OBJECT_COMPILE_STATUS_ARB) == 1)
|
||||
return hShader;
|
||||
|
||||
// Did not work :/
|
||||
glDeleteObjectARB(hShader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool C4LandscapeRenderGL::InitShaders()
|
||||
{
|
||||
// Already initialized or no shader load?
|
||||
if(hProg || LandscapeShader.getLength() <= 0)
|
||||
return false;
|
||||
|
||||
// No support?
|
||||
if(!GLEW_ARB_fragment_program)
|
||||
{
|
||||
Log(" gl: no shader support!");
|
||||
Log(" gl: no shader support!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try all workarounds until one works
|
||||
int iWorkaround;
|
||||
for(iWorkaround = 0; iWorkaround < (1 << C4LR_ShaderWorkaroundCount); iWorkaround++)
|
||||
{
|
||||
// Create trivial fragment shader
|
||||
const char *szVert = "#version 110\nvoid main() { gl_TexCoord[0] = gl_MultiTexCoord0; gl_TexCoord[1] = gl_MultiTexCoord1; gl_Position = ftransform(); } ";
|
||||
hVert = CreateShader(GL_VERTEX_SHADER_ARB, "vertex shader", szVert, iWorkaround);
|
||||
hFrag = CreateShader(GL_FRAGMENT_SHADER_ARB, "fragment shader", LandscapeShader.getData(), iWorkaround);
|
||||
if(!hFrag || !hVert)
|
||||
continue;
|
||||
// First, clear out all existing shaders
|
||||
ClearShaders();
|
||||
|
||||
// Link program
|
||||
hProg = glCreateProgramObjectARB();
|
||||
glAttachObjectARB(hProg, hVert);
|
||||
glAttachObjectARB(hProg, hFrag);
|
||||
glLinkProgramARB(hProg);
|
||||
// Create vertex shader (hard-coded)
|
||||
Shader.AddVertexDefaults();
|
||||
hLandscapeTexCoord = Shader.AddTexCoord("landscapeCoord");
|
||||
hLightTexCoord = Shader.AddTexCoord("lightCoord");
|
||||
|
||||
// Link successful?
|
||||
DumpInfoLog("shader program", hProg, iWorkaround);
|
||||
if(GetObjectStatus(hProg, GL_OBJECT_LINK_STATUS_ARB) == 1)
|
||||
break;
|
||||
// Then load slices for fragment shader
|
||||
Shader.LoadSlices(pGroups, "UtilShader.c");
|
||||
Shader.LoadSlices(pGroups, "LandscapeShader.c");
|
||||
Shader.LoadSlices(pGroups, "LightShader.c");
|
||||
Shader.LoadSlices(pGroups, "AmbientShader.c");
|
||||
Shader.LoadSlices(pGroups, "ScalerShader.c");
|
||||
|
||||
// Clear up
|
||||
glDetachObjectARB(hProg, hVert);
|
||||
glDetachObjectARB(hProg, hFrag);
|
||||
glDeleteObjectARB(hVert);
|
||||
glDeleteObjectARB(hFrag);
|
||||
glDeleteObjectARB(hProg);
|
||||
hProg = hVert = hFrag = 0;
|
||||
}
|
||||
|
||||
// Did not get it to work?
|
||||
if(!hProg)
|
||||
{
|
||||
Log(" gl: Failed to link shader!");
|
||||
return false;
|
||||
}
|
||||
LogF(" gl: Shader %d linked successfully", iWorkaround);
|
||||
// Make uniform name map
|
||||
ZeroMem(UniformNames, sizeof(UniformNames));
|
||||
UniformNames[C4LRU_LandscapeTex] = "landscapeTex";
|
||||
UniformNames[C4LRU_ScalerTex] = "scalerTex";
|
||||
UniformNames[C4LRU_MaterialTex] = "materialTex";
|
||||
UniformNames[C4LRU_LightTex] = "lightTex";
|
||||
UniformNames[C4LRU_AmbientTex] = "ambientTex";
|
||||
UniformNames[C4LRU_Resolution] = "resolution";
|
||||
UniformNames[C4LRU_Center] = "center";
|
||||
UniformNames[C4LRU_MatMap] = "matMap";
|
||||
UniformNames[C4LRU_MatMapTex] = "matMapTex";
|
||||
UniformNames[C4LRU_MaterialDepth]= "materialDepth";
|
||||
UniformNames[C4LRU_MaterialSize] = "materialSize";
|
||||
UniformNames[C4LRU_AmbientScale] = "ambientScale";
|
||||
|
||||
// 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())
|
||||
{
|
||||
LogF(" gl: Error code %d while linking shader!", err);
|
||||
// Initialise!
|
||||
if (!Shader.Init("landscape", UniformNames)) {
|
||||
Shader.ClearSlices();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -678,37 +549,14 @@ bool C4LandscapeRenderGL::InitShaders()
|
|||
|
||||
void C4LandscapeRenderGL::ClearShaders()
|
||||
{
|
||||
if (!hProg) return;
|
||||
|
||||
// Need to be detached, then deleted
|
||||
glDetachObjectARB(hProg, hFrag);
|
||||
glDetachObjectARB(hProg, hVert);
|
||||
glDeleteObjectARB(hFrag);
|
||||
glDeleteObjectARB(hVert);
|
||||
glDeleteObjectARB(hProg);
|
||||
hFrag = hVert = hProg = 0;
|
||||
|
||||
ZeroMem(hUniforms, sizeof(hUniforms));
|
||||
if (!Shader.Initialised()) return;
|
||||
Shader.Clear();
|
||||
Shader.ClearSlices();
|
||||
}
|
||||
|
||||
bool C4LandscapeRenderGL::LoadShaders(C4GroupSet *pGroups)
|
||||
void C4LandscapeRenderGL::RefreshShaders()
|
||||
{
|
||||
// First, clear out all existing shaders
|
||||
ClearShaders();
|
||||
// Search for our shaders
|
||||
C4Group *pGroup = pGroups->FindEntry(C4CFN_LandscapeShader);
|
||||
if(!pGroup) return false;
|
||||
// Load it, save the path for later reloading
|
||||
if(!pGroup->LoadEntryString(C4CFN_LandscapeShader, &LandscapeShader))
|
||||
return false;
|
||||
// If it physically exists, save back file name
|
||||
if(FileExists(pGroup->GetFullName().getData()))
|
||||
{
|
||||
LandscapeShaderPath.Format("%s" DirSep C4CFN_LandscapeShader, pGroup->GetFullName().getData());
|
||||
iLandscapeShaderTime = FileTime(LandscapeShaderPath.getData());
|
||||
}
|
||||
// Initialize
|
||||
return InitShaders();
|
||||
Shader.Refresh("landscape", UniformNames);
|
||||
}
|
||||
|
||||
bool C4LandscapeRenderGL::LoadScaler(C4GroupSet *pGroups)
|
||||
|
@ -806,26 +654,6 @@ bool C4LandscapeRenderGL::LoadScaler(C4GroupSet *pGroups)
|
|||
return fctScaler.Surface->Unlock();
|
||||
}
|
||||
|
||||
void C4LandscapeRenderGL::RefreshShaders()
|
||||
{
|
||||
// File changed?
|
||||
if(!LandscapeShaderPath.isNull() &&
|
||||
FileTime(LandscapeShaderPath.getData()) != iLandscapeShaderTime)
|
||||
{
|
||||
ClearShaders();
|
||||
// Load new shader
|
||||
char szParentPath[_MAX_PATH+1]; C4Group Group;
|
||||
GetParentPath(LandscapeShaderPath.getData(),szParentPath);
|
||||
if(!Group.Open(szParentPath) ||
|
||||
!Group.LoadEntryString(GetFilename(LandscapeShaderPath.getData()),&LandscapeShader) ||
|
||||
!Group.Close())
|
||||
return;
|
||||
// Reinitialize
|
||||
InitShaders();
|
||||
iLandscapeShaderTime = FileTime(LandscapeShaderPath.getData());
|
||||
}
|
||||
}
|
||||
|
||||
int32_t C4LandscapeRenderGL::LookupTextureTransition(const char *szFrom, const char *szTo)
|
||||
{
|
||||
// Is this actually a transition? Otherwise we're looking for a single texture
|
||||
|
@ -976,7 +804,7 @@ void C4LandscapeRenderGL::BuildMatMap(GLfloat *pFMap, GLubyte *pIMap)
|
|||
void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo, const C4FoWRegion &Light)
|
||||
{
|
||||
// Must have GL and be initialized
|
||||
if(!pGL && !hProg) return;
|
||||
if(!pGL && !Shader.Initialised()) return;
|
||||
|
||||
// prepare rendering to surface
|
||||
C4Surface *sfcTarget = cgo.Surface;
|
||||
|
@ -990,58 +818,42 @@ void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo, const C4FoWRegion &Ligh
|
|||
while(glGetError()) {}
|
||||
|
||||
// Activate shader
|
||||
glUseProgramObjectARB(hProg);
|
||||
C4ShaderCall ShaderCall(&Shader);
|
||||
ShaderCall.Start();
|
||||
|
||||
// Bind data
|
||||
if (hUniforms[C4LRU_Resolution] != GLhandleARB(-1))
|
||||
glUniform2fARB(hUniforms[C4LRU_Resolution], Surfaces[0]->Wdt, Surfaces[0]->Hgt);
|
||||
if (hUniforms[C4LRU_Center] != GLhandleARB(-1))
|
||||
{
|
||||
float x = float(cgo.TargetX)+float(cgo.Wdt)/2,
|
||||
y = float(cgo.TargetY)+float(cgo.Hgt)/2;
|
||||
glUniform2fARB(hUniforms[C4LRU_Center],
|
||||
x / float(Surfaces[0]->Wdt), y / float(Surfaces[0]->Hgt));
|
||||
}
|
||||
if (hUniforms[C4LRU_MatMap] != GLhandleARB(-1))
|
||||
ShaderCall.SetUniform2f(C4LRU_Resolution, Surfaces[0]->Wdt, Surfaces[0]->Hgt);
|
||||
float centerX = float(cgo.TargetX)+float(cgo.Wdt)/2,
|
||||
centerY = float(cgo.TargetY)+float(cgo.Hgt)/2;
|
||||
ShaderCall.SetUniform2f(C4LRU_Center,
|
||||
centerX / float(Surfaces[0]->Wdt),
|
||||
centerY / float(Surfaces[0]->Hgt));
|
||||
if (Shader.HaveUniform(C4LRU_MatMap))
|
||||
{
|
||||
GLfloat MatMap[256];
|
||||
BuildMatMap(MatMap, NULL);
|
||||
glUniform1fvARB(hUniforms[C4LRU_MatMap], 256, MatMap);
|
||||
}
|
||||
if (hUniforms[C4LRU_MaterialDepth] != GLhandleARB(-1))
|
||||
glUniform1iARB(hUniforms[C4LRU_MaterialDepth], iMaterialTextureDepth);
|
||||
if (hUniforms[C4LRU_MaterialSize] != GLhandleARB(-1))
|
||||
glUniform2fARB(hUniforms[C4LRU_MaterialSize], float(iMaterialWidth) / ::Game.C4S.Landscape.MaterialZoom,
|
||||
float(iMaterialHeight) / ::Game.C4S.Landscape.MaterialZoom);
|
||||
if (hUniforms[C4LRU_AmbientScale] != GLhandleARB(-1))
|
||||
{
|
||||
// factor between actual landscape size and surface size, so that we can use the landscape
|
||||
// coordinates for the ambient map lookup.
|
||||
// TODO: These could actually be shader constants, and do not really need to be uniforms...
|
||||
const float sx = static_cast<float>(Surfaces[0]->Wdt) / iWidth;
|
||||
const float sy = static_cast<float>(Surfaces[0]->Hgt) / iHeight;
|
||||
glUniform2fARB(hUniforms[C4LRU_AmbientScale], sx, sy);
|
||||
ShaderCall.SetUniform1fv(C4LRU_MatMap, 256, MatMap);
|
||||
}
|
||||
ShaderCall.SetUniform1i(C4LRU_MaterialDepth, iMaterialTextureDepth);
|
||||
ShaderCall.SetUniform2f(C4LRU_MaterialSize,
|
||||
float(iMaterialWidth) / ::Game.C4S.Landscape.MaterialZoom,
|
||||
float(iMaterialHeight) / ::Game.C4S.Landscape.MaterialZoom);
|
||||
|
||||
// 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 != GLhandleARB(-1)) glUniform1iARB(hUniform, iUnit); \
|
||||
glActiveTexture(GL_TEXTURE0 + iUnit); \
|
||||
iUnitMap[iUnit] = iType; \
|
||||
glEnable(iType); \
|
||||
iUnit++; \
|
||||
assert(iUnit < 32); \
|
||||
} while(false)
|
||||
|
||||
// factor between actual landscape size and surface size, so that we can use the landscape
|
||||
// coordinates for the ambient map lookup.
|
||||
// TODO: These could actually be shader constants, and do not really need to be uniforms...
|
||||
ShaderCall.SetUniform2f(C4LRU_AmbientScale,
|
||||
static_cast<float>(Surfaces[0]->Wdt) / iWidth,
|
||||
static_cast<float>(Surfaces[0]->Hgt) / iHeight);
|
||||
|
||||
// Start binding textures
|
||||
if(hUniforms[C4LRU_LandscapeTex] != GLhandleARB(-1))
|
||||
if(Shader.HaveUniform(C4LRU_LandscapeTex))
|
||||
{
|
||||
GLint iLandscapeUnits[C4LR_SurfaceCount];
|
||||
for(int i = 0; i < C4LR_SurfaceCount; i++)
|
||||
{
|
||||
iLandscapeUnits[i] = iUnit;
|
||||
ALLOC_UNIT(GLhandleARB(-1), GL_TEXTURE_2D);
|
||||
iLandscapeUnits[i] = ShaderCall.AllocTexUnit(-1, GL_TEXTURE_2D) - GL_TEXTURE0;
|
||||
glBindTexture(GL_TEXTURE_2D, Surfaces[i]->ppTex[0]->texName);
|
||||
if (pGL->Zoom != 1.0)
|
||||
{
|
||||
|
@ -1054,34 +866,29 @@ void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo, const C4FoWRegion &Ligh
|
|||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
}
|
||||
}
|
||||
glUniform1ivARB(hUniforms[C4LRU_LandscapeTex], C4LR_SurfaceCount, iLandscapeUnits);
|
||||
ShaderCall.SetUniform1iv(C4LRU_LandscapeTex, C4LR_SurfaceCount, iLandscapeUnits);
|
||||
}
|
||||
if(hUniforms[C4LRU_LightTex] != GLhandleARB(-1))
|
||||
if(ShaderCall.AllocTexUnit(C4LRU_LightTex, GL_TEXTURE_2D))
|
||||
{
|
||||
ALLOC_UNIT(hUniforms[C4LRU_LightTex], GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, Light.getSurface()->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_AmbientTex] != GLhandleARB(-1))
|
||||
if(ShaderCall.AllocTexUnit(C4LRU_AmbientTex, GL_TEXTURE_2D))
|
||||
{
|
||||
ALLOC_UNIT(hUniforms[C4LRU_AmbientTex], GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, Light.getFoW()->Ambient.Tex);
|
||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
}
|
||||
if(hUniforms[C4LRU_ScalerTex] != GLhandleARB(-1))
|
||||
if(ShaderCall.AllocTexUnit(C4LRU_ScalerTex, GL_TEXTURE_2D))
|
||||
{
|
||||
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] != GLhandleARB(-1))
|
||||
if(ShaderCall.AllocTexUnit(C4LRU_MaterialTex, GL_TEXTURE_3D))
|
||||
{
|
||||
ALLOC_UNIT(hUniforms[C4LRU_MaterialTex], GL_TEXTURE_3D);
|
||||
|
||||
// Decide which mip-map level to use
|
||||
// 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++; }
|
||||
|
@ -1089,9 +896,8 @@ void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo, const C4FoWRegion &Ligh
|
|||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
}
|
||||
if(hUniforms[C4LRU_MatMapTex] != GLhandleARB(-1))
|
||||
if(ShaderCall.AllocTexUnit(C4LRU_MatMapTex, GL_TEXTURE_1D))
|
||||
{
|
||||
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);
|
||||
|
@ -1124,19 +930,17 @@ void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo, const C4FoWRegion &Ligh
|
|||
tTexBlt.top = ty;
|
||||
tTexBlt.right = tx + float(cgo.Wdt) * pGL->Zoom;
|
||||
tTexBlt.bottom= ty + float(cgo.Hgt) * pGL->Zoom;
|
||||
|
||||
|
||||
// Blend it
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
#if 1
|
||||
|
||||
// To the blit
|
||||
glColor3f(1.0, 1.0, 1.0);
|
||||
glBegin(GL_QUADS);
|
||||
|
||||
#define VERTEX(x, y) \
|
||||
glMultiTexCoord2f(GL_TEXTURE0, fTexBlt.x, fTexBlt.y); \
|
||||
glMultiTexCoord2f(GL_TEXTURE1, lTexBlt.x, lTexBlt.y); \
|
||||
glMultiTexCoord2f(hLandscapeTexCoord, fTexBlt.x, fTexBlt.y); \
|
||||
glMultiTexCoord2f(hLightTexCoord, lTexBlt.x, lTexBlt.y); \
|
||||
glVertex2f(tTexBlt.x, tTexBlt.y);
|
||||
|
||||
VERTEX(left, top);
|
||||
|
@ -1145,59 +949,12 @@ void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo, const C4FoWRegion &Ligh
|
|||
VERTEX(left, bottom);
|
||||
|
||||
#undef VERTEX
|
||||
|
||||
|
||||
glEnd();
|
||||
|
||||
#else
|
||||
// blit positions
|
||||
C4BltVertex Vtx[4];
|
||||
Vtx[0].ftx = tTexBlt.left; Vtx[0].fty = tTexBlt.top;
|
||||
Vtx[1].ftx = tTexBlt.right; Vtx[1].fty = tTexBlt.top;
|
||||
Vtx[2].ftx = tTexBlt.right; Vtx[2].fty = tTexBlt.bottom;
|
||||
Vtx[3].ftx = tTexBlt.left; Vtx[3].fty = tTexBlt.bottom;
|
||||
Vtx[0].tx = fTexBlt.left; Vtx[0].ty = fTexBlt.top;
|
||||
Vtx[1].tx = fTexBlt.right; Vtx[1].ty = fTexBlt.top;
|
||||
Vtx[2].tx = fTexBlt.right; Vtx[2].ty = fTexBlt.bottom;
|
||||
Vtx[3].tx = fTexBlt.left; Vtx[3].ty = fTexBlt.bottom;
|
||||
for (int i=0; i<4; ++i)
|
||||
{
|
||||
Vtx[i].tx /= float(Surfaces[0]->Wdt);
|
||||
Vtx[i].ty /= float(Surfaces[0]->Hgt);
|
||||
Vtx[i].ftz = 0;
|
||||
Vtx[i].color[0] = 255;
|
||||
Vtx[i].color[1] = 255;
|
||||
Vtx[i].color[2] = 255;
|
||||
Vtx[i].color[3] = 255;
|
||||
//DwTo4UB(RGBA(255, 255, 255, 255), Vtx[i].color);
|
||||
}
|
||||
|
||||
// color modulation?
|
||||
//DWORD dwModClr = BlitModulated ? BlitModulateClr : 0xffffffff;
|
||||
//for (int i=0; i<4; ++i)
|
||||
// DwTo4UB(dwModClr | dwModMask, Vtx[i].color);
|
||||
|
||||
|
||||
// Blit
|
||||
glInterleavedArrays(GL_T2F_C4UB_V3F, sizeof(C4BltVertex), Vtx);
|
||||
glDrawArrays(GL_QUADS, 0, 4);
|
||||
#endif
|
||||
|
||||
// Remove shader
|
||||
glUseProgramObjectARB(0);
|
||||
ShaderCall.Finish();
|
||||
|
||||
// Unbind textures
|
||||
while(iUnit > 0)
|
||||
{
|
||||
iUnit--;
|
||||
glActiveTexture(GL_TEXTURE0 + iUnit);
|
||||
glDisable(iUnitMap[iUnit]);
|
||||
}
|
||||
|
||||
// Got an error?
|
||||
if(int err = glGetError())
|
||||
{
|
||||
LogF("GL error: %d", err /*, gluErrorString(err)*/);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #ifndef USE_CONSOLE
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "C4Surface.h"
|
||||
#include "C4FacetEx.h"
|
||||
#include "C4Shader.h"
|
||||
|
||||
// Data we want to store per landscape pixel
|
||||
enum C4LR_Byte {
|
||||
|
@ -89,13 +90,12 @@ private:
|
|||
C4Surface *Surfaces[C4LR_SurfaceCount];
|
||||
|
||||
// shader sources
|
||||
StdStrBuf LandscapeShader;
|
||||
StdStrBuf LandscapeShaderPath;
|
||||
int iLandscapeShaderTime;
|
||||
// shaders
|
||||
GLhandleARB hVert, hFrag, hProg;
|
||||
// shader variables
|
||||
GLhandleARB hUniforms[C4LRU_Count];
|
||||
// shader
|
||||
C4Shader Shader;
|
||||
static const char *UniformNames[];
|
||||
GLenum hLandscapeTexCoord, hLightTexCoord;
|
||||
|
||||
// 3D texture of material textures
|
||||
GLuint hMaterialTexture[C4LR_MipMapCount];
|
||||
|
@ -109,7 +109,6 @@ private:
|
|||
// scaler image
|
||||
C4FacetSurface fctScaler;
|
||||
|
||||
|
||||
public:
|
||||
virtual bool ReInit(int32_t iWidth, int32_t iHeight);
|
||||
virtual bool Init(int32_t iWidth, int32_t iHeight, C4TextureMap *pMap, C4GroupSet *pGraphics);
|
||||
|
@ -126,15 +125,9 @@ private:
|
|||
bool InitLandscapeTexture();
|
||||
bool InitMaterialTexture(C4TextureMap *pMap);
|
||||
bool LoadShaders(C4GroupSet *pGraphics);
|
||||
void ClearShaders();
|
||||
bool LoadScaler(C4GroupSet *pGraphics);
|
||||
|
||||
void DumpInfoLog(const char *szWhat, GLhandleARB hShader, int32_t iWorkaround);
|
||||
int GetObjectStatus(GLhandleARB hObj, GLenum type);
|
||||
GLhandleARB CreateShader(GLenum iShaderType, const char *szWhat, const char *szCode, int32_t iWorkaround);
|
||||
|
||||
bool InitShaders();
|
||||
void ClearShaders();
|
||||
|
||||
int32_t LookupTextureTransition(const char *szFrom, const char *szTo);
|
||||
void AddTextureTransition(const char *szFrom, const char *szTo);
|
||||
void AddTextureAnim(const char *szTextureAnim);
|
||||
|
|
Loading…
Reference in New Issue