forked from Mirrors/openclonk
Make mesh shaders use the C4Shader slice machinery
parent
fdd94a3311
commit
8686441d45
|
@ -1,10 +0,0 @@
|
|||
varying vec2 texcoord;
|
||||
|
||||
slice(init+1)
|
||||
{
|
||||
// TODO: Add emission part of the material. Note we cannot just
|
||||
// add this to the color, but it would need to be handled separately,
|
||||
// such that it is independent from the incident light direction.
|
||||
// Could make it #ifdef MESH.
|
||||
color = gl_FrontMaterial.diffuse * color;
|
||||
}
|
|
@ -3,8 +3,17 @@ uniform vec4 clrMod;
|
|||
slice(init)
|
||||
{
|
||||
#define color gl_FragColor
|
||||
|
||||
#ifdef MESH
|
||||
// TODO: Add emission part of the material. Note we cannot just
|
||||
// add this to the color, but it would need to be handled separately,
|
||||
// such that it is independent from the incident light direction.
|
||||
color = gl_FrontMaterial.diffuse;
|
||||
#else
|
||||
vec4 baseColor = gl_Color;
|
||||
color = baseColor;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
slice(color)
|
||||
|
|
|
@ -21,7 +21,7 @@ slice(normal)
|
|||
vec3 normal = normalize(gl_NormalMatrix * normalPxDir);
|
||||
#else
|
||||
#ifdef MESH
|
||||
vec4 normal = normalize(gl_NormalMatrix * normalDir);
|
||||
vec3 normal = normalDir; // Normal matrix is already applied in vertex shader
|
||||
#else
|
||||
vec3 normal = vec3(0.0, 0.0, 1.0);
|
||||
#endif
|
||||
|
|
|
@ -32,14 +32,6 @@ material NormalMap
|
|||
|
||||
fragment_program_ref normal_map_fragment
|
||||
{
|
||||
// Will be configured automatically via slices:
|
||||
// param_named_auto oc_Mod2 oc_mod2
|
||||
// param_named_auto oc_ColorModulation oc_color_modulation
|
||||
// param_named_auto oc_UseLight oc_use_light
|
||||
// param_named_auto oc_Light oc_light
|
||||
// param_named_auto oc_Ambient oc_ambient
|
||||
// param_named_auto oc_AmbientBrightness oc_ambient_brightness
|
||||
|
||||
param_named basemap int 0
|
||||
param_named normalTex int 1
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
uniform sampler2D basemap;
|
||||
uniform sampler2D normalTex;
|
||||
|
||||
#ifndef OPENCLONK
|
||||
#define slice(x)
|
||||
|
@ -11,11 +12,10 @@ void main()
|
|||
|
||||
slice(init+1)
|
||||
{
|
||||
// This will make ObjectLightShader.glsl pick up the path that
|
||||
// Looks up the direction from the normal map.
|
||||
// This picks up the normal map lookup in ObjectLightShader.c:
|
||||
#define HAVE_NORMALMAP
|
||||
|
||||
color = color * gl_FrontMaterial.diffuse * texture2D(basemap, texcoord);
|
||||
color = color * texture2D(basemap, texcoord);
|
||||
|
||||
#ifndef OPENCLONK
|
||||
// TODO: Could apply some default lighting here, for viewing the mesh in
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
varying vec2 texcoord;
|
||||
|
||||
#ifndef OPENCLONK
|
||||
#define slice(x)
|
||||
varying vec2 texcoord;
|
||||
|
||||
void main()
|
||||
{
|
||||
#endif
|
||||
|
|
|
@ -218,8 +218,7 @@ public:
|
|||
void Grayscale(C4Surface * sfcSfc, int32_t iOffset = 0);
|
||||
void LockingPrimary() { PrimaryLocked=true; }
|
||||
void PrimaryUnlocked() { PrimaryLocked=false; }
|
||||
virtual std::unique_ptr<StdMeshMaterialShader> CompileShader(const char* language, StdMeshMaterialShader::Type type, const char* text) = 0; // Compile shader of the given language
|
||||
virtual bool PrepareMaterial(StdMeshMatManager& mat_manager, StdMeshMaterial &mat) = 0; // Find best technique, fail if there is none
|
||||
virtual bool PrepareMaterial(StdMeshMatManager& mat_manager, StdMeshMaterialLoader& loader, StdMeshMaterial& mat) = 0; // Find best technique, fail if there is none
|
||||
virtual bool PrepareRendering(C4Surface * sfcToSurface) = 0; // check if/make rendering possible to given surface
|
||||
// Blit
|
||||
virtual void BlitLandscape(C4Surface * sfcSource, float fx, float fy,
|
||||
|
|
|
@ -37,110 +37,6 @@
|
|||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
||||
C4DrawGLShader::C4DrawGLShader(Type shader_type)
|
||||
{
|
||||
GLint gl_type;
|
||||
switch(shader_type)
|
||||
{
|
||||
case FRAGMENT: gl_type = GL_FRAGMENT_SHADER_ARB; break;
|
||||
case VERTEX: gl_type = GL_VERTEX_SHADER_ARB; break;
|
||||
case GEOMETRY: gl_type = GL_GEOMETRY_SHADER_ARB; break;
|
||||
default: assert(false); break;
|
||||
}
|
||||
|
||||
Shader = glCreateShaderObjectARB(gl_type);
|
||||
if(!Shader) throw C4DrawGLError(FormatString("Failed to create shader")); // TODO: custom error class?
|
||||
}
|
||||
|
||||
C4DrawGLShader::~C4DrawGLShader()
|
||||
{
|
||||
glDeleteObjectARB(Shader);
|
||||
}
|
||||
|
||||
void C4DrawGLShader::Load(const char* code)
|
||||
{
|
||||
glShaderSourceARB(Shader, 1, &code, NULL);
|
||||
glCompileShaderARB(Shader);
|
||||
|
||||
GLint compile_status;
|
||||
glGetObjectParameterivARB(Shader, GL_OBJECT_COMPILE_STATUS_ARB, &compile_status);
|
||||
if(compile_status != GL_TRUE)
|
||||
{
|
||||
const char* shader_type_str;
|
||||
switch(GetType())
|
||||
{
|
||||
case VERTEX: shader_type_str = "vertex"; break;
|
||||
case FRAGMENT: shader_type_str = "fragment"; break;
|
||||
case GEOMETRY: shader_type_str = "geometry"; break;
|
||||
default: assert(false); break;
|
||||
}
|
||||
|
||||
GLint length;
|
||||
glGetObjectParameterivARB(Shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
|
||||
if(length > 0)
|
||||
{
|
||||
std::vector<char> error_message(length);
|
||||
glGetInfoLogARB(Shader, length, NULL, &error_message[0]);
|
||||
throw C4DrawGLError(FormatString("Failed to compile %s shader: %s", shader_type_str, &error_message[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw C4DrawGLError(FormatString("Failed to compile %s shader", shader_type_str));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StdMeshMaterialShader::Type C4DrawGLShader::GetType() const
|
||||
{
|
||||
GLint shader_type;
|
||||
glGetObjectParameterivARB(Shader, GL_OBJECT_SUBTYPE_ARB, &shader_type);
|
||||
|
||||
switch(shader_type)
|
||||
{
|
||||
case GL_FRAGMENT_SHADER_ARB: return FRAGMENT;
|
||||
case GL_VERTEX_SHADER_ARB: return VERTEX;
|
||||
case GL_GEOMETRY_SHADER_ARB: return GEOMETRY;
|
||||
default: assert(false); return static_cast<StdMeshMaterialShader::Type>(-1);
|
||||
}
|
||||
}
|
||||
|
||||
C4DrawGLProgram::C4DrawGLProgram(const C4DrawGLShader* fragment_shader, const C4DrawGLShader* vertex_shader, const C4DrawGLShader* geometry_shader)
|
||||
{
|
||||
Program = glCreateProgramObjectARB();
|
||||
if(fragment_shader != NULL)
|
||||
glAttachObjectARB(Program, fragment_shader->Shader);
|
||||
if(vertex_shader != NULL)
|
||||
glAttachObjectARB(Program, vertex_shader->Shader);
|
||||
if(geometry_shader != NULL)
|
||||
glAttachObjectARB(Program, geometry_shader->Shader);
|
||||
glLinkProgramARB(Program);
|
||||
|
||||
GLint link_status;
|
||||
glGetObjectParameterivARB(Program, GL_OBJECT_LINK_STATUS_ARB, &link_status);
|
||||
if(link_status != GL_TRUE)
|
||||
{
|
||||
GLint length;
|
||||
glGetObjectParameterivARB(Program, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
|
||||
if(length > 0)
|
||||
{
|
||||
std::vector<char> error_message(length);
|
||||
glGetInfoLogARB(Program, length, NULL, &error_message[0]);
|
||||
glDeleteObjectARB(Program);
|
||||
throw C4DrawGLError(FormatString("Failed to link program: %s", &error_message[0]));
|
||||
}
|
||||
else
|
||||
{
|
||||
glDeleteObjectARB(Program);
|
||||
throw C4DrawGLError(StdStrBuf("Failed to link program"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
C4DrawGLProgram::~C4DrawGLProgram()
|
||||
{
|
||||
glDeleteObjectARB(Program);
|
||||
}
|
||||
|
||||
CStdGL::CStdGL():
|
||||
pMainCtx(0)
|
||||
{
|
||||
|
@ -362,24 +258,13 @@ void CStdGL::SetupMultiBlt(C4ShaderCall& call, const C4BltTransform* pTransform,
|
|||
{
|
||||
const C4Rect ClipRect = GetClipRect();
|
||||
const C4Rect LightRect = pFoW->getRegion();
|
||||
const int32_t iLightWdt = pFoW->getSurface()->Wdt;
|
||||
const int32_t iLightHgt = pFoW->getSurface()->Hgt;
|
||||
const float zx = static_cast<float>(LightRect.Wdt) / ClipRect.Wdt;
|
||||
const float zy = static_cast<float>(LightRect.Hgt) / ClipRect.Hgt;
|
||||
|
||||
// Dynamic Light
|
||||
call.AllocTexUnit(C4SSU_LightTex, GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, pFoW->getSurface()->ppTex[0]->texName);
|
||||
|
||||
// Transformation to go from fragment coordinates to light texture coordinates
|
||||
// TODO: Should be moved to C4FoWRegion...
|
||||
float lightTransform[6];
|
||||
lightTransform[0] = zx / iLightWdt;
|
||||
lightTransform[1] = 0.f;
|
||||
lightTransform[2] = -ClipRect.x * zx / iLightWdt;
|
||||
lightTransform[3] = 0.f;
|
||||
lightTransform[4] = zy / iLightHgt;
|
||||
lightTransform[5] = 1.0f - (LightRect.Hgt) / iLightHgt;
|
||||
pFoW->GetFragTransform(ClipRect, lightTransform);
|
||||
call.SetUniformMatrix2x3fv(C4SSU_LightTransform, 1, lightTransform);
|
||||
|
||||
// Ambient Light
|
||||
|
@ -585,6 +470,7 @@ bool CStdGL::CreateSpriteShader(C4Shader& shader, const char* name, int ssc, C4G
|
|||
shader.AddTexCoord("texcoord");
|
||||
|
||||
// Then load slices for fragment shader
|
||||
shader.AddFragmentSlice(-1, "#define OPENCLONK");
|
||||
if (ssc & C4SSC_MOD2) shader.AddFragmentSlice(-1, "#define CLRMOD_MOD2");
|
||||
if (ssc & C4SSC_NORMAL) shader.AddFragmentSlice(-1, "#define HAVE_NORMALMAP");
|
||||
if (ssc & C4SSC_LIGHT) shader.AddFragmentSlice(-1, "#define HAVE_LIGHT");
|
||||
|
|
|
@ -50,29 +50,6 @@ private:
|
|||
StdCopyStrBuf Buf;
|
||||
};
|
||||
|
||||
// GLSL shaders
|
||||
class C4DrawGLShader: public StdMeshMaterialShader
|
||||
{
|
||||
public:
|
||||
C4DrawGLShader(Type shader_type);
|
||||
virtual ~C4DrawGLShader();
|
||||
|
||||
void Load(const char* code);
|
||||
|
||||
virtual Type GetType() const;
|
||||
|
||||
GLuint Shader;
|
||||
};
|
||||
|
||||
class C4DrawGLProgram: public StdMeshMaterialProgram
|
||||
{
|
||||
public:
|
||||
C4DrawGLProgram(const C4DrawGLShader* fragment_shader, const C4DrawGLShader* vertex_shader, const C4DrawGLShader* geometry_shader);
|
||||
virtual ~C4DrawGLProgram();
|
||||
|
||||
GLuint Program;
|
||||
};
|
||||
|
||||
// Shader combinations
|
||||
static const int C4SSC_MOD2 = 1; // signed addition instead of multiplication for clrMod
|
||||
static const int C4SSC_BASE = 2; // use a base texture instead of just a single color
|
||||
|
@ -186,8 +163,7 @@ public:
|
|||
virtual bool OnResolutionChanged(unsigned int iXRes, unsigned int iYRes); // reinit clipper for new resolution
|
||||
// Clipper
|
||||
bool UpdateClipper(); // set current clipper to render target
|
||||
std::unique_ptr<StdMeshMaterialShader> CompileShader(const char* language, StdMeshMaterialShader::Type type, const char* text);
|
||||
bool PrepareMaterial(StdMeshMatManager& mat_manager, StdMeshMaterial& mat);
|
||||
bool PrepareMaterial(StdMeshMatManager& mat_manager, StdMeshMaterialLoader& loader, StdMeshMaterial& mat);
|
||||
// Surface
|
||||
bool PrepareRendering(C4Surface * sfcToSurface); // check if/make rendering possible to given surface
|
||||
virtual CStdGLCtx *CreateContext(C4Window * pWindow, C4AbstractApp *pApp);
|
||||
|
|
|
@ -78,7 +78,7 @@ namespace
|
|||
StdStrBuf alpha_source1 = FormatString("%s.a", TextureUnitSourceToCode(index, texunit.AlphaOpSources[0], texunit.ColorOpManualColor1, texunit.AlphaOpManualAlpha1).getData());
|
||||
StdStrBuf alpha_source2 = FormatString("%s.a", TextureUnitSourceToCode(index, texunit.AlphaOpSources[1], texunit.ColorOpManualColor2, texunit.AlphaOpManualAlpha2).getData());
|
||||
|
||||
return FormatString("currentColor = vec4(%s, %s);", TextureUnitBlendToCode(index, texunit.ColorOpEx, color_source1.getData(), color_source2.getData(), texunit.ColorOpManualFactor).getData(), TextureUnitBlendToCode(index, texunit.AlphaOpEx, alpha_source1.getData(), alpha_source2.getData(), texunit.AlphaOpManualFactor).getData());
|
||||
return FormatString("currentColor = vec4(%s, %s);\n", TextureUnitBlendToCode(index, texunit.ColorOpEx, color_source1.getData(), color_source2.getData(), texunit.ColorOpManualFactor).getData(), TextureUnitBlendToCode(index, texunit.AlphaOpEx, alpha_source1.getData(), alpha_source2.getData(), texunit.AlphaOpManualFactor).getData());
|
||||
}
|
||||
|
||||
// Simple helper function
|
||||
|
@ -105,19 +105,29 @@ namespace
|
|||
StdStrBuf buf;
|
||||
|
||||
buf.Copy(
|
||||
"varying vec3 normal;"
|
||||
"varying vec2 texcoord;"
|
||||
"void main()"
|
||||
"{"
|
||||
" normal = normalize(gl_NormalMatrix * gl_Normal);" // TODO: Do we need to normalize? I think we enable GL_NORMALIZE in cases we have to... note if we don't normalize, interpolation of normals won't work
|
||||
" texcoord = gl_MultiTexCoord0.xy;"
|
||||
" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;"
|
||||
"}"
|
||||
"varying vec3 normalDir;\n"
|
||||
"\n"
|
||||
"slice(position)\n"
|
||||
"{\n"
|
||||
" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"slice(texcoord)\n"
|
||||
"{\n"
|
||||
" texcoord = gl_MultiTexCoord0.xy;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"slice(normal)\n"
|
||||
"{\n"
|
||||
" normalDir = normalize(gl_NormalMatrix * gl_Normal);\n"
|
||||
"}\n"
|
||||
);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
// Note this only gets the code which inserts the slices specific for the pass
|
||||
// -- other slices are independent from this!
|
||||
StdStrBuf GetFragmentShaderCodeForPass(const StdMeshMaterialPass& pass, StdMeshMaterialShaderParameters& params)
|
||||
{
|
||||
StdStrBuf buf;
|
||||
|
@ -134,68 +144,24 @@ namespace
|
|||
|
||||
if(texunit.HasTexture())
|
||||
{
|
||||
textureUnitDeclCode.Append(FormatString("uniform sampler2D oc_Texture%u;", texIndex).getData());
|
||||
textureUnitDeclCode.Append(FormatString("uniform sampler2D oc_Texture%u;\n", texIndex).getData());
|
||||
params.AddParameter(FormatString("oc_Texture%u", texIndex).getData(), StdMeshMaterialShaderParameter::INT).GetInt() = texIndex;
|
||||
++texIndex;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Only add this parameter if the player color is actually used in the shader -- otherwise
|
||||
// it is optimized out anyway.
|
||||
params.AddParameter("oc_PlayerColor", StdMeshMaterialShaderParameter::AUTO).GetAuto() = StdMeshMaterialShaderParameter::AUTO_OC_PLAYER_COLOR;
|
||||
params.AddParameter("oc_ColorModulation", StdMeshMaterialShaderParameter::AUTO).GetAuto() = StdMeshMaterialShaderParameter::AUTO_OC_COLOR_MODULATION;
|
||||
params.AddParameter("oc_Mod2", StdMeshMaterialShaderParameter::AUTO).GetAuto() = StdMeshMaterialShaderParameter::AUTO_OC_MOD2;
|
||||
params.AddParameter("oc_UseLight", StdMeshMaterialShaderParameter::AUTO).GetAuto() = StdMeshMaterialShaderParameter::AUTO_OC_USE_LIGHT;
|
||||
params.AddParameter("oc_Light", StdMeshMaterialShaderParameter::AUTO).GetAuto() = StdMeshMaterialShaderParameter::AUTO_OC_LIGHT;
|
||||
params.AddParameter("oc_Ambient", StdMeshMaterialShaderParameter::AUTO).GetAuto() = StdMeshMaterialShaderParameter::AUTO_OC_AMBIENT;
|
||||
params.AddParameter("oc_AmbientBrightness", StdMeshMaterialShaderParameter::AUTO).GetAuto() = StdMeshMaterialShaderParameter::AUTO_OC_AMBIENT_BRIGHTNESS;
|
||||
|
||||
return FormatString(
|
||||
"varying vec3 normal;" // linearly interpolated -- not necessarily normalized
|
||||
"varying vec2 texcoord;"
|
||||
"%s" // Texture units with active textures, only if >0 texture units
|
||||
"uniform vec3 oc_PlayerColor;"
|
||||
"uniform vec4 oc_ColorModulation;"
|
||||
"uniform int oc_Mod2;"
|
||||
"uniform int oc_UseLight;"
|
||||
"uniform sampler2D oc_Light;"
|
||||
"uniform sampler2D oc_Ambient;"
|
||||
"uniform float oc_AmbientBrightness;"
|
||||
"void main()"
|
||||
"{"
|
||||
" vec4 lightClr;"
|
||||
" vec3 normalDir = normalize(normal);"
|
||||
" if(oc_UseLight != 0)"
|
||||
" {"
|
||||
// Light calculation
|
||||
" vec4 lightPx = texture2D(oc_Light, (gl_TextureMatrix[%d] * gl_FragCoord).xy);"
|
||||
" vec3 lightDir = normalize(vec3(vec2(1.0, 1.0) - lightPx.gb * 3.0, 0.3));"
|
||||
" float lightIntensity = 2.0 * lightPx.r;"
|
||||
" float ambient = texture2D(oc_Ambient, (gl_TextureMatrix[%d] * gl_FragCoord).xy).r * oc_AmbientBrightness;"
|
||||
// Don't actually use the ambient part of the material and instead a diffuse light from the front, like in the master branch
|
||||
// Because meshes are not tuned for ambient light at the moment, every mesh material would need to be fixed.
|
||||
// Otherwise the first term would be ambient * gl_FrontMaterial.ambient
|
||||
" lightClr = vec4(ambient * (gl_FrontMaterial.emission.rgb + gl_FrontMaterial.diffuse.rgb * (0.25 + 0.75 * max(dot(normalDir, vec3(0.0, 0.0, 1.0)), 0.0))) + (1.0 - min(ambient, 1.0)) * lightIntensity * (gl_FrontMaterial.emission.rgb + gl_FrontMaterial.diffuse.rgb * (0.25 + 0.75 * max(dot(normalDir, lightDir), 0.0))), gl_FrontMaterial.emission.a + gl_FrontMaterial.diffuse.a);"
|
||||
" }"
|
||||
" else"
|
||||
" {"
|
||||
// No light -- place a simple directional light from the front (equivalent to the behaviour in
|
||||
// the master branch, modulo interpolated normals)
|
||||
" vec3 lightDir = vec3(0.0, 0.0, 1.0);"
|
||||
" lightClr = vec4(gl_FrontMaterial.emission.rgb + gl_FrontMaterial.diffuse.rgb * (0.25 + 0.75 * max(dot(normalDir, lightDir), 0.0)), gl_FrontMaterial.emission.a + gl_FrontMaterial.diffuse.a);"
|
||||
" }"
|
||||
// Texture units from material script
|
||||
" vec4 diffuse = lightClr;"
|
||||
" vec4 currentColor = diffuse;"
|
||||
" %s"
|
||||
// Output with color modulation and mod2
|
||||
" if(oc_Mod2 != 0)"
|
||||
" gl_FragColor = clamp(2.0 * currentColor * oc_ColorModulation - 0.5, 0.0, 1.0);"
|
||||
" else"
|
||||
" gl_FragColor = clamp(currentColor * oc_ColorModulation, 0.0, 1.0);"
|
||||
"}",
|
||||
"%s\n" // Texture units with active textures, only if >0 texture units
|
||||
"uniform vec3 oc_PlayerColor;\n" // This needs to be in-sync with the naming in StdMeshMaterialProgram::CompileShader()
|
||||
"\n"
|
||||
"slice(texture)\n"
|
||||
"{\n"
|
||||
" vec4 diffuse = color;\n"
|
||||
" vec4 currentColor = diffuse;\n"
|
||||
" %s\n"
|
||||
" color = currentColor;\n"
|
||||
"}\n",
|
||||
textureUnitDeclCode.getData(),
|
||||
(int)texIndex, (int)texIndex + 1, // The light and ambient textures are added after all other textures
|
||||
textureUnitCode.getData()
|
||||
);
|
||||
}
|
||||
|
@ -211,48 +177,7 @@ namespace
|
|||
}
|
||||
} // anonymous namespace
|
||||
|
||||
class C4DrawMeshGLProgramInstance: public StdMeshMaterialPass::ProgramInstance
|
||||
{
|
||||
public:
|
||||
C4DrawMeshGLProgramInstance(const C4DrawGLProgram* program);
|
||||
void AddParameters(const StdMeshMaterialShaderParameters& parameters);
|
||||
|
||||
struct Parameter {
|
||||
GLint Location;
|
||||
const StdMeshMaterialShaderParameter* ShaderParameter;
|
||||
};
|
||||
|
||||
std::vector<Parameter> Parameters;
|
||||
};
|
||||
|
||||
C4DrawMeshGLProgramInstance::C4DrawMeshGLProgramInstance(const C4DrawGLProgram* program):
|
||||
StdMeshMaterialPass::ProgramInstance(program)
|
||||
{
|
||||
}
|
||||
|
||||
void C4DrawMeshGLProgramInstance::AddParameters(const StdMeshMaterialShaderParameters& parameters)
|
||||
{
|
||||
const C4DrawGLProgram* program = static_cast<const C4DrawGLProgram*>(Program);
|
||||
for(unsigned int i = 0; i < parameters.NamedParameters.size(); ++i)
|
||||
{
|
||||
const GLint location = glGetUniformLocationARB(program->Program, parameters.NamedParameters[i].first.getData());
|
||||
Parameters.push_back(Parameter());
|
||||
Parameters.back().Location = location;
|
||||
Parameters.back().ShaderParameter = ¶meters.NamedParameters[i].second;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<StdMeshMaterialShader> CStdGL::CompileShader(const char* language, StdMeshMaterialShader::Type type, const char* text)
|
||||
{
|
||||
if(strcmp(language, "glsl") != 0)
|
||||
throw C4DrawGLError(StdStrBuf("Not a GLSL shader"));
|
||||
|
||||
std::unique_ptr<C4DrawGLShader> shader(new C4DrawGLShader(type));
|
||||
shader->Load(text);
|
||||
return std::move(shader);
|
||||
}
|
||||
|
||||
bool CStdGL::PrepareMaterial(StdMeshMatManager& mat_manager, StdMeshMaterial& mat)
|
||||
bool CStdGL::PrepareMaterial(StdMeshMatManager& mat_manager, StdMeshMaterialLoader& loader, StdMeshMaterial& mat)
|
||||
{
|
||||
// TODO: If a technique is not available, show an error message what the problem is
|
||||
|
||||
|
@ -409,43 +334,36 @@ bool CStdGL::PrepareMaterial(StdMeshMatManager& mat_manager, StdMeshMaterial& ma
|
|||
} // loop over textures
|
||||
} // loop over texture units
|
||||
|
||||
try
|
||||
// Create fragment and/or vertex shader
|
||||
// if a custom shader is not provided.
|
||||
// Re-use existing programs if the generated
|
||||
// code is the same (determined by SHA1 hash).
|
||||
if(!pass.VertexShader.Shader)
|
||||
{
|
||||
// Create fragment and/or vertex shader
|
||||
// if a custom shader is not provided.
|
||||
// Re-use existing programs if the generated
|
||||
// code is the same (determined by SHA1 hash).
|
||||
if(!pass.VertexShader.Shader)
|
||||
{
|
||||
StdStrBuf buf = GetVertexShaderCodeForPass(pass);
|
||||
StdStrBuf hash = GetSHA1HexDigest(buf.getData(), buf.getLength());
|
||||
pass.VertexShader.Shader = mat_manager.AddShader(hash.getData(), "glsl", StdMeshMaterialShader::VERTEX, buf.getData(), true);
|
||||
}
|
||||
|
||||
if(!pass.FragmentShader.Shader)
|
||||
{
|
||||
// TODO: Should use shared_params once we introduce them
|
||||
StdStrBuf buf = GetFragmentShaderCodeForPass(pass, pass.FragmentShader.Parameters);
|
||||
StdStrBuf hash = GetSHA1HexDigest(buf.getData(), buf.getLength());
|
||||
pass.FragmentShader.Shader = mat_manager.AddShader(hash.getData(), "glsl", StdMeshMaterialShader::FRAGMENT, buf.getData(), true);
|
||||
}
|
||||
|
||||
// Then, link the program, and resolve parameter locations
|
||||
const C4DrawGLShader* fragment_shader = static_cast<const C4DrawGLShader*>(pass.FragmentShader.Shader);
|
||||
const C4DrawGLShader* vertex_shader = static_cast<const C4DrawGLShader*>(pass.VertexShader.Shader);
|
||||
const C4DrawGLShader* geometry_shader = static_cast<const C4DrawGLShader*>(pass.GeometryShader.Shader);
|
||||
std::unique_ptr<C4DrawGLProgram> program(new C4DrawGLProgram(fragment_shader, vertex_shader, geometry_shader));
|
||||
const StdMeshMaterialProgram* added_program = &mat_manager.AddProgram(fragment_shader, vertex_shader, geometry_shader, std::move(program));
|
||||
std::unique_ptr<C4DrawMeshGLProgramInstance> program_instance(new C4DrawMeshGLProgramInstance(static_cast<const C4DrawGLProgram*>(added_program)));
|
||||
if(pass.FragmentShader.Shader) program_instance->AddParameters(pass.FragmentShader.Parameters);
|
||||
if(pass.VertexShader.Shader) program_instance->AddParameters(pass.VertexShader.Parameters);
|
||||
if(pass.GeometryShader.Shader) program_instance->AddParameters(pass.GeometryShader.Parameters);
|
||||
pass.Program = std::move(program_instance);
|
||||
StdStrBuf buf = GetVertexShaderCodeForPass(pass);
|
||||
StdStrBuf hash = GetSHA1HexDigest(buf.getData(), buf.getLength());
|
||||
pass.VertexShader.Shader = mat_manager.AddShader("auto-generated vertex shader", hash.getData(), "glsl", SMMS_VERTEX, buf.getData(), true);
|
||||
}
|
||||
catch(const C4DrawGLError& error)
|
||||
|
||||
if(!pass.FragmentShader.Shader)
|
||||
{
|
||||
// TODO: Should use shared_params once we introduce them
|
||||
StdStrBuf buf = GetFragmentShaderCodeForPass(pass, pass.FragmentShader.Parameters);
|
||||
StdStrBuf hash = GetSHA1HexDigest(buf.getData(), buf.getLength());
|
||||
pass.FragmentShader.Shader = mat_manager.AddShader("auto-generated fragment shader", hash.getData(), "glsl", SMMS_FRAGMENT, buf.getData(), true);
|
||||
}
|
||||
|
||||
// Then, link the program, and resolve parameter locations
|
||||
StdStrBuf name(FormatString("%s:%s:%s", mat.Name.getData(), technique.Name.getData(), pass.Name.getData()));
|
||||
const StdMeshMaterialProgram* added_program = mat_manager.AddProgram(name.getData(), loader, pass.FragmentShader, pass.VertexShader, pass.GeometryShader);
|
||||
if(!added_program)
|
||||
{
|
||||
technique.Available = false;
|
||||
LogF("Failed to compile shader: %s\n", error.what());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::unique_ptr<StdMeshMaterialPass::ProgramInstance> program_instance(new StdMeshMaterialPass::ProgramInstance(added_program, &pass.FragmentShader, &pass.VertexShader, &pass.GeometryShader));
|
||||
pass.Program = std::move(program_instance);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -489,108 +407,50 @@ namespace
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ResolveAutoParameter(StdMeshMaterialShaderParameter& parameter, StdMeshMaterialShaderParameter::Auto value, DWORD dwModClr, DWORD dwPlayerColor, DWORD dwBlitMode, const C4FoWRegion* pFoW, const C4Rect& clipRect, std::vector<GLint>& textures)
|
||||
void SetStandardUniforms(C4ShaderCall& call, DWORD dwModClr, DWORD dwPlayerColor, DWORD dwBlitMode, const C4FoWRegion* pFoW, const C4Rect& clipRect)
|
||||
{
|
||||
float* out;
|
||||
GLint texIndex;
|
||||
C4Rect LightRect;
|
||||
int32_t iLightWdt;
|
||||
int32_t iLightHgt;
|
||||
// Draw transform
|
||||
const float fMod[4] = {
|
||||
((dwModClr >> 16) & 0xff) / 255.0f,
|
||||
((dwModClr >> 8) & 0xff) / 255.0f,
|
||||
((dwModClr ) & 0xff) / 255.0f,
|
||||
((dwModClr >> 24) & 0xff) / 255.0f
|
||||
};
|
||||
call.SetUniform4fv(C4SSU_ClrMod, 1, fMod);
|
||||
|
||||
switch(value)
|
||||
// Player color
|
||||
const float fPlrClr[3] = {
|
||||
((dwPlayerColor >> 16) & 0xff) / 255.0f,
|
||||
((dwPlayerColor >> 8) & 0xff) / 255.0f,
|
||||
((dwPlayerColor ) & 0xff) / 255.0f,
|
||||
};
|
||||
call.SetUniform3fv(C4SSU_OverlayClr, 1, fPlrClr);
|
||||
|
||||
// Dynamic light
|
||||
if(pFoW != NULL)
|
||||
{
|
||||
case StdMeshMaterialShaderParameter::AUTO_OC_PLAYER_COLOR:
|
||||
parameter.SetType(StdMeshMaterialShaderParameter::FLOAT3);
|
||||
out = parameter.GetFloatv();
|
||||
|
||||
out[0] = ((dwPlayerColor >> 16) & 0xff) / 255.0f;
|
||||
out[1] = ((dwPlayerColor >> 8) & 0xff) / 255.0f;
|
||||
out[2] = ((dwPlayerColor ) & 0xff) / 255.0f;
|
||||
return true;
|
||||
case StdMeshMaterialShaderParameter::AUTO_OC_COLOR_MODULATION:
|
||||
parameter.SetType(StdMeshMaterialShaderParameter::FLOAT4);
|
||||
out = parameter.GetFloatv();
|
||||
|
||||
out[0] = ((dwModClr >> 16) & 0xff) / 255.0f;
|
||||
out[1] = ((dwModClr >> 8) & 0xff) / 255.0f;
|
||||
out[2] = ((dwModClr ) & 0xff) / 255.0f;
|
||||
out[3] = ((dwModClr >> 24) & 0xff) / 255.0f;
|
||||
return true;
|
||||
case StdMeshMaterialShaderParameter::AUTO_OC_MOD2:
|
||||
parameter.SetType(StdMeshMaterialShaderParameter::INT);
|
||||
parameter.GetInt() = (dwBlitMode & C4GFXBLIT_MOD2) != 0;
|
||||
return true;
|
||||
case StdMeshMaterialShaderParameter::AUTO_OC_USE_LIGHT:
|
||||
parameter.SetType(StdMeshMaterialShaderParameter::INT);
|
||||
parameter.GetInt() = (pFoW != NULL);
|
||||
return true;
|
||||
case StdMeshMaterialShaderParameter::AUTO_OC_LIGHT:
|
||||
if(!pFoW) return false;
|
||||
|
||||
texIndex = textures.size();
|
||||
textures.push_back(texIndex);
|
||||
|
||||
// Load the texture
|
||||
glActiveTexture(GL_TEXTURE0+texIndex);
|
||||
//glClientActiveTexture(GL_TEXTURE0+texIndex);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
call.AllocTexUnit(C4SSU_LightTex, GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, pFoW->getSurface()->ppTex[0]->texName);
|
||||
float lightTransform[6];
|
||||
pFoW->GetFragTransform(clipRect, lightTransform);
|
||||
call.SetUniformMatrix2x3fv(C4SSU_LightTransform, 1, lightTransform);
|
||||
|
||||
// Transformation matrix for the texture coordinates
|
||||
// TODO: Should maybe be a separate uniform variable?
|
||||
LightRect = pFoW->getRegion();
|
||||
iLightWdt = pFoW->getSurface()->Wdt;
|
||||
iLightHgt = pFoW->getSurface()->Hgt;
|
||||
|
||||
glLoadIdentity();
|
||||
glTranslatef(0.0f, 1.0f - (float)LightRect.Hgt/(float)iLightHgt, 0.0f);
|
||||
glScalef(1.0f/iLightWdt, 1.0f/iLightHgt, 1.0f);
|
||||
glScalef( (float)LightRect.Wdt / (float)clipRect.Wdt, (float)LightRect.Hgt / (float)clipRect.Hgt, 1.0f);
|
||||
glTranslatef(-clipRect.x, 0.0f, 0.0f);
|
||||
|
||||
parameter.SetType(StdMeshMaterialShaderParameter::INT);
|
||||
parameter.GetInt() = texIndex;
|
||||
return true;
|
||||
case StdMeshMaterialShaderParameter::AUTO_OC_AMBIENT:
|
||||
if(!pFoW) return false;
|
||||
|
||||
texIndex = textures.size();
|
||||
textures.push_back(texIndex);
|
||||
|
||||
// Load the texture
|
||||
glActiveTexture(GL_TEXTURE0+texIndex);
|
||||
//glClientActiveTexture(GL_TEXTURE0+texIndex);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
call.AllocTexUnit(C4SSU_AmbientTex, GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, pFoW->getFoW()->Ambient.Tex);
|
||||
|
||||
// Transformation matrix for the texture coordinates
|
||||
// TODO: Should maybe be a separate uniform variable?
|
||||
LightRect = pFoW->getRegion();
|
||||
iLightWdt = pFoW->getSurface()->Wdt;
|
||||
iLightHgt = pFoW->getSurface()->Hgt;
|
||||
|
||||
// Setup the texture matrix
|
||||
glLoadIdentity();
|
||||
glScalef(1.0f/pFoW->getFoW()->Ambient.GetLandscapeWidth(), 1.0f/pFoW->getFoW()->Ambient.GetLandscapeHeight(), 1.0f);
|
||||
glTranslatef(LightRect.x, LightRect.y, 0.0f);
|
||||
glScalef( (float)LightRect.Wdt / (float)clipRect.Wdt, (float)LightRect.Hgt / (float)clipRect.Hgt, 1.0f);
|
||||
glTranslatef(-clipRect.x, clipRect.Hgt, 0.0f);
|
||||
glScalef(1.0f, -1.0f, 1.0f);
|
||||
|
||||
parameter.SetType(StdMeshMaterialShaderParameter::INT);
|
||||
parameter.GetInt() = texIndex;
|
||||
return true;
|
||||
case StdMeshMaterialShaderParameter::AUTO_OC_AMBIENT_BRIGHTNESS:
|
||||
if(!pFoW) return false;
|
||||
parameter.SetType(StdMeshMaterialShaderParameter::FLOAT);
|
||||
parameter.GetFloat() = pFoW->getFoW()->Ambient.GetBrightness();
|
||||
return true;
|
||||
default:
|
||||
assert(false);
|
||||
return false;
|
||||
call.SetUniform1f(C4SSU_AmbientBrightness, pFoW->getFoW()->Ambient.GetBrightness());
|
||||
float ambientTransform[6];
|
||||
pFoW->getFoW()->Ambient.GetFragTransform(pFoW->getRegion(), clipRect, ambientTransform);
|
||||
call.SetUniformMatrix2x3fv(C4SSU_AmbientTransform, 1, ambientTransform);
|
||||
}
|
||||
}
|
||||
|
||||
bool ResolveAutoParameter(C4ShaderCall& call, StdMeshMaterialShaderParameter& parameter, StdMeshMaterialShaderParameter::Auto value, DWORD dwModClr, DWORD dwPlayerColor, DWORD dwBlitMode, const C4FoWRegion* pFoW, const C4Rect& clipRect)
|
||||
{
|
||||
// There are no auto parameters implemented yet
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
void RenderSubMeshImpl(const StdMeshInstance& mesh_instance, const StdSubMeshInstance& instance, DWORD dwModClr, DWORD dwBlitMode, DWORD dwPlayerColor, const C4FoWRegion* pFoW, const C4Rect& clipRect, bool parity)
|
||||
{
|
||||
const StdMeshMaterial& material = instance.GetMaterial();
|
||||
|
@ -667,36 +527,31 @@ namespace
|
|||
|
||||
// TODO: Use vbo if available.
|
||||
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(StdMeshVertex), &vertices->u);
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(StdMeshVertex), &vertices->x);
|
||||
glNormalPointer(GL_FLOAT, sizeof(StdMeshVertex), &vertices->nx);
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
|
||||
std::vector<GLint> textures;
|
||||
textures.reserve(pass.TextureUnits.size());
|
||||
assert(pass.Program.get() != NULL);
|
||||
|
||||
// Upload all parameters to the shader (keep GL_TEXTURE matrix mode for this)
|
||||
int ssc = 0;
|
||||
if(dwBlitMode & C4GFXBLIT_MOD2) ssc |= C4SSC_MOD2;
|
||||
if(pFoW != NULL) ssc |= C4SSC_LIGHT;
|
||||
const C4Shader* shader = pass.Program->Program->GetShader(ssc);
|
||||
C4ShaderCall call(shader);
|
||||
call.Start();
|
||||
|
||||
for (unsigned int j = 0; j < pass.TextureUnits.size(); ++j)
|
||||
{
|
||||
const StdMeshMaterialTextureUnit& texunit = pass.TextureUnits[j];
|
||||
const unsigned int texIndex = textures.size();
|
||||
|
||||
if (texunit.HasTexture())
|
||||
{
|
||||
// Array with texture indices set for passing the textures to the
|
||||
// shader -- shader cannot use fixed texture image units before OGL 4.2.
|
||||
textures.push_back(texIndex);
|
||||
|
||||
// Note that it is guaranteed that the GL_TEXTUREn
|
||||
// constants are contiguous.
|
||||
glActiveTexture(GL_TEXTURE0+texIndex);
|
||||
glClientActiveTexture(GL_TEXTURE0+texIndex);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
call.AllocTexUnit(-1, GL_TEXTURE_2D);
|
||||
const unsigned int Phase = instance.GetTexturePhase(i, j);
|
||||
glBindTexture(GL_TEXTURE_2D, texunit.GetTexture(Phase).texName);
|
||||
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glTexCoordPointer(2, GL_FLOAT, sizeof(StdMeshVertex), &vertices->u);
|
||||
|
||||
// Setup texture coordinate transform
|
||||
glLoadIdentity();
|
||||
const double Position = instance.GetTexturePosition(i, j);
|
||||
|
@ -748,22 +603,19 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
assert(pass.Program.get() != NULL);
|
||||
const C4DrawMeshGLProgramInstance& program_instance = static_cast<const C4DrawMeshGLProgramInstance&>(*pass.Program);
|
||||
|
||||
// Upload all parameters to the shader (keep GL_TEXTURE matrix mode, since we might initialize clrmodmap during this)
|
||||
glUseProgramObjectARB(static_cast<const C4DrawGLProgram*>(program_instance.Program)->Program);
|
||||
for(unsigned int i = 0; i < program_instance.Parameters.size(); ++i)
|
||||
// Set uniforms and instance parameters
|
||||
SetStandardUniforms(call, dwModClr, dwPlayerColor, dwBlitMode, pFoW, clipRect);
|
||||
for(unsigned int i = 0; i < pass.Program->Parameters.size(); ++i)
|
||||
{
|
||||
const GLint location = program_instance.Parameters[i].Location;
|
||||
if(location == -1) continue; // parameter optimized out, or misnamed
|
||||
const int uniform = pass.Program->Parameters[i].UniformIndex;
|
||||
if(!shader->HaveUniform(uniform)) continue; // optimized out
|
||||
|
||||
const StdMeshMaterialShaderParameter* parameter = program_instance.Parameters[i].ShaderParameter;
|
||||
const StdMeshMaterialShaderParameter* parameter = pass.Program->Parameters[i].Parameter;
|
||||
|
||||
StdMeshMaterialShaderParameter auto_resolved;
|
||||
if(parameter->GetType() == StdMeshMaterialShaderParameter::AUTO)
|
||||
{
|
||||
if(!ResolveAutoParameter(auto_resolved, parameter->GetAuto(), dwModClr, dwPlayerColor, dwBlitMode, pFoW, clipRect, textures))
|
||||
if(!ResolveAutoParameter(call, auto_resolved, parameter->GetAuto(), dwModClr, dwPlayerColor, dwBlitMode, pFoW, clipRect))
|
||||
continue;
|
||||
parameter = &auto_resolved;
|
||||
}
|
||||
|
@ -771,22 +623,22 @@ namespace
|
|||
switch(parameter->GetType())
|
||||
{
|
||||
case StdMeshMaterialShaderParameter::INT:
|
||||
glUniform1iARB(location, parameter->GetInt());
|
||||
call.SetUniform1i(uniform, parameter->GetInt());
|
||||
break;
|
||||
case StdMeshMaterialShaderParameter::FLOAT:
|
||||
glUniform1fARB(location, parameter->GetFloat());
|
||||
call.SetUniform1f(uniform, parameter->GetFloat());
|
||||
break;
|
||||
case StdMeshMaterialShaderParameter::FLOAT2:
|
||||
glUniform2fvARB(location, 1, parameter->GetFloatv());
|
||||
call.SetUniform2fv(uniform, 1, parameter->GetFloatv());
|
||||
break;
|
||||
case StdMeshMaterialShaderParameter::FLOAT3:
|
||||
glUniform3fvARB(location, 1, parameter->GetFloatv());
|
||||
call.SetUniform3fv(uniform, 1, parameter->GetFloatv());
|
||||
break;
|
||||
case StdMeshMaterialShaderParameter::FLOAT4:
|
||||
glUniform4fvARB(location, 1, parameter->GetFloatv());
|
||||
call.SetUniform4fv(uniform, 1, parameter->GetFloatv());
|
||||
break;
|
||||
case StdMeshMaterialShaderParameter::MATRIX_4X4:
|
||||
glUniformMatrix4fvARB(location, 1, GL_TRUE, parameter->GetMatrix());
|
||||
call.SetUniformMatrix4x4fv(uniform, 1, parameter->GetMatrix());
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
|
@ -796,15 +648,7 @@ namespace
|
|||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glDrawElements(GL_TRIANGLES, instance.GetNumFaces()*3, GL_UNSIGNED_INT, instance.GetFaces());
|
||||
|
||||
// Clean-up, re-set default state
|
||||
for (unsigned int j = 0; j < textures.size(); ++j)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0+textures[j]);
|
||||
glClientActiveTexture(GL_TEXTURE0+textures[j]);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
call.Finish();
|
||||
|
||||
if(!pass.DepthCheck)
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
@ -955,11 +799,11 @@ void CStdGL::PerformMesh(StdMeshInstance &instance, float tx, float ty, float tw
|
|||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_BLEND); // TODO: Shouldn't this always be enabled? - blending does not work for meshes without this though.
|
||||
|
||||
glClientActiveTexture(GL_TEXTURE0); // our only texcoord corresponds to tex0
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY); // might still be active from a previous (non-mesh-rendering) GL operation
|
||||
glClientActiveTexture(GL_TEXTURE0);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY); // same -- we enable this individually for every texture unit in RenderSubMeshImpl
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
// TODO: We ignore the additive drawing flag for meshes but instead
|
||||
// set the blending mode of the corresponding material. I'm not sure
|
||||
|
@ -1132,8 +976,6 @@ void CStdGL::PerformMesh(StdMeshInstance &instance, float tx, float ty, float tw
|
|||
clipRect.y = iClipY1; if(clipRect.y < 0) { clipRect.Hgt += clipRect.y; clipRect.y = 0; }
|
||||
RenderMeshImpl(instance, dwModClr, dwBlitMode, dwPlayerColor, pFoW, clipRect, parity);
|
||||
|
||||
glUseProgramObjectARB(0);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
@ -1143,6 +985,7 @@ void CStdGL::PerformMesh(StdMeshInstance &instance, float tx, float ty, float tw
|
|||
glClientActiveTexture(GL_TEXTURE0); // switch back to default
|
||||
glDepthMask(GL_TRUE);
|
||||
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glDisableClientState(GL_NORMAL_ARRAY);
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ bool CStdNoGfx::CreatePrimarySurfaces(bool Fullscreen, unsigned int iXRes, unsig
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CStdNoGfx::PrepareMaterial(StdMeshMatManager& mat_manager, StdMeshMaterial &mat)
|
||||
bool CStdNoGfx::PrepareMaterial(StdMeshMatManager& mat_manager, StdMeshMaterialLoader& loader, StdMeshMaterial& mat)
|
||||
{
|
||||
mat.BestTechniqueIndex=0; return true;
|
||||
mat.BestTechniqueIndex=0; return true;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ public:
|
|||
virtual void TaskIn() { }
|
||||
virtual bool UpdateClipper() { return true; }
|
||||
virtual bool OnResolutionChanged(unsigned int, unsigned int) { return true; }
|
||||
virtual bool PrepareMaterial(StdMeshMatManager& mat_manager, StdMeshMaterial &mat);
|
||||
virtual bool PrepareMaterial(StdMeshMatManager& mat_manager, StdMeshMaterialLoader& loader, StdMeshMaterial& mat);
|
||||
virtual bool PrepareRendering(C4Surface *) { return true; }
|
||||
virtual void FillBG(DWORD dwClr=0) { }
|
||||
virtual void PerformMesh(StdMeshInstance &, float, float, float, float, DWORD, C4BltTransform* pTransform) { }
|
||||
|
|
|
@ -18,7 +18,7 @@ C4ShaderPosName C4SH_PosNames[] = {
|
|||
|
||||
{ C4Shader_Vertex_TexCoordPos, "texcoord" },
|
||||
{ C4Shader_Vertex_NormalPos, "normal" },
|
||||
{ C4Shader_Vertxe_PositionPos, "position" }
|
||||
{ C4Shader_Vertex_PositionPos, "position" }
|
||||
};
|
||||
|
||||
C4Shader::C4Shader()
|
||||
|
@ -516,6 +516,7 @@ GLint C4ShaderCall::AllocTexUnit(int iUniform, GLenum iType)
|
|||
void C4ShaderCall::Start()
|
||||
{
|
||||
assert(!fStarted);
|
||||
assert(pShader->hProg != 0); // Shader must be initialized
|
||||
|
||||
// Activate shader
|
||||
glUseProgramObjectARB(pShader->hProg);
|
||||
|
|
|
@ -144,6 +144,14 @@ public:
|
|||
if (pShader->HaveUniform(iUniform))
|
||||
glUniform1fvARB(pShader->GetUniform(iUniform), iLength, pVals);
|
||||
}
|
||||
void SetUniform2fv(int iUniform, int iLength, const float *pVals) const {
|
||||
if (pShader->HaveUniform(iUniform))
|
||||
glUniform2fvARB(pShader->GetUniform(iUniform), iLength, pVals);
|
||||
}
|
||||
void SetUniform3fv(int iUniform, int iLength, const float *pVals) const {
|
||||
if (pShader->HaveUniform(iUniform))
|
||||
glUniform3fvARB(pShader->GetUniform(iUniform), iLength, pVals);
|
||||
}
|
||||
void SetUniform4fv(int iUniform, int iLength, const float *pVals) const {
|
||||
if (pShader->HaveUniform(iUniform))
|
||||
glUniform4fvARB(pShader->GetUniform(iUniform), iLength, pVals);
|
||||
|
@ -154,6 +162,10 @@ public:
|
|||
if (pShader->HaveUniform(iUniform))
|
||||
glUniformMatrix3x2fv(pShader->GetUniform(iUniform), iLength, GL_TRUE, pVals);
|
||||
}
|
||||
void SetUniformMatrix4x4fv(int iUniform, int iLength, const float* pVals) const {
|
||||
if (pShader->HaveUniform(iUniform))
|
||||
glUniformMatrix4fvARB(pShader->GetUniform(iUniform), iLength, GL_TRUE, pVals);
|
||||
}
|
||||
|
||||
void Start();
|
||||
void Finish();
|
||||
|
|
|
@ -182,6 +182,22 @@ void C4FoWRegion::Render(const C4TargetFacet *pOnScreen)
|
|||
|
||||
}
|
||||
|
||||
void C4FoWRegion::GetFragTransform(const C4Rect& clipRect, float lightTransform[6]) const
|
||||
{
|
||||
const C4Rect& lightRect = getRegion();
|
||||
const int32_t iLightWdt = getSurface()->Wdt;
|
||||
const int32_t iLightHgt = getSurface()->Hgt;
|
||||
const float zx = static_cast<float>(lightRect.Wdt) / clipRect.Wdt;
|
||||
const float zy = static_cast<float>(lightRect.Hgt) / clipRect.Hgt;
|
||||
|
||||
lightTransform[0] = zx / iLightWdt;
|
||||
lightTransform[1] = 0.f;
|
||||
lightTransform[2] = -clipRect.x * zx / iLightWdt;
|
||||
lightTransform[3] = 0.f;
|
||||
lightTransform[4] = zy / iLightHgt;
|
||||
lightTransform[5] = 1.0f - (lightRect.Hgt) / iLightHgt;
|
||||
}
|
||||
|
||||
C4FoWRegion::C4FoWRegion(C4FoW *pFoW, C4Player *pPlayer)
|
||||
: pFoW(pFoW)
|
||||
, pPlayer(pPlayer)
|
||||
|
@ -189,4 +205,4 @@ C4FoWRegion::C4FoWRegion(C4FoW *pFoW, C4Player *pPlayer)
|
|||
, Region(0,0,0,0), OldRegion(0,0,0,0)
|
||||
, pSurface(NULL), pBackSurface(NULL)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,9 @@ public:
|
|||
void Update(C4Rect r);
|
||||
void Render(const C4TargetFacet *pOnScreen = NULL);
|
||||
|
||||
// Fills a 2x3 matrix to transform fragment coordinates to light texture coordinates
|
||||
// TODO: This might be more precise for highly zoomed cases if the lightRect was using floating point accuracy
|
||||
void GetFragTransform(const C4Rect& clipRect, float lightTransform[6]) const;
|
||||
private:
|
||||
bool BindFramebuf();
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include "C4Include.h"
|
||||
#include <StdMeshMaterial.h>
|
||||
#include <StdMeshUpdate.h>
|
||||
#include <C4Draw.h>
|
||||
#include <C4DrawGL.h>
|
||||
|
||||
#include <cctype>
|
||||
#include <memory>
|
||||
|
@ -54,15 +54,6 @@ namespace
|
|||
|
||||
const Enumerator<StdMeshMaterialShaderParameter::Auto> ShaderParameterAutoEnumerators[] =
|
||||
{
|
||||
{ "oc_player_color", StdMeshMaterialShaderParameter::AUTO_OC_PLAYER_COLOR },
|
||||
{ "oc_player_colour", StdMeshMaterialShaderParameter::AUTO_OC_PLAYER_COLOR },
|
||||
{ "oc_color_modulation", StdMeshMaterialShaderParameter::AUTO_OC_COLOR_MODULATION },
|
||||
{ "oc_colour_modulation", StdMeshMaterialShaderParameter::AUTO_OC_COLOR_MODULATION },
|
||||
{ "oc_mod2", StdMeshMaterialShaderParameter::AUTO_OC_MOD2 },
|
||||
{ "oc_use_light", StdMeshMaterialShaderParameter::AUTO_OC_USE_LIGHT },
|
||||
{ "oc_light", StdMeshMaterialShaderParameter::AUTO_OC_LIGHT },
|
||||
{ "oc_ambient", StdMeshMaterialShaderParameter::AUTO_OC_AMBIENT },
|
||||
{ "oc_ambient_brightness", StdMeshMaterialShaderParameter::AUTO_OC_AMBIENT_BRIGHTNESS },
|
||||
{ NULL, static_cast<StdMeshMaterialShaderParameter::Auto>(0) }
|
||||
};
|
||||
|
||||
|
@ -589,7 +580,7 @@ void StdMeshMaterialSubLoader::Load(StdMeshMaterialParserCtx& ctx, std::vector<S
|
|||
}
|
||||
}
|
||||
|
||||
void LoadShader(StdMeshMaterialParserCtx& ctx, StdMeshMaterialShader::Type type)
|
||||
void LoadShader(StdMeshMaterialParserCtx& ctx, StdMeshMaterialShaderType type)
|
||||
{
|
||||
StdStrBuf token_name;
|
||||
StdStrBuf name, language;
|
||||
|
@ -621,14 +612,7 @@ void LoadShader(StdMeshMaterialParserCtx& ctx, StdMeshMaterialShader::Type type)
|
|||
if (token != TOKEN_BRACE_CLOSE)
|
||||
ctx.Error(StdCopyStrBuf("'") + token_name.getData() + "' unexpected");
|
||||
|
||||
try
|
||||
{
|
||||
ctx.Manager.AddShader(name.getData(), language.getData(), type, code.getData(), false);
|
||||
}
|
||||
catch(const std::exception& ex)
|
||||
{
|
||||
ctx.Error(StdCopyStrBuf("Failed to compile shader: ") + ex.what());
|
||||
}
|
||||
ctx.Manager.AddShader(source.getData(), name.getData(), language.getData(), type, code.getData(), false);
|
||||
}
|
||||
|
||||
StdMeshMaterialShaderParameter::StdMeshMaterialShaderParameter():
|
||||
|
@ -829,6 +813,97 @@ StdMeshMaterialShaderParameter& StdMeshMaterialShaderParameters::AddParameter(co
|
|||
return NamedParameters.back().second;
|
||||
}
|
||||
|
||||
StdMeshMaterialProgram::StdMeshMaterialProgram(const char* name, const StdMeshMaterialShader* fragment_shader, const StdMeshMaterialShader* vertex_shader, const StdMeshMaterialShader* geometry_shader):
|
||||
Name(name), FragmentShader(fragment_shader), VertexShader(vertex_shader), GeometryShader(geometry_shader)
|
||||
{
|
||||
assert(FragmentShader != NULL);
|
||||
assert(VertexShader != NULL);
|
||||
// Geometry shader is optional (and not even implemented at the moment!)
|
||||
}
|
||||
|
||||
bool StdMeshMaterialProgram::AddParameterNames(const StdMeshMaterialShaderParameters& parameters)
|
||||
{
|
||||
// TODO: This is O(n^2) -- not optimal!
|
||||
bool added = false;
|
||||
for (unsigned int i = 0; i < parameters.NamedParameters.size(); ++i)
|
||||
{
|
||||
const std::vector<StdCopyStrBuf>::const_iterator iter = std::find(ParameterNames.begin(), ParameterNames.end(), parameters.NamedParameters[i].first);
|
||||
if (iter == ParameterNames.end())
|
||||
{
|
||||
ParameterNames.push_back(parameters.NamedParameters[i].first);
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
bool StdMeshMaterialProgram::CompileShader(StdMeshMaterialLoader& loader, C4Shader& shader, int ssc)
|
||||
{
|
||||
// Add standard slices
|
||||
shader.AddFragmentSlice(-1, "#define MESH");
|
||||
loader.AddShaderSlices(shader, ssc);
|
||||
// Add our slices
|
||||
shader.AddVertexSlice(-1, "varying vec2 texcoord;");
|
||||
shader.AddFragmentSlice(-1, "varying vec2 texcoord;");
|
||||
shader.AddVertexSlices(VertexShader->GetFilename(), VertexShader->GetCode(), VertexShader->GetFilename());
|
||||
shader.AddFragmentSlices(FragmentShader->GetFilename(), FragmentShader->GetCode(), FragmentShader->GetFilename());
|
||||
// Construct the list of uniforms
|
||||
std::vector<const char*> uniformNames(C4SSU_Count + ParameterNames.size() + 1);
|
||||
uniformNames[C4SSU_ClrMod] = "clrMod";
|
||||
uniformNames[C4SSU_BaseTex] = "baseTex"; // unused
|
||||
uniformNames[C4SSU_OverlayTex] = "overlayTex"; // unused
|
||||
uniformNames[C4SSU_OverlayClr] = "oc_PlayerColor";
|
||||
uniformNames[C4SSU_LightTex] = "lightTex";
|
||||
uniformNames[C4SSU_LightTransform] = "lightTransform";
|
||||
uniformNames[C4SSU_NormalTex] = "normalTex"; // unused
|
||||
uniformNames[C4SSU_AmbientTex] = "ambientTex";
|
||||
uniformNames[C4SSU_AmbientTransform] = "ambientTransform";
|
||||
uniformNames[C4SSU_AmbientBrightness] = "ambientBrightness";
|
||||
for (unsigned int i = 0; i < ParameterNames.size(); ++i)
|
||||
uniformNames[C4SSU_Count + i] = ParameterNames[i].getData();
|
||||
uniformNames[C4SSU_Count + ParameterNames.size()] = NULL;
|
||||
// Compile the shader
|
||||
StdCopyStrBuf name(Name);
|
||||
if (ssc != 0) name.Append(":");
|
||||
if (ssc & C4SSC_LIGHT) name.Append("Light");
|
||||
if (ssc & C4SSC_MOD2) name.Append("Mod2");
|
||||
return shader.Init(name.getData(), &uniformNames[0]);
|
||||
}
|
||||
|
||||
bool StdMeshMaterialProgram::Compile(StdMeshMaterialLoader& loader)
|
||||
{
|
||||
if (!CompileShader(loader, Shader, 0)) return false;
|
||||
if (!CompileShader(loader, ShaderMod2, C4SSC_MOD2)) return false;
|
||||
if (!CompileShader(loader, ShaderLight, C4SSC_LIGHT)) return false;
|
||||
if (!CompileShader(loader, ShaderLightMod2, C4SSC_LIGHT | C4SSC_MOD2)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
const C4Shader* StdMeshMaterialProgram::GetShader(int ssc) const
|
||||
{
|
||||
const C4Shader* shaders[4] = {
|
||||
&Shader,
|
||||
&ShaderMod2,
|
||||
&ShaderLight,
|
||||
&ShaderLightMod2
|
||||
};
|
||||
|
||||
int index = 0;
|
||||
if(ssc & C4SSC_MOD2) index += 1;
|
||||
if(ssc & C4SSC_LIGHT) index += 2;
|
||||
|
||||
assert(index < 4);
|
||||
return shaders[index];
|
||||
}
|
||||
|
||||
int StdMeshMaterialProgram::GetParameterIndex(const char* name) const
|
||||
{
|
||||
std::vector<StdCopyStrBuf>::const_iterator iter = std::find(ParameterNames.begin(), ParameterNames.end(), name);
|
||||
if(iter == ParameterNames.end()) return -1;
|
||||
return C4SSU_Count + std::distance(ParameterNames.begin(), iter);
|
||||
}
|
||||
|
||||
double StdMeshMaterialTextureUnit::Transformation::GetWaveXForm(double t) const
|
||||
{
|
||||
assert(TransformType == T_WAVE_XFORM);
|
||||
|
@ -1081,6 +1156,44 @@ void StdMeshMaterialTextureUnit::Load(StdMeshMaterialParserCtx& ctx)
|
|||
ctx.Error(StdCopyStrBuf("'") + token_name.getData() + "' unexpected");
|
||||
}
|
||||
|
||||
StdMeshMaterialPass::ProgramInstance::ProgramInstance(const StdMeshMaterialProgram* program, const ShaderInstance* fragment_instance, const ShaderInstance* vertex_instance, const ShaderInstance* geometry_instance):
|
||||
Program(program)
|
||||
{
|
||||
// Consistency check
|
||||
assert(Program->GetFragmentShader() == fragment_instance->Shader);
|
||||
assert(Program->GetVertexShader() == vertex_instance->Shader);
|
||||
assert(Program->GetGeometryShader() == geometry_instance->Shader);
|
||||
|
||||
// Load instance parameters, i.e. connect parameter values with uniform index
|
||||
LoadParameterRefs(fragment_instance);
|
||||
LoadParameterRefs(vertex_instance);
|
||||
LoadParameterRefs(geometry_instance);
|
||||
}
|
||||
|
||||
void StdMeshMaterialPass::ProgramInstance::LoadParameterRefs(const ShaderInstance* instance)
|
||||
{
|
||||
for(unsigned int i = 0; i < instance->Parameters.NamedParameters.size(); ++i)
|
||||
{
|
||||
const int index = Program->GetParameterIndex(instance->Parameters.NamedParameters[i].first.getData());
|
||||
assert(index != -1);
|
||||
|
||||
const std::vector<ParameterRef>::const_iterator parameter_iter =
|
||||
std::find_if(Parameters.begin(), Parameters.end(), [index](const ParameterRef& ref) { return ref.UniformIndex == index; });
|
||||
if(parameter_iter != Parameters.end())
|
||||
{
|
||||
// TODO: Check that the current parameter has the same value as the found one
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
ParameterRef ref;
|
||||
ref.Parameter = &instance->Parameters.NamedParameters[i].second;
|
||||
ref.UniformIndex = index;
|
||||
Parameters.push_back(ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StdMeshMaterialPass::StdMeshMaterialPass():
|
||||
DepthCheck(true), DepthWrite(true), CullHardware(CH_Clockwise)
|
||||
{
|
||||
|
@ -1094,7 +1207,7 @@ StdMeshMaterialPass::StdMeshMaterialPass():
|
|||
VertexShader.Shader = FragmentShader.Shader = GeometryShader.Shader = NULL;
|
||||
}
|
||||
|
||||
void StdMeshMaterialPass::LoadShaderRef(StdMeshMaterialParserCtx& ctx, StdMeshMaterialShader::Type type)
|
||||
void StdMeshMaterialPass::LoadShaderRef(StdMeshMaterialParserCtx& ctx, StdMeshMaterialShaderType type)
|
||||
{
|
||||
StdStrBuf program_name, token;
|
||||
ctx.AdvanceRequired(program_name, TOKEN_IDTF);
|
||||
|
@ -1105,17 +1218,17 @@ void StdMeshMaterialPass::LoadShaderRef(StdMeshMaterialParserCtx& ctx, StdMeshMa
|
|||
|
||||
switch(type)
|
||||
{
|
||||
case StdMeshMaterialShader::FRAGMENT:
|
||||
case SMMS_FRAGMENT:
|
||||
cur_shader = &FragmentShader;
|
||||
shader = ctx.Manager.GetFragmentShader(program_name.getData());
|
||||
shader_type_name = "fragment";
|
||||
break;
|
||||
case StdMeshMaterialShader::VERTEX:
|
||||
case SMMS_VERTEX:
|
||||
cur_shader = &VertexShader;
|
||||
shader = ctx.Manager.GetVertexShader(program_name.getData());
|
||||
shader_type_name = "vertex";
|
||||
break;
|
||||
case StdMeshMaterialShader::GEOMETRY:
|
||||
case SMMS_GEOMETRY:
|
||||
cur_shader = &GeometryShader;
|
||||
shader = ctx.Manager.GetGeometryShader(program_name.getData());
|
||||
shader_type_name = "geometry";
|
||||
|
@ -1254,15 +1367,15 @@ void StdMeshMaterialPass::Load(StdMeshMaterialParserCtx& ctx)
|
|||
}
|
||||
else if (token_name == "vertex_program_ref")
|
||||
{
|
||||
LoadShaderRef(ctx, StdMeshMaterialShader::VERTEX);
|
||||
LoadShaderRef(ctx, SMMS_VERTEX);
|
||||
}
|
||||
else if (token_name == "fragment_program_ref")
|
||||
{
|
||||
LoadShaderRef(ctx, StdMeshMaterialShader::FRAGMENT);
|
||||
LoadShaderRef(ctx, SMMS_FRAGMENT);
|
||||
}
|
||||
else if (token_name == "geometry_program_ref")
|
||||
{
|
||||
LoadShaderRef(ctx, StdMeshMaterialShader::GEOMETRY);
|
||||
LoadShaderRef(ctx, SMMS_GEOMETRY);
|
||||
}
|
||||
else
|
||||
ctx.ErrorUnexpectedIdentifier(token_name);
|
||||
|
@ -1399,7 +1512,7 @@ void StdMeshMatManager::Parse(const char* mat_script, const char* filename, StdM
|
|||
Materials[material_name] = mat;
|
||||
|
||||
// To Gfxspecific setup of the material; choose working techniques
|
||||
if (!pDraw->PrepareMaterial(*this, Materials[material_name]))
|
||||
if (!pDraw->PrepareMaterial(*this, loader, Materials[material_name]))
|
||||
{
|
||||
Materials.erase(material_name);
|
||||
ctx.Error(StdCopyStrBuf("No working technique for material '") + material_name + "'");
|
||||
|
@ -1407,15 +1520,15 @@ void StdMeshMatManager::Parse(const char* mat_script, const char* filename, StdM
|
|||
}
|
||||
else if (token_name == "vertex_program")
|
||||
{
|
||||
LoadShader(ctx, StdMeshMaterialShader::VERTEX);
|
||||
LoadShader(ctx, SMMS_VERTEX);
|
||||
}
|
||||
else if (token_name == "fragment_program")
|
||||
{
|
||||
LoadShader(ctx, StdMeshMaterialShader::FRAGMENT);
|
||||
LoadShader(ctx, SMMS_FRAGMENT);
|
||||
}
|
||||
else if (token_name == "geometry_program")
|
||||
{
|
||||
LoadShader(ctx, StdMeshMaterialShader::GEOMETRY);
|
||||
LoadShader(ctx, SMMS_GEOMETRY);
|
||||
}
|
||||
else
|
||||
ctx.ErrorUnexpectedIdentifier(token_name);
|
||||
|
@ -1462,18 +1575,18 @@ const StdMeshMaterialShader* StdMeshMatManager::GetGeometryShader(const char* na
|
|||
return iter->second.get();
|
||||
}
|
||||
|
||||
const StdMeshMaterialShader* StdMeshMatManager::AddShader(const char* name, const char* language, StdMeshMaterialShader::Type type, const char* text, bool success_if_exists)
|
||||
const StdMeshMaterialShader* StdMeshMatManager::AddShader(const char* filename, const char* name, const char* language, StdMeshMaterialShaderType type, const char* text, bool success_if_exists)
|
||||
{
|
||||
ShaderMap* map = NULL;
|
||||
switch(type)
|
||||
{
|
||||
case StdMeshMaterialShader::FRAGMENT:
|
||||
case SMMS_FRAGMENT:
|
||||
map = &FragmentShaders;
|
||||
break;
|
||||
case StdMeshMaterialShader::VERTEX:
|
||||
case SMMS_VERTEX:
|
||||
map = &VertexShaders;
|
||||
break;
|
||||
case StdMeshMaterialShader::GEOMETRY:
|
||||
case SMMS_GEOMETRY:
|
||||
map = &GeometryShaders;
|
||||
break;
|
||||
}
|
||||
|
@ -1490,7 +1603,7 @@ const StdMeshMaterialShader* StdMeshMatManager::AddShader(const char* name, cons
|
|||
}
|
||||
else
|
||||
{
|
||||
std::unique_ptr<StdMeshMaterialShader> shader = pDraw->CompileShader(language, type, text);
|
||||
std::unique_ptr<StdMeshMaterialShader> shader(new StdMeshMaterialShader(filename, name, language, type, text));
|
||||
std::pair<ShaderMap::iterator, bool> inserted = map->insert(std::make_pair(name_buf, std::move(shader)));
|
||||
assert(inserted.second == true);
|
||||
iter = inserted.first;
|
||||
|
@ -1499,12 +1612,29 @@ const StdMeshMaterialShader* StdMeshMatManager::AddShader(const char* name, cons
|
|||
}
|
||||
}
|
||||
|
||||
const StdMeshMaterialProgram& StdMeshMatManager::AddProgram(const StdMeshMaterialShader* fragment_shader, const StdMeshMaterialShader* vertex_shader, const StdMeshMaterialShader* geometry_shader, std::unique_ptr<StdMeshMaterialProgram> RREF program)
|
||||
const StdMeshMaterialProgram* StdMeshMatManager::AddProgram(const char* name, StdMeshMaterialLoader& loader, const StdMeshMaterialPass::ShaderInstance& fragment_shader, const StdMeshMaterialPass::ShaderInstance& vertex_shader, const StdMeshMaterialPass::ShaderInstance& geometry_shader)
|
||||
{
|
||||
std::tuple<const StdMeshMaterialShader*, const StdMeshMaterialShader*, const StdMeshMaterialShader*> key = std::make_tuple(fragment_shader, vertex_shader, geometry_shader);
|
||||
std::tuple<const StdMeshMaterialShader*, const StdMeshMaterialShader*, const StdMeshMaterialShader*> key = std::make_tuple(fragment_shader.Shader, vertex_shader.Shader, geometry_shader.Shader);
|
||||
ProgramMap::iterator iter = Programs.find(key);
|
||||
if(iter == Programs.end())
|
||||
{
|
||||
std::unique_ptr<StdMeshMaterialProgram> program(new StdMeshMaterialProgram(name, fragment_shader.Shader, vertex_shader.Shader, geometry_shader.Shader));
|
||||
iter = Programs.insert(std::make_pair(key, std::move(program))).first;
|
||||
}
|
||||
|
||||
std::pair<ProgramMap::iterator, bool> inserted = Programs.insert(std::make_pair(key, std::move(program)));
|
||||
return *inserted.first->second;
|
||||
StdMeshMaterialProgram& inserted_program = *iter->second;
|
||||
|
||||
const bool fragment_added = inserted_program.AddParameterNames(fragment_shader.Parameters);
|
||||
const bool vertex_added = inserted_program.AddParameterNames(vertex_shader.Parameters);
|
||||
const bool geometry_added = inserted_program.AddParameterNames(geometry_shader.Parameters);
|
||||
|
||||
// Re-compile the program (and assign new uniform locations if new
|
||||
// parameters were encountered).
|
||||
if(!inserted_program.IsCompiled() || fragment_added || vertex_added || geometry_added)
|
||||
if(!inserted_program.Compile(loader))
|
||||
return NULL;
|
||||
|
||||
return &inserted_program;
|
||||
}
|
||||
|
||||
StdMeshMatManager MeshMaterialManager;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <StdBuf.h>
|
||||
#include <C4Surface.h>
|
||||
#include <C4Shader.h>
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
@ -55,15 +56,8 @@ public:
|
|||
};
|
||||
|
||||
enum Auto {
|
||||
AUTO_OC_PLAYER_COLOR,
|
||||
AUTO_OC_COLOR_MODULATION,
|
||||
AUTO_OC_MOD2,
|
||||
AUTO_OC_USE_LIGHT,
|
||||
AUTO_OC_LIGHT,
|
||||
AUTO_OC_AMBIENT,
|
||||
AUTO_OC_AMBIENT_BRIGHTNESS
|
||||
|
||||
// TODO: Other ogre auto values
|
||||
// TODO: OGRE auto values
|
||||
AUTO_DUMMY
|
||||
};
|
||||
|
||||
StdMeshMaterialShaderParameter(); // type=FLOAT, value uninitialized
|
||||
|
@ -121,25 +115,10 @@ private:
|
|||
StdMeshMaterialShaderParameter LoadAutoParameter(StdMeshMaterialParserCtx& ctx);
|
||||
};
|
||||
|
||||
// An abstract shader class. This is supposed to be implemented by the
|
||||
// GFX implementation, such as C4DrawGL.
|
||||
class StdMeshMaterialShader
|
||||
{
|
||||
public:
|
||||
enum Type {
|
||||
FRAGMENT,
|
||||
VERTEX,
|
||||
GEOMETRY
|
||||
};
|
||||
|
||||
virtual ~StdMeshMaterialShader() {}
|
||||
virtual Type GetType() const = 0;
|
||||
};
|
||||
|
||||
class StdMeshMaterialProgram
|
||||
{
|
||||
public:
|
||||
virtual ~StdMeshMaterialProgram() {}
|
||||
enum StdMeshMaterialShaderType {
|
||||
SMMS_FRAGMENT,
|
||||
SMMS_VERTEX,
|
||||
SMMS_GEOMETRY
|
||||
};
|
||||
|
||||
// Interface to load additional resources.
|
||||
|
@ -152,9 +131,66 @@ class StdMeshMaterialLoader
|
|||
public:
|
||||
virtual C4Surface* LoadTexture(const char* filename) = 0;
|
||||
virtual StdStrBuf LoadShaderCode(const char* filename) = 0;
|
||||
virtual void AddShaderSlices(C4Shader& shader, int ssc) = 0; // add default shader slices
|
||||
virtual ~StdMeshMaterialLoader() {}
|
||||
};
|
||||
|
||||
// This is just a container class to hold the shader code; the C4Shader
|
||||
// objects are later created from that code by mixing them with the default
|
||||
// slices.
|
||||
class StdMeshMaterialShader
|
||||
{
|
||||
public:
|
||||
StdMeshMaterialShader(const char* filename, const char* name, const char* language, StdMeshMaterialShaderType type, const char* code):
|
||||
Filename(filename), Name(name), Language(language), Type(type), Code(code) {}
|
||||
|
||||
const char* GetFilename() const { return Filename.getData(); }
|
||||
const char* GetCode() const { return Code.getData(); }
|
||||
|
||||
private:
|
||||
StdCopyStrBuf Filename;
|
||||
StdCopyStrBuf Name;
|
||||
StdCopyStrBuf Language;
|
||||
StdMeshMaterialShaderType Type;
|
||||
StdCopyStrBuf Code;
|
||||
};
|
||||
|
||||
class StdMeshMaterialProgram
|
||||
{
|
||||
public:
|
||||
StdMeshMaterialProgram(const char* name, const StdMeshMaterialShader* fragment_shader, const StdMeshMaterialShader* vertex_shader, const StdMeshMaterialShader* geometry_shader);
|
||||
bool AddParameterNames(const StdMeshMaterialShaderParameters& parameters); // returns true if some parameter names were not yet registered.
|
||||
|
||||
bool IsCompiled() const { return Shader.Initialised(); }
|
||||
bool Compile(StdMeshMaterialLoader& loader);
|
||||
|
||||
const C4Shader* GetShader(int ssc) const;
|
||||
int GetParameterIndex(const char* name) const;
|
||||
|
||||
const StdMeshMaterialShader* GetFragmentShader() const { return FragmentShader; }
|
||||
const StdMeshMaterialShader* GetVertexShader() const { return VertexShader; }
|
||||
const StdMeshMaterialShader* GetGeometryShader() const { return GeometryShader; }
|
||||
private:
|
||||
bool CompileShader(StdMeshMaterialLoader& loader, C4Shader& shader, int ssc);
|
||||
|
||||
// Human-readable program name
|
||||
const StdCopyStrBuf Name;
|
||||
|
||||
// Program components
|
||||
const StdMeshMaterialShader* FragmentShader;
|
||||
const StdMeshMaterialShader* VertexShader;
|
||||
const StdMeshMaterialShader* GeometryShader;
|
||||
|
||||
// Compiled shaders
|
||||
C4Shader Shader;
|
||||
C4Shader ShaderMod2;
|
||||
C4Shader ShaderLight;
|
||||
C4Shader ShaderLightMod2;
|
||||
|
||||
// Filled as program references are encountered;
|
||||
std::vector<StdCopyStrBuf> ParameterNames;
|
||||
};
|
||||
|
||||
class StdMeshMaterialTextureUnit
|
||||
{
|
||||
public:
|
||||
|
@ -389,17 +425,27 @@ public:
|
|||
class ProgramInstance
|
||||
{
|
||||
public:
|
||||
ProgramInstance(const StdMeshMaterialProgram* program):
|
||||
Program(program) {}
|
||||
virtual ~ProgramInstance() {}
|
||||
ProgramInstance(const StdMeshMaterialProgram* program, const ShaderInstance* fragment_instance, const ShaderInstance* vertex_instance, const ShaderInstance* geometry_instance);
|
||||
|
||||
// This points into the StdMeshMatManager map
|
||||
const StdMeshMaterialProgram* const Program;
|
||||
|
||||
// Parameters for this instance
|
||||
struct ParameterRef {
|
||||
const StdMeshMaterialShaderParameter* Parameter;
|
||||
int UniformIndex; // Index into parameter table for this program
|
||||
};
|
||||
|
||||
std::vector<ParameterRef> Parameters;
|
||||
|
||||
private:
|
||||
void LoadParameterRefs(const ShaderInstance* instance);
|
||||
};
|
||||
|
||||
ShaderInstance FragmentShader;
|
||||
ShaderInstance VertexShader;
|
||||
ShaderInstance GeometryShader;
|
||||
|
||||
// This is a shared_ptr and not a unique_ptr so that this class is
|
||||
// copyable, so it can be inherited. However, when the inherited
|
||||
// material is prepared, the ProgramInstance will be overwritten
|
||||
|
@ -408,8 +454,9 @@ public:
|
|||
// provide inheritance by copying all other fields, and letting
|
||||
// PrepareMaterial fill the program instance.
|
||||
std::shared_ptr<ProgramInstance> Program;
|
||||
|
||||
private:
|
||||
void LoadShaderRef(StdMeshMaterialParserCtx& ctx, StdMeshMaterialShader::Type type);
|
||||
void LoadShaderRef(StdMeshMaterialParserCtx& ctx, StdMeshMaterialShaderType type);
|
||||
};
|
||||
|
||||
class StdMeshMaterialTechnique
|
||||
|
@ -497,8 +544,8 @@ public:
|
|||
Iterator End() { return Iterator(Materials.end()); }
|
||||
Iterator Remove(const Iterator& iter, class StdMeshMaterialUpdate* update);
|
||||
|
||||
const StdMeshMaterialShader* AddShader(const char* name, const char* language, StdMeshMaterialShader::Type type, const char* text, bool success_if_exists); // if pass_if_exists is TRUE, the function returns the existing shader, otherwise returns NULL.
|
||||
const StdMeshMaterialProgram& AddProgram(const StdMeshMaterialShader* fragment_shader, const StdMeshMaterialShader* vertex_shader, const StdMeshMaterialShader* geometry_shader, std::unique_ptr<StdMeshMaterialProgram> RREF program);
|
||||
const StdMeshMaterialShader* AddShader(const char* filename, const char* name, const char* language, StdMeshMaterialShaderType type, const char* text, bool success_if_exists); // if pass_if_exists is TRUE, the function returns the existing shader, otherwise returns NULL.
|
||||
const StdMeshMaterialProgram* AddProgram(const char* name, StdMeshMaterialLoader& loader, const StdMeshMaterialPass::ShaderInstance& fragment_shader, const StdMeshMaterialPass::ShaderInstance& vertex_shader, const StdMeshMaterialPass::ShaderInstance& geometry_shader); // returns NULL if shader code cannot be compiled
|
||||
|
||||
const StdMeshMaterialShader* GetFragmentShader(const char* name) const;
|
||||
const StdMeshMaterialShader* GetVertexShader(const char* name) const;
|
||||
|
@ -506,10 +553,8 @@ public:
|
|||
private:
|
||||
MaterialMap Materials;
|
||||
|
||||
// Compiled shaders
|
||||
// TODO: Some sort of post-init should delete compiled shaders after all programs have been linked
|
||||
// c.f. http://stackoverflow.com/questions/9113154/proper-way-to-delete-glsl-shader
|
||||
typedef std::map<StdCopyStrBuf, std::unique_ptr<StdMeshMaterialShader> > ShaderMap;
|
||||
// Shader code for custom shaders.
|
||||
typedef std::map<StdCopyStrBuf, std::unique_ptr<StdMeshMaterialShader>> ShaderMap;
|
||||
ShaderMap FragmentShaders;
|
||||
ShaderMap VertexShaders;
|
||||
ShaderMap GeometryShaders;
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
#include <C4Include.h>
|
||||
#include <C4Def.h>
|
||||
#include <C4DrawGL.h>
|
||||
#include <C4GraphicsResource.h>
|
||||
|
||||
#include <C4Components.h>
|
||||
#include <C4Config.h>
|
||||
|
@ -54,6 +56,29 @@ public:
|
|||
return ret;
|
||||
}
|
||||
|
||||
virtual void AddShaderSlices(C4Shader& shader, int ssc)
|
||||
{
|
||||
// Add mesh-independent slices
|
||||
shader.AddFragmentSlice(-1, "#define OPENCLONK");
|
||||
shader.AddVertexSlice(-1, "#define OPENCLONK");
|
||||
|
||||
if (ssc & C4SSC_MOD2) shader.AddFragmentSlice(-1, "#define CLRMOD_MOD2");
|
||||
if (ssc & C4SSC_LIGHT) shader.AddFragmentSlice(-1, "#define HAVE_LIGHT");
|
||||
|
||||
shader.LoadSlices(&::GraphicsResource.Files, "UtilShader.glsl");
|
||||
shader.LoadSlices(&::GraphicsResource.Files, "ObjectBaseShader.glsl");
|
||||
shader.LoadSlices(&::GraphicsResource.Files, "MeshShader.glsl");
|
||||
|
||||
if (ssc & C4SSC_BASE) shader.LoadSlices(&::GraphicsResource.Files, "SpriteTextureShader.glsl");
|
||||
if (ssc & C4SSC_OVERLAY) shader.LoadSlices(&::GraphicsResource.Files, "SpriteOverlayShader.glsl");
|
||||
if (ssc & C4SSC_LIGHT)
|
||||
{
|
||||
shader.LoadSlices(&::GraphicsResource.Files, "ObjectLightShader.glsl");
|
||||
shader.LoadSlices(&::GraphicsResource.Files, "LightShader.glsl");
|
||||
shader.LoadSlices(&::GraphicsResource.Files, "AmbientShader.glsl");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
C4Group& Group;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue