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 <tomaszka...@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 _______________________________________________ Pkg-games-commits mailing list Pkg-games-commits@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-games-commits