Rewritten shadow mapping implementation

dev-time-step
Tomasz Kapuściński 2016-03-07 18:33:19 +01:00
parent 9679546988
commit e6a2fc9671
6 changed files with 246 additions and 283 deletions

View File

@ -99,12 +99,22 @@ struct DeviceConfig
} }
}; };
/**
* \enum TextureUnit
* \brief Texture unit values for binding textures
*
* These enums should be used for indexing textures instead of raw integers.
*/
enum TextureUnit
{
TEXTURE_PRIMARY = 0,
TEXTURE_SECONDARY = 1,
TEXTURE_SHADOW = 2,
};
/** /**
* \enum TransformType * \enum TransformType
* \brief Type of transformation in rendering pipeline * \brief Type of transformation in rendering pipeline
*
* These correspond to DirectX's three transformation matrices.
*/ */
enum TransformType enum TransformType
{ {
@ -128,6 +138,7 @@ enum RenderState
RENDER_STATE_ALPHA_TEST, RENDER_STATE_ALPHA_TEST,
RENDER_STATE_CULLING, RENDER_STATE_CULLING,
RENDER_STATE_DEPTH_BIAS, RENDER_STATE_DEPTH_BIAS,
RENDER_STATE_SHADOW_MAPPING,
}; };
/** /**

View File

@ -3486,6 +3486,7 @@ void CEngine::RenderShadowMap()
m_device->SetTexture(0, 0); m_device->SetTexture(0, 0);
m_device->SetTexture(1, 0); m_device->SetTexture(1, 0);
m_device->SetTexture(2, 0);
// render objects into shadow map // render objects into shadow map
for (int objRank = 0; objRank < static_cast<int>(m_objects.size()); objRank++) for (int objRank = 0; objRank < static_cast<int>(m_objects.size()); objRank++)
@ -3552,173 +3553,17 @@ void CEngine::UseShadowMapping(bool enable)
if (!m_shadowMapping) return; if (!m_shadowMapping) return;
if (m_shadowMap.id == 0) return; if (m_shadowMap.id == 0) return;
// all devices that are not OpenGL 1.4 if (enable)
if (m_device->GetName() != "OpenGL 1.4")
{ {
if (enable) m_device->SetShadowColor(m_shadowColor);
{ m_device->SetTransform(TRANSFORM_SHADOW, m_shadowTextureMat);
m_device->SetShadowColor(m_shadowColor); m_device->SetTexture(TEXTURE_SHADOW, m_shadowMap.id);
m_device->SetRenderState(RENDER_STATE_SHADOW_MAPPING, true);
m_device->SetTextureEnabled(2, true);
m_device->SetTexture(2, m_shadowMap);
m_device->SetTransform(TRANSFORM_SHADOW, m_shadowTextureMat);
}
else
{
m_device->SetTexture(2, 0);
m_device->SetTextureEnabled(2, false);
}
} }
// special case for OpenGL 1.4 device
else else
{ {
if (enable) m_device->SetRenderState(RENDER_STATE_SHADOW_MAPPING, false);
{ m_device->SetTexture(TEXTURE_SHADOW, 0);
m_device->SetShadowColor(m_shadowColor);
if (m_qualityShadows)
{
// Texture Unit 2
m_device->SetTextureEnabled(2, true);
m_device->SetTexture(2, m_shadowMap);
m_device->SetTransform(TRANSFORM_SHADOW, m_shadowTextureMat);
Math::Matrix identity;
identity.LoadIdentity();
m_device->SetTransform(TRANSFORM_WORLD, identity);
float shadowBias = m_shadowColor;
float shadowUnbias = 1.0f - shadowBias;
TextureStageParams params;
params.colorOperation = TEX_MIX_OPER_MODULATE;
params.colorArg1 = TEX_MIX_ARG_TEXTURE;
params.colorArg2 = TEX_MIX_ARG_FACTOR;
params.colorOperation = TEX_MIX_OPER_DEFAULT;
params.factor = Color(shadowBias, shadowBias, shadowBias, 1.0f);
params.wrapS = TEX_WRAP_CLAMP_TO_BORDER;
params.wrapT = TEX_WRAP_CLAMP_TO_BORDER;
m_device->SetTextureStageParams(2, params);
TextureGenerationParams genParams;
for (int i = 0; i < 4; i++)
{
genParams.coords[i].mode = TEX_GEN_EYE_LINEAR;
for (int j = 0; j < 4; j++)
{
genParams.coords[i].plane[j] = (i == j ? 1.0f : 0.0f);
}
}
m_device->SetTextureCoordGeneration(2, genParams);
// Texture Unit 3
m_device->SetTextureEnabled(3, true);
m_device->SetTexture(3, m_shadowMap);
params.LoadDefault();
params.colorOperation = TEX_MIX_OPER_ADD;
params.colorArg1 = TEX_MIX_ARG_COMPUTED_COLOR;
params.colorArg2 = TEX_MIX_ARG_FACTOR;
params.alphaOperation = TEX_MIX_OPER_DEFAULT;
params.factor = Color(shadowUnbias, shadowUnbias, shadowUnbias, 0.0f);
params.wrapS = TEX_WRAP_CLAMP_TO_BORDER;
params.wrapT = TEX_WRAP_CLAMP_TO_BORDER;
m_device->SetTextureStageParams(3, params);
// Texture Unit 4
m_device->SetTextureEnabled(4, true);
m_device->SetTexture(4, m_shadowMap);
params.LoadDefault();
params.colorOperation = TEX_MIX_OPER_MODULATE;
params.colorArg1 = TEX_MIX_ARG_COMPUTED_COLOR;
params.colorArg2 = TEX_MIX_ARG_SRC_COLOR;
params.alphaOperation = TEX_MIX_OPER_DEFAULT;
params.wrapS = TEX_WRAP_CLAMP_TO_BORDER;
params.wrapT = TEX_WRAP_CLAMP_TO_BORDER;
m_device->SetTextureStageParams(4, params);
// Texture Unit 5
m_device->SetTextureEnabled(5, true);
m_device->SetTexture(5, m_shadowMap);
params.LoadDefault();
params.colorOperation = TEX_MIX_OPER_MODULATE;
params.colorArg1 = TEX_MIX_ARG_COMPUTED_COLOR;
params.colorArg2 = TEX_MIX_ARG_TEXTURE_0;
params.alphaOperation = TEX_MIX_OPER_DEFAULT;
params.wrapS = TEX_WRAP_CLAMP_TO_BORDER;
params.wrapT = TEX_WRAP_CLAMP_TO_BORDER;
m_device->SetTextureStageParams(5, params);
}
else // Simpler shadows
{
// Texture Unit 2
m_device->SetTextureEnabled(2, true);
m_device->SetTexture(2, m_shadowMap);
m_device->SetTransform(TRANSFORM_SHADOW, m_shadowTextureMat);
Math::Matrix identity;
identity.LoadIdentity();
m_device->SetTransform(TRANSFORM_WORLD, identity);
TextureStageParams params;
params.colorOperation = TEX_MIX_OPER_MODULATE;
params.wrapS = TEX_WRAP_CLAMP_TO_BORDER;
params.wrapT = TEX_WRAP_CLAMP_TO_BORDER;
m_device->SetTextureStageParams(2, params);
TextureGenerationParams genParams;
for (int i = 0; i < 4; i++)
{
genParams.coords[i].mode = TEX_GEN_EYE_LINEAR;
for (int j = 0; j < 4; j++)
{
genParams.coords[i].plane[j] = (i == j ? 1.0f : 0.0f);
}
}
m_device->SetTextureCoordGeneration(2, genParams);
}
}
// disable shadows
else
{
Math::Matrix identity;
identity.LoadIdentity();
m_device->SetTexture(2, 0);
m_device->SetTextureEnabled(2, false);
m_device->SetTransform(TRANSFORM_SHADOW, identity);
TextureGenerationParams params;
for (int i = 0; i < 4; i++)
params.coords[i].mode = TEX_GEN_NONE;
m_device->SetTextureCoordGeneration(2, params);
if (m_qualityShadows)
{
m_device->SetTexture(3, 0);
m_device->SetTextureEnabled(3, false);
m_device->SetTexture(4, 0);
m_device->SetTextureEnabled(4, false);
m_device->SetTexture(5, 0);
m_device->SetTextureEnabled(5, false);
}
}
} }
} }

View File

@ -602,6 +602,9 @@ void CGL21Device::BeginScene()
void CGL21Device::EndScene() void CGL21Device::EndScene()
{ {
#ifdef DEV_BUILD
CheckGLErrors();
#endif
} }
void CGL21Device::Clear() void CGL21Device::Clear()
@ -1852,6 +1855,12 @@ void CGL21Device::SetRenderState(RenderState state, bool enabled)
return; return;
} }
else if (state == RENDER_STATE_SHADOW_MAPPING)
{
SetTextureEnabled(TEXTURE_SHADOW, enabled);
return;
}
GLenum flag = 0; GLenum flag = 0;

View File

@ -608,6 +608,9 @@ void CGL33Device::BeginScene()
void CGL33Device::EndScene() void CGL33Device::EndScene()
{ {
#ifdef DEV_BUILD
CheckGLErrors();
#endif
} }
void CGL33Device::Clear() void CGL33Device::Clear()
@ -2105,6 +2108,12 @@ void CGL33Device::SetRenderState(RenderState state, bool enabled)
return; return;
} }
else if (state == RENDER_STATE_SHADOW_MAPPING)
{
SetTextureEnabled(TEXTURE_SHADOW, enabled);
return;
}
GLenum flag = 0; GLenum flag = 0;

View File

@ -193,11 +193,6 @@ bool CGLDevice::Create()
GetLogger()->Info("OpenGL %s\n", version); GetLogger()->Info("OpenGL %s\n", version);
GetLogger()->Info("%s\n", renderer); GetLogger()->Info("%s\n", renderer);
// Detect multitexture support
m_multitextureAvailable = glewIsSupported("GL_ARB_multitexture GL_ARB_texture_env_combine");
if (!m_multitextureAvailable)
GetLogger()->Warn("GLEW reports multitexturing not supported - graphics quality will be degraded!\n");
// Detect Shadow mapping support // Detect Shadow mapping support
if (glVersion >= 14) // Core depth texture+shadow, OpenGL 1.4+ if (glVersion >= 14) // Core depth texture+shadow, OpenGL 1.4+
{ {
@ -215,10 +210,6 @@ bool CGLDevice::Create()
GetLogger()->Info("Shadow mapping not available\n"); GetLogger()->Info("Shadow mapping not available\n");
} }
m_shadowAmbientSupported = glewIsSupported("GL_ARB_shadow_ambient");
if (m_shadowAmbientSupported)
GetLogger()->Info("Shadow ambient supported\n");
// Detect support of anisotropic filtering // Detect support of anisotropic filtering
m_anisotropyAvailable = glewIsSupported("GL_EXT_texture_filter_anisotropic"); m_anisotropyAvailable = glewIsSupported("GL_EXT_texture_filter_anisotropic");
if(m_anisotropyAvailable) if(m_anisotropyAvailable)
@ -309,6 +300,23 @@ bool CGLDevice::Create()
m_currentTextures = std::vector<Texture> (maxTextures, Texture()); m_currentTextures = std::vector<Texture> (maxTextures, Texture());
m_texturesEnabled = std::vector<bool> (maxTextures, false); m_texturesEnabled = std::vector<bool> (maxTextures, false);
m_textureStageParams = std::vector<TextureStageParams>(maxTextures, TextureStageParams()); m_textureStageParams = std::vector<TextureStageParams>(maxTextures, TextureStageParams());
m_remap = std::vector<int> (maxTextures, 0);
// default mapping
for (int i = 0; i < maxTextures; i++)
m_remap[i] = i;
// special remapping for quality shadows
if (maxTextures >= 4)
{
m_remap[0] = 2;
m_remap[1] = 3;
m_remap[2] = 0;
m_remap[3] = 1;
m_shadowQuality = true;
GetLogger()->Debug("Using quality shadows\n");
}
// create default framebuffer object // create default framebuffer object
FramebufferParams framebufferParams; FramebufferParams framebufferParams;
@ -387,6 +395,9 @@ void CGLDevice::BeginScene()
void CGLDevice::EndScene() void CGLDevice::EndScene()
{ {
#ifdef DEV_BUILD
CheckGLErrors();
#endif
} }
void CGLDevice::Clear() void CGLDevice::Clear()
@ -426,13 +437,11 @@ void CGLDevice::SetTransform(TransformType type, const Math::Matrix &matrix)
} }
else if (type == TRANSFORM_SHADOW) else if (type == TRANSFORM_SHADOW)
{ {
if (!m_multitextureAvailable) m_shadowMatrix = matrix;
return;
Math::Matrix temp = matrix; glActiveTexture(GL_TEXTURE0 + m_remap[2]);
glActiveTexture(GL_TEXTURE2);
glMatrixMode(GL_TEXTURE); glMatrixMode(GL_TEXTURE);
glLoadMatrixf(temp.Array()); glLoadMatrixf(m_shadowMatrix.Array());
} }
else else
{ {
@ -650,8 +659,7 @@ Texture CGLDevice::CreateTexture(ImageData *data, const TextureCreateParams &par
result.originalSize = result.size; result.originalSize = result.size;
// Use & enable 1st texture stage // Use & enable 1st texture stage
if (m_multitextureAvailable) glActiveTexture(GL_TEXTURE0 + m_remap[0]);
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
@ -839,8 +847,7 @@ Texture CGLDevice::CreateDepthTexture(int width, int height, int depth)
result.size.y = height; result.size.y = height;
// Use & enable 1st texture stage // Use & enable 1st texture stage
if (m_multitextureAvailable) glActiveTexture(GL_TEXTURE0 + m_remap[0]);
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &result.id); glGenTextures(1, &result.id);
glBindTexture(GL_TEXTURE_2D, result.id); glBindTexture(GL_TEXTURE_2D, result.id);
@ -886,11 +893,6 @@ Texture CGLDevice::CreateDepthTexture(int width, int height, int depth)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
} }
if (m_shadowAmbientSupported)
{
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, 0.5f);
}
float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; float color[] = { 1.0f, 1.0f, 1.0f, 1.0f };
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@ -950,14 +952,10 @@ void CGLDevice::SetTexture(int index, const Texture &texture)
m_currentTextures[index] = texture; // remember the new value m_currentTextures[index] = texture; // remember the new value
if (!m_multitextureAvailable && index != 0)
return;
if (same) if (same)
return; // nothing to do return; // nothing to do
if (m_multitextureAvailable) glActiveTexture(GL_TEXTURE0 + m_remap[index]);
glActiveTexture(GL_TEXTURE0 + index);
glBindTexture(GL_TEXTURE_2D, texture.id); glBindTexture(GL_TEXTURE_2D, texture.id);
@ -967,18 +965,14 @@ void CGLDevice::SetTexture(int index, const Texture &texture)
void CGLDevice::SetTexture(int index, unsigned int textureId) void CGLDevice::SetTexture(int index, unsigned int textureId)
{ {
assert(index >= 0 && index < static_cast<int>( m_currentTextures.size() )); assert(index >= 0 && index < static_cast<int>(m_currentTextures.size()));
if (m_currentTextures[index].id == textureId) if (m_currentTextures[index].id == textureId)
return; // nothing to do return; // nothing to do
m_currentTextures[index].id = textureId; m_currentTextures[index].id = textureId;
if (!m_multitextureAvailable && index != 0) glActiveTexture(GL_TEXTURE0 + m_remap[index]);
return;
if (m_multitextureAvailable)
glActiveTexture(GL_TEXTURE0 + index);
glBindTexture(GL_TEXTURE_2D, textureId); glBindTexture(GL_TEXTURE_2D, textureId);
@ -988,7 +982,7 @@ void CGLDevice::SetTexture(int index, unsigned int textureId)
void CGLDevice::SetTextureEnabled(int index, bool enabled) void CGLDevice::SetTextureEnabled(int index, bool enabled)
{ {
assert(index >= 0 && index < static_cast<int>( m_currentTextures.size() )); assert(index >= 0 && index < static_cast<int>(m_currentTextures.size()));
bool same = m_texturesEnabled[index] == enabled; bool same = m_texturesEnabled[index] == enabled;
@ -997,11 +991,7 @@ void CGLDevice::SetTextureEnabled(int index, bool enabled)
if (same) if (same)
return; // nothing to do return; // nothing to do
if (!m_multitextureAvailable && index != 0) glActiveTexture(GL_TEXTURE0 + m_remap[index]);
return;
if (m_multitextureAvailable)
glActiveTexture(GL_TEXTURE0 + index);
if (enabled) if (enabled)
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
@ -1015,7 +1005,7 @@ void CGLDevice::SetTextureEnabled(int index, bool enabled)
The settings are remembered, even if texturing is disabled at the moment. */ The settings are remembered, even if texturing is disabled at the moment. */
void CGLDevice::SetTextureStageParams(int index, const TextureStageParams &params) void CGLDevice::SetTextureStageParams(int index, const TextureStageParams &params)
{ {
assert(index >= 0 && index < static_cast<int>( m_currentTextures.size() )); assert(index >= 0 && index < static_cast<int>(m_currentTextures.size()));
// Remember the settings // Remember the settings
m_textureStageParams[index] = params; m_textureStageParams[index] = params;
@ -1025,11 +1015,7 @@ void CGLDevice::SetTextureStageParams(int index, const TextureStageParams &param
void CGLDevice::SetTextureCoordGeneration(int index, TextureGenerationParams &params) void CGLDevice::SetTextureCoordGeneration(int index, TextureGenerationParams &params)
{ {
if (!m_multitextureAvailable && index != 0) glActiveTexture(GL_TEXTURE0 + m_remap[index]);
return;
if (m_multitextureAvailable)
glActiveTexture(GL_TEXTURE0 + index);
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
@ -1069,10 +1055,7 @@ void CGLDevice::SetTextureCoordGeneration(int index, TextureGenerationParams &pa
void CGLDevice::UpdateTextureParams(int index) void CGLDevice::UpdateTextureParams(int index)
{ {
assert(index >= 0 && index < static_cast<int>( m_currentTextures.size() )); assert(index >= 0 && index < static_cast<int>(m_currentTextures.size()));
if (!m_multitextureAvailable && index != 0)
return;
// Don't actually do anything if texture not set // Don't actually do anything if texture not set
if (! m_currentTextures[index].Valid()) if (! m_currentTextures[index].Valid())
@ -1080,8 +1063,7 @@ void CGLDevice::UpdateTextureParams(int index)
const TextureStageParams &params = m_textureStageParams[index]; const TextureStageParams &params = m_textureStageParams[index];
if (m_multitextureAvailable) glActiveTexture(GL_TEXTURE0 + m_remap[index]);
glActiveTexture(GL_TEXTURE0 + index);
if (params.wrapS == TEX_WRAP_CLAMP) if (params.wrapS == TEX_WRAP_CLAMP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@ -1099,10 +1081,6 @@ void CGLDevice::UpdateTextureParams(int index)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
else assert(false); else assert(false);
// Texture env setting is silly without multitexturing
if (!m_multitextureAvailable)
return;
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, params.factor.Array()); glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, params.factor.Array());
// To save some trouble // To save some trouble
@ -1240,6 +1218,129 @@ after_tex_color:
after_tex_operations: ; after_tex_operations: ;
} }
void CGLDevice::EnableShadows()
{
// already enabled
if (m_shadowMapping) return;
// shadow map unit
glActiveTexture(GL_TEXTURE0 + m_remap[2]);
glEnable(GL_TEXTURE_2D);
glMatrixMode(GL_TEXTURE);
glLoadMatrixf(m_shadowMatrix.Array());
// enable texture coordinate generation
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glEnable(GL_TEXTURE_GEN_R);
glEnable(GL_TEXTURE_GEN_Q);
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
float plane1[] = { 1.0f, 0.0f, 0.0f, 0.0f };
float plane2[] = { 0.0f, 1.0f, 0.0f, 0.0f };
float plane3[] = { 0.0f, 0.0f, 1.0f, 0.0f };
float plane4[] = { 0.0f, 0.0f, 0.0f, 1.0f };
glTexGenfv(GL_S, GL_EYE_PLANE, plane1);
glTexGenfv(GL_T, GL_EYE_PLANE, plane2);
glTexGenfv(GL_R, GL_EYE_PLANE, plane3);
glTexGenfv(GL_Q, GL_EYE_PLANE, plane4);
// simple shadows
if (!m_shadowQuality)
{
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}
// quality shadows
else
{
// texture environment settings
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
float half[] = { 0.5f, 0.5f, 0.5f, 1.0f };
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, half);
// color = 0.5 * (1.0 - shadow)
// = 0.5 for shadow = 0.0
// = 0.0 for shadow = 1.0
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
// alpha = previous
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
// combine unit
glActiveTexture(GL_TEXTURE0 + m_remap[3]);
glEnable(GL_TEXTURE_2D);
int color = 0xFFFFFFFF;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &color);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// texture enviromnent settings
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
// color = (1.0 - previous) * primary color
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
// alpha = primary color
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR);
glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
}
m_shadowMapping = true;
}
void CGLDevice::DisableShadows()
{
// already disabled
if (!m_shadowMapping) return;
glActiveTexture(GL_TEXTURE0 + m_remap[2]);
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glDisable(GL_TEXTURE_GEN_R);
glDisable(GL_TEXTURE_GEN_Q);
// quality shadows
if (m_shadowQuality)
{
glActiveTexture(GL_TEXTURE0 + m_remap[3]);
glDisable(GL_TEXTURE_2D);
}
m_shadowMapping = false;
}
void CGLDevice::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode wrapT) void CGLDevice::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode wrapT)
{ {
assert(index >= 0 && index < static_cast<int>( m_currentTextures.size() )); assert(index >= 0 && index < static_cast<int>( m_currentTextures.size() ));
@ -1252,11 +1353,7 @@ void CGLDevice::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode wr
if (! m_currentTextures[index].Valid()) if (! m_currentTextures[index].Valid())
return; return;
if (!m_multitextureAvailable && index != 0) glActiveTexture(GL_TEXTURE0 + m_remap[index]);
return;
if (m_multitextureAvailable)
glActiveTexture(GL_TEXTURE0 + index);
if (wrapS == TEX_WRAP_CLAMP) if (wrapS == TEX_WRAP_CLAMP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@ -1286,9 +1383,7 @@ void CGLDevice::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int ve
glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, sizeof(Vertex), reinterpret_cast<GLfloat*>(&vs[0].normal)); glNormalPointer(GL_FLOAT, sizeof(Vertex), reinterpret_cast<GLfloat*>(&vs[0].normal));
if (m_multitextureAvailable) glClientActiveTexture(GL_TEXTURE0 + m_remap[0]);
glClientActiveTexture(GL_TEXTURE0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), reinterpret_cast<GLfloat*>(&vs[0].texCoord)); glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), reinterpret_cast<GLfloat*>(&vs[0].texCoord));
@ -1312,18 +1407,13 @@ void CGLDevice::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, in
glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, sizeof(VertexTex2), reinterpret_cast<GLfloat*>(&vs[0].normal)); glNormalPointer(GL_FLOAT, sizeof(VertexTex2), reinterpret_cast<GLfloat*>(&vs[0].normal));
if (m_multitextureAvailable) glClientActiveTexture(GL_TEXTURE0 + m_remap[0]);
glClientActiveTexture(GL_TEXTURE0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast<GLfloat*>(&vs[0].texCoord)); glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast<GLfloat*>(&vs[0].texCoord));
if (m_multitextureAvailable) glClientActiveTexture(GL_TEXTURE0 + m_remap[1]);
{ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTexture(GL_TEXTURE1); glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast<GLfloat*>(&vs[0].texCoord2));
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast<GLfloat*>(&vs[0].texCoord2));
}
glColor4fv(color.Array()); glColor4fv(color.Array());
@ -1332,11 +1422,10 @@ void CGLDevice::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, in
glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE1 glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE1
if (m_multitextureAvailable)
{ glClientActiveTexture(GL_TEXTURE0 + m_remap[0]);
glClientActiveTexture(GL_TEXTURE0);
glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
} }
void CGLDevice::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount) void CGLDevice::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount)
@ -1366,9 +1455,7 @@ void CGLDevice::DrawPrimitives(PrimitiveType type, const Vertex *vertices,
glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, sizeof(Vertex), reinterpret_cast<GLfloat*>(&vs[0].normal)); glNormalPointer(GL_FLOAT, sizeof(Vertex), reinterpret_cast<GLfloat*>(&vs[0].normal));
if (m_multitextureAvailable) glClientActiveTexture(GL_TEXTURE0 + m_remap[0]);
glClientActiveTexture(GL_TEXTURE0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), reinterpret_cast<GLfloat*>(&vs[0].texCoord)); glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), reinterpret_cast<GLfloat*>(&vs[0].texCoord));
@ -1402,18 +1489,13 @@ void CGLDevice::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices,
glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, sizeof(VertexTex2), reinterpret_cast<GLfloat*>(&vs[0].normal)); glNormalPointer(GL_FLOAT, sizeof(VertexTex2), reinterpret_cast<GLfloat*>(&vs[0].normal));
if (m_multitextureAvailable) glClientActiveTexture(GL_TEXTURE0 + m_remap[0]);
glClientActiveTexture(GL_TEXTURE0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast<GLfloat*>(&vs[0].texCoord)); glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast<GLfloat*>(&vs[0].texCoord));
if (m_multitextureAvailable) glClientActiveTexture(GL_TEXTURE0 + m_remap[1]);
{ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTexture(GL_TEXTURE1); glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast<GLfloat*>(&vs[0].texCoord2));
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast<GLfloat*>(&vs[0].texCoord2));
}
glColor4fv(color.Array()); glColor4fv(color.Array());
@ -1432,11 +1514,9 @@ void CGLDevice::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices,
glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE1 glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE1
if (m_multitextureAvailable)
{ glClientActiveTexture(GL_TEXTURE0 + m_remap[0]);
glClientActiveTexture(GL_TEXTURE0); glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
} }
void CGLDevice::DrawPrimitives(PrimitiveType type, const VertexCol *vertices, void CGLDevice::DrawPrimitives(PrimitiveType type, const VertexCol *vertices,
@ -1729,9 +1809,7 @@ void CGLDevice::DrawStaticBuffer(unsigned int bufferId)
glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, sizeof(Vertex), static_cast<char*>(nullptr) + offsetof(Vertex, normal)); glNormalPointer(GL_FLOAT, sizeof(Vertex), static_cast<char*>(nullptr) + offsetof(Vertex, normal));
if (m_multitextureAvailable) glClientActiveTexture(GL_TEXTURE0 + m_remap[0]);
glClientActiveTexture(GL_TEXTURE0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), static_cast<char*>(nullptr) + offsetof(Vertex, texCoord)); glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), static_cast<char*>(nullptr) + offsetof(Vertex, texCoord));
} }
@ -1743,18 +1821,13 @@ void CGLDevice::DrawStaticBuffer(unsigned int bufferId)
glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, sizeof(VertexTex2), static_cast<char*>(nullptr) + offsetof(VertexTex2, normal)); glNormalPointer(GL_FLOAT, sizeof(VertexTex2), static_cast<char*>(nullptr) + offsetof(VertexTex2, normal));
if (m_multitextureAvailable) glClientActiveTexture(GL_TEXTURE0 + m_remap[0]);
glClientActiveTexture(GL_TEXTURE0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), static_cast<char*>(nullptr) + offsetof(VertexTex2, texCoord)); glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), static_cast<char*>(nullptr) + offsetof(VertexTex2, texCoord));
if (m_multitextureAvailable) glClientActiveTexture(GL_TEXTURE0 + m_remap[1]);
{ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTexture(GL_TEXTURE1); glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), static_cast<char*>(nullptr) + offsetof(VertexTex2, texCoord2));
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), static_cast<char*>(nullptr) + offsetof(VertexTex2, texCoord2));
}
} }
else if ((*it).second.vertexType == VERTEX_TYPE_COL) else if ((*it).second.vertexType == VERTEX_TYPE_COL)
{ {
@ -1779,11 +1852,9 @@ void CGLDevice::DrawStaticBuffer(unsigned int bufferId)
glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE1 glDisableClientState(GL_TEXTURE_COORD_ARRAY); // GL_TEXTURE1
if (m_multitextureAvailable)
{ glClientActiveTexture(GL_TEXTURE0 + m_remap[0]);
glClientActiveTexture(GL_TEXTURE0); glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
} }
else if ((*it).second.vertexType == VERTEX_TYPE_COL) else if ((*it).second.vertexType == VERTEX_TYPE_COL)
{ {
@ -1934,6 +2005,15 @@ void CGLDevice::SetRenderState(RenderState state, bool enabled)
return; return;
} }
else if (state == RENDER_STATE_SHADOW_MAPPING)
{
if (enabled)
EnableShadows();
else
DisableShadows();
return;
}
GLenum flag = 0; GLenum flag = 0;
@ -2036,8 +2116,7 @@ void CGLDevice::CopyFramebufferToTexture(Texture& texture, int xOffset, int yOff
if (texture.id == 0) return; if (texture.id == 0) return;
// Use & enable 1st texture stage // Use & enable 1st texture stage
if (m_multitextureAvailable) glActiveTexture(GL_TEXTURE0 + m_remap[0]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture.id); glBindTexture(GL_TEXTURE_2D, texture.id);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, x, y, width, height); glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, x, y, width, height);

View File

@ -204,6 +204,11 @@ private:
//! Updates the texture params for given texture stage //! Updates the texture params for given texture stage
void UpdateTextureParams(int index); void UpdateTextureParams(int index);
//! Enables shadows
void EnableShadows();
//! Disables shadows
void DisableShadows();
private: private:
//! Current config //! Current config
DeviceConfig m_config; DeviceConfig m_config;
@ -218,6 +223,8 @@ private:
Math::Matrix m_projectionMat; Math::Matrix m_projectionMat;
//! Combined world-view-projection matrix //! Combined world-view-projection matrix
Math::Matrix m_combinedMatrix; Math::Matrix m_combinedMatrix;
//! Current shadow matrix
Math::Matrix m_shadowMatrix;
//! true means that combined matrix is outdated //! true means that combined matrix is outdated
bool m_combinedMatrixOutdated = true; bool m_combinedMatrixOutdated = true;
@ -237,6 +244,8 @@ private:
std::vector<bool> m_texturesEnabled; std::vector<bool> m_texturesEnabled;
//! Current texture params //! Current texture params
std::vector<TextureStageParams> m_textureStageParams; std::vector<TextureStageParams> m_textureStageParams;
//! Texture unit remap
std::vector<int> m_remap;
//! Set of all created textures //! Set of all created textures
std::set<Texture> m_allTextures; std::set<Texture> m_allTextures;
@ -264,10 +273,6 @@ private:
//! Detected capabilities //! Detected capabilities
//! Depth texture support //! Depth texture support
ShadowMappingSupport m_shadowMappingSupport = SMS_NONE; ShadowMappingSupport m_shadowMappingSupport = SMS_NONE;
//! Shadow ambient support
bool m_shadowAmbientSupported = false;
//! Whether to use multitexturing
bool m_multitextureAvailable = false;
//! Whether to use VBOs or display lists //! Whether to use VBOs or display lists
bool m_vboAvailable = false; bool m_vboAvailable = false;
//! Whether anisotropic filtering is available //! Whether anisotropic filtering is available
@ -288,6 +293,11 @@ private:
std::map<unsigned int, VboObjectInfo> m_vboObjects; std::map<unsigned int, VboObjectInfo> m_vboObjects;
//! Last ID of VBO object //! Last ID of VBO object
unsigned int m_lastVboId = 0; unsigned int m_lastVboId = 0;
//! true means shadow mapping is enabled
bool m_shadowMapping = false;
//! true means that quality shadows are enabled
bool m_shadowQuality = true;
}; };