From 6b7e6cbc7541f8bcaa91ff69a7ad953c078d7e8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Kapu=C5=9Bci=C5=84ski?= Date: Sat, 13 Feb 2016 03:54:49 +0100 Subject: [PATCH] Added rendering modes and implemented additional OpenGL 2.1 shaders --- src/graphics/core/device.h | 14 + src/graphics/core/nulldevice.cpp | 4 + src/graphics/core/nulldevice.h | 2 + src/graphics/engine/engine.cpp | 36 +- src/graphics/opengl/gl21device.cpp | 379 +++++++++++++----- src/graphics/opengl/gl21device.h | 148 +++---- src/graphics/opengl/gl33device.cpp | 5 + src/graphics/opengl/gl33device.h | 2 + src/graphics/opengl/gldevice.cpp | 5 + src/graphics/opengl/gldevice.h | 2 + .../shaders/fragment_shader_21_interface.glsl | 39 ++ .../shaders/fragment_shader_21_shadow.glsl | 47 +++ .../shaders/vertex_shader_21_interface.glsl | 35 ++ .../shaders/vertex_shader_21_shadow.glsl | 33 ++ 14 files changed, 571 insertions(+), 180 deletions(-) create mode 100644 src/graphics/opengl/shaders/fragment_shader_21_interface.glsl create mode 100644 src/graphics/opengl/shaders/fragment_shader_21_shadow.glsl create mode 100644 src/graphics/opengl/shaders/vertex_shader_21_interface.glsl create mode 100644 src/graphics/opengl/shaders/vertex_shader_21_shadow.glsl diff --git a/src/graphics/core/device.h b/src/graphics/core/device.h index f0dde198..7d5a9fc0 100644 --- a/src/graphics/core/device.h +++ b/src/graphics/core/device.h @@ -130,6 +130,17 @@ enum RenderState RENDER_STATE_DEPTH_BIAS, }; +/** +* \enum RenderMode +* \brief Render modes the graphics device can be in +*/ +enum RenderMode +{ + RENDER_MODE_NORMAL, + RENDER_MODE_INTERFACE, + RENDER_MODE_SHADOW, +}; + /** * \enum CompFunc * \brief Type of function used to compare values @@ -310,6 +321,9 @@ public: //! Clears the screen to blank virtual void Clear() = 0; + //! Sets current rendering mode + virtual void SetRenderMode(RenderMode mode) = 0; + //! Sets the transform matrix of given type virtual void SetTransform(TransformType type, const Math::Matrix &matrix) = 0; diff --git a/src/graphics/core/nulldevice.cpp b/src/graphics/core/nulldevice.cpp index 64302b83..d9ba06ab 100644 --- a/src/graphics/core/nulldevice.cpp +++ b/src/graphics/core/nulldevice.cpp @@ -69,6 +69,10 @@ void CNullDevice::Clear() { } +void CNullDevice::SetRenderMode(RenderMode mode) +{ +} + void CNullDevice::SetTransform(TransformType type, const Math::Matrix &matrix) { } diff --git a/src/graphics/core/nulldevice.h b/src/graphics/core/nulldevice.h index 214545cf..edef460c 100644 --- a/src/graphics/core/nulldevice.h +++ b/src/graphics/core/nulldevice.h @@ -59,6 +59,8 @@ public: void Clear() override; + void SetRenderMode(RenderMode mode) override; + void SetTransform(TransformType type, const Math::Matrix &matrix) override; void SetMaterial(const Material &material) override; diff --git a/src/graphics/engine/engine.cpp b/src/graphics/engine/engine.cpp index 68f7645e..5d116277 100644 --- a/src/graphics/engine/engine.cpp +++ b/src/graphics/engine/engine.cpp @@ -2038,7 +2038,8 @@ void CEngine::SetState(int state, const Color& color) } else if (state & ENG_RSTATE_ALPHA) // image with alpha channel? { - m_device->SetRenderState(RENDER_STATE_BLENDING, false); + m_device->SetRenderState(RENDER_STATE_BLENDING, true); + m_device->SetBlendFunc(BLEND_SRC_ALPHA, BLEND_INV_SRC_ALPHA); m_device->SetRenderState(RENDER_STATE_FOG, true); m_device->SetRenderState(RENDER_STATE_DEPTH_WRITE, true); @@ -3113,6 +3114,8 @@ void CEngine::Render() UseMSAA(true); DrawBackground(); // draws the background + + if (m_drawWorld) Draw3DScene(); @@ -3367,6 +3370,7 @@ void CEngine::Draw3DScene() void CEngine::RenderShadowMap() { + m_shadowMapping = m_shadowMapping && m_device->IsShadowMappingSupported(); m_offscreenShadowRendering = m_offscreenShadowRendering && m_device->IsFramebufferSupported(); m_offscreenShadowRenderingResolution = Math::Min(m_offscreenShadowRenderingResolution, m_device->GetMaxTextureSize()); @@ -3387,7 +3391,7 @@ void CEngine::RenderShadowMap() FramebufferParams params; params.width = params.height = width; - params.depth = depth = 32; + params.depth = depth = 16; params.depthTexture = true; CFramebuffer *framebuffer = m_device->CreateFramebuffer("shadow", params); @@ -3427,6 +3431,7 @@ void CEngine::RenderShadowMap() m_device->GetFramebuffer("shadow")->Bind(); } + m_device->SetRenderMode(RENDER_MODE_SHADOW); m_device->Clear(); // change state to rendering shadow maps @@ -3441,7 +3446,7 @@ void CEngine::RenderShadowMap() m_device->SetRenderState(RENDER_STATE_DEPTH_BIAS, false); m_device->SetAlphaTestFunc(COMP_FUNC_GREATER, 0.5f); m_device->SetRenderState(RENDER_STATE_DEPTH_BIAS, true); - m_device->SetDepthBias(1.5f, 8.0f); + m_device->SetDepthBias(2.0f, 8.0f); m_device->SetViewport(0, 0, m_shadowMap.size.x, m_shadowMap.size.y); @@ -3543,6 +3548,7 @@ void CEngine::RenderShadowMap() m_app->StopPerformanceCounter(PCNT_RENDER_SHADOW_MAP); + m_device->SetRenderMode(RENDER_MODE_NORMAL); m_device->SetRenderState(RENDER_STATE_DEPTH_TEST, false); } @@ -3776,6 +3782,8 @@ void CEngine::DrawObject(const EngineBaseObjDataTier& p4) void CEngine::DrawInterface() { + m_device->SetRenderMode(RENDER_MODE_INTERFACE); + m_device->SetRenderState(RENDER_STATE_DEPTH_TEST, false); m_device->SetRenderState(RENDER_STATE_LIGHTING, false); m_device->SetRenderState(RENDER_STATE_FOG, false); @@ -3808,6 +3816,8 @@ void CEngine::DrawInterface() // 3D objects drawn in front of interface if (m_drawFront) { + m_device->SetRenderMode(RENDER_MODE_NORMAL); + // Display the objects m_device->SetRenderState(RENDER_STATE_DEPTH_TEST, true); @@ -3877,6 +3887,8 @@ void CEngine::DrawInterface() m_device->SetRenderState(RENDER_STATE_LIGHTING, false); m_device->SetRenderState(RENDER_STATE_FOG, false); + m_device->SetRenderMode(RENDER_MODE_INTERFACE); + m_device->SetTransform(TRANSFORM_VIEW, m_matViewInterface); m_device->SetTransform(TRANSFORM_PROJECTION, m_matProjInterface); m_device->SetTransform(TRANSFORM_WORLD, m_matWorldInterface); @@ -3893,6 +3905,8 @@ void CEngine::DrawInterface() DrawStats(); if (m_renderInterface) DrawMouse(); + + m_device->SetRenderMode(RENDER_MODE_NORMAL); } void CEngine::UpdateGroundSpotTextures() @@ -4366,6 +4380,8 @@ void CEngine::DrawShadowSpots() void CEngine::DrawBackground() { + m_device->SetRenderMode(RENDER_MODE_INTERFACE); + if (m_cloud->GetLevel() != 0.0f) // clouds ? { if (m_backgroundCloudUp != m_backgroundCloudDown) // degraded? @@ -4381,6 +4397,8 @@ void CEngine::DrawBackground() { DrawBackgroundImage(); // image } + + m_device->SetRenderMode(RENDER_MODE_NORMAL); } void CEngine::DrawBackgroundGradient(const Color& up, const Color& down) @@ -4502,6 +4520,8 @@ void CEngine::DrawPlanet() if (! m_planet->PlanetExist()) return; + m_device->SetRenderMode(RENDER_MODE_INTERFACE); + m_device->SetRenderState(RENDER_STATE_DEPTH_WRITE, false); m_device->SetRenderState(RENDER_STATE_LIGHTING, false); m_device->SetRenderState(RENDER_STATE_FOG, false); @@ -4511,6 +4531,8 @@ void CEngine::DrawPlanet() m_device->SetTransform(TRANSFORM_WORLD, m_matWorldInterface); m_planet->Draw(); // draws the planets + + m_device->SetRenderMode(RENDER_MODE_NORMAL); } void CEngine::DrawForegroundImage() @@ -4541,12 +4563,16 @@ void CEngine::DrawForegroundImage() SetTexture(m_foregroundTex); SetState(ENG_RSTATE_CLAMP | ENG_RSTATE_TTEXTURE_BLACK); + m_device->SetRenderMode(RENDER_MODE_INTERFACE); + m_device->SetTransform(TRANSFORM_VIEW, m_matViewInterface); m_device->SetTransform(TRANSFORM_PROJECTION, m_matProjInterface); m_device->SetTransform(TRANSFORM_WORLD, m_matWorldInterface); m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, 4); AddStatisticTriangle(2); + + m_device->SetRenderMode(RENDER_MODE_NORMAL); } void CEngine::DrawOverColor() @@ -4565,6 +4591,8 @@ void CEngine::DrawOverColor() Color(0.0f, 0.0f, 0.0f, 0.0f) }; + m_device->SetRenderMode(RENDER_MODE_INTERFACE); + SetState(m_overMode); m_device->SetTransform(TRANSFORM_VIEW, m_matViewInterface); @@ -4582,6 +4610,8 @@ void CEngine::DrawOverColor() m_device->DrawPrimitive(PRIMITIVE_TRIANGLE_STRIP, vertex, 4); AddStatisticTriangle(2); + + m_device->SetRenderMode(RENDER_MODE_NORMAL); } void CEngine::DrawHighlight() diff --git a/src/graphics/opengl/gl21device.cpp b/src/graphics/opengl/gl21device.cpp index 0cebf824..561a9516 100644 --- a/src/graphics/opengl/gl21device.cpp +++ b/src/graphics/opengl/gl21device.cpp @@ -251,21 +251,24 @@ bool CGL21Device::Create() m_perPixelLighting = value > 0; } + char shading[16]; + if (m_perPixelLighting) + { GetLogger()->Info("Using per-pixel lighting\n"); + strcpy(shading, "perpixel"); + } else + { GetLogger()->Info("Using per-vertex lighting\n"); + strcpy(shading, "pervertex"); + } - - // Create normal shader program + // Create shader program for normal rendering GLint shaders[2]; char filename[128]; - if (m_perPixelLighting) - sprintf(filename, "shaders/vertex_shader_21_perpixel.glsl"); - else - sprintf(filename, "shaders/vertex_shader_21_pervertex.glsl"); - + sprintf(filename, "shaders/vertex_shader_21_%s.glsl", shading); shaders[0] = LoadShader(GL_VERTEX_SHADER, filename); if (shaders[0] == 0) { @@ -273,114 +276,242 @@ bool CGL21Device::Create() return false; } - if (m_perPixelLighting) - sprintf(filename, "shaders/fragment_shader_21_perpixel.glsl"); - else - sprintf(filename, "shaders/fragment_shader_21_pervertex.glsl"); - + sprintf(filename, "shaders/fragment_shader_21_%s.glsl", shading); shaders[1] = LoadShader(GL_FRAGMENT_SHADER, filename); if (shaders[1] == 0) { m_errorMessage = GetLastShaderError(); + GetLogger()->Error("Count not create vertex shader from file '%s'\n", filename); return false; } - m_program = LinkProgram(2, shaders); - if (m_program == 0) + m_normalProgram = LinkProgram(2, shaders); + if (m_normalProgram == 0) { m_errorMessage = GetLastShaderError(); + GetLogger()->Error("Count not link shader program for normal rendering\n"); return false; } glDeleteShader(shaders[0]); glDeleteShader(shaders[1]); - // Obtain uniform locations - uni_ProjectionMatrix = glGetUniformLocation(m_program, "uni_ProjectionMatrix"); - uni_ViewMatrix = glGetUniformLocation(m_program, "uni_ViewMatrix"); - uni_ModelMatrix = glGetUniformLocation(m_program, "uni_ModelMatrix"); - uni_NormalMatrix = glGetUniformLocation(m_program, "uni_NormalMatrix"); - uni_ShadowMatrix = glGetUniformLocation(m_program, "uni_ShadowMatrix"); - - uni_PrimaryTexture = glGetUniformLocation(m_program, "uni_PrimaryTexture"); - uni_SecondaryTexture = glGetUniformLocation(m_program, "uni_SecondaryTexture"); - uni_ShadowTexture = glGetUniformLocation(m_program, "uni_ShadowTexture"); - - for (int i = 0; i < 3; i++) + // Create shader program for interface rendering + strcpy(filename, "shaders/vertex_shader_21_interface.glsl"); + shaders[0] = LoadShader(GL_VERTEX_SHADER, filename); + if (shaders[0] == 0) { - char name[64]; - sprintf(name, "uni_TextureEnabled[%d]", i); - uni_TextureEnabled[i] = glGetUniformLocation(m_program, name); + m_errorMessage = GetLastShaderError(); + GetLogger()->Error("Count not create vertex shader from file '%s'\n", filename); + return false; } - uni_AlphaTestEnabled = glGetUniformLocation(m_program, "uni_AlphaTestEnabled"); - uni_AlphaReference = glGetUniformLocation(m_program, "uni_AlphaReference"); - - uni_FogEnabled = glGetUniformLocation(m_program, "uni_FogEnabled"); - uni_FogRange = glGetUniformLocation(m_program, "uni_FogRange"); - uni_FogColor = glGetUniformLocation(m_program, "uni_FogColor"); - - uni_ShadowColor = glGetUniformLocation(m_program, "uni_ShadowColor"); - uni_LightingEnabled = glGetUniformLocation(m_program, "uni_LightingEnabled"); - - uni_AmbientColor = glGetUniformLocation(m_program, "uni_AmbientColor"); - uni_DiffuseColor = glGetUniformLocation(m_program, "uni_DiffuseColor"); - uni_SpecularColor = glGetUniformLocation(m_program, "uni_SpecularColor"); - - GLchar name[64]; - for (int i = 0; i < 8; i++) + strcpy(filename, "shaders/fragment_shader_21_interface.glsl"); + shaders[1] = LoadShader(GL_FRAGMENT_SHADER, filename); + if (shaders[1] == 0) { - sprintf(name, "uni_Light[%d].Enabled", i); - uni_Light[i].Enabled = glGetUniformLocation(m_program, name); - - sprintf(name, "uni_Light[%d].Position", i); - uni_Light[i].Position = glGetUniformLocation(m_program, name); - - sprintf(name, "uni_Light[%d].Ambient", i); - uni_Light[i].Ambient = glGetUniformLocation(m_program, name); - - sprintf(name, "uni_Light[%d].Diffuse", i); - uni_Light[i].Diffuse = glGetUniformLocation(m_program, name); - - sprintf(name, "uni_Light[%d].Specular", i); - uni_Light[i].Specular = glGetUniformLocation(m_program, name); - - sprintf(name, "uni_Light[%d].Attenuation", i); - uni_Light[i].Attenuation = glGetUniformLocation(m_program, name); + m_errorMessage = GetLastShaderError(); + GetLogger()->Error("Count not compile fragment shader from file '%s'\n", filename); + return false; } - // Set default uniform values - Math::Matrix matrix; - matrix.LoadIdentity(); + m_interfaceProgram = LinkProgram(2, shaders); + if (m_interfaceProgram == 0) + { + m_errorMessage = GetLastShaderError(); + GetLogger()->Error("Count not link shader program for interface rendering\n"); + return false; + } - glUseProgram(m_program); + glDeleteShader(shaders[0]); + glDeleteShader(shaders[1]); - glUniformMatrix4fv(uni_ProjectionMatrix, 1, GL_FALSE, matrix.Array()); - glUniformMatrix4fv(uni_ViewMatrix, 1, GL_FALSE, matrix.Array()); - glUniformMatrix4fv(uni_ModelMatrix, 1, GL_FALSE, matrix.Array()); - glUniformMatrix4fv(uni_NormalMatrix, 1, GL_FALSE, matrix.Array()); - glUniformMatrix4fv(uni_ShadowMatrix, 1, GL_FALSE, matrix.Array()); + // Create shader program for shadow rendering + strcpy(filename, "shaders/vertex_shader_21_shadow.glsl"); + shaders[0] = LoadShader(GL_VERTEX_SHADER, filename); + if (shaders[0] == 0) + { + m_errorMessage = GetLastShaderError(); + GetLogger()->Error("Count not create vertex shader from file '%s'\n", filename); + return false; + } - glUniform1i(uni_PrimaryTexture, 0); - glUniform1i(uni_SecondaryTexture, 1); - glUniform1i(uni_ShadowTexture, 2); + strcpy(filename, "shaders/fragment_shader_21_shadow.glsl"); + shaders[1] = LoadShader(GL_FRAGMENT_SHADER, filename); + if (shaders[1] == 0) + { + m_errorMessage = GetLastShaderError(); + GetLogger()->Error("Count not compile fragment shader from file '%s'\n", filename); + return false; + } - for (int i = 0; i < 3; i++) - glUniform1i(uni_TextureEnabled[i], 0); + m_shadowProgram = LinkProgram(2, shaders); + if (m_shadowProgram == 0) + { + m_errorMessage = GetLastShaderError(); + GetLogger()->Error("Count not link shader program for shadow rendering\n"); + return false; + } - glUniform1i(uni_AlphaTestEnabled, 0); - glUniform1f(uni_AlphaReference, 0.5f); + glDeleteShader(shaders[0]); + glDeleteShader(shaders[1]); - glUniform1i(uni_FogEnabled, 0); - glUniform2f(uni_FogRange, 100.0f, 200.0f); - glUniform4f(uni_FogColor, 0.8f, 0.8f, 0.8f, 1.0f); + // Obtain uniform locations from normal rendering program and initialize them + { + UniformLocations &uni = m_uniforms[0]; - glUniform1f(uni_ShadowColor, 0.5f); + uni.projectionMatrix = glGetUniformLocation(m_normalProgram, "uni_ProjectionMatrix"); + uni.viewMatrix = glGetUniformLocation(m_normalProgram, "uni_ViewMatrix"); + uni.modelMatrix = glGetUniformLocation(m_normalProgram, "uni_ModelMatrix"); + uni.normalMatrix = glGetUniformLocation(m_normalProgram, "uni_NormalMatrix"); + uni.shadowMatrix = glGetUniformLocation(m_normalProgram, "uni_ShadowMatrix"); - glUniform1i(uni_LightingEnabled, 0); - for (int i = 0; i < 8; i++) - glUniform1i(uni_Light[i].Enabled, 0); + uni.primaryTexture = glGetUniformLocation(m_normalProgram, "uni_PrimaryTexture"); + uni.secondaryTexture = glGetUniformLocation(m_normalProgram, "uni_SecondaryTexture"); + uni.shadowTexture = glGetUniformLocation(m_normalProgram, "uni_ShadowTexture"); + for (int i = 0; i < 3; i++) + { + char name[64]; + sprintf(name, "uni_TextureEnabled[%d]", i); + uni.textureEnabled[i] = glGetUniformLocation(m_normalProgram, name); + } + + uni.alphaTestEnabled = glGetUniformLocation(m_normalProgram, "uni_AlphaTestEnabled"); + uni.alphaReference = glGetUniformLocation(m_normalProgram, "uni_AlphaReference"); + + uni.fogEnabled = glGetUniformLocation(m_normalProgram, "uni_FogEnabled"); + uni.fogRange = glGetUniformLocation(m_normalProgram, "uni_FogRange"); + uni.fogColor = glGetUniformLocation(m_normalProgram, "uni_FogColor"); + + uni.shadowColor = glGetUniformLocation(m_normalProgram, "uni_ShadowColor"); + uni.lightingEnabled = glGetUniformLocation(m_normalProgram, "uni_LightingEnabled"); + + uni.ambientColor = glGetUniformLocation(m_normalProgram, "uni_AmbientColor"); + uni.diffuseColor = glGetUniformLocation(m_normalProgram, "uni_DiffuseColor"); + uni.specularColor = glGetUniformLocation(m_normalProgram, "uni_SpecularColor"); + + GLchar name[64]; + for (int i = 0; i < 8; i++) + { + sprintf(name, "uni_Light[%d].Enabled", i); + uni.lights[i].enabled = glGetUniformLocation(m_normalProgram, name); + + sprintf(name, "uni_Light[%d].Position", i); + uni.lights[i].position = glGetUniformLocation(m_normalProgram, name); + + sprintf(name, "uni_Light[%d].Ambient", i); + uni.lights[i].ambient = glGetUniformLocation(m_normalProgram, name); + + sprintf(name, "uni_Light[%d].Diffuse", i); + uni.lights[i].diffuse = glGetUniformLocation(m_normalProgram, name); + + sprintf(name, "uni_Light[%d].Specular", i); + uni.lights[i].specular = glGetUniformLocation(m_normalProgram, name); + + sprintf(name, "uni_Light[%d].Attenuation", i); + uni.lights[i].attenuation = glGetUniformLocation(m_normalProgram, name); + } + + // Set default uniform values + Math::Matrix matrix; + matrix.LoadIdentity(); + + glUseProgram(m_normalProgram); + + glUniformMatrix4fv(uni.projectionMatrix, 1, GL_FALSE, matrix.Array()); + glUniformMatrix4fv(uni.viewMatrix, 1, GL_FALSE, matrix.Array()); + glUniformMatrix4fv(uni.modelMatrix, 1, GL_FALSE, matrix.Array()); + glUniformMatrix4fv(uni.normalMatrix, 1, GL_FALSE, matrix.Array()); + glUniformMatrix4fv(uni.shadowMatrix, 1, GL_FALSE, matrix.Array()); + + glUniform1i(uni.primaryTexture, 0); + glUniform1i(uni.secondaryTexture, 1); + glUniform1i(uni.shadowTexture, 2); + + for (int i = 0; i < 3; i++) + glUniform1i(uni.textureEnabled[i], 0); + + glUniform1i(uni.alphaTestEnabled, 0); + glUniform1f(uni.alphaReference, 0.5f); + + glUniform1i(uni.fogEnabled, 0); + glUniform2f(uni.fogRange, 100.0f, 200.0f); + glUniform4f(uni.fogColor, 0.8f, 0.8f, 0.8f, 1.0f); + + glUniform1f(uni.shadowColor, 0.5f); + + glUniform1i(uni.lightingEnabled, 0); + + for (int i = 0; i < 8; i++) + glUniform1i(uni.lights[i].enabled, 0); + } + + // Obtain uniform locations from interface rendering program and initialize them + { + UniformLocations &uni = m_uniforms[1]; + + uni.projectionMatrix = glGetUniformLocation(m_interfaceProgram, "uni_ProjectionMatrix"); + uni.viewMatrix = glGetUniformLocation(m_interfaceProgram, "uni_ViewMatrix"); + uni.modelMatrix = glGetUniformLocation(m_interfaceProgram, "uni_ModelMatrix"); + + uni.primaryTexture = glGetUniformLocation(m_interfaceProgram, "uni_PrimaryTexture"); + + uni.textureEnabled[0] = glGetUniformLocation(m_interfaceProgram, "uni_TextureEnabled"); + uni.textureEnabled[1] = -1; + uni.textureEnabled[2] = -1; + + // Set default uniform values + Math::Matrix matrix; + matrix.LoadIdentity(); + + glUseProgram(m_interfaceProgram); + + glUniformMatrix4fv(uni.projectionMatrix, 1, GL_FALSE, matrix.Array()); + glUniformMatrix4fv(uni.viewMatrix, 1, GL_FALSE, matrix.Array()); + glUniformMatrix4fv(uni.modelMatrix, 1, GL_FALSE, matrix.Array()); + + glUniform1i(uni.primaryTexture, 0); + + glUniform1i(uni.textureEnabled[0], 0); + } + + // Obtain uniform locations from shadow rendering program and initialize them + { + UniformLocations &uni = m_uniforms[2]; + + uni.projectionMatrix = glGetUniformLocation(m_shadowProgram, "uni_ProjectionMatrix"); + uni.viewMatrix = glGetUniformLocation(m_shadowProgram, "uni_ViewMatrix"); + uni.modelMatrix = glGetUniformLocation(m_shadowProgram, "uni_ModelMatrix"); + + uni.primaryTexture = glGetUniformLocation(m_shadowProgram, "uni_PrimaryTexture"); + + uni.textureEnabled[0] = glGetUniformLocation(m_shadowProgram, "uni_TextureEnabled"); + uni.textureEnabled[1] = -1; + uni.textureEnabled[2] = -1; + + uni.alphaTestEnabled = glGetUniformLocation(m_shadowProgram, "uni_AlphaTestEnabled"); + uni.alphaReference = glGetUniformLocation(m_shadowProgram, "uni_AlphaReference"); + + // Set default uniform values + Math::Matrix matrix; + matrix.LoadIdentity(); + + glUseProgram(m_shadowProgram); + + glUniformMatrix4fv(uni.projectionMatrix, 1, GL_FALSE, matrix.Array()); + glUniformMatrix4fv(uni.viewMatrix, 1, GL_FALSE, matrix.Array()); + glUniformMatrix4fv(uni.modelMatrix, 1, GL_FALSE, matrix.Array()); + + glUniform1i(uni.primaryTexture, 0); + + glUniform1i(uni.textureEnabled[0], 0); + + glUniform1i(uni.alphaTestEnabled, 0); + glUniform1f(uni.alphaReference, 0.5f); + } + + glUseProgram(m_normalProgram); glEnable(GL_VERTEX_PROGRAM_TWO_SIDE); // create default framebuffer object @@ -402,7 +533,9 @@ void CGL21Device::Destroy() // Delete the remaining textures // Should not be strictly necessary, but just in case glUseProgram(0); - glDeleteProgram(m_program); + glDeleteProgram(m_normalProgram); + glDeleteProgram(m_interfaceProgram); + glDeleteProgram(m_shadowProgram); // delete framebuffers for (auto& framebuffer : m_framebuffers) @@ -454,13 +587,39 @@ void CGL21Device::Clear() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } +void CGL21Device::SetRenderMode(RenderMode mode) +{ + switch (mode) + { + case RENDER_MODE_NORMAL: + glUseProgram(m_normalProgram); + m_mode = 0; + break; + case RENDER_MODE_INTERFACE: + glUseProgram(m_interfaceProgram); + m_mode = 1; + break; + case RENDER_MODE_SHADOW: + glUseProgram(m_shadowProgram); + m_mode = 2; + break; + default: + assert(false); + } + + for (int i = 0; i < 3; i++) + { + glUniform1i(m_uniforms[m_mode].textureEnabled[i], m_texturesEnabled[i]); + } +} + void CGL21Device::SetTransform(TransformType type, const Math::Matrix &matrix) { if (type == TRANSFORM_WORLD) { m_worldMat = matrix; - glUniformMatrix4fv(uni_ModelMatrix, 1, GL_FALSE, m_worldMat.Array()); + glUniformMatrix4fv(m_uniforms[m_mode].modelMatrix, 1, GL_FALSE, m_worldMat.Array()); m_modelviewMat = Math::MultiplyMatrices(m_viewMat, m_worldMat); m_combinedMatrix = Math::MultiplyMatrices(m_projectionMat, m_modelviewMat); @@ -471,7 +630,7 @@ void CGL21Device::SetTransform(TransformType type, const Math::Matrix &matrix) if (fabs(normalMat.Det()) > 1e-6) normalMat = normalMat.Inverse(); - glUniformMatrix4fv(uni_NormalMatrix, 1, GL_TRUE, normalMat.Array()); + glUniformMatrix4fv(m_uniforms[m_mode].normalMatrix, 1, GL_TRUE, normalMat.Array()); } else if (type == TRANSFORM_VIEW) { @@ -482,7 +641,7 @@ void CGL21Device::SetTransform(TransformType type, const Math::Matrix &matrix) m_modelviewMat = Math::MultiplyMatrices(m_viewMat, m_worldMat); m_combinedMatrix = Math::MultiplyMatrices(m_projectionMat, m_modelviewMat); - glUniformMatrix4fv(uni_ViewMatrix, 1, GL_FALSE, m_viewMat.Array()); + glUniformMatrix4fv(m_uniforms[m_mode].viewMatrix, 1, GL_FALSE, m_viewMat.Array()); } else if (type == TRANSFORM_PROJECTION) { @@ -490,12 +649,12 @@ void CGL21Device::SetTransform(TransformType type, const Math::Matrix &matrix) m_combinedMatrix = Math::MultiplyMatrices(m_projectionMat, m_modelviewMat); - glUniformMatrix4fv(uni_ProjectionMatrix, 1, GL_FALSE, m_projectionMat.Array()); + glUniformMatrix4fv(m_uniforms[m_mode].projectionMatrix, 1, GL_FALSE, m_projectionMat.Array()); } else if (type == TRANSFORM_SHADOW) { Math::Matrix temp = matrix; - glUniformMatrix4fv(uni_ShadowMatrix, 1, GL_FALSE, temp.Array()); + glUniformMatrix4fv(m_uniforms[m_mode].shadowMatrix, 1, GL_FALSE, temp.Array()); } else { @@ -507,9 +666,9 @@ void CGL21Device::SetMaterial(const Material &material) { m_material = material; - glUniform4fv(uni_AmbientColor, 1, m_material.ambient.Array()); - glUniform4fv(uni_DiffuseColor, 1, m_material.diffuse.Array()); - glUniform4fv(uni_SpecularColor, 1, m_material.specular.Array()); + glUniform4fv(m_uniforms[m_mode].ambientColor, 1, m_material.ambient.Array()); + glUniform4fv(m_uniforms[m_mode].diffuseColor, 1, m_material.diffuse.Array()); + glUniform4fv(m_uniforms[m_mode].specularColor, 1, m_material.specular.Array()); } int CGL21Device::GetMaxLightCount() @@ -524,18 +683,20 @@ void CGL21Device::SetLight(int index, const Light &light) m_lights[index] = light; - glUniform4fv(uni_Light[index].Ambient, 1, light.ambient.Array()); - glUniform4fv(uni_Light[index].Diffuse, 1, light.diffuse.Array()); - glUniform4fv(uni_Light[index].Specular, 1, light.specular.Array()); - glUniform3f(uni_Light[index].Attenuation, light.attenuation0, light.attenuation1, light.attenuation2); + UniformLocations::LightLocations &loc = m_uniforms[m_mode].lights[index]; + + glUniform4fv(loc.ambient, 1, light.ambient.Array()); + glUniform4fv(loc.diffuse, 1, light.diffuse.Array()); + glUniform4fv(loc.specular, 1, light.specular.Array()); + glUniform3f(loc.attenuation, light.attenuation0, light.attenuation1, light.attenuation2); if (light.type == LIGHT_DIRECTIONAL) { - glUniform4f(uni_Light[index].Position, -light.direction.x, -light.direction.y, -light.direction.z, 0.0f); + glUniform4f(loc.position, -light.direction.x, -light.direction.y, -light.direction.z, 0.0f); } else { - glUniform4f(uni_Light[index].Position, light.position.x, light.position.y, light.position.z, 1.0f); + glUniform4f(loc.position, light.position.x, light.position.y, light.position.z, 1.0f); } // TODO: add spotlight params @@ -548,7 +709,7 @@ void CGL21Device::SetLightEnabled(int index, bool enabled) m_lightsEnabled[index] = enabled; - glUniform1i(uni_Light[index].Enabled, enabled ? 1 : 0); + glUniform1i(m_uniforms[m_mode].lights[index].enabled, enabled ? 1 : 0); } /** If image is invalid, returns invalid texture. @@ -899,7 +1060,7 @@ void CGL21Device::UpdateTextureStatus() for (int i = 0; i < 3; i++) { bool enabled = m_texturesEnabled[i] && (m_currentTextures[i].id != 0); - glUniform1i(uni_TextureEnabled[i], enabled ? 1 : 0); + glUniform1i(m_uniforms[m_mode].textureEnabled[i], enabled ? 1 : 0); } } @@ -1639,19 +1800,19 @@ void CGL21Device::SetRenderState(RenderState state, bool enabled) { m_lighting = enabled; - glUniform1i(uni_LightingEnabled, enabled ? 1 : 0); + glUniform1i(m_uniforms[m_mode].lightingEnabled, enabled ? 1 : 0); return; } else if (state == RENDER_STATE_ALPHA_TEST) { - glUniform1i(uni_AlphaTestEnabled, enabled ? 1 : 0); + glUniform1i(m_uniforms[m_mode].alphaTestEnabled, enabled ? 1 : 0); return; } else if (state == RENDER_STATE_FOG) { - glUniform1i(uni_FogEnabled, enabled ? 1 : 0); + glUniform1i(m_uniforms[m_mode].fogEnabled, enabled ? 1 : 0); return; } @@ -1691,7 +1852,7 @@ void CGL21Device::SetDepthBias(float factor, float units) void CGL21Device::SetAlphaTestFunc(CompFunc func, float refValue) { - glUniform1i(uni_AlphaReference, refValue); + glUniform1i(m_uniforms[m_mode].alphaReference, refValue); } void CGL21Device::SetBlendFunc(BlendFunc srcBlend, BlendFunc dstBlend) @@ -1711,8 +1872,8 @@ void CGL21Device::SetGlobalAmbient(const Color &color) void CGL21Device::SetFogParams(FogMode mode, const Color &color, float start, float end, float density) { - glUniform2f(uni_FogRange, start, end); - glUniform4f(uni_FogColor, color.r, color.g, color.b, color.a); + glUniform2f(m_uniforms[m_mode].fogRange, start, end); + glUniform4f(m_uniforms[m_mode].fogColor, color.r, color.g, color.b, color.a); /* if (mode == FOG_LINEAR) glFogi(GL_FOG_MODE, GL_LINEAR); @@ -1745,7 +1906,7 @@ void CGL21Device::SetShadeModel(ShadeModel model) void CGL21Device::SetShadowColor(float value) { - glUniform1f(uni_ShadowColor, value); + glUniform1f(m_uniforms[m_mode].shadowColor, value); } void CGL21Device::SetFillMode(FillMode mode) diff --git a/src/graphics/opengl/gl21device.h b/src/graphics/opengl/gl21device.h index a0b5f499..a93eef34 100644 --- a/src/graphics/opengl/gl21device.h +++ b/src/graphics/opengl/gl21device.h @@ -42,6 +42,74 @@ namespace Gfx { +struct UniformLocations +{ + // Uniforms + //! Projection matrix + GLint projectionMatrix = -1; + //! View matrix + GLint viewMatrix = -1; + //! Model matrix + GLint modelMatrix = -1; + //! Shadow matrix + GLint shadowMatrix = -1; + //! Normal matrix + GLint normalMatrix = -1; + + //! Primary texture sampler + GLint primaryTexture = -1; + //! Secondary texture sampler + GLint secondaryTexture = -1; + //! Shadow texture sampler + GLint shadowTexture = -1; + + //! true enables texture + GLint textureEnabled[3] = {}; + + // Alpha test parameters + //! true enables alpha test + GLint alphaTestEnabled = -1; + //! Alpha test reference value + GLint alphaReference = -1; + + //! true enables fog + GLint fogEnabled = -1; + //! Fog range + GLint fogRange = -1; + //! Fog color + GLint fogColor = -1; + + //! Shadow color + GLint shadowColor = -1; + + //! true enables lighting + GLint lightingEnabled = -1; + //! Ambient color + GLint ambientColor = -1; + //! Diffuse color + GLint diffuseColor = -1; + //! Specular color + GLint specularColor = -1; + + struct LightLocations + { + //! true enables light + GLint enabled = -1; + //! Light type + GLint type = -1; + //! Position or direction vector + GLint position = -1; + //! Ambient color + GLint ambient = -1; + //! Diffuse color + GLint diffuse = -1; + //! Specular color + GLint specular = -1; + //! Attenuation + GLint attenuation = -1; + } lights[8]; +}; + /** \class CGL21Device \brief Implementation of CDevice interface in OpenGL @@ -72,6 +140,8 @@ public: void Clear() override; + void SetRenderMode(RenderMode mode) override; + void SetTransform(TransformType type, const Math::Matrix &matrix) override; void SetMaterial(const Material &material) override; @@ -254,75 +324,17 @@ private: //! true enables per-pixel lighting bool m_perPixelLighting = false; - //! Shader program - GLuint m_program = 0; + //! Shader program for normal rendering + GLuint m_normalProgram = 0; + //! Shader program for interface rendering + GLuint m_interfaceProgram = 0; + //! Shader program for shadow rendering + GLuint m_shadowProgram = 0; - // Uniforms - //! Projection matrix - GLint uni_ProjectionMatrix = 0; - //! View matrix - GLint uni_ViewMatrix = 0; - //! Model matrix - GLint uni_ModelMatrix = 0; - //! Shadow matrix - GLint uni_ShadowMatrix = 0; - //! Normal matrix - GLint uni_NormalMatrix = 0; - - //! Primary texture sampler - GLint uni_PrimaryTexture = 0; - //! Secondary texture sampler - GLint uni_SecondaryTexture = 0; - //! Shadow texture sampler - GLint uni_ShadowTexture = 0; - - //! true enables texture - GLint uni_TextureEnabled[3] = {}; - - // Alpha test parameters - //! true enables alpha test - GLint uni_AlphaTestEnabled = 0; - //! Alpha test reference value - GLint uni_AlphaReference = 0; - - //! true enables fog - GLint uni_FogEnabled = 0; - //! Fog range - GLint uni_FogRange = 0; - //! Fog color - GLint uni_FogColor = 0; - - //! Shadow color - GLint uni_ShadowColor = 0; - - //! true enables lighting - GLint uni_LightingEnabled = 0; - //! Ambient color - GLint uni_AmbientColor = 0; - //! Diffuse color - GLint uni_DiffuseColor = 0; - //! Specular color - GLint uni_SpecularColor = 0; - - struct LightUniforms - { - //! true enables light - GLint Enabled = 0; - //! Light type - GLint Type = 0; - //! Position or direction vector - GLint Position = 0; - //! Ambient color - GLint Ambient = 0; - //! Diffuse color - GLint Diffuse = 0; - //! Specular color - GLint Specular = 0; - //! Attenuation - GLint Attenuation = 0; - }; - - LightUniforms uni_Light[8]; + //! Uniform locations + UniformLocations m_uniforms[3]; + //! Current mode + int m_mode = 0; }; diff --git a/src/graphics/opengl/gl33device.cpp b/src/graphics/opengl/gl33device.cpp index 5bcafd27..8f9d9de0 100644 --- a/src/graphics/opengl/gl33device.cpp +++ b/src/graphics/opengl/gl33device.cpp @@ -479,6 +479,11 @@ void CGL33Device::Clear() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } +void CGL33Device::SetRenderMode(RenderMode mode) +{ + // TODO: implement +} + void CGL33Device::SetTransform(TransformType type, const Math::Matrix &matrix) { if (type == TRANSFORM_WORLD) diff --git a/src/graphics/opengl/gl33device.h b/src/graphics/opengl/gl33device.h index 44db526d..32afa422 100644 --- a/src/graphics/opengl/gl33device.h +++ b/src/graphics/opengl/gl33device.h @@ -84,6 +84,8 @@ public: void Clear() override; + void SetRenderMode(RenderMode mode) override; + void SetTransform(TransformType type, const Math::Matrix &matrix) override; void SetMaterial(const Material &material) override; diff --git a/src/graphics/opengl/gldevice.cpp b/src/graphics/opengl/gldevice.cpp index 1df95c67..6162d29b 100644 --- a/src/graphics/opengl/gldevice.cpp +++ b/src/graphics/opengl/gldevice.cpp @@ -386,6 +386,11 @@ void CGLDevice::Clear() glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } +void CGLDevice::SetRenderMode(RenderMode mode) +{ + // nothing is done +} + void CGLDevice::SetTransform(TransformType type, const Math::Matrix &matrix) { if (type == TRANSFORM_WORLD) diff --git a/src/graphics/opengl/gldevice.h b/src/graphics/opengl/gldevice.h index 24df9229..658d697a 100644 --- a/src/graphics/opengl/gldevice.h +++ b/src/graphics/opengl/gldevice.h @@ -91,6 +91,8 @@ public: void Clear() override; + void SetRenderMode(RenderMode mode) override; + void SetTransform(TransformType type, const Math::Matrix &matrix) override; void SetMaterial(const Material &material) override; diff --git a/src/graphics/opengl/shaders/fragment_shader_21_interface.glsl b/src/graphics/opengl/shaders/fragment_shader_21_interface.glsl new file mode 100644 index 00000000..ef15cde3 --- /dev/null +++ b/src/graphics/opengl/shaders/fragment_shader_21_interface.glsl @@ -0,0 +1,39 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ +// FRAGMENT SHADER - INTERFACE MODE +#version 120 + +uniform sampler2D uni_PrimaryTexture; + +uniform bool uni_TextureEnabled; + +varying vec4 pass_Color; +varying vec2 pass_TexCoord0; + +void main() +{ + if (uni_TextureEnabled) + { + gl_FragColor = pass_Color * texture2D(uni_PrimaryTexture, pass_TexCoord0); + } + else + { + gl_FragColor = pass_Color; + } +} diff --git a/src/graphics/opengl/shaders/fragment_shader_21_shadow.glsl b/src/graphics/opengl/shaders/fragment_shader_21_shadow.glsl new file mode 100644 index 00000000..7b35925b --- /dev/null +++ b/src/graphics/opengl/shaders/fragment_shader_21_shadow.glsl @@ -0,0 +1,47 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ +// FRAGMENT SHADER - SHADOW MODE +#version 120 + +uniform sampler2D uni_PrimaryTexture; + +uniform bool uni_TextureEnabled; + +uniform bool uni_AlphaTestEnabled; +uniform float uni_AlphaReference; + +varying vec2 pass_TexCoord0; + +void main() +{ + vec4 color = vec4(1.0f); + + if (uni_TextureEnabled) + { + color = color * texture2D(uni_PrimaryTexture, pass_TexCoord0); + } + + if (uni_AlphaTestEnabled) + { + if(color.a < uni_AlphaReference) + discard; + } + + gl_FragColor = vec4(1.0f); +} diff --git a/src/graphics/opengl/shaders/vertex_shader_21_interface.glsl b/src/graphics/opengl/shaders/vertex_shader_21_interface.glsl new file mode 100644 index 00000000..e4b75c97 --- /dev/null +++ b/src/graphics/opengl/shaders/vertex_shader_21_interface.glsl @@ -0,0 +1,35 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ +// VERTEX SHADER - INTERFACE MODE +#version 120 + +uniform mat4 uni_ProjectionMatrix; +uniform mat4 uni_ViewMatrix; +uniform mat4 uni_ModelMatrix; + +varying vec4 pass_Color; +varying vec2 pass_TexCoord0; + +void main() +{ + gl_Position = uni_ProjectionMatrix * uni_ViewMatrix * uni_ModelMatrix * gl_Vertex; + + pass_Color = gl_Color; + pass_TexCoord0 = gl_MultiTexCoord0.st; +} diff --git a/src/graphics/opengl/shaders/vertex_shader_21_shadow.glsl b/src/graphics/opengl/shaders/vertex_shader_21_shadow.glsl new file mode 100644 index 00000000..c3ed0147 --- /dev/null +++ b/src/graphics/opengl/shaders/vertex_shader_21_shadow.glsl @@ -0,0 +1,33 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2014, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsitec.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ +// VERTEX SHADER - SHADOW MODE +#version 120 + +uniform mat4 uni_ProjectionMatrix; +uniform mat4 uni_ViewMatrix; +uniform mat4 uni_ModelMatrix; + +varying vec2 pass_TexCoord0; + +void main() +{ + gl_Position = uni_ProjectionMatrix * uni_ViewMatrix * uni_ModelMatrix * gl_Vertex; + + pass_TexCoord0 = gl_MultiTexCoord0.st; +}