[colobot] 350/390: Added experimental support for dynamic shadows (shadow mapping)
Didier Raboud
odyx at moszumanska.debian.org
Fri Jun 12 14:22:03 UTC 2015
This is an automated email from the git hooks/post-receive script.
odyx pushed a commit to branch upstream/latest
in repository colobot.
commit 0b2f00530bc05cf918665223c4dde07dc506cf09
Author: Tomasz Kapuściński <tomaszkax86 at gmail.com>
Date: Mon May 11 15:21:17 2015 +0200
Added experimental support for dynamic shadows (shadow mapping)
---
src/app/app.h | 1 +
src/graphics/core/device.h | 25 +++-
src/graphics/core/nulldevice.cpp | 29 ++++-
src/graphics/core/nulldevice.h | 11 +-
src/graphics/core/texture.h | 49 ++++++++
src/graphics/engine/engine.cpp | 239 ++++++++++++++++++++++++++++++++++++++-
src/graphics/engine/engine.h | 23 ++++
src/graphics/opengl/gldevice.cpp | 228 +++++++++++++++++++++++++++++++++----
src/graphics/opengl/gldevice.h | 27 ++++-
9 files changed, 594 insertions(+), 38 deletions(-)
diff --git a/src/app/app.h b/src/app/app.h
index d8a1e1d..651e3be 100644
--- a/src/app/app.h
+++ b/src/app/app.h
@@ -123,6 +123,7 @@ enum PerformanceCounter
PCNT_RENDER_TERRAIN, //! < rendering the terrain
PCNT_RENDER_OBJECTS, //! < rendering the 3D objects
PCNT_RENDER_INTERFACE, //! < rendering 2D interface
+ PCNT_RENDER_SHADOW_MAP, //! < rendering shadow map
PCNT_ALL, //! < all counters together
diff --git a/src/graphics/core/device.h b/src/graphics/core/device.h
index f790c24..16b32b3 100644
--- a/src/graphics/core/device.h
+++ b/src/graphics/core/device.h
@@ -91,8 +91,7 @@ enum TransformType
{
TRANSFORM_WORLD,
TRANSFORM_VIEW,
- TRANSFORM_PROJECTION,
- TRANSFORM_TEXTURE
+ TRANSFORM_PROJECTION
};
/**
@@ -107,7 +106,8 @@ enum RenderState
RENDER_STATE_DEPTH_TEST,
RENDER_STATE_DEPTH_WRITE,
RENDER_STATE_ALPHA_TEST,
- RENDER_STATE_CULLING
+ RENDER_STATE_CULLING,
+ RENDER_STATE_DEPTH_BIAS
};
/**
@@ -276,6 +276,8 @@ public:
virtual Texture CreateTexture(CImage *image, const TextureCreateParams ¶ms) = 0;
//! Creates a texture from raw image data; image data can be freed after that
virtual Texture CreateTexture(ImageData *data, const TextureCreateParams ¶ms) = 0;
+ //! Creates a depth texture with specific dimensions and depth
+ virtual Texture CreateDepthTexture(int width, int height, int depth) = 0;
//! Deletes a given texture, freeing it from video memory
virtual void DestroyTexture(const Texture &texture) = 0;
//! Deletes all textures created so far
@@ -296,6 +298,12 @@ public:
//! Sets only the texture wrap modes (for faster than thru stage params)
virtual void SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode wrapT) = 0;
+ //! Sets the texture coordinate generation mode for given texture unit
+ virtual void SetTextureCoordGeneration(int index, TextureGenerationParams ¶ms) = 0;
+
+ //! Sets texture coordinate transform matrix
+ virtual void SetTextureMatrix(int index, Math::Matrix& matrix) = 0;
+
//! Renders primitive composed of vertices with single texture
virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount,
Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) = 0;
@@ -333,14 +341,20 @@ public:
//! Returns a mask of frustum planes for which the test is positive
virtual int ComputeSphereVisibility(const Math::Vector ¢er, float radius) = 0;
+ //! Changes rendering viewport
+ virtual void SetViewport(int x, int y, int width, int height) = 0;
+
//! Enables/disables the given render state
virtual void SetRenderState(RenderState state, bool enabled) = 0;
+ //! Sets the color mask
+ virtual void SetColorMask(bool red, bool green, bool blue, bool alpha) = 0;
+
//! Sets the function of depth test
virtual void SetDepthTestFunc(CompFunc func) = 0;
//! Sets the depth bias (constant value added to Z-coords)
- virtual void SetDepthBias(float factor) = 0;
+ virtual void SetDepthBias(float factor, float units) = 0;
//! Sets the alpha test function and reference value
virtual void SetAlphaTestFunc(CompFunc func, float refValue) = 0;
@@ -366,6 +380,9 @@ public:
//! Sets the current fill mode
virtual void SetFillMode(FillMode mode) = 0;
+ //! Copies content of framebuffer to texture
+ virtual void CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height) = 0;
+
//! Returns the pixels of the entire screen
virtual void* GetFrameBufferPixels() const = 0;
};
diff --git a/src/graphics/core/nulldevice.cpp b/src/graphics/core/nulldevice.cpp
index f5e426d..869bb89 100644
--- a/src/graphics/core/nulldevice.cpp
+++ b/src/graphics/core/nulldevice.cpp
@@ -128,6 +128,13 @@ Texture CNullDevice::CreateTexture(ImageData *data, const TextureCreateParams &p
return tex;
}
+Texture CNullDevice::CreateDepthTexture(int width, int height, int depth)
+{
+ Texture tex;
+ tex.id = 1; // tex.id = 0 => invalid texture
+ return tex;
+}
+
void CNullDevice::DestroyTexture(const Texture &texture)
{
}
@@ -171,6 +178,14 @@ void CNullDevice::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode
{
}
+void CNullDevice::SetTextureCoordGeneration(int index, TextureGenerationParams ¶ms)
+{
+}
+
+void CNullDevice::SetTextureMatrix(int index, Math::Matrix& matrix)
+{
+}
+
TextureStageParams CNullDevice::GetTextureStageParams(int index)
{
return TextureStageParams();
@@ -230,6 +245,10 @@ int CNullDevice::ComputeSphereVisibility(const Math::Vector ¢er, float radiu
return 0;
}
+void CNullDevice::SetViewport(int x, int y, int width, int height)
+{
+}
+
void CNullDevice::SetRenderState(RenderState state, bool enabled)
{
}
@@ -239,6 +258,10 @@ bool CNullDevice::GetRenderState(RenderState state)
return false;
}
+void CNullDevice::SetColorMask(bool red, bool green, bool blue, bool alpha)
+{
+}
+
void CNullDevice::SetDepthTestFunc(CompFunc func)
{
}
@@ -248,7 +271,7 @@ CompFunc CNullDevice::GetDepthTestFunc()
return COMP_FUNC_NEVER;
}
-void CNullDevice::SetDepthBias(float factor)
+void CNullDevice::SetDepthBias(float factor, float units)
{
}
@@ -332,6 +355,10 @@ FillMode CNullDevice::GetFillMode()
return FILL_POINT;
}
+void CNullDevice::CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height)
+{
+}
+
void* CNullDevice::GetFrameBufferPixels() const
{
return nullptr;
diff --git a/src/graphics/core/nulldevice.h b/src/graphics/core/nulldevice.h
index c6065a6..a80c5fa 100644
--- a/src/graphics/core/nulldevice.h
+++ b/src/graphics/core/nulldevice.h
@@ -67,6 +67,7 @@ public:
virtual Texture CreateTexture(CImage *image, const TextureCreateParams ¶ms);
virtual Texture CreateTexture(ImageData *data, const TextureCreateParams ¶ms);
+ virtual Texture CreateDepthTexture(int width, int height, int depth);
virtual void DestroyTexture(const Texture &texture);
virtual void DestroyAllTextures();
@@ -81,6 +82,8 @@ public:
virtual TextureStageParams GetTextureStageParams(int index);
virtual void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT);
+ virtual void SetTextureCoordGeneration(int index, TextureGenerationParams ¶ms);
+ virtual void SetTextureMatrix(int index, Math::Matrix& matrix);
virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount,
Color color = Color(1.0f, 1.0f, 1.0f, 1.0f));
@@ -98,14 +101,18 @@ public:
virtual void DestroyStaticBuffer(unsigned int bufferId);
virtual int ComputeSphereVisibility(const Math::Vector ¢er, float radius);
+
+ virtual void SetViewport(int x, int y, int width, int height);
virtual void SetRenderState(RenderState state, bool enabled);
virtual bool GetRenderState(RenderState state);
+
+ virtual void SetColorMask(bool red, bool green, bool blue, bool alpha);
virtual void SetDepthTestFunc(CompFunc func);
virtual CompFunc GetDepthTestFunc();
- virtual void SetDepthBias(float factor);
+ virtual void SetDepthBias(float factor, float units);
virtual float GetDepthBias();
virtual void SetAlphaTestFunc(CompFunc func, float refValue);
@@ -131,6 +138,8 @@ public:
virtual void SetFillMode(FillMode mode) ;
virtual FillMode GetFillMode();
+
+ virtual void CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height);
virtual void* GetFrameBufferPixels() const;
diff --git a/src/graphics/core/texture.h b/src/graphics/core/texture.h
index 038bbbb..70fc845 100644
--- a/src/graphics/core/texture.h
+++ b/src/graphics/core/texture.h
@@ -98,6 +98,7 @@ enum TexMagFilter
enum TexWrapMode
{
TEX_WRAP_CLAMP,
+ TEX_WRAP_CLAMP_TO_BORDER,
TEX_WRAP_REPEAT
};
@@ -216,6 +217,54 @@ struct TextureStageParams
};
/**
+* \struct TexGenMode
+* \brief Texture generation mode
+*/
+enum TexGenMode
+{
+ //! No texture generation
+ TEX_GEN_NONE,
+ //! Object linear mode
+ TEX_GEN_OBJECT_LINEAR,
+ //! Eye linear mode
+ TEX_GEN_EYE_LINEAR,
+ //! Spherical mapping mode
+ TEX_GEN_SPHERE_MAP,
+ //! Normal mapping mode
+ TEX_GEN_NORMAL_MAP,
+ //! Reflection mapping mode
+ TEX_GEN_REFLECTION_MAP
+};
+
+/**
+* \struct TextureGenerationParams
+* \brief Parameters for texture coordinate generation
+*
+* These params define the generation of texture coordinate for given texture unit.
+*/
+struct TextureGenerationParams
+{
+ struct
+ {
+ TexGenMode mode;
+ float plane[4];
+ } coords[4];
+
+ TextureGenerationParams()
+ {
+ LoadDefault();
+ }
+
+ inline void LoadDefault()
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ coords[i].mode = TEX_GEN_NONE;
+ }
+ }
+};
+
+/**
* \struct Texture
* \brief Info about a texture
*
diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp
index d26304d..849b585 100644
--- a/src/graphics/engine/engine.cpp
+++ b/src/graphics/engine/engine.cpp
@@ -116,6 +116,8 @@ CEngine::CEngine(CApplication *app)
m_textureQuality = 1;
m_textureMipmapLevel = 1;
m_textureAnisotropy = 1;
+ m_shadowMapping = false;
+ m_npotShadowMap = false;
m_totoMode = true;
m_lensMode = true;
m_waterMode = true;
@@ -181,6 +183,12 @@ CEngine::CEngine(CApplication *app)
m_textureAnisotropy = value;
}
+ if (CProfile::GetInstance().GetIntProperty("Setup", "ShadowMapping", value))
+ {
+ m_shadowMapping = (value > 0);
+ m_npotShadowMap = (value > 1);
+ }
+
m_defaultTexParams.format = TEX_IMG_AUTO;
m_defaultTexParams.mipmap = mipmaps;
m_defaultTexParams.filter = filter;
@@ -188,6 +196,13 @@ CEngine::CEngine(CApplication *app)
m_terrainTexParams.format = TEX_IMG_AUTO;
m_terrainTexParams.mipmap = mipmaps;
m_terrainTexParams.filter = filter;
+
+ // Compute bias matrix for shadow mapping
+ Math::Matrix temp1, temp2;
+ Math::LoadScaleMatrix(temp1, Math::Vector(0.5f, 0.5f, 0.5f));
+ Math::LoadTranslationMatrix(temp2, Math::Vector(1.0f, 1.0f, 1.0f));
+ //m_shadowBias = Math::MultiplyMatrices(m_shadowBias, temporary);
+ m_shadowBias = Math::MultiplyMatrices(temp1, temp2);
}
CEngine::~CEngine()
@@ -2965,6 +2980,16 @@ int CEngine::GetTextureAnisotropyLevel()
return m_textureAnisotropy;
}
+void CEngine::SetShadowMapping(bool value)
+{
+ m_shadowMapping = value;
+}
+
+bool CEngine::GetShadowMapping()
+{
+ return m_shadowMapping;
+}
+
void CEngine::SetTotoMode(bool present)
{
m_totoMode = present;
@@ -3165,6 +3190,9 @@ void CEngine::Render()
// Begin the scene
m_device->BeginScene();
+ if (m_shadowMapping)
+ RenderShadowMap();
+
if (m_drawWorld)
Draw3DScene();
@@ -3207,6 +3235,38 @@ void CEngine::Draw3DScene()
m_lightMan->UpdateDeviceLights(ENG_OBJTYPE_TERRAIN);
+ // Enable shadow mapping
+ if (m_shadowMapping)
+ {
+ m_device->SetTextureEnabled(2, true);
+ m_device->SetTexture(2, m_shadowMap);
+ m_device->SetTextureMatrix(2, 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);
+ }
+
for (int objRank = 0; objRank < static_cast<int>(m_objects.size()); objRank++)
{
if (! m_objects[objRank].used)
@@ -3260,6 +3320,24 @@ void CEngine::Draw3DScene()
}
}
+ // Disable shadow mapping
+ if (m_shadowMapping)
+ {
+ Math::Matrix identity;
+ identity.LoadIdentity();
+
+ m_device->SetTexture(2, 0);
+ m_device->SetTextureEnabled(2, false);
+ m_device->SetTextureMatrix(2, identity);
+
+ TextureGenerationParams params;
+
+ for (int i = 0; i < 4; i++)
+ params.coords[i].mode = TEX_GEN_NONE;
+
+ m_device->SetTextureCoordGeneration(2, params);
+ }
+
// Draws the shadows , if shadows enabled
if (m_shadowVisible)
DrawShadow();
@@ -3431,6 +3509,154 @@ void CEngine::Draw3DScene()
if (! m_overFront) DrawOverColor(); // draws the foreground color
}
+void CEngine::RenderShadowMap()
+{
+ if (!m_shadowMapping) return;
+
+ m_app->StartPerformanceCounter(PCNT_RENDER_SHADOW_MAP);
+
+ m_device->Clear();
+
+ // If no shadow map texture exists, create it
+ if (m_shadowMap.id == 0)
+ {
+ int width, height;
+
+ int depth = m_app->GetInstance().GetVideoConfig().depthSize;
+
+ if (m_npotShadowMap)
+ {
+ width = height = Math::Min(m_size.x, m_size.y);
+ }
+ else
+ {
+ int min = Math::Min(m_size.x, m_size.y);
+
+ for (int i = 0; i < 16; i++)
+ {
+ if (min < (1 << i)) break;
+
+ width = height = 1 << i;
+ }
+ }
+
+ m_shadowMap = m_device->CreateDepthTexture(width, height, depth);
+
+ GetLogger()->Info("Created shadow map texture: %dx%d, depth %d\n", width, height, depth);
+ }
+
+ // change state to rendering shadow maps
+ m_device->SetColorMask(false, false, false, false);
+ //m_device->SetDepthTestFunc(COMP_FUNC_LEQUAL);
+ m_device->SetRenderState(RENDER_STATE_DEPTH_TEST, true);
+ m_device->SetRenderState(RENDER_STATE_DEPTH_WRITE, true);
+ m_device->SetRenderState(RENDER_STATE_BLENDING, false);
+ m_device->SetRenderState(RENDER_STATE_LIGHTING, false);
+ m_device->SetRenderState(RENDER_STATE_FOG, false);
+ m_device->SetRenderState(RENDER_STATE_CULLING, false);
+ m_device->SetRenderState(RENDER_STATE_ALPHA_TEST, true);
+
+ m_device->SetViewport(0, 0, m_shadowMap.size.x, m_shadowMap.size.y);
+
+ // recompute matrices
+ Math::Vector worldUp(1.0f, 0.0f, 0.0f);
+ Math::Vector dir = m_lookatPt - m_eyePt;
+ float change = Math::Max(1.0f, dir.Length() / 25.0f);
+ dir.Normalize();
+ Math::Vector pos = m_lookatPt + 40.0f * dir;
+
+ Math::Vector lightPos = pos + Math::Vector(3.0f, 30.0f, 3.0f);
+ Math::Vector lookAt = pos + Math::Vector(0.0, 100.0f, 0.0f);
+
+ float dist = 75.0f; // *change;
+
+ Math::LoadOrthoProjectionMatrix(m_shadowProjMat, -dist, dist, -dist, dist, -50.0f, 50.0f);
+ Math::LoadViewMatrix(m_shadowViewMat, lightPos, lookAt, worldUp);
+
+ Math::Matrix temporary = Math::MultiplyMatrices(m_shadowProjMat, m_shadowViewMat);
+ m_shadowTextureMat = Math::MultiplyMatrices(m_shadowBias, temporary);
+
+ m_device->SetTransform(TRANSFORM_PROJECTION, m_shadowProjMat);
+ m_device->SetTransform(TRANSFORM_VIEW, m_shadowViewMat);
+
+ m_device->SetTexture(0, 0);
+ m_device->SetTexture(1, 0);
+
+ //m_device->SetCullMode(CULL_CW);
+ //m_device->SetRenderState(RENDER_STATE_DEPTH_BIAS, true);
+ //m_device->SetDepthBias(2.0f, 4.0f);
+
+ // render objects into shadow map
+ for (int objRank = 0; objRank < static_cast<int>(m_objects.size()); objRank++)
+ {
+ if (!m_objects[objRank].used)
+ continue;
+
+ if (m_objects[objRank].type == ENG_OBJTYPE_TERRAIN)
+ continue;
+
+ //if (!m_objects[objRank].drawWorld)
+ // continue;
+
+ m_device->SetTransform(TRANSFORM_WORLD, m_objects[objRank].transform);
+
+ // TODO: check proper object filtering
+ if (!IsVisible(objRank))
+ continue;
+
+ int baseObjRank = m_objects[objRank].baseObjRank;
+ if (baseObjRank == -1)
+ continue;
+
+ assert(baseObjRank >= 0 && baseObjRank < static_cast<int>(m_baseObjects.size()));
+
+ EngineBaseObject& p1 = m_baseObjects[baseObjRank];
+ if (!p1.used)
+ continue;
+
+ //m_lightMan->UpdateDeviceLights(m_objects[objRank].type);
+
+ for (int l2 = 0; l2 < static_cast<int>(p1.next.size()); l2++)
+ {
+ EngineBaseObjTexTier& p2 = p1.next[l2];
+
+ for (int l3 = 0; l3 < static_cast<int>(p2.next.size()); l3++)
+ {
+ EngineBaseObjLODTier& p3 = p2.next[l3];
+
+ if (!IsWithinLODLimit(m_objects[objRank].distance, p3.lodLevel))
+ continue;
+
+ for (int l4 = 0; l4 < static_cast<int>(p3.next.size()); l4++)
+ {
+ EngineBaseObjDataTier& p4 = p3.next[l4];
+
+ //if (m_objects[objRank].transparency != 0.0f) // transparent ?
+ // continue;
+
+ DrawObject(p4);
+ }
+ }
+ }
+ }
+
+ m_device->SetCullMode(CULL_CCW);
+ m_device->SetRenderState(RENDER_STATE_DEPTH_BIAS, false);
+
+ // copy depth buffer to shadow map
+ m_device->CopyFramebufferToTexture(m_shadowMap, 0, 0, 0, 0, m_shadowMap.size.x, m_shadowMap.size.y);
+
+ // restore default state
+ m_device->SetViewport(0, 0, m_size.x, m_size.y);
+
+ m_device->SetColorMask(true, true, true, true);
+ m_device->Clear();
+
+ m_app->StopPerformanceCounter(PCNT_RENDER_SHADOW_MAP);
+
+ m_device->SetRenderState(RENDER_STATE_DEPTH_TEST, false);
+}
+
void CEngine::DrawObject(const EngineBaseObjDataTier& p4)
{
if (p4.staticBufferId != 0)
@@ -4406,8 +4632,8 @@ void CEngine::DrawStats()
if (!m_showStats)
return;
- float height = m_text->GetAscent(FONT_COLOBOT, 12.0f);
- float width = 0.2f;
+ float height = m_text->GetAscent(FONT_COLOBOT, 13.0f);
+ float width = 0.25f;
Math::Point pos(0.04f, 0.04f + 20 * height);
@@ -4510,12 +4736,19 @@ void CEngine::DrawStats()
pos.y -= height;
+ str.str("");
+ str << "Shadow map render: " << std::fixed << std::setprecision(2) << m_app->GetPerformanceCounterData(PCNT_RENDER_SHADOW_MAP);
+ m_text->DrawText(str.str(), FONT_COLOBOT, 12.0f, pos, 1.0f, TEXT_ALIGN_LEFT, 0, Color(1.0f, 1.0f, 1.0f, 1.0f));
+
+ pos.y -= height;
+
float otherRender = m_app->GetPerformanceCounterData(PCNT_RENDER_ALL) -
m_app->GetPerformanceCounterData(PCNT_RENDER_PARTICLE) -
m_app->GetPerformanceCounterData(PCNT_RENDER_WATER) -
m_app->GetPerformanceCounterData(PCNT_RENDER_TERRAIN) -
m_app->GetPerformanceCounterData(PCNT_RENDER_OBJECTS) -
- m_app->GetPerformanceCounterData(PCNT_RENDER_INTERFACE);
+ m_app->GetPerformanceCounterData(PCNT_RENDER_INTERFACE) -
+ m_app->GetPerformanceCounterData(PCNT_RENDER_SHADOW_MAP);
str.str("");
str << "Other render: " << std::fixed << std::setprecision(2) << otherRender;
diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h
index 903c22d..5a5533b 100644
--- a/src/graphics/engine/engine.h
+++ b/src/graphics/engine/engine.h
@@ -1135,6 +1135,12 @@ public:
//@}
//@{
+ //! Management of shadow mapping
+ void SetShadowMapping(bool value);
+ bool GetShadowMapping();
+ //@}
+
+ //@{
//! Management mode of toto
void SetTotoMode(bool present);
bool GetTotoMode();
@@ -1227,6 +1233,8 @@ public:
protected:
//! Prepares the interface for 3D scene
void Draw3DScene();
+ //! Renders shadow map
+ void RenderShadowMap();
//! Draw 3D object
void DrawObject(const EngineBaseObjDataTier& p4);
//! Draws the user interface over the scene
@@ -1339,6 +1347,15 @@ protected:
//! Camera angle for 3D scene
float m_focus;
+ //! Projection matrix for rendering shadow maps
+ Math::Matrix m_shadowProjMat;
+ //! View matrix for rendering shadow maps
+ Math::Matrix m_shadowViewMat;
+ //! Texture matrix for rendering shadow maps
+ Math::Matrix m_shadowTextureMat;
+ //! Texture bias for sampling shadow maps
+ Math::Matrix m_shadowBias;
+
//! World matrix for 2D interface
Math::Matrix m_matWorldInterface;
//! Projection matrix for 2D interface
@@ -1416,6 +1433,8 @@ protected:
int m_editIndentValue;
float m_tracePrecision;
+ Texture m_shadowMap;
+
//! Ranks of highlighted objects
int m_highlightRank[100];
//! Highlight visible?
@@ -1436,6 +1455,10 @@ protected:
int m_textureMipmapLevel;
//! Requested texture anisotropy level
int m_textureAnisotropy;
+ //! true if shadow mapping enabled
+ bool m_shadowMapping;
+ //! Override for NPOT shadow map texture
+ bool m_npotShadowMap;
//! Map of loaded textures (by name)
std::map<std::string, Texture> m_texNameMap;
diff --git a/src/graphics/opengl/gldevice.cpp b/src/graphics/opengl/gldevice.cpp
index 8809fd2..8380088 100644
--- a/src/graphics/opengl/gldevice.cpp
+++ b/src/graphics/opengl/gldevice.cpp
@@ -59,8 +59,8 @@ void GLDeviceConfig::LoadDefault()
vboMode = VBO_MODE_AUTO;
}
-
-
+GLuint textureCoordinates[] = { GL_S, GL_T, GL_R, GL_Q };
+GLuint textureCoordGen[] = { GL_TEXTURE_GEN_S, GL_TEXTURE_GEN_T, GL_TEXTURE_GEN_R, GL_TEXTURE_GEN_Q };
CGLDevice::CGLDevice(const GLDeviceConfig &config)
{
@@ -72,6 +72,9 @@ CGLDevice::CGLDevice(const GLDeviceConfig &config)
m_vertexBufferType = VBT_DISPLAY_LIST;
m_anisotropyAvailable = false;
m_maxAnisotropy = 1;
+ m_glMajor = 1;
+ m_glMinor = 1;
+ m_shadowMappingSupport = SMS_NONE;
}
@@ -204,10 +207,33 @@ bool CGLDevice::Create()
return false;
}
+ // Extract OpenGL version
+ const char *version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
+ sscanf(version, "%d.%d", &m_glMajor, &m_glMinor);
+ GetLogger()->Info("OpenGL %d.%d\n", m_glMajor, m_glMinor);
+
+ // 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
+ if (m_glMajor >= 2 || m_glMinor >= 4) // Core depth texture+shadow, OpenGL 1.4+
+ {
+ m_shadowMappingSupport = SMS_CORE;
+ GetLogger()->Info("Shadow mapping available (core)\n");
+ }
+ else if (glewIsSupported("GL_ARB_depth_texture GL_ARB_shadow")) // ARB depth texture + shadow
+ {
+ m_shadowMappingSupport = SMS_ARB;
+ GetLogger()->Info("Shadow mapping available (ARB)\n");
+ }
+ else // No Shadow mapping
+ {
+ m_shadowMappingSupport = SMS_NONE;
+ GetLogger()->Info("Shadow mapping not available\n");
+ }
+
// Detect support of anisotropic filtering
m_anisotropyAvailable = glewIsSupported("GL_EXT_texture_filter_anisotropic");
if(m_anisotropyAvailable)
@@ -239,30 +265,24 @@ bool CGLDevice::Create()
{
GetLogger()->Info("Auto-detecting VBO support\n");
- // extracting OpenGL version
- const char *version = reinterpret_cast<const char*>(glGetString(GL_VERSION));
- int major = 0, minor = 0;
-
- sscanf(version, "%d.%d", &major, &minor);
-
// detecting VBO ARB extension
bool vboARB = glewIsSupported("GL_ARB_vertex_buffer_object");
// VBO is core OpenGL feature since 1.5
// everything below 1.5 means no VBO support
- if(major > 1 || minor > 4)
+ if (m_glMajor > 1 || m_glMinor > 4)
{
- GetLogger()->Info("OpenGL %d.%d, VBO supported\n", major, minor);
+ GetLogger()->Info("Core VBO supported\n", m_glMajor, m_glMinor);
SetVertexBufferType(VBT_VBO_CORE);
}
else if(vboARB) // VBO ARB extension available
{
- GetLogger()->Info("OpenGL %d.%d with GL_ARB_vertex_buffer_object, VBO supported\n", major, minor);
+ GetLogger()->Info("ARB VBO supported\n");
SetVertexBufferType(VBT_VBO_ARB);
}
else // no VBO support
{
- GetLogger()->Info("OpenGL %d.%d without GL_ARB_vertex_buffer_object, VBO not supported\n", major, minor);
+ GetLogger()->Info("VBO not supported\n");
SetVertexBufferType(VBT_DISPLAY_LIST);
}
}
@@ -275,9 +295,10 @@ bool CGLDevice::Create()
// To avoid problems with scaling & lighting
glEnable(GL_RESCALE_NORMAL);
+ //glEnable(GL_NORMALIZE); // this needs some testing
// Minimal depth bias to avoid Z-fighting
- SetDepthBias(0.001f);
+ //SetDepthBias(0.001f);
// Set just to be sure
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
@@ -380,12 +401,6 @@ void CGLDevice::SetTransform(TransformType type, const Math::Matrix &matrix)
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(m_projectionMat.Array());
}
- else if (type == TRANSFORM_TEXTURE)
- {
- m_textureMat = matrix;
- glMatrixMode(GL_TEXTURE);
- glLoadMatrixf(m_textureMat.Array());
- }
else
{
assert(false);
@@ -412,9 +427,9 @@ void CGLDevice::SetMaterial(const Material &material)
{
m_material = material;
- glMaterialfv(GL_FRONT, GL_AMBIENT, m_material.ambient.Array());
- glMaterialfv(GL_FRONT, GL_DIFFUSE, m_material.diffuse.Array());
- glMaterialfv(GL_FRONT, GL_SPECULAR, m_material.specular.Array());
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, m_material.ambient.Array());
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, m_material.diffuse.Array());
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, m_material.specular.Array());
}
int CGLDevice::GetMaxLightCount()
@@ -715,6 +730,81 @@ Texture CGLDevice::CreateTexture(ImageData *data, const TextureCreateParams &par
return result;
}
+Texture CGLDevice::CreateDepthTexture(int width, int height, int depth)
+{
+ Texture result;
+
+ if (m_shadowMappingSupport == SMS_NONE)
+ {
+ result.id = 0;
+ return result;
+ }
+
+ result.alpha = false;
+ result.size.x = width;
+ result.size.y = height;
+
+ // Use & enable 1st texture stage
+ if (m_multitextureAvailable)
+ glActiveTexture(GL_TEXTURE0);
+
+ glGenTextures(1, &result.id);
+ glBindTexture(GL_TEXTURE_2D, result.id);
+
+ GLuint format = GL_DEPTH_COMPONENT;
+
+ if (m_shadowMappingSupport == SMS_CORE)
+ {
+ switch (depth)
+ {
+ case 16:
+ format = GL_DEPTH_COMPONENT16;
+ break;
+ case 24:
+ format = GL_DEPTH_COMPONENT24;
+ break;
+ case 32:
+ format = GL_DEPTH_COMPONENT32;
+ break;
+ }
+
+ glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_INT, nullptr);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
+ }
+ else
+ {
+ switch (depth)
+ {
+ case 16:
+ format = GL_DEPTH_COMPONENT16_ARB;
+ break;
+ case 24:
+ format = GL_DEPTH_COMPONENT24_ARB;
+ break;
+ case 32:
+ format = GL_DEPTH_COMPONENT32_ARB;
+ break;
+ }
+
+ glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_INT, nullptr);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
+ }
+
+ 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_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color);
+
+ glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id);
+
+ return result;
+}
+
void CGLDevice::DestroyTexture(const Texture &texture)
{
// Unbind the texture if in use anywhere
@@ -833,6 +923,60 @@ void CGLDevice::SetTextureStageParams(int index, const TextureStageParams ¶m
UpdateTextureParams(index);
}
+void CGLDevice::SetTextureCoordGeneration(int index, TextureGenerationParams ¶ms)
+{
+ if (!m_multitextureAvailable && index != 0)
+ return;
+
+ if (m_multitextureAvailable)
+ glActiveTexture(GL_TEXTURE0 + index);
+
+ for (int i = 0; i < 4; i++)
+ {
+ GLuint texCoordGen = textureCoordGen[i];
+ GLuint texCoord = textureCoordinates[i];
+
+ if (params.coords[i].mode == TEX_GEN_NONE)
+ {
+ glDisable(texCoordGen);
+ }
+ else
+ {
+ glEnable(texCoordGen);
+
+ switch (params.coords[i].mode)
+ {
+ case TEX_GEN_OBJECT_LINEAR:
+ glTexGeni(texCoord, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+ glTexGenfv(texCoord, GL_OBJECT_PLANE, params.coords[i].plane);
+ break;
+ case TEX_GEN_EYE_LINEAR:
+ glTexGeni(texCoord, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+ glTexGenfv(texCoord, GL_EYE_PLANE, params.coords[i].plane);
+ break;
+ case TEX_GEN_SPHERE_MAP:
+ glTexGeni(texCoord, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
+ break;
+ case TEX_GEN_NORMAL_MAP:
+ glTexGeni(texCoord, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
+ break;
+ case TEX_GEN_REFLECTION_MAP:
+ glTexGeni(texCoord, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
+ break;
+ }
+ }
+ }
+}
+
+void CGLDevice::SetTextureMatrix(int index, Math::Matrix& matrix)
+{
+ if (!m_multitextureAvailable && index != 0)
+ return;
+
+ glMatrixMode(GL_TEXTURE);
+ glLoadMatrixf(matrix.Array());
+}
+
void CGLDevice::UpdateTextureParams(int index)
{
assert(index >= 0 && index < static_cast<int>( m_currentTextures.size() ));
@@ -851,12 +995,16 @@ void CGLDevice::UpdateTextureParams(int index)
if (params.wrapS == TEX_WRAP_CLAMP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ else if (params.wrapS == TEX_WRAP_CLAMP_TO_BORDER)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
else if (params.wrapS == TEX_WRAP_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
else assert(false);
if (params.wrapT == TEX_WRAP_CLAMP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ else if (params.wrapT == TEX_WRAP_CLAMP_TO_BORDER)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
else if (params.wrapT == TEX_WRAP_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
else assert(false);
@@ -987,15 +1135,19 @@ void CGLDevice::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode wr
if (m_multitextureAvailable)
glActiveTexture(GL_TEXTURE0 + index);
-
+
if (wrapS == TEX_WRAP_CLAMP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ else if (wrapS == TEX_WRAP_CLAMP_TO_BORDER)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
else if (wrapS == TEX_WRAP_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
else assert(false);
if (wrapT == TEX_WRAP_CLAMP)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ else if (wrapT == TEX_WRAP_CLAMP_TO_BORDER)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
else if (wrapT == TEX_WRAP_REPEAT)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
else assert(false);
@@ -1546,6 +1698,11 @@ int CGLDevice::ComputeSphereVisibility(const Math::Vector ¢er, float radius)
return result;
}
+void CGLDevice::SetViewport(int x, int y, int width, int height)
+{
+ glViewport(x, y, width, height);
+}
+
void CGLDevice::SetRenderState(RenderState state, bool enabled)
{
if (state == RENDER_STATE_DEPTH_WRITE)
@@ -1580,6 +1737,7 @@ void CGLDevice::SetRenderState(RenderState state, bool enabled)
case RENDER_STATE_DEPTH_TEST: flag = GL_DEPTH_TEST; break;
case RENDER_STATE_ALPHA_TEST: flag = GL_ALPHA_TEST; break;
case RENDER_STATE_CULLING: flag = GL_CULL_FACE; break;
+ case RENDER_STATE_DEPTH_BIAS: flag = GL_POLYGON_OFFSET_FILL; break;
default: assert(false); break;
}
@@ -1623,14 +1781,19 @@ GLenum TranslateGfxCompFunc(CompFunc func)
return 0;
}
+void CGLDevice::SetColorMask(bool red, bool green, bool blue, bool alpha)
+{
+ glColorMask(red, green, blue, alpha);
+}
+
void CGLDevice::SetDepthTestFunc(CompFunc func)
{
glDepthFunc(TranslateGfxCompFunc(func));
}
-void CGLDevice::SetDepthBias(float factor)
+void CGLDevice::SetDepthBias(float factor, float units)
{
- glPolygonOffset(factor, 0.0f);
+ glPolygonOffset(factor, units);
}
void CGLDevice::SetAlphaTestFunc(CompFunc func, float refValue)
@@ -1731,6 +1894,21 @@ void CGLDevice::SetFillMode(FillMode mode)
else assert(false);
}
+void CGLDevice::CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height)
+{
+ if (texture.id == 0) return;
+
+ // Use & enable 1st texture stage
+ if (m_multitextureAvailable)
+ glActiveTexture(GL_TEXTURE0);
+
+ glBindTexture(GL_TEXTURE_2D, texture.id);
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, x, y, width, height);
+
+ // Restore previous texture
+ glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id);
+}
+
void* CGLDevice::GetFrameBufferPixels()const{
GLubyte* pixels = new GLubyte[4 * m_config.size.x * m_config.size.y];
diff --git a/src/graphics/opengl/gldevice.h b/src/graphics/opengl/gldevice.h
index e543f13..4ba1410 100644
--- a/src/graphics/opengl/gldevice.h
+++ b/src/graphics/opengl/gldevice.h
@@ -58,6 +58,13 @@ enum VertexBufferType
VBT_VBO_ARB //! use ARB extension VBOs
};
+enum ShadowMappingSupport
+{
+ SMS_NONE, //! No support for depth textures
+ SMS_ARB, //! ARB extension
+ SMS_CORE //! Core support
+};
+
/**
\struct GLDeviceConfig
\brief Additional config with OpenGL-specific settings */
@@ -132,6 +139,7 @@ public:
virtual Texture CreateTexture(CImage *image, const TextureCreateParams ¶ms) OVERRIDE;
virtual Texture CreateTexture(ImageData *data, const TextureCreateParams ¶ms) OVERRIDE;
+ virtual Texture CreateDepthTexture(int width, int height, int depth) OVERRIDE;
virtual void DestroyTexture(const Texture &texture) OVERRIDE;
virtual void DestroyAllTextures() OVERRIDE;
@@ -143,6 +151,8 @@ public:
virtual void SetTextureStageParams(int index, const TextureStageParams ¶ms) OVERRIDE;
virtual void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) OVERRIDE;
+ virtual void SetTextureCoordGeneration(int index, TextureGenerationParams ¶ms) OVERRIDE;
+ virtual void SetTextureMatrix(int index, Math::Matrix& matrix) OVERRIDE;
virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount,
Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) OVERRIDE;
@@ -161,11 +171,15 @@ public:
virtual int ComputeSphereVisibility(const Math::Vector ¢er, float radius) OVERRIDE;
+ virtual void SetViewport(int x, int y, int width, int height) OVERRIDE;
+
virtual void SetRenderState(RenderState state, bool enabled) OVERRIDE;
+ virtual void SetColorMask(bool red, bool green, bool blue, bool alpha) OVERRIDE;
+
virtual void SetDepthTestFunc(CompFunc func) OVERRIDE;
- virtual void SetDepthBias(float factor) OVERRIDE;
+ virtual void SetDepthBias(float factor, float units) OVERRIDE;
virtual void SetAlphaTestFunc(CompFunc func, float refValue) OVERRIDE;
@@ -181,7 +195,9 @@ public:
virtual void SetShadeModel(ShadeModel model) OVERRIDE;
- virtual void SetFillMode(FillMode mode) OVERRIDE;
+ virtual void SetFillMode(FillMode mode) OVERRIDE;
+
+ virtual void CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height) OVERRIDE;
virtual void* GetFrameBufferPixels() const OVERRIDE;
@@ -205,8 +221,6 @@ private:
Math::Matrix m_modelviewMat;
//! Current projection matrix
Math::Matrix m_projectionMat;
- //! Current texture matrix
- Math::Matrix m_textureMat;
//! The current material
Material m_material;
@@ -245,6 +259,11 @@ private:
int vertexCount;
};
+ //! Detected capabilities
+ //! OpenGL version
+ int m_glMajor, m_glMinor;
+ //! Depth texture support
+ ShadowMappingSupport m_shadowMappingSupport;
//! Whether to use multitexturing
bool m_multitextureAvailable;
//! Whether to use VBOs or display lists
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/colobot.git
More information about the Pkg-games-commits
mailing list