Implement light calculations for meshes

issue1247
Armin Burgmeier 2014-11-06 14:24:41 -05:00
parent 0795715465
commit 219fa8597c
7 changed files with 100 additions and 75 deletions

View File

@ -14,7 +14,7 @@
<text>Material scripts can also be crafted or edited by hand. The format is described in the <a href="http://www.ogre3d.org/docs/manual/manual_14.html">OGRE manual</a>. However not all of the features described there are supported (yet): Especially usage of LOD (Level of Detail) is not yet possible. The usage of pixel, vertex and geometry shaders has some restrictions, as discussed in the section below. For the source1 and source2 fields in the colour_op_ex field in texture units the additional value src_player_colour can be specified to refer to the player color of the object's owner. This can be used to colorize objects (partly) by the player color.</text>
<text>At runtime the material script can be changed using the C4Script function <funclink>SetMeshMaterial</funclink>.</text>
<h id="Shaders">Shaders</h>
<text>Pixel, vertex and geometry Shaders can be used to customize the appearance of an object beyond what is possible by the declaratinos in OGRE passes and texture units. The <a href="http://www.ogre3d.org/docs/manual/manual_14.html">OGRE manual</a> should be consulted to learn how shaders can be used, however, there are some restrictions in OpenClonk.</text>
<text>Pixel, vertex and geometry Shaders can be used to customize the appearance of an object beyond what is possible by the declarations in OGRE passes and texture units. The <a href="http://www.ogre3d.org/docs/manual/manual_14.html">OGRE manual</a> should be consulted to learn how shaders can be used, however, there are some restrictions in OpenClonk.</text>
<text>First and foremost, only shaders written in the GLSL are supported at the moment. None of the <a href="http://www.ogre3d.org/docs/manual/manual_23.html#param_005findexed_005fauto">automatic parameters</a> are available for shaders, however, some of these are implicitly available as GLSL variables. Instead, the following <em>additional</em> automatic parameters are available:</text>
<text>
<table>
@ -40,14 +40,14 @@
<col>1 if the Mod2 drawing mode is activated, see <emlink href="script/fn/SetObjectBlitMode.html">SetObjectBlitMode</emlink>. 0 otherwise.</col>
</row>
<row>
<literal_col>oc_use_clrmodmap</literal_col>
<literal_col>oc_use_light</literal_col>
<literal_col>int</literal_col>
<col>1 if the object drawing should be modulated with the global color modulation map (FoW).</col>
<col>1 if the object drawing should take into account the light texture (FoW), or 0 otherwise. If 0, a single directional light from the front (0,0,1) should be assumed.</col>
</row>
<row>
<literal_col>oc_clrmodmap</literal_col>
<literal_col>oc_light</literal_col>
<literal_col>sampler2D</literal_col>
<col>Texture containing the clrmodmap, for lookup of the global modulation value. The corresponding texture transformation matrix is set up such that the fragment coordinate should be used for sampling the texture (gl_FragCoord.xy).</col>
<col>Texture containing the light map. The red component of the map corresponds to the halfed light intensity, and the green and blue components the light direction in x-y, scaled by 1/3 and shifted by +1 in both directions. The fragment coordinates (<code>gl_FragCoord</code>) can be used as texture coordinates to look up the light information when transformed with the texture matrix of 1 plus the last texture unit. Therefore, if the pass uses one texture unit, the second texture unit will be used for the light texture, and the lookup can be performed with <code>texture2D(oc_Light, (gl_TextureMatrix[2] * gl_FragCoord).xy)</code>.</col>
</row>
</table>
</text>
@ -62,9 +62,9 @@
<col>Description</col>
</rowh>
<row>
<literal_col>diffuse</literal_col>
<literal_col>vec4</literal_col>
<col>The interpolated diffuse color of the surface from lighting calculations.</col>
<literal_col>normal</literal_col>
<literal_col>vec3</literal_col>
<col>The interpolated normal vector for lighting calculations.</col>
</row>
<row>
<literal_col>texcoord</literal_col>
@ -74,14 +74,12 @@
</table>
</text>
<text>The standard fragment shader uses these values and possibly processes them with what is specified in the texture units declarations. The standard vertex shader creates these values from the GL state, and is independent of the texture units or other declarations. If no custom vertex shader is provided, the following shader is used:</text>
<code>varying vec4 diffuse;
<code>varying vec3 normal;
varying vec2 texcoord;
void main()
{
vec3 normal = normalize(gl_NormalMatrix * gl_Normal);
vec3 lightDir = normalize(gl_LightSource[0].position.xyz);
diffuse = clamp(gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + gl_FrontLightProduct[0].diffuse * max(0.0, dot(normal, lightDir)), 0.0, 1.0);
normal = normalize(gl_NormalMatrix * gl_Normal);
texcoord = gl_MultiTexCoord0.xy;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}</code>

View File

@ -8,7 +8,7 @@ material Clonk_Body
ambient 0.500000 0.500000 0.500000 1.000000
diffuse 0.810000 0.810000 0.810000 1.000000
specular 0.000000 0.000000 0.000000 1.000000 3.000000
emissive 0.000000 0.000000 0.000000 1.000000
emissive 0.200000 0.200000 0.200000 1.000000
texture_unit Overlay
{

View File

@ -34,8 +34,8 @@ material NormalMap
{
param_named_auto oc_Mod2 oc_mod2
param_named_auto oc_ColorModulation oc_color_modulation
param_named_auto oc_UseClrModMap oc_use_clrmodmap
param_named_auto oc_ClrModMap oc_clrmodmap
param_named_auto oc_UseLight oc_use_light
param_named_auto oc_Light oc_light
param_named basemap int 0
param_named normalmap int 1

View File

@ -4,25 +4,36 @@ uniform sampler2D normalmap;
uniform int oc_Mod2;
uniform vec4 oc_ColorModulation;
uniform int oc_UseClrModMap;
uniform sampler2D oc_ClrModMap;
uniform int oc_UseLight;
uniform sampler2D oc_Light;
// This is mostly copied from C4DrawMeshGL.cpp -- only the calculation
// of the normal has been replaced
void main()
{
// Do the lights calculation (based on normal map)
vec3 lightDir;
float lightIntensity;
if(oc_UseLight != 0)
{
vec4 lightPx = texture2D(oc_Light, (gl_TextureMatrix[2] * gl_FragCoord).xy);
lightDir = normalize(vec3(vec2(1.0, 1.0) - lightPx.gb * 3.0, 0.3));
lightIntensity = 2.0 * lightPx.r;
}
else
{
lightDir = vec3(0.0, 0.0, 1.0);
lightIntensity = 1.0;
}
vec3 normal = normalize((texture2D(normalmap, texcoord).rgb * 2.0 - 1.0)); // TODO: This might be normalized already
vec3 lightDir = normalize(gl_LightSource[0].position.xyz);
vec4 lightColor = clamp(gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + gl_FrontLightProduct[0].diffuse * max(0.0, dot(normal, lightDir)), 0.0, 1.0);
vec4 diffuse = gl_FrontMaterial.emission + 0.0 * gl_FrontMaterial.ambient + gl_FrontMaterial.diffuse * max(dot(normalize(normal), lightDir), 0.0);
// Modulate with base texture
vec4 finalColor = lightColor * texture2D(basemap, texcoord);
vec4 finalColor = diffuse * texture2D(basemap, texcoord);
// Apply openclonk blit parameters
vec4 clrModMapClr = vec4(1.0, 1.0, 1.0, 1.0);
if(oc_UseClrModMap != 0)
clrModMapClr = texture2D(oc_ClrModMap, gl_FragCoord.xy);
if(oc_Mod2 != 0)
gl_FragColor = clamp(2.0 * finalColor * oc_ColorModulation * clrModMapClr - 0.5, 0.0, 1.0);
gl_FragColor = clamp(2.0 * finalColor * oc_ColorModulation - 0.5, 0.0, 1.0);
else
gl_FragColor = finalColor * oc_ColorModulation * clrModMapClr;
gl_FragColor = finalColor * oc_ColorModulation;
}

View File

@ -19,6 +19,7 @@
#include "C4Include.h"
#include <C4Object.h>
#include <C4DrawGL.h>
#include <C4FoWRegion.h>
#include <SHA1.h>
#include "StdMesh.h"
@ -77,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 = clamp(vec4(%s, %s), 0.0, 1.0);", 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);", 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
@ -104,13 +105,11 @@ namespace
StdStrBuf buf;
buf.Copy(
"varying vec4 diffuse;"
"varying vec3 normal;"
"varying vec2 texcoord;"
"void main()"
"{"
" vec3 normal = normalize(gl_NormalMatrix * gl_Normal);" // TODO: Do we need to normalize? I think we enable GL_NORMALIZE in cases we have to...
" vec3 lightDir = normalize(gl_LightSource[0].position.xyz);" // TODO: Do we need to normalize?
" diffuse = clamp(gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + gl_FrontLightProduct[0].diffuse * max(0.0, dot(normal, lightDir)), 0.0, 1.0);"
" 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;"
"}"
@ -146,31 +145,49 @@ namespace
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_UseClrModMap", StdMeshMaterialShaderParameter::AUTO).GetAuto() = StdMeshMaterialShaderParameter::AUTO_OC_USE_CLRMODMAP;
params.AddParameter("oc_ClrModMap", StdMeshMaterialShaderParameter::AUTO).GetAuto() = StdMeshMaterialShaderParameter::AUTO_OC_CLRMODMAP;
params.AddParameter("oc_UseLight", StdMeshMaterialShaderParameter::AUTO).GetAuto() = StdMeshMaterialShaderParameter::AUTO_OC_USE_LIGHT;
params.AddParameter("oc_Light", StdMeshMaterialShaderParameter::AUTO).GetAuto() = StdMeshMaterialShaderParameter::AUTO_OC_LIGHT;
return FormatString(
"varying vec4 diffuse;"
"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_UseClrModMap;"
"uniform sampler2D oc_ClrModMap;"
"uniform int oc_UseLight;"
"uniform sampler2D oc_Light;"
"void main()"
"{"
" vec3 lightDir;"
" float lightIntensity;"
" if(oc_UseLight != 0)"
" {"
// Light calculation
" vec4 lightPx = texture2D(oc_Light, (gl_TextureMatrix[%d] * gl_FragCoord).xy);"
" lightDir = normalize(vec3(vec2(1.0, 1.0) - lightPx.gb * 3.0, 0.3));"
" lightIntensity = 2.0 * lightPx.r;"
" }"
" else"
" {"
// No light -- place a simple directional light from the front (equivalent to the behaviour in the main branch, modulo interpolated normals)
" lightDir = vec3(0.0, 0.0, 1.0);"
" lightIntensity = 1.0;"
" }"
" vec4 diffuse = gl_FrontMaterial.emission + 0.0 * gl_FrontMaterial.ambient + gl_FrontMaterial.diffuse * max(dot(normalize(normal), lightDir), 0.0);" // ambient is ignored since we don't have ambient lights
// Texture units from material script
" vec4 currentColor = diffuse;"
" %s"
" vec4 clrModMapClr = vec4(1.0, 1.0, 1.0, 1.0);"
" if(oc_UseClrModMap != 0)"
" clrModMapClr = texture2D(oc_ClrModMap, gl_FragCoord.xy);"
// Intensity (lightPx.r) only applies to RGB components, not A
" currentColor = vec4(lightIntensity * currentColor.rgb, currentColor.a);"
// Output with color modulation and mod2
" if(oc_Mod2 != 0)"
" gl_FragColor = clamp(2.0 * currentColor * oc_ColorModulation * clrModMapClr - 0.5, 0.0, 1.0);"
" gl_FragColor = clamp(2.0 * currentColor * oc_ColorModulation - 0.5, 0.0, 1.0);"
" else"
" gl_FragColor = currentColor * oc_ColorModulation * clrModMapClr;"
" gl_FragColor = clamp(currentColor * oc_ColorModulation, 0.0, 1.0);"
"}",
textureUnitDeclCode.getData(),
(int)texIndex, // The light texture is added after all other textures
textureUnitCode.getData()
);
}
@ -464,11 +481,13 @@ namespace
return true;
}
bool ResolveAutoParameter(StdMeshMaterialShaderParameter& parameter, StdMeshMaterialShaderParameter::Auto value, DWORD dwModClr, DWORD dwPlayerColor, DWORD dwBlitMode, bool fUseClrModMap, C4FogOfWar* pClrModMap, std::vector<GLint>& textures)
bool ResolveAutoParameter(StdMeshMaterialShaderParameter& parameter, StdMeshMaterialShaderParameter::Auto value, DWORD dwModClr, DWORD dwPlayerColor, DWORD dwBlitMode, const C4FoWRegion* pFoW, float zoom, std::vector<GLint>& textures)
{
float* out;
GLint texIndex;
C4Surface* pSurface;
C4Rect LightRect;
int32_t iLightWdt;
int32_t iLightHgt;
switch(value)
{
@ -493,35 +512,32 @@ namespace
parameter.SetType(StdMeshMaterialShaderParameter::INT);
parameter.GetInt() = (dwBlitMode & C4GFXBLIT_MOD2) != 0;
return true;
case StdMeshMaterialShaderParameter::AUTO_OC_USE_CLRMODMAP:
case StdMeshMaterialShaderParameter::AUTO_OC_USE_LIGHT:
parameter.SetType(StdMeshMaterialShaderParameter::INT);
parameter.GetInt() = (fUseClrModMap == true);
parameter.GetInt() = (pFoW != NULL);
return true;
case StdMeshMaterialShaderParameter::AUTO_OC_CLRMODMAP:
if(!fUseClrModMap) return false;
pSurface = pClrModMap->GetSurface();
case StdMeshMaterialShaderParameter::AUTO_OC_LIGHT:
if(!pFoW) return false;
texIndex = textures.size();
textures.push_back(texIndex);
// Load the clr mod map
// Load the texture
glActiveTexture(GL_TEXTURE0+texIndex);
glClientActiveTexture(GL_TEXTURE0+texIndex);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, pSurface->ppTex[0]->texName);
glBindTexture(GL_TEXTURE_2D, pFoW->getSurface()->ppTex[0]->texName);
// 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();
glScalef(1.0f/(pClrModMap->GetResolutionX()*(*pSurface->ppTex)->iSizeX), 1.0f/(pClrModMap->GetResolutionY()*(*pSurface->ppTex)->iSizeY), 1.0f);
glTranslatef(float(-pClrModMap->OffX), float(-pClrModMap->OffY), 0.0f);
// TODO: Fix this once FoW rendering is fixed:
// TODO ApplyZoomAndTransform();
// TODO: Here, scale from device coordinates to viewport coordinates ( (x+1) * size/2)
// This allows the clrmod lookup to be performed with the fragment coordinate. We cannot
// use the interpolated vertex coordinate (after modelview matrix but before projection),
// since the modelview coordinates do not correspond to viewport coordinates
glTranslatef(0.0f, 1.0f - (float)LightRect.Hgt/(float)iLightHgt, 0.0f);
glScalef(1.0f/iLightWdt, 1.0f/iLightHgt, 1.0f);
glScalef(1.0f/zoom, 1.0f/zoom, 1.0f);
parameter.SetType(StdMeshMaterialShaderParameter::INT);
parameter.GetInt() = texIndex;
@ -532,7 +548,7 @@ namespace
}
}
void RenderSubMeshImpl(const StdMeshInstance& mesh_instance, const StdSubMeshInstance& instance, DWORD dwModClr, DWORD dwBlitMode, DWORD dwPlayerColor, bool fUseClrModMap, C4FogOfWar* pClrModMap, bool parity)
void RenderSubMeshImpl(const StdMeshInstance& mesh_instance, const StdSubMeshInstance& instance, DWORD dwModClr, DWORD dwBlitMode, DWORD dwPlayerColor, const C4FoWRegion* pFoW, float zoom, bool parity)
{
const StdMeshMaterial& material = instance.GetMaterial();
assert(material.BestTechniqueIndex != -1);
@ -707,7 +723,7 @@ namespace
StdMeshMaterialShaderParameter auto_resolved;
if(parameter->GetType() == StdMeshMaterialShaderParameter::AUTO)
{
if(!ResolveAutoParameter(auto_resolved, parameter->GetAuto(), dwModClr, dwPlayerColor, dwBlitMode, fUseClrModMap, pClrModMap, textures))
if(!ResolveAutoParameter(auto_resolved, parameter->GetAuto(), dwModClr, dwPlayerColor, dwBlitMode, pFoW, zoom, textures))
continue;
parameter = &auto_resolved;
}
@ -755,9 +771,9 @@ namespace
}
}
void RenderMeshImpl(StdMeshInstance& instance, DWORD dwModClr, DWORD dwBlitMode, DWORD dwPlayerColor, bool fUseClrModmap, C4FogOfWar* pClrModMap, bool parity); // Needed by RenderAttachedMesh
void RenderMeshImpl(StdMeshInstance& instance, DWORD dwModClr, DWORD dwBlitMode, DWORD dwPlayerColor, const C4FoWRegion* pFoW, float zoom, bool parity); // Needed by RenderAttachedMesh
void RenderAttachedMesh(StdMeshInstance::AttachedMesh* attach, DWORD dwModClr, DWORD dwBlitMode, DWORD dwPlayerColor, bool fUseClrModMap, C4FogOfWar* pClrModMap, bool parity)
void RenderAttachedMesh(StdMeshInstance::AttachedMesh* attach, DWORD dwModClr, DWORD dwBlitMode, DWORD dwPlayerColor, const C4FoWRegion* pFoW, float zoom, bool parity)
{
const StdMeshMatrix& FinalTrans = attach->GetFinalTransformation();
@ -784,7 +800,7 @@ namespace
// TODO: Take attach transform's parity into account
glPushMatrix();
glMultMatrixf(attach_trans_gl);
RenderMeshImpl(*attach->Child, dwModClr, dwBlitMode, dwPlayerColor, fUseClrModMap, pClrModMap, parity);
RenderMeshImpl(*attach->Child, dwModClr, dwBlitMode, dwPlayerColor, pFoW, zoom, parity);
glPopMatrix();
#if 0
@ -806,7 +822,7 @@ namespace
#endif
}
void RenderMeshImpl(StdMeshInstance& instance, DWORD dwModClr, DWORD dwBlitMode, DWORD dwPlayerColor, bool fUseClrModMap, C4FogOfWar* pClrModMap, bool parity)
void RenderMeshImpl(StdMeshInstance& instance, DWORD dwModClr, DWORD dwBlitMode, DWORD dwPlayerColor, const C4FoWRegion* pFoW, float zoom, bool parity)
{
const StdMesh& mesh = instance.GetMesh();
@ -814,7 +830,7 @@ namespace
StdMeshInstance::AttachedMeshIter attach_iter = instance.AttachedMeshesBegin();
for (; attach_iter != instance.AttachedMeshesEnd() && ((*attach_iter)->GetFlags() & StdMeshInstance::AM_DrawBefore); ++attach_iter)
RenderAttachedMesh(*attach_iter, dwModClr, dwBlitMode, dwPlayerColor, fUseClrModMap, pClrModMap, parity);
RenderAttachedMesh(*attach_iter, dwModClr, dwBlitMode, dwPlayerColor, pFoW, zoom, parity);
GLint modes[2];
// Check if we should draw in wireframe or normal mode
@ -827,7 +843,7 @@ namespace
// Render each submesh
for (unsigned int i = 0; i < mesh.GetNumSubMeshes(); ++i)
RenderSubMeshImpl(instance, instance.GetSubMeshOrdered(i), dwModClr, dwBlitMode, dwPlayerColor, fUseClrModMap, pClrModMap, parity);
RenderSubMeshImpl(instance, instance.GetSubMeshOrdered(i), dwModClr, dwBlitMode, dwPlayerColor, pFoW, zoom, parity);
// reset old mode to prevent rendering errors
if(dwBlitMode & C4GFXBLIT_WIREFRAME)
@ -859,7 +875,7 @@ namespace
// Render non-AM_DrawBefore attached meshes
for (; attach_iter != instance.AttachedMeshesEnd(); ++attach_iter)
RenderAttachedMesh(*attach_iter, dwModClr, dwBlitMode, dwPlayerColor, fUseClrModMap, pClrModMap, parity);
RenderAttachedMesh(*attach_iter, dwModClr, dwBlitMode, dwPlayerColor, pFoW, zoom, parity);
}
}
@ -1086,7 +1102,7 @@ void CStdGL::PerformMesh(StdMeshInstance &instance, float tx, float ty, float tw
DWORD dwModClr = BlitModulated ? BlitModulateClr : 0xffffffff;
RenderMeshImpl(instance, dwModClr, dwBlitMode, dwPlayerColor, fUseClrModMap, pClrModMap, parity);
RenderMeshImpl(instance, dwModClr, dwBlitMode, dwPlayerColor, pFoW, Zoom, parity);
glUseProgramObjectARB(0);

View File

@ -59,8 +59,8 @@ namespace
{ "oc_color_modulation", StdMeshMaterialShaderParameter::AUTO_OC_COLOR_MODULATION },
{ "oc_colour_modulation", StdMeshMaterialShaderParameter::AUTO_OC_COLOR_MODULATION },
{ "oc_mod2", StdMeshMaterialShaderParameter::AUTO_OC_MOD2 },
{ "oc_use_clrmodmap", StdMeshMaterialShaderParameter::AUTO_OC_USE_CLRMODMAP },
{ "oc_clrmodmap", StdMeshMaterialShaderParameter::AUTO_OC_CLRMODMAP },
{ "oc_use_light", StdMeshMaterialShaderParameter::AUTO_OC_USE_LIGHT },
{ "oc_light", StdMeshMaterialShaderParameter::AUTO_OC_LIGHT },
{ NULL, static_cast<StdMeshMaterialShaderParameter::Auto>(0) }
};

View File

@ -58,8 +58,8 @@ public:
AUTO_OC_PLAYER_COLOR,
AUTO_OC_COLOR_MODULATION,
AUTO_OC_MOD2,
AUTO_OC_USE_CLRMODMAP,
AUTO_OC_CLRMODMAP,
AUTO_OC_USE_LIGHT,
AUTO_OC_LIGHT
// TODO: Other ogre auto values
};