diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b3ef8c16..1df04d13 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,7 +10,7 @@ if(TOOLS) #add_subdirectory(tools) endif() -add_subdirectory(graphics/opengl/shaders) +add_subdirectory(graphics/opengl33/shaders) # Configure file configure_file(common/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/common/config.h) @@ -147,18 +147,22 @@ add_library(colobotbase STATIC graphics/model/model_triangle.h graphics/model/model_txt.cpp graphics/model/model_txt.h - graphics/opengl/gl33device.cpp - graphics/opengl/gl33device.h - graphics/opengl/gl33renderers.cpp - graphics/opengl/gl33renderers.h - graphics/opengl/gl33objectrenderer.cpp - graphics/opengl/gl33objectrenderer.h - graphics/opengl/gl33particlerenderer.cpp - graphics/opengl/gl33particlerenderer.h - graphics/opengl/glframebuffer.cpp - graphics/opengl/glframebuffer.h - graphics/opengl/glutil.cpp - graphics/opengl/glutil.h + graphics/opengl33/gl33_device.cpp + graphics/opengl33/gl33_device.h + graphics/opengl33/gl33_object_renderer.cpp + graphics/opengl33/gl33_object_renderer.h + graphics/opengl33/gl33_particle_renderer.cpp + graphics/opengl33/gl33_particle_renderer.h + graphics/opengl33/gl33_terrain_renderer.cpp + graphics/opengl33/gl33_terrain_renderer.h + graphics/opengl33/gl33_shadow_renderer.cpp + graphics/opengl33/gl33_shadow_renderer.h + graphics/opengl33/gl33_ui_renderer.cpp + graphics/opengl33/gl33_ui_renderer.h + graphics/opengl33/glframebuffer.cpp + graphics/opengl33/glframebuffer.h + graphics/opengl33/glutil.cpp + graphics/opengl33/glutil.h level/build_type.h level/level_category.cpp level/level_category.h diff --git a/src/app/app.cpp b/src/app/app.cpp index 80ab3e6d..2a14689b 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -37,7 +37,7 @@ #include "common/system/system.h" #include "graphics/engine/engine.h" -#include "graphics/opengl/glutil.h" +#include "graphics/opengl33/glutil.h" #include "level/robotmain.h" diff --git a/src/graphics/opengl/README.txt b/src/graphics/opengl/README.txt deleted file mode 100644 index 1a6bedd8..00000000 --- a/src/graphics/opengl/README.txt +++ /dev/null @@ -1,8 +0,0 @@ -/** - * \dir src/graphics/opengl - * \brief OpenGL engine implementation - * - * Contains the concrete implementation using OpenGL of abstract CDevice class - * from src/graphics/core - */ - diff --git a/src/graphics/opengl/gl33renderers.cpp b/src/graphics/opengl/gl33renderers.cpp deleted file mode 100644 index 44472120..00000000 --- a/src/graphics/opengl/gl33renderers.cpp +++ /dev/null @@ -1,770 +0,0 @@ -#include "graphics/opengl/gl33renderers.h" - -#include "graphics/opengl/gl33device.h" -#include "graphics/opengl/glutil.h" - -#include "graphics/core/material.h" -#include "graphics/core/transparency.h" -#include "graphics/core/vertex.h" - -#include "common/logger.h" - -#include - -#include -#include - -#include - -namespace Gfx -{ - -CGL33UIRenderer::CGL33UIRenderer(CGL33Device* device) - : m_device(device) -{ - GetLogger()->Info("Creating CGL33UIRenderer\n"); - - GLint shaders[2] = {}; - - shaders[0] = LoadShader(GL_VERTEX_SHADER, "shaders/gl33/ui_vs.glsl"); - if (shaders[0] == 0) - { - GetLogger()->Error("Cound not create vertex shader from file 'ui_vs.glsl'\n"); - return; - } - - shaders[1] = LoadShader(GL_FRAGMENT_SHADER, "shaders/gl33/ui_fs.glsl"); - if (shaders[1] == 0) - { - GetLogger()->Error("Cound not create fragment shader from file 'ui_fs.glsl'\n"); - return; - } - - m_program = LinkProgram(2, shaders); - if (m_program == 0) - { - GetLogger()->Error("Cound not link shader program for interface renderer\n"); - return; - } - - glDeleteShader(shaders[0]); - glDeleteShader(shaders[1]); - - glUseProgram(m_program); - - // Create uniform buffer - glGenBuffers(1, &m_uniformBuffer); - - m_uniforms.projectionMatrix = glm::ortho(0.0f, +1.0f, 0.0f, +1.0f); - m_uniforms.color = { 1.0f, 1.0f, 1.0f, 1.0f }; - - m_uniformsDirty = true; - - UpdateUniforms(); - - // Bind uniform block to uniform buffer binding - GLuint blockIndex = glGetUniformBlockIndex(m_program, "Uniforms"); - - glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_uniformBuffer); - glUniformBlockBinding(m_program, blockIndex, 0); - - // Set texture unit to 8th - auto texture = glGetUniformLocation(m_program, "uni_Texture"); - glUniform1i(texture, 8); - - // Generic buffer - glGenBuffers(1, &m_bufferVBO); - glBindBuffer(GL_COPY_WRITE_BUFFER, m_bufferVBO); - glBufferData(GL_COPY_WRITE_BUFFER, m_bufferCapacity * sizeof(Vertex2D), nullptr, GL_STREAM_DRAW); - m_bufferOffset = m_bufferCapacity; - - glGenVertexArrays(1, &m_bufferVAO); - glBindVertexArray(m_bufferVAO); - - // White texture - glActiveTexture(GL_TEXTURE0); - glGenTextures(1, &m_whiteTexture); - glBindTexture(GL_TEXTURE_2D, m_whiteTexture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ONE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ONE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ONE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE); - - glUseProgram(0); - - GetLogger()->Info("CGL33UIRenderer created successfully\n"); -} - -CGL33UIRenderer::~CGL33UIRenderer() -{ - glDeleteProgram(m_program); - glDeleteTextures(1, &m_whiteTexture); - - glDeleteBuffers(1, &m_bufferVBO); - glDeleteVertexArrays(1, &m_bufferVAO); -} - -void CGL33UIRenderer::SetProjection(float left, float right, float bottom, float top) -{ - m_uniforms.projectionMatrix = glm::ortho(left, right, bottom, top); - m_uniformsDirty = true; -} - -void CGL33UIRenderer::SetTexture(const Texture& texture) -{ - if (m_currentTexture == texture.id) return; - - glActiveTexture(GL_TEXTURE8); - - m_currentTexture = texture.id; - - if (m_currentTexture == 0) - glBindTexture(GL_TEXTURE_2D, m_whiteTexture); - else - glBindTexture(GL_TEXTURE_2D, m_currentTexture); -} - -void CGL33UIRenderer::SetColor(const glm::vec4& color) -{ - m_uniforms.color = color; - m_uniformsDirty = true; -} - -void CGL33UIRenderer::SetTransparency(TransparencyMode mode) -{ - m_device->SetTransparency(mode); -} - -void CGL33UIRenderer::DrawPrimitive(PrimitiveType type, int count, const Vertex2D* vertices) -{ - auto ptr = BeginPrimitive(type, count); - - std::copy_n(vertices, count, ptr); - - EndPrimitive(); -} - -Vertex2D* CGL33UIRenderer::BeginPrimitive(PrimitiveType type, int count) -{ - return BeginPrimitives(type, 1, &count); -} - -Vertex2D* CGL33UIRenderer::BeginPrimitives(PrimitiveType type, int drawCount, const int* counts) -{ - glBindVertexArray(m_bufferVAO); - glBindBuffer(GL_ARRAY_BUFFER, m_bufferVBO); - - m_currentCount = 0; - - for (size_t i = 0; i < drawCount; i++) - { - m_currentCount += counts[i]; - } - - GLuint total = m_bufferOffset + m_currentCount; - - // Buffer full, orphan - if (total >= m_bufferCapacity) - { - glBufferData(GL_ARRAY_BUFFER, m_bufferCapacity * sizeof(Vertex2D), nullptr, GL_STREAM_DRAW); - - m_bufferOffset = 0; - - // Respecify vertex attributes - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), - reinterpret_cast(offsetof(Vertex2D, position))); - - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), - reinterpret_cast(offsetof(Vertex2D, uv))); - - glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex2D), - reinterpret_cast(offsetof(Vertex2D, color))); - } - - m_first.resize(drawCount); - m_count.resize(drawCount); - - GLsizei currentOffset = m_bufferOffset; - - for (size_t i = 0; i < drawCount; i++) - { - m_first[i] = currentOffset; - m_count[i] = counts[i]; - - currentOffset += counts[i]; - } - - auto ptr = glMapBufferRange(GL_ARRAY_BUFFER, - m_bufferOffset * sizeof(Vertex2D), - m_currentCount * sizeof(Vertex2D), - GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); - - m_mapped = true; - m_type = type; - m_drawCount = drawCount; - - // Mapping failed, use backup buffer - if (ptr == nullptr) - { - m_backup = true; - m_buffer.resize(m_currentCount); - - return m_buffer.data(); - } - else - { - return reinterpret_cast(ptr); - } -} - -bool CGL33UIRenderer::EndPrimitive() -{ - if (!m_mapped) return false; - - if (m_backup) - { - glBufferSubData(GL_ARRAY_BUFFER, - m_bufferOffset * sizeof(Vertex2D), - m_currentCount * sizeof(Vertex2D), - m_buffer.data()); - } - else - { - glUnmapBuffer(GL_ARRAY_BUFFER); - } - - glUseProgram(m_program); - - glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_uniformBuffer); - - UpdateUniforms(); - - m_device->SetDepthTest(false); - m_device->SetCullFace(CullFace::NONE); - - if (m_drawCount == 1) - glDrawArrays(TranslateGfxPrimitive(m_type), m_first.front(), m_count.front()); - else - glMultiDrawArrays(TranslateGfxPrimitive(m_type), m_first.data(), m_count.data(), m_drawCount); - - m_bufferOffset += m_currentCount; - - m_mapped = false; - m_backup = false; - - return true; -} - -void CGL33UIRenderer::UpdateUniforms() -{ - if (!m_uniformsDirty) return; - - glBindBuffer(GL_COPY_WRITE_BUFFER, m_uniformBuffer); - glBufferData(GL_COPY_WRITE_BUFFER, sizeof(Uniforms), nullptr, GL_STREAM_DRAW); - glBufferSubData(GL_COPY_WRITE_BUFFER, 0, sizeof(Uniforms), &m_uniforms); - glBindBuffer(GL_COPY_WRITE_BUFFER, 0); -} - - -CGL33TerrainRenderer::CGL33TerrainRenderer(CGL33Device* device) - : m_device(device) -{ - GetLogger()->Info("Creating CGL33TerrainRenderer\n"); - - std::string preamble = LoadSource("shaders/gl33/preamble.glsl"); - std::string shadowSource = LoadSource("shaders/gl33/shadow.glsl"); - std::string lightingSource = LoadSource("shaders/gl33/lighting.glsl"); - std::string vsSource = LoadSource("shaders/gl33/terrain_vs.glsl"); - std::string fsSource = LoadSource("shaders/gl33/terrain_fs.glsl"); - - GLint vsShader = CreateShader(GL_VERTEX_SHADER, { preamble, lightingSource, shadowSource, vsSource }); - if (vsShader == 0) - { - GetLogger()->Error("Cound not create vertex shader from file 'terrain_vs.glsl'\n"); - return; - } - - GLint fsShader = CreateShader(GL_FRAGMENT_SHADER, { preamble, lightingSource, shadowSource, fsSource }); - if (fsShader == 0) - { - GetLogger()->Error("Cound not create fragment shader from file 'terrain_vs.glsl'\n"); - return; - } - - m_program = LinkProgram({ vsShader, fsShader }); - if (m_program == 0) - { - GetLogger()->Error("Cound not link shader program for terrain renderer\n"); - return; - } - - glDeleteShader(vsShader); - glDeleteShader(fsShader); - - glUseProgram(m_program); - - // Setup uniforms - glm::mat4 identity(1.0f); - - m_projectionMatrix = glGetUniformLocation(m_program, "uni_ProjectionMatrix"); - m_viewMatrix = glGetUniformLocation(m_program, "uni_ViewMatrix"); - m_shadowMatrix = glGetUniformLocation(m_program, "uni_ShadowMatrix"); - m_modelMatrix = glGetUniformLocation(m_program, "uni_ModelMatrix"); - m_normalMatrix = glGetUniformLocation(m_program, "uni_NormalMatrix"); - - m_cameraPosition = glGetUniformLocation(m_program, "uni_CameraPosition"); - m_lightPosition = glGetUniformLocation(m_program, "uni_LightPosition"); - m_lightIntensity = glGetUniformLocation(m_program, "uni_LightIntensity"); - m_lightColor = glGetUniformLocation(m_program, "uni_LightColor"); - - m_skyColor = glGetUniformLocation(m_program, "uni_SkyColor"); - m_skyIntensity = glGetUniformLocation(m_program, "uni_SkyIntensity"); - - m_fogRange = glGetUniformLocation(m_program, "uni_FogRange"); - m_fogColor = glGetUniformLocation(m_program, "uni_FogColor"); - - m_albedoColor = glGetUniformLocation(m_program, "uni_AlbedoColor"); - m_emissiveColor = glGetUniformLocation(m_program, "uni_EmissiveColor"); - m_roughness = glGetUniformLocation(m_program, "uni_Roughness"); - m_metalness = glGetUniformLocation(m_program, "uni_Metalness"); - m_aoStrength = glGetUniformLocation(m_program, "uni_AOStrength"); - - m_shadowRegions = glGetUniformLocation(m_program, "uni_ShadowRegions"); - - GLchar name[64]; - - for (int i = 0; i < 4; i++) - { - sprintf(name, "uni_ShadowParam[%d].transform", i); - m_shadows[i].transform = glGetUniformLocation(m_program, name); - - sprintf(name, "uni_ShadowParam[%d].uv_offset", i); - m_shadows[i].offset = glGetUniformLocation(m_program, name); - - sprintf(name, "uni_ShadowParam[%d].uv_scale", i); - m_shadows[i].scale = glGetUniformLocation(m_program, name); - } - - // Set texture units - auto texture = glGetUniformLocation(m_program, "uni_AlbedoTexture"); - glUniform1i(texture, m_albedoIndex); - - texture = glGetUniformLocation(m_program, "uni_DetailTexture"); - glUniform1i(texture, m_detailIndex); - - texture = glGetUniformLocation(m_program, "uni_EmissiveTexture"); - glUniform1i(texture, m_emissiveIndex); - - texture = glGetUniformLocation(m_program, "uni_MaterialTexture"); - glUniform1i(texture, m_materialIndex); - - texture = glGetUniformLocation(m_program, "uni_ShadowMap"); - glUniform1i(texture, m_shadowIndex); - - // White texture - glActiveTexture(GL_TEXTURE0); - glGenTextures(1, &m_whiteTexture); - glBindTexture(GL_TEXTURE_2D, m_whiteTexture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ONE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ONE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ONE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE); - - glUseProgram(0); - - GetLogger()->Info("CGL33TerrainRenderer created successfully\n"); -} - -CGL33TerrainRenderer::~CGL33TerrainRenderer() -{ - glDeleteProgram(m_program); - glDeleteTextures(1, &m_whiteTexture); -} - -void CGL33TerrainRenderer::Begin() -{ - glUseProgram(m_program); - - m_device->SetDepthTest(true); - m_device->SetDepthMask(true); - m_device->SetCullFace(CullFace::BACK); - - m_device->SetTransparency(TransparencyMode::NONE); - - glActiveTexture(GL_TEXTURE0 + m_albedoIndex); - glBindTexture(GL_TEXTURE_2D, m_whiteTexture); - - glActiveTexture(GL_TEXTURE0 + m_detailIndex); - glBindTexture(GL_TEXTURE_2D, m_whiteTexture); - - glActiveTexture(GL_TEXTURE0 + m_emissiveIndex); - glBindTexture(GL_TEXTURE_2D, m_whiteTexture); - - glActiveTexture(GL_TEXTURE0 + m_materialIndex); - glBindTexture(GL_TEXTURE_2D, m_whiteTexture); - - glActiveTexture(GL_TEXTURE0 + m_shadowIndex); - glBindTexture(GL_TEXTURE_2D, 0); - - m_albedoTexture = 0; - m_detailTexture = 0; - m_emissiveTexture = 0; - m_materialTexture = 0; - m_shadowMap = 0; - - m_device->SetDepthTest(true); - m_device->SetDepthMask(true); - m_device->SetTransparency(TransparencyMode::NONE); - m_device->SetCullFace(CullFace::BACK); - - SetFog(1e+6f, 1e+6, {}); -} - -void CGL33TerrainRenderer::End() -{ - glActiveTexture(GL_TEXTURE0 + m_albedoIndex); - glBindTexture(GL_TEXTURE_2D, 0); - - glActiveTexture(GL_TEXTURE0 + m_detailIndex); - glBindTexture(GL_TEXTURE_2D, 0); - - glActiveTexture(GL_TEXTURE0 + m_emissiveIndex); - glBindTexture(GL_TEXTURE_2D, 0); - - glActiveTexture(GL_TEXTURE0 + m_materialIndex); - glBindTexture(GL_TEXTURE_2D, 0); - - glActiveTexture(GL_TEXTURE0 + m_shadowIndex); - glBindTexture(GL_TEXTURE_2D, 0); - - m_albedoTexture = 0; - m_detailTexture = 0; - m_emissiveTexture = 0; - m_materialTexture = 0; - m_shadowMap = 0; -} - -void CGL33TerrainRenderer::SetProjectionMatrix(const glm::mat4& matrix) -{ - glUniformMatrix4fv(m_projectionMatrix, 1, GL_FALSE, value_ptr(matrix)); -} - -void CGL33TerrainRenderer::SetViewMatrix(const glm::mat4& matrix) -{ - glm::mat4 scale(1.0f); - scale[2][2] = -1.0f; - - auto viewMatrix = scale * matrix; - auto cameraMatrix = glm::inverse(viewMatrix); - auto cameraPos = cameraMatrix[3]; - - glUniformMatrix4fv(m_viewMatrix, 1, GL_FALSE, value_ptr(viewMatrix)); - glUniform3f(m_cameraPosition, cameraPos.x, cameraPos.y, cameraPos.z); -} - -void CGL33TerrainRenderer::SetModelMatrix(const glm::mat4& matrix) -{ - auto normalMatrix = glm::transpose(glm::inverse(glm::mat3(matrix))); - - glUniformMatrix4fv(m_modelMatrix, 1, GL_FALSE, value_ptr(matrix)); - glUniformMatrix3fv(m_normalMatrix, 1, GL_FALSE, value_ptr(normalMatrix)); -} - -void CGL33TerrainRenderer::SetAlbedoColor(const Color& color) -{ - glUniform4f(m_albedoColor, color.r, color.g, color.b, color.a); -} - -void CGL33TerrainRenderer::SetAlbedoTexture(const Texture& texture) -{ - if (m_albedoTexture == texture.id) return; - - m_albedoTexture = texture.id; - - glActiveTexture(GL_TEXTURE0 + m_albedoIndex); - - if (texture.id == 0) - glBindTexture(GL_TEXTURE_2D, m_whiteTexture); - else - glBindTexture(GL_TEXTURE_2D, texture.id); -} - -void CGL33TerrainRenderer::SetEmissiveColor(const Color& color) -{ - glUniform3f(m_emissiveColor, color.r, color.g, color.b); -} - -void CGL33TerrainRenderer::SetEmissiveTexture(const Texture& texture) -{ - if (m_emissiveTexture == texture.id) return; - - m_emissiveTexture = texture.id; - - glActiveTexture(GL_TEXTURE0 + m_emissiveIndex); - - if (texture.id == 0) - glBindTexture(GL_TEXTURE_2D, m_whiteTexture); - else - glBindTexture(GL_TEXTURE_2D, texture.id); -} - -void CGL33TerrainRenderer::SetMaterialParams(float roughness, float metalness, float aoStrength) -{ - glUniform1f(m_roughness, roughness); - glUniform1f(m_metalness, metalness); - glUniform1f(m_aoStrength, aoStrength); -} - -void CGL33TerrainRenderer::SetMaterialTexture(const Texture& texture) -{ - if (m_materialTexture == texture.id) return; - - m_materialTexture = texture.id; - - glActiveTexture(GL_TEXTURE0 + m_materialIndex); - - if (texture.id == 0) - glBindTexture(GL_TEXTURE_2D, m_whiteTexture); - else - glBindTexture(GL_TEXTURE_2D, texture.id); -} - -void CGL33TerrainRenderer::SetDetailTexture(const Texture& texture) -{ - if (m_detailTexture == texture.id) return; - - m_detailTexture = texture.id; - - glActiveTexture(GL_TEXTURE0 + m_detailIndex); - - if (texture.id == 0) - glBindTexture(GL_TEXTURE_2D, m_whiteTexture); - else - glBindTexture(GL_TEXTURE_2D, texture.id); -} - -void CGL33TerrainRenderer::SetShadowMap(const Texture& texture) -{ - if (m_shadowMap == texture.id) return; - - m_shadowMap = texture.id; - - glActiveTexture(GL_TEXTURE0 + m_shadowIndex); - - if (texture.id == 0) - glBindTexture(GL_TEXTURE_2D, 0); - else - glBindTexture(GL_TEXTURE_2D, texture.id); -} - -void CGL33TerrainRenderer::SetLight(const glm::vec4& position, const float& intensity, const glm::vec3& color) -{ - glUniform4fv(m_lightPosition, 1, glm::value_ptr(position)); - glUniform1f(m_lightIntensity, intensity); - glUniform3fv(m_lightColor, 1, glm::value_ptr(color)); -} - -void CGL33TerrainRenderer::SetSky(const Color& color, float intensity) -{ - glUniform3f(m_skyColor, color.r, color.g, color.b); - glUniform1f(m_skyIntensity, intensity); -} - -void CGL33TerrainRenderer::SetShadowParams(int count, const ShadowParam* params) -{ - glUniform1i(m_shadowRegions, count); - - for (int i = 0; i < count; i++) - { - glUniformMatrix4fv(m_shadows[i].transform, 1, GL_FALSE, glm::value_ptr(params[i].matrix)); - glUniform2fv(m_shadows[i].offset, 1, glm::value_ptr(params[i].uv_offset)); - glUniform2fv(m_shadows[i].scale, 1, glm::value_ptr(params[i].uv_scale)); - } -} - -void CGL33TerrainRenderer::SetFog(float min, float max, const glm::vec3& color) -{ - glUniform2f(m_fogRange, min, max); - glUniform3f(m_fogColor, color.r, color.g, color.b); -} - -void CGL33TerrainRenderer::DrawObject(const glm::mat4& matrix, const CVertexBuffer* buffer) -{ - auto b = dynamic_cast(buffer); - - if (b == nullptr) return; - - SetModelMatrix(matrix); - glBindVertexArray(b->GetVAO()); - - glDrawArrays(TranslateGfxPrimitive(b->GetType()), 0, b->Size()); -} - -CGL33ShadowRenderer::CGL33ShadowRenderer(CGL33Device* device) - : m_device(device) -{ - GetLogger()->Info("Creating CGL33ShadowRenderer\n"); - - GLint shaders[2] = {}; - - shaders[0] = LoadShader(GL_VERTEX_SHADER, "shaders/gl33/shadow_vs.glsl"); - if (shaders[0] == 0) - { - GetLogger()->Error("Cound not create vertex shader from file 'shadow_vs.glsl'\n"); - return; - } - - shaders[1] = LoadShader(GL_FRAGMENT_SHADER, "shaders/gl33/shadow_fs.glsl"); - if (shaders[1] == 0) - { - GetLogger()->Error("Cound not create fragment shader from file 'shadow_fs.glsl'\n"); - return; - } - - m_program = LinkProgram(2, shaders); - if (m_program == 0) - { - GetLogger()->Error("Cound not link shader program for terrain renderer\n"); - return; - } - - glDeleteShader(shaders[0]); - glDeleteShader(shaders[1]); - - glUseProgram(m_program); - - // Setup uniforms - auto texture = glGetUniformLocation(m_program, "uni_Texture"); - glUniform1i(texture, 0); - - glm::mat4 identity(1.0f); - - m_projectionMatrix = glGetUniformLocation(m_program, "uni_ProjectionMatrix"); - m_viewMatrix = glGetUniformLocation(m_program, "uni_ViewMatrix"); - m_modelMatrix = glGetUniformLocation(m_program, "uni_ModelMatrix"); - m_alphaScissor = glGetUniformLocation(m_program, "uni_AlphaScissor"); - - glUseProgram(0); - - glGenFramebuffers(1, &m_framebuffer); - - GetLogger()->Info("CGL33ShadowRenderer created successfully\n"); -} - -CGL33ShadowRenderer::~CGL33ShadowRenderer() -{ - glDeleteProgram(m_program); - - glDeleteFramebuffers(1, &m_framebuffer); -} - -void CGL33ShadowRenderer::Begin() -{ - glViewport(0, 0, m_width, m_height); - m_device->SetDepthMask(true); - glClear(GL_DEPTH_BUFFER_BIT); - - glUseProgram(m_program); - - glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); - - glEnable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(2.0f, 8.0f); - - m_device->SetColorMask(false, false, false, false); - m_device->SetDepthTest(true); - m_device->SetDepthMask(true); - - m_device->SetTransparency(TransparencyMode::NONE); - m_device->SetCullFace(CullFace::NONE); -} - -void CGL33ShadowRenderer::End() -{ - glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 0, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - glDisable(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(0.0f, 0.0f); - - m_device->SetColorMask(true, true, true, true); -} - -void CGL33ShadowRenderer::SetProjectionMatrix(const glm::mat4& matrix) -{ - glUniformMatrix4fv(m_projectionMatrix, 1, GL_FALSE, value_ptr(matrix)); -} - -void CGL33ShadowRenderer::SetViewMatrix(const glm::mat4& matrix) -{ - glm::mat4 scale(1.0f); - scale[2][2] = -1.0f; - - auto viewMatrix = scale * matrix; - - glUniformMatrix4fv(m_viewMatrix, 1, GL_FALSE, value_ptr(viewMatrix)); -} - -void CGL33ShadowRenderer::SetModelMatrix(const glm::mat4& matrix) -{ - glUniformMatrix4fv(m_modelMatrix, 1, GL_FALSE, value_ptr(matrix)); -} - -void CGL33ShadowRenderer::SetTexture(const Texture& texture) -{ - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, texture.id); -} - -void CGL33ShadowRenderer::SetShadowMap(const Texture& texture) -{ - glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texture.id, 0); - - m_width = texture.size.x; - m_height = texture.size.y; - - auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - - if (status != GL_FRAMEBUFFER_COMPLETE) - { - GetLogger()->Error("Framebuffer incomplete: %d\n", status); - } -} - -void CGL33ShadowRenderer::SetShadowRegion(const glm::vec2& offset, const glm::vec2& scale) -{ - int x = static_cast(m_width * offset.x); - int y = static_cast(m_height * offset.y); - int width = static_cast(m_width * scale.x); - int height = static_cast(m_height * scale.y); - - glViewport(x, y, width, height); -} - -void CGL33ShadowRenderer::DrawObject(const CVertexBuffer* buffer, bool transparent) -{ - auto b = dynamic_cast(buffer); - - if (b == nullptr) return; - - glUniform1i(m_alphaScissor, transparent ? 1 : 0); - - glBindVertexArray(b->GetVAO()); - - glDrawArrays(TranslateGfxPrimitive(b->GetType()), 0, b->Size()); -} - -} // namespace Gfx diff --git a/src/graphics/opengl33/README.txt b/src/graphics/opengl33/README.txt new file mode 100644 index 00000000..3eea20fa --- /dev/null +++ b/src/graphics/opengl33/README.txt @@ -0,0 +1,8 @@ +/** + * \dir src/graphics/opengl33 + * \brief OpenGL 3.3 engine implementation + * + * Contains the concrete implementation using OpenGL 3.3 of abstract CDevice class + * from src/graphics/core + */ + diff --git a/src/graphics/opengl/gl33device.cpp b/src/graphics/opengl33/gl33_device.cpp similarity index 97% rename from src/graphics/opengl/gl33device.cpp rename to src/graphics/opengl33/gl33_device.cpp index 33ed7eb3..b6d90008 100644 --- a/src/graphics/opengl/gl33device.cpp +++ b/src/graphics/opengl33/gl33_device.cpp @@ -1,6 +1,6 @@ /* * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2021, Daniel Roux, EPSITEC SA & TerranovaTeam + * Copyright (C) 2001-2022, 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 @@ -17,7 +17,14 @@ * along with this program. If not, see http://gnu.org/licenses */ -#include "graphics/opengl/gl33device.h" +#include "graphics/opengl33/gl33_device.h" + +#include "graphics/opengl33/gl33_object_renderer.h" +#include "graphics/opengl33/gl33_particle_renderer.h" +#include "graphics/opengl33/gl33_shadow_renderer.h" +#include "graphics/opengl33/gl33_terrain_renderer.h" +#include "graphics/opengl33/gl33_ui_renderer.h" +#include "graphics/opengl33/glframebuffer.h" #include "common/config.h" @@ -31,14 +38,8 @@ #include "graphics/engine/engine.h" -#include "graphics/opengl/glframebuffer.h" -#include "graphics/opengl/gl33renderers.h" -#include "graphics/opengl/gl33objectrenderer.h" -#include "graphics/opengl/gl33particlerenderer.h" - #include "math/geometry.h" - #include #include diff --git a/src/graphics/opengl/gl33device.h b/src/graphics/opengl33/gl33_device.h similarity index 96% rename from src/graphics/opengl/gl33device.h rename to src/graphics/opengl33/gl33_device.h index 7617e994..3aa28e4c 100644 --- a/src/graphics/opengl/gl33device.h +++ b/src/graphics/opengl33/gl33_device.h @@ -1,6 +1,6 @@ /* * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2021, Daniel Roux, EPSITEC SA & TerranovaTeam + * Copyright (C) 2001-2022, 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 @@ -18,7 +18,7 @@ */ /** - * \file graphics/opengl/gl33device.h + * \file graphics/opengl33/gl33_device.h * \brief OpenGL 3.3 implementation - CGL33Device class */ @@ -26,8 +26,8 @@ #include "graphics/core/device.h" -#include "graphics/opengl/glframebuffer.h" -#include "graphics/opengl/glutil.h" +#include "graphics/opengl33/glframebuffer.h" +#include "graphics/opengl33/glutil.h" #include #include diff --git a/src/graphics/opengl/gl33objectrenderer.cpp b/src/graphics/opengl33/gl33_object_renderer.cpp similarity index 98% rename from src/graphics/opengl/gl33objectrenderer.cpp rename to src/graphics/opengl33/gl33_object_renderer.cpp index 2280d64e..a5a41e2a 100644 --- a/src/graphics/opengl/gl33objectrenderer.cpp +++ b/src/graphics/opengl33/gl33_object_renderer.cpp @@ -1,6 +1,6 @@ /* * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2021, Daniel Roux, EPSITEC SA & TerranovaTeam + * Copyright (C) 2001-2022, 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 @@ -17,10 +17,10 @@ * along with this program. If not, see http://gnu.org/licenses */ -#include "graphics/opengl/gl33objectrenderer.h" +#include "graphics/opengl33/gl33_object_renderer.h" -#include "graphics/opengl/gl33device.h" -#include "graphics/opengl/glutil.h" +#include "graphics/opengl33/gl33_device.h" +#include "graphics/opengl33/glutil.h" #include "graphics/core/material.h" #include "graphics/core/transparency.h" diff --git a/src/graphics/opengl/gl33objectrenderer.h b/src/graphics/opengl33/gl33_object_renderer.h similarity index 98% rename from src/graphics/opengl/gl33objectrenderer.h rename to src/graphics/opengl33/gl33_object_renderer.h index da16c220..0a3c4c53 100644 --- a/src/graphics/opengl/gl33objectrenderer.h +++ b/src/graphics/opengl33/gl33_object_renderer.h @@ -1,6 +1,6 @@ /* * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2021, Daniel Roux, EPSITEC SA & TerranovaTeam + * Copyright (C) 2001-2022, 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 @@ -18,7 +18,7 @@ */ /** - * \file graphics/opengl/gl33objectrenderer.h + * \file graphics/opengl33/gl33_object_renderer.h * \brief OpenGL 3.3 object renderer */ diff --git a/src/graphics/opengl/gl33particlerenderer.cpp b/src/graphics/opengl33/gl33_particle_renderer.cpp similarity index 85% rename from src/graphics/opengl/gl33particlerenderer.cpp rename to src/graphics/opengl33/gl33_particle_renderer.cpp index 06948879..1d732df1 100644 --- a/src/graphics/opengl/gl33particlerenderer.cpp +++ b/src/graphics/opengl33/gl33_particle_renderer.cpp @@ -1,7 +1,26 @@ -#include "graphics/opengl/gl33particlerenderer.h" +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2022, 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 + */ -#include "graphics/opengl/gl33device.h" -#include "graphics/opengl/glutil.h" +#include "graphics/opengl33/gl33_particle_renderer.h" + +#include "graphics/opengl33/gl33_device.h" +#include "graphics/opengl33/glutil.h" #include "graphics/core/material.h" #include "graphics/core/transparency.h" diff --git a/src/graphics/opengl/gl33particlerenderer.h b/src/graphics/opengl33/gl33_particle_renderer.h similarity index 94% rename from src/graphics/opengl/gl33particlerenderer.h rename to src/graphics/opengl33/gl33_particle_renderer.h index cf1bf577..4b222493 100644 --- a/src/graphics/opengl/gl33particlerenderer.h +++ b/src/graphics/opengl33/gl33_particle_renderer.h @@ -1,6 +1,6 @@ /* * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2021, Daniel Roux, EPSITEC SA & TerranovaTeam + * Copyright (C) 2001-2022, 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 @@ -18,8 +18,8 @@ */ /** - * \file graphics/opengl/gl33objectrenderer.h - * \brief OpenGL 3.3 object renderer + * \file graphics/opengl33/gl33_particle_renderer.h + * \brief OpenGL 3.3 particle renderer */ #pragma once diff --git a/src/graphics/opengl33/gl33_shadow_renderer.cpp b/src/graphics/opengl33/gl33_shadow_renderer.cpp new file mode 100644 index 00000000..7214215d --- /dev/null +++ b/src/graphics/opengl33/gl33_shadow_renderer.cpp @@ -0,0 +1,192 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2022, 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 + */ + +#include "graphics/opengl33/gl33_shadow_renderer.h" + +#include "graphics/opengl33/gl33_device.h" +#include "graphics/opengl33/glutil.h" + +#include "graphics/core/material.h" +#include "graphics/core/transparency.h" +#include "graphics/core/vertex.h" + +#include "common/logger.h" + +#include + +#include +#include + +#include + +using namespace Gfx; + +CGL33ShadowRenderer::CGL33ShadowRenderer(CGL33Device* device) + : m_device(device) +{ + GetLogger()->Info("Creating CGL33ShadowRenderer\n"); + + GLint shaders[2] = {}; + + shaders[0] = LoadShader(GL_VERTEX_SHADER, "shaders/gl33/shadow_vs.glsl"); + if (shaders[0] == 0) + { + GetLogger()->Error("Cound not create vertex shader from file 'shadow_vs.glsl'\n"); + return; + } + + shaders[1] = LoadShader(GL_FRAGMENT_SHADER, "shaders/gl33/shadow_fs.glsl"); + if (shaders[1] == 0) + { + GetLogger()->Error("Cound not create fragment shader from file 'shadow_fs.glsl'\n"); + return; + } + + m_program = LinkProgram(2, shaders); + if (m_program == 0) + { + GetLogger()->Error("Cound not link shader program for terrain renderer\n"); + return; + } + + glDeleteShader(shaders[0]); + glDeleteShader(shaders[1]); + + glUseProgram(m_program); + + // Setup uniforms + auto texture = glGetUniformLocation(m_program, "uni_Texture"); + glUniform1i(texture, 0); + + glm::mat4 identity(1.0f); + + m_projectionMatrix = glGetUniformLocation(m_program, "uni_ProjectionMatrix"); + m_viewMatrix = glGetUniformLocation(m_program, "uni_ViewMatrix"); + m_modelMatrix = glGetUniformLocation(m_program, "uni_ModelMatrix"); + m_alphaScissor = glGetUniformLocation(m_program, "uni_AlphaScissor"); + + glUseProgram(0); + + glGenFramebuffers(1, &m_framebuffer); + + GetLogger()->Info("CGL33ShadowRenderer created successfully\n"); +} + +CGL33ShadowRenderer::~CGL33ShadowRenderer() +{ + glDeleteProgram(m_program); + + glDeleteFramebuffers(1, &m_framebuffer); +} + +void CGL33ShadowRenderer::Begin() +{ + glViewport(0, 0, m_width, m_height); + m_device->SetDepthMask(true); + glClear(GL_DEPTH_BUFFER_BIT); + + glUseProgram(m_program); + + glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); + + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(2.0f, 8.0f); + + m_device->SetColorMask(false, false, false, false); + m_device->SetDepthTest(true); + m_device->SetDepthMask(true); + + m_device->SetTransparency(TransparencyMode::NONE); + m_device->SetCullFace(CullFace::NONE); +} + +void CGL33ShadowRenderer::End() +{ + glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 0, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glDisable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(0.0f, 0.0f); + + m_device->SetColorMask(true, true, true, true); +} + +void CGL33ShadowRenderer::SetProjectionMatrix(const glm::mat4& matrix) +{ + glUniformMatrix4fv(m_projectionMatrix, 1, GL_FALSE, value_ptr(matrix)); +} + +void CGL33ShadowRenderer::SetViewMatrix(const glm::mat4& matrix) +{ + glm::mat4 scale(1.0f); + scale[2][2] = -1.0f; + + auto viewMatrix = scale * matrix; + + glUniformMatrix4fv(m_viewMatrix, 1, GL_FALSE, value_ptr(viewMatrix)); +} + +void CGL33ShadowRenderer::SetModelMatrix(const glm::mat4& matrix) +{ + glUniformMatrix4fv(m_modelMatrix, 1, GL_FALSE, value_ptr(matrix)); +} + +void CGL33ShadowRenderer::SetTexture(const Texture& texture) +{ + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture.id); +} + +void CGL33ShadowRenderer::SetShadowMap(const Texture& texture) +{ + glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texture.id, 0); + + m_width = texture.size.x; + m_height = texture.size.y; + + auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) + { + GetLogger()->Error("Framebuffer incomplete: %d\n", status); + } +} + +void CGL33ShadowRenderer::SetShadowRegion(const glm::vec2& offset, const glm::vec2& scale) +{ + int x = static_cast(m_width * offset.x); + int y = static_cast(m_height * offset.y); + int width = static_cast(m_width * scale.x); + int height = static_cast(m_height * scale.y); + + glViewport(x, y, width, height); +} + +void CGL33ShadowRenderer::DrawObject(const CVertexBuffer* buffer, bool transparent) +{ + auto b = dynamic_cast(buffer); + + if (b == nullptr) return; + + glUniform1i(m_alphaScissor, transparent ? 1 : 0); + + glBindVertexArray(b->GetVAO()); + + glDrawArrays(TranslateGfxPrimitive(b->GetType()), 0, b->Size()); +} diff --git a/src/graphics/opengl33/gl33_shadow_renderer.h b/src/graphics/opengl33/gl33_shadow_renderer.h new file mode 100644 index 00000000..3651acc0 --- /dev/null +++ b/src/graphics/opengl33/gl33_shadow_renderer.h @@ -0,0 +1,86 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2022, 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 + */ + + /** + * \file graphics/opengl33/gl33_shadow_renderer.h + * \brief OpenGL 3.3 shadow renderer + */ + +#pragma once + +#include "graphics/core/renderers.h" + +#include + +#include +#include + +// Graphics module namespace +namespace Gfx +{ + +class CGL33Device; + +class CGL33ShadowRenderer : public CShadowRenderer +{ +public: + CGL33ShadowRenderer(CGL33Device* device); + virtual ~CGL33ShadowRenderer(); + + virtual void Begin() override; + + virtual void End() override; + + //! Sets projection matrix + virtual void SetProjectionMatrix(const glm::mat4& matrix) override; + //! Sets view matrix + virtual void SetViewMatrix(const glm::mat4& matrix) override; + //! Sets model matrix + virtual void SetModelMatrix(const glm::mat4& matrix) override; + + //! Sets texture + virtual void SetTexture(const Texture& texture) override; + + //! Sets shadow map + virtual void SetShadowMap(const Texture& texture) override; + //! Sets shadow region + virtual void SetShadowRegion(const glm::vec2& offset, const glm::vec2& scale) override; + + //! Draws terrain object + virtual void DrawObject(const CVertexBuffer* buffer, bool transparent) override; + +private: + CGL33Device* const m_device; + + // Uniform data + GLint m_projectionMatrix = -1; + GLint m_viewMatrix = -1; + GLint m_modelMatrix = -1; + GLint m_alphaScissor = -1; + + // Shader program + GLuint m_program = 0; + + // Framebuffer + GLuint m_framebuffer = 0; + int m_width = 0; + int m_height = 0; +}; + +} // namespace Gfx diff --git a/src/graphics/opengl33/gl33_terrain_renderer.cpp b/src/graphics/opengl33/gl33_terrain_renderer.cpp new file mode 100644 index 00000000..8820fa0a --- /dev/null +++ b/src/graphics/opengl33/gl33_terrain_renderer.cpp @@ -0,0 +1,377 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2022, 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 + */ + +#include "graphics/opengl33/gl33_terrain_renderer.h" + +#include "graphics/opengl33/gl33_device.h" +#include "graphics/opengl33/glutil.h" + +#include "graphics/core/material.h" +#include "graphics/core/transparency.h" +#include "graphics/core/vertex.h" + +#include "common/logger.h" + +#include + +#include +#include + +#include + +using namespace Gfx; + +CGL33TerrainRenderer::CGL33TerrainRenderer(CGL33Device* device) + : m_device(device) +{ + GetLogger()->Info("Creating CGL33TerrainRenderer\n"); + + std::string preamble = LoadSource("shaders/gl33/preamble.glsl"); + std::string shadowSource = LoadSource("shaders/gl33/shadow.glsl"); + std::string lightingSource = LoadSource("shaders/gl33/lighting.glsl"); + std::string vsSource = LoadSource("shaders/gl33/terrain_vs.glsl"); + std::string fsSource = LoadSource("shaders/gl33/terrain_fs.glsl"); + + GLint vsShader = CreateShader(GL_VERTEX_SHADER, { preamble, lightingSource, shadowSource, vsSource }); + if (vsShader == 0) + { + GetLogger()->Error("Cound not create vertex shader from file 'terrain_vs.glsl'\n"); + return; + } + + GLint fsShader = CreateShader(GL_FRAGMENT_SHADER, { preamble, lightingSource, shadowSource, fsSource }); + if (fsShader == 0) + { + GetLogger()->Error("Cound not create fragment shader from file 'terrain_vs.glsl'\n"); + return; + } + + m_program = LinkProgram({ vsShader, fsShader }); + if (m_program == 0) + { + GetLogger()->Error("Cound not link shader program for terrain renderer\n"); + return; + } + + glDeleteShader(vsShader); + glDeleteShader(fsShader); + + glUseProgram(m_program); + + // Setup uniforms + glm::mat4 identity(1.0f); + + m_projectionMatrix = glGetUniformLocation(m_program, "uni_ProjectionMatrix"); + m_viewMatrix = glGetUniformLocation(m_program, "uni_ViewMatrix"); + m_shadowMatrix = glGetUniformLocation(m_program, "uni_ShadowMatrix"); + m_modelMatrix = glGetUniformLocation(m_program, "uni_ModelMatrix"); + m_normalMatrix = glGetUniformLocation(m_program, "uni_NormalMatrix"); + + m_cameraPosition = glGetUniformLocation(m_program, "uni_CameraPosition"); + m_lightPosition = glGetUniformLocation(m_program, "uni_LightPosition"); + m_lightIntensity = glGetUniformLocation(m_program, "uni_LightIntensity"); + m_lightColor = glGetUniformLocation(m_program, "uni_LightColor"); + + m_skyColor = glGetUniformLocation(m_program, "uni_SkyColor"); + m_skyIntensity = glGetUniformLocation(m_program, "uni_SkyIntensity"); + + m_fogRange = glGetUniformLocation(m_program, "uni_FogRange"); + m_fogColor = glGetUniformLocation(m_program, "uni_FogColor"); + + m_albedoColor = glGetUniformLocation(m_program, "uni_AlbedoColor"); + m_emissiveColor = glGetUniformLocation(m_program, "uni_EmissiveColor"); + m_roughness = glGetUniformLocation(m_program, "uni_Roughness"); + m_metalness = glGetUniformLocation(m_program, "uni_Metalness"); + m_aoStrength = glGetUniformLocation(m_program, "uni_AOStrength"); + + m_shadowRegions = glGetUniformLocation(m_program, "uni_ShadowRegions"); + + GLchar name[64]; + + for (int i = 0; i < 4; i++) + { + sprintf(name, "uni_ShadowParam[%d].transform", i); + m_shadows[i].transform = glGetUniformLocation(m_program, name); + + sprintf(name, "uni_ShadowParam[%d].uv_offset", i); + m_shadows[i].offset = glGetUniformLocation(m_program, name); + + sprintf(name, "uni_ShadowParam[%d].uv_scale", i); + m_shadows[i].scale = glGetUniformLocation(m_program, name); + } + + // Set texture units + auto texture = glGetUniformLocation(m_program, "uni_AlbedoTexture"); + glUniform1i(texture, m_albedoIndex); + + texture = glGetUniformLocation(m_program, "uni_DetailTexture"); + glUniform1i(texture, m_detailIndex); + + texture = glGetUniformLocation(m_program, "uni_EmissiveTexture"); + glUniform1i(texture, m_emissiveIndex); + + texture = glGetUniformLocation(m_program, "uni_MaterialTexture"); + glUniform1i(texture, m_materialIndex); + + texture = glGetUniformLocation(m_program, "uni_ShadowMap"); + glUniform1i(texture, m_shadowIndex); + + // White texture + glActiveTexture(GL_TEXTURE0); + glGenTextures(1, &m_whiteTexture); + glBindTexture(GL_TEXTURE_2D, m_whiteTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ONE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ONE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ONE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE); + + glUseProgram(0); + + GetLogger()->Info("CGL33TerrainRenderer created successfully\n"); +} + +CGL33TerrainRenderer::~CGL33TerrainRenderer() +{ + glDeleteProgram(m_program); + glDeleteTextures(1, &m_whiteTexture); +} + +void CGL33TerrainRenderer::Begin() +{ + glUseProgram(m_program); + + m_device->SetDepthTest(true); + m_device->SetDepthMask(true); + m_device->SetCullFace(CullFace::BACK); + + m_device->SetTransparency(TransparencyMode::NONE); + + glActiveTexture(GL_TEXTURE0 + m_albedoIndex); + glBindTexture(GL_TEXTURE_2D, m_whiteTexture); + + glActiveTexture(GL_TEXTURE0 + m_detailIndex); + glBindTexture(GL_TEXTURE_2D, m_whiteTexture); + + glActiveTexture(GL_TEXTURE0 + m_emissiveIndex); + glBindTexture(GL_TEXTURE_2D, m_whiteTexture); + + glActiveTexture(GL_TEXTURE0 + m_materialIndex); + glBindTexture(GL_TEXTURE_2D, m_whiteTexture); + + glActiveTexture(GL_TEXTURE0 + m_shadowIndex); + glBindTexture(GL_TEXTURE_2D, 0); + + m_albedoTexture = 0; + m_detailTexture = 0; + m_emissiveTexture = 0; + m_materialTexture = 0; + m_shadowMap = 0; + + m_device->SetDepthTest(true); + m_device->SetDepthMask(true); + m_device->SetTransparency(TransparencyMode::NONE); + m_device->SetCullFace(CullFace::BACK); + + SetFog(1e+6f, 1e+6, {}); +} + +void CGL33TerrainRenderer::End() +{ + glActiveTexture(GL_TEXTURE0 + m_albedoIndex); + glBindTexture(GL_TEXTURE_2D, 0); + + glActiveTexture(GL_TEXTURE0 + m_detailIndex); + glBindTexture(GL_TEXTURE_2D, 0); + + glActiveTexture(GL_TEXTURE0 + m_emissiveIndex); + glBindTexture(GL_TEXTURE_2D, 0); + + glActiveTexture(GL_TEXTURE0 + m_materialIndex); + glBindTexture(GL_TEXTURE_2D, 0); + + glActiveTexture(GL_TEXTURE0 + m_shadowIndex); + glBindTexture(GL_TEXTURE_2D, 0); + + m_albedoTexture = 0; + m_detailTexture = 0; + m_emissiveTexture = 0; + m_materialTexture = 0; + m_shadowMap = 0; +} + +void CGL33TerrainRenderer::SetProjectionMatrix(const glm::mat4& matrix) +{ + glUniformMatrix4fv(m_projectionMatrix, 1, GL_FALSE, value_ptr(matrix)); +} + +void CGL33TerrainRenderer::SetViewMatrix(const glm::mat4& matrix) +{ + glm::mat4 scale(1.0f); + scale[2][2] = -1.0f; + + auto viewMatrix = scale * matrix; + auto cameraMatrix = glm::inverse(viewMatrix); + auto cameraPos = cameraMatrix[3]; + + glUniformMatrix4fv(m_viewMatrix, 1, GL_FALSE, value_ptr(viewMatrix)); + glUniform3f(m_cameraPosition, cameraPos.x, cameraPos.y, cameraPos.z); +} + +void CGL33TerrainRenderer::SetModelMatrix(const glm::mat4& matrix) +{ + auto normalMatrix = glm::transpose(glm::inverse(glm::mat3(matrix))); + + glUniformMatrix4fv(m_modelMatrix, 1, GL_FALSE, value_ptr(matrix)); + glUniformMatrix3fv(m_normalMatrix, 1, GL_FALSE, value_ptr(normalMatrix)); +} + +void CGL33TerrainRenderer::SetAlbedoColor(const Color& color) +{ + glUniform4f(m_albedoColor, color.r, color.g, color.b, color.a); +} + +void CGL33TerrainRenderer::SetAlbedoTexture(const Texture& texture) +{ + if (m_albedoTexture == texture.id) return; + + m_albedoTexture = texture.id; + + glActiveTexture(GL_TEXTURE0 + m_albedoIndex); + + if (texture.id == 0) + glBindTexture(GL_TEXTURE_2D, m_whiteTexture); + else + glBindTexture(GL_TEXTURE_2D, texture.id); +} + +void CGL33TerrainRenderer::SetEmissiveColor(const Color& color) +{ + glUniform3f(m_emissiveColor, color.r, color.g, color.b); +} + +void CGL33TerrainRenderer::SetEmissiveTexture(const Texture& texture) +{ + if (m_emissiveTexture == texture.id) return; + + m_emissiveTexture = texture.id; + + glActiveTexture(GL_TEXTURE0 + m_emissiveIndex); + + if (texture.id == 0) + glBindTexture(GL_TEXTURE_2D, m_whiteTexture); + else + glBindTexture(GL_TEXTURE_2D, texture.id); +} + +void CGL33TerrainRenderer::SetMaterialParams(float roughness, float metalness, float aoStrength) +{ + glUniform1f(m_roughness, roughness); + glUniform1f(m_metalness, metalness); + glUniform1f(m_aoStrength, aoStrength); +} + +void CGL33TerrainRenderer::SetMaterialTexture(const Texture& texture) +{ + if (m_materialTexture == texture.id) return; + + m_materialTexture = texture.id; + + glActiveTexture(GL_TEXTURE0 + m_materialIndex); + + if (texture.id == 0) + glBindTexture(GL_TEXTURE_2D, m_whiteTexture); + else + glBindTexture(GL_TEXTURE_2D, texture.id); +} + +void CGL33TerrainRenderer::SetDetailTexture(const Texture& texture) +{ + if (m_detailTexture == texture.id) return; + + m_detailTexture = texture.id; + + glActiveTexture(GL_TEXTURE0 + m_detailIndex); + + if (texture.id == 0) + glBindTexture(GL_TEXTURE_2D, m_whiteTexture); + else + glBindTexture(GL_TEXTURE_2D, texture.id); +} + +void CGL33TerrainRenderer::SetShadowMap(const Texture& texture) +{ + if (m_shadowMap == texture.id) return; + + m_shadowMap = texture.id; + + glActiveTexture(GL_TEXTURE0 + m_shadowIndex); + + if (texture.id == 0) + glBindTexture(GL_TEXTURE_2D, 0); + else + glBindTexture(GL_TEXTURE_2D, texture.id); +} + +void CGL33TerrainRenderer::SetLight(const glm::vec4& position, const float& intensity, const glm::vec3& color) +{ + glUniform4fv(m_lightPosition, 1, glm::value_ptr(position)); + glUniform1f(m_lightIntensity, intensity); + glUniform3fv(m_lightColor, 1, glm::value_ptr(color)); +} + +void CGL33TerrainRenderer::SetSky(const Color& color, float intensity) +{ + glUniform3f(m_skyColor, color.r, color.g, color.b); + glUniform1f(m_skyIntensity, intensity); +} + +void CGL33TerrainRenderer::SetShadowParams(int count, const ShadowParam* params) +{ + glUniform1i(m_shadowRegions, count); + + for (int i = 0; i < count; i++) + { + glUniformMatrix4fv(m_shadows[i].transform, 1, GL_FALSE, glm::value_ptr(params[i].matrix)); + glUniform2fv(m_shadows[i].offset, 1, glm::value_ptr(params[i].uv_offset)); + glUniform2fv(m_shadows[i].scale, 1, glm::value_ptr(params[i].uv_scale)); + } +} + +void CGL33TerrainRenderer::SetFog(float min, float max, const glm::vec3& color) +{ + glUniform2f(m_fogRange, min, max); + glUniform3f(m_fogColor, color.r, color.g, color.b); +} + +void CGL33TerrainRenderer::DrawObject(const glm::mat4& matrix, const CVertexBuffer* buffer) +{ + auto b = dynamic_cast(buffer); + + if (b == nullptr) return; + + SetModelMatrix(matrix); + glBindVertexArray(b->GetVAO()); + + glDrawArrays(TranslateGfxPrimitive(b->GetType()), 0, b->Size()); +} diff --git a/src/graphics/opengl/gl33renderers.h b/src/graphics/opengl33/gl33_terrain_renderer.h similarity index 55% rename from src/graphics/opengl/gl33renderers.h rename to src/graphics/opengl33/gl33_terrain_renderer.h index 06448156..308818f3 100644 --- a/src/graphics/opengl/gl33renderers.h +++ b/src/graphics/opengl33/gl33_terrain_renderer.h @@ -1,6 +1,6 @@ /* * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2021, Daniel Roux, EPSITEC SA & TerranovaTeam + * Copyright (C) 2001-2022, 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 @@ -18,8 +18,8 @@ */ /** - * \file graphics/opengl/gl33renderers.h - * \brief OpenGL 3.3 renderers + * \file graphics/opengl33/gl33_terrain_renderer.h + * \brief OpenGL 3.3 terrain renderer */ #pragma once @@ -35,80 +35,10 @@ namespace Gfx { +struct Texture; + class CGL33Device; -class CGL33UIRenderer : public CUIRenderer -{ -public: - CGL33UIRenderer(CGL33Device* device); - virtual ~CGL33UIRenderer(); - - virtual void SetProjection(float left, float right, float bottom, float top) override; - virtual void SetTexture(const Texture& texture) override; - virtual void SetColor(const glm::vec4& color) override; - virtual void SetTransparency(TransparencyMode mode) override; - - virtual void DrawPrimitive(PrimitiveType type, int count, const Vertex2D* vertices) override; - - virtual Vertex2D* BeginPrimitive(PrimitiveType type, int count) override; - virtual Vertex2D* BeginPrimitives(PrimitiveType type, int drawCount, const int* counts) override; - virtual bool EndPrimitive() override; - -private: - void UpdateUniforms(); - - CGL33Device* const m_device; - - // Uniform data - struct Uniforms - { - glm::mat4 projectionMatrix; - glm::vec4 color; - }; - Uniforms m_uniforms = {}; - - // true means uniforms need to be updated - bool m_uniformsDirty = false; - - // Uniform buffer object - GLuint m_uniformBuffer = 0; - - // Vertex buffer object - GLuint m_bufferVBO = 0; - // Vertex array object - GLuint m_bufferVAO = 0; - // VBO capacity - GLsizei m_bufferCapacity = 128 * 1024; - // Buffer offset - GLsizei m_bufferOffset = 0; - - // Buffer mapping state - PrimitiveType m_type = {}; - // Number of drawn primitives - GLuint m_drawCount = 0; - // Total count of drawn vertices - GLuint m_currentCount = 0; - // Starting offset for each drawn primitive - std::vector m_first; - // Numbers of vertices for each drawn primitive - std::vector m_count; - // True means currently drawing - bool m_mapped = false; - // True means mapping failed, using auxiliary buffer - bool m_backup = false; - - // Buffered vertex data - std::vector m_buffer; - - // Shader program - GLuint m_program = 0; - - // 1x1 white texture - GLuint m_whiteTexture = 0; - // Currently bound texture - GLuint m_currentTexture = 0; -}; - class CGL33TerrainRenderer : public CTerrainRenderer { public: @@ -218,50 +148,4 @@ private: GLuint m_shadowMap = 0; }; -class CGL33ShadowRenderer : public CShadowRenderer -{ -public: - CGL33ShadowRenderer(CGL33Device* device); - virtual ~CGL33ShadowRenderer(); - - virtual void Begin() override; - - virtual void End() override; - - //! Sets projection matrix - virtual void SetProjectionMatrix(const glm::mat4& matrix) override; - //! Sets view matrix - virtual void SetViewMatrix(const glm::mat4& matrix) override; - //! Sets model matrix - virtual void SetModelMatrix(const glm::mat4& matrix) override; - - //! Sets texture - virtual void SetTexture(const Texture& texture) override; - - //! Sets shadow map - virtual void SetShadowMap(const Texture& texture) override; - //! Sets shadow region - virtual void SetShadowRegion(const glm::vec2& offset, const glm::vec2& scale) override; - - //! Draws terrain object - virtual void DrawObject(const CVertexBuffer* buffer, bool transparent) override; - -private: - CGL33Device* const m_device; - - // Uniform data - GLint m_projectionMatrix = -1; - GLint m_viewMatrix = -1; - GLint m_modelMatrix = -1; - GLint m_alphaScissor = -1; - - // Shader program - GLuint m_program = 0; - - // Framebuffer - GLuint m_framebuffer = 0; - int m_width = 0; - int m_height = 0; -}; - -} // namespace Gfx +} diff --git a/src/graphics/opengl33/gl33_ui_renderer.cpp b/src/graphics/opengl33/gl33_ui_renderer.cpp new file mode 100644 index 00000000..798333b5 --- /dev/null +++ b/src/graphics/opengl33/gl33_ui_renderer.cpp @@ -0,0 +1,295 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2022, 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 + */ + +#include "graphics/opengl33/gl33_ui_renderer.h" + +#include "graphics/opengl33/gl33_device.h" +#include "graphics/opengl33/glutil.h" + +#include "graphics/core/material.h" +#include "graphics/core/transparency.h" +#include "graphics/core/vertex.h" + +#include "common/logger.h" + +#include + +#include +#include + +#include + +#include +#include + +using namespace Gfx; + +CGL33UIRenderer::CGL33UIRenderer(CGL33Device* device) + : m_device(device) +{ + GetLogger()->Info("Creating CGL33UIRenderer\n"); + + GLint shaders[2] = {}; + + shaders[0] = LoadShader(GL_VERTEX_SHADER, "shaders/gl33/ui_vs.glsl"); + if (shaders[0] == 0) + { + GetLogger()->Error("Cound not create vertex shader from file 'ui_vs.glsl'\n"); + return; + } + + shaders[1] = LoadShader(GL_FRAGMENT_SHADER, "shaders/gl33/ui_fs.glsl"); + if (shaders[1] == 0) + { + GetLogger()->Error("Cound not create fragment shader from file 'ui_fs.glsl'\n"); + return; + } + + m_program = LinkProgram(2, shaders); + if (m_program == 0) + { + GetLogger()->Error("Cound not link shader program for interface renderer\n"); + return; + } + + glDeleteShader(shaders[0]); + glDeleteShader(shaders[1]); + + glUseProgram(m_program); + + // Create uniform buffer + glGenBuffers(1, &m_uniformBuffer); + + m_uniforms.projectionMatrix = glm::ortho(0.0f, +1.0f, 0.0f, +1.0f); + m_uniforms.color = { 1.0f, 1.0f, 1.0f, 1.0f }; + + m_uniformsDirty = true; + + UpdateUniforms(); + + // Bind uniform block to uniform buffer binding + GLuint blockIndex = glGetUniformBlockIndex(m_program, "Uniforms"); + + glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_uniformBuffer); + glUniformBlockBinding(m_program, blockIndex, 0); + + // Set texture unit to 8th + auto texture = glGetUniformLocation(m_program, "uni_Texture"); + glUniform1i(texture, 8); + + // Generic buffer + glGenBuffers(1, &m_bufferVBO); + glBindBuffer(GL_COPY_WRITE_BUFFER, m_bufferVBO); + glBufferData(GL_COPY_WRITE_BUFFER, m_bufferCapacity * sizeof(Vertex2D), nullptr, GL_STREAM_DRAW); + m_bufferOffset = m_bufferCapacity; + + glGenVertexArrays(1, &m_bufferVAO); + glBindVertexArray(m_bufferVAO); + + // White texture + glActiveTexture(GL_TEXTURE0); + glGenTextures(1, &m_whiteTexture); + glBindTexture(GL_TEXTURE_2D, m_whiteTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ONE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ONE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ONE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE); + + glUseProgram(0); + + GetLogger()->Info("CGL33UIRenderer created successfully\n"); +} + +CGL33UIRenderer::~CGL33UIRenderer() +{ + glDeleteProgram(m_program); + glDeleteTextures(1, &m_whiteTexture); + + glDeleteBuffers(1, &m_bufferVBO); + glDeleteVertexArrays(1, &m_bufferVAO); +} + +void CGL33UIRenderer::SetProjection(float left, float right, float bottom, float top) +{ + m_uniforms.projectionMatrix = glm::ortho(left, right, bottom, top); + m_uniformsDirty = true; +} + +void CGL33UIRenderer::SetTexture(const Texture& texture) +{ + if (m_currentTexture == texture.id) return; + + glActiveTexture(GL_TEXTURE8); + + m_currentTexture = texture.id; + + if (m_currentTexture == 0) + glBindTexture(GL_TEXTURE_2D, m_whiteTexture); + else + glBindTexture(GL_TEXTURE_2D, m_currentTexture); +} + +void CGL33UIRenderer::SetColor(const glm::vec4& color) +{ + m_uniforms.color = color; + m_uniformsDirty = true; +} + +void CGL33UIRenderer::SetTransparency(TransparencyMode mode) +{ + m_device->SetTransparency(mode); +} + +void CGL33UIRenderer::DrawPrimitive(PrimitiveType type, int count, const Vertex2D* vertices) +{ + auto ptr = BeginPrimitive(type, count); + + std::copy_n(vertices, count, ptr); + + EndPrimitive(); +} + +Vertex2D* CGL33UIRenderer::BeginPrimitive(PrimitiveType type, int count) +{ + return BeginPrimitives(type, 1, &count); +} + +Vertex2D* CGL33UIRenderer::BeginPrimitives(PrimitiveType type, int drawCount, const int* counts) +{ + glBindVertexArray(m_bufferVAO); + glBindBuffer(GL_ARRAY_BUFFER, m_bufferVBO); + + m_currentCount = 0; + + for (size_t i = 0; i < drawCount; i++) + { + m_currentCount += counts[i]; + } + + GLuint total = m_bufferOffset + m_currentCount; + + // Buffer full, orphan + if (total >= m_bufferCapacity) + { + glBufferData(GL_ARRAY_BUFFER, m_bufferCapacity * sizeof(Vertex2D), nullptr, GL_STREAM_DRAW); + + m_bufferOffset = 0; + + // Respecify vertex attributes + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), + reinterpret_cast(offsetof(Vertex2D, position))); + + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), + reinterpret_cast(offsetof(Vertex2D, uv))); + + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex2D), + reinterpret_cast(offsetof(Vertex2D, color))); + } + + m_first.resize(drawCount); + m_count.resize(drawCount); + + GLsizei currentOffset = m_bufferOffset; + + for (size_t i = 0; i < drawCount; i++) + { + m_first[i] = currentOffset; + m_count[i] = counts[i]; + + currentOffset += counts[i]; + } + + auto ptr = glMapBufferRange(GL_ARRAY_BUFFER, + m_bufferOffset * sizeof(Vertex2D), + m_currentCount * sizeof(Vertex2D), + GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); + + m_mapped = true; + m_type = type; + m_drawCount = drawCount; + + // Mapping failed, use backup buffer + if (ptr == nullptr) + { + m_backup = true; + m_buffer.resize(m_currentCount); + + return m_buffer.data(); + } + else + { + return reinterpret_cast(ptr); + } +} + +bool CGL33UIRenderer::EndPrimitive() +{ + if (!m_mapped) return false; + + if (m_backup) + { + glBufferSubData(GL_ARRAY_BUFFER, + m_bufferOffset * sizeof(Vertex2D), + m_currentCount * sizeof(Vertex2D), + m_buffer.data()); + } + else + { + glUnmapBuffer(GL_ARRAY_BUFFER); + } + + glUseProgram(m_program); + + glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_uniformBuffer); + + UpdateUniforms(); + + m_device->SetDepthTest(false); + m_device->SetCullFace(CullFace::NONE); + + if (m_drawCount == 1) + glDrawArrays(TranslateGfxPrimitive(m_type), m_first.front(), m_count.front()); + else + glMultiDrawArrays(TranslateGfxPrimitive(m_type), m_first.data(), m_count.data(), m_drawCount); + + m_bufferOffset += m_currentCount; + + m_mapped = false; + m_backup = false; + + return true; +} + +void CGL33UIRenderer::UpdateUniforms() +{ + if (!m_uniformsDirty) return; + + glBindBuffer(GL_COPY_WRITE_BUFFER, m_uniformBuffer); + glBufferData(GL_COPY_WRITE_BUFFER, sizeof(Uniforms), nullptr, GL_STREAM_DRAW); + glBufferSubData(GL_COPY_WRITE_BUFFER, 0, sizeof(Uniforms), &m_uniforms); + glBindBuffer(GL_COPY_WRITE_BUFFER, 0); +} diff --git a/src/graphics/opengl33/gl33_ui_renderer.h b/src/graphics/opengl33/gl33_ui_renderer.h new file mode 100644 index 00000000..82dc9022 --- /dev/null +++ b/src/graphics/opengl33/gl33_ui_renderer.h @@ -0,0 +1,112 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2022, 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 + */ + + /** + * \file graphics/opengl33/gl33_ui_renderer.h + * \brief OpenGL 3.3 UI renderer + */ + +#pragma once + +#include "graphics/core/renderers.h" + +#include + +#include +#include + +// Graphics module namespace +namespace Gfx +{ + +class CGL33Device; + +class CGL33UIRenderer : public CUIRenderer +{ +public: + CGL33UIRenderer(CGL33Device* device); + virtual ~CGL33UIRenderer(); + + virtual void SetProjection(float left, float right, float bottom, float top) override; + virtual void SetTexture(const Texture& texture) override; + virtual void SetColor(const glm::vec4& color) override; + virtual void SetTransparency(TransparencyMode mode) override; + + virtual void DrawPrimitive(PrimitiveType type, int count, const Vertex2D* vertices) override; + + virtual Vertex2D* BeginPrimitive(PrimitiveType type, int count) override; + virtual Vertex2D* BeginPrimitives(PrimitiveType type, int drawCount, const int* counts) override; + virtual bool EndPrimitive() override; + +private: + void UpdateUniforms(); + + CGL33Device* const m_device; + + // Uniform data + struct Uniforms + { + glm::mat4 projectionMatrix; + glm::vec4 color; + }; + Uniforms m_uniforms = {}; + + // true means uniforms need to be updated + bool m_uniformsDirty = false; + + // Uniform buffer object + GLuint m_uniformBuffer = 0; + + // Vertex buffer object + GLuint m_bufferVBO = 0; + // Vertex array object + GLuint m_bufferVAO = 0; + // VBO capacity + GLsizei m_bufferCapacity = 128 * 1024; + // Buffer offset + GLsizei m_bufferOffset = 0; + + // Buffer mapping state + PrimitiveType m_type = {}; + // Number of drawn primitives + GLuint m_drawCount = 0; + // Total count of drawn vertices + GLuint m_currentCount = 0; + // Starting offset for each drawn primitive + std::vector m_first; + // Numbers of vertices for each drawn primitive + std::vector m_count; + // True means currently drawing + bool m_mapped = false; + // True means mapping failed, using auxiliary buffer + bool m_backup = false; + + // Buffered vertex data + std::vector m_buffer; + + // Shader program + GLuint m_program = 0; + + // 1x1 white texture + GLuint m_whiteTexture = 0; + // Currently bound texture + GLuint m_currentTexture = 0; +}; + +} diff --git a/src/graphics/opengl/glframebuffer.cpp b/src/graphics/opengl33/glframebuffer.cpp similarity index 99% rename from src/graphics/opengl/glframebuffer.cpp rename to src/graphics/opengl33/glframebuffer.cpp index febfdf08..f22fc557 100644 --- a/src/graphics/opengl/glframebuffer.cpp +++ b/src/graphics/opengl33/glframebuffer.cpp @@ -1,6 +1,6 @@ /* * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2021, Daniel Roux, EPSITEC SA & TerranovaTeam + * Copyright (C) 2001-2022, 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 @@ -17,7 +17,7 @@ * along with this program. If not, see http://gnu.org/licenses */ -#include "graphics/opengl/glframebuffer.h" +#include "graphics/opengl33/glframebuffer.h" #include "common/logger.h" diff --git a/src/graphics/opengl/glframebuffer.h b/src/graphics/opengl33/glframebuffer.h similarity index 96% rename from src/graphics/opengl/glframebuffer.h rename to src/graphics/opengl33/glframebuffer.h index 201fb059..e697b614 100644 --- a/src/graphics/opengl/glframebuffer.h +++ b/src/graphics/opengl33/glframebuffer.h @@ -1,6 +1,6 @@ /* * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2021, Daniel Roux, EPSITEC SA & TerranovaTeam + * Copyright (C) 2001-2022, 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 @@ -21,7 +21,7 @@ #include "graphics/core/framebuffer.h" -#include "graphics/opengl/glutil.h" +#include "graphics/opengl33/glutil.h" namespace Gfx { diff --git a/src/graphics/opengl/glutil.cpp b/src/graphics/opengl33/glutil.cpp similarity index 99% rename from src/graphics/opengl/glutil.cpp rename to src/graphics/opengl33/glutil.cpp index 11f99c9b..95b78616 100644 --- a/src/graphics/opengl/glutil.cpp +++ b/src/graphics/opengl33/glutil.cpp @@ -17,13 +17,13 @@ * along with this program. If not, see http://gnu.org/licenses */ -#include "graphics/opengl/glutil.h" +#include "graphics/opengl33/glutil.h" + +#include "graphics/opengl33/gl33_device.h" #include "common/image.h" #include "common/logger.h" -#include "graphics/opengl/gl33device.h" - #include #include #include diff --git a/src/graphics/opengl/glutil.h b/src/graphics/opengl33/glutil.h similarity index 100% rename from src/graphics/opengl/glutil.h rename to src/graphics/opengl33/glutil.h diff --git a/src/graphics/opengl/shaders/CMakeLists.txt b/src/graphics/opengl33/shaders/CMakeLists.txt similarity index 100% rename from src/graphics/opengl/shaders/CMakeLists.txt rename to src/graphics/opengl33/shaders/CMakeLists.txt diff --git a/src/graphics/opengl/shaders/gl33/lighting.glsl b/src/graphics/opengl33/shaders/gl33/lighting.glsl similarity index 100% rename from src/graphics/opengl/shaders/gl33/lighting.glsl rename to src/graphics/opengl33/shaders/gl33/lighting.glsl diff --git a/src/graphics/opengl/shaders/gl33/object_fs.glsl b/src/graphics/opengl33/shaders/gl33/object_fs.glsl similarity index 100% rename from src/graphics/opengl/shaders/gl33/object_fs.glsl rename to src/graphics/opengl33/shaders/gl33/object_fs.glsl diff --git a/src/graphics/opengl/shaders/gl33/object_vs.glsl b/src/graphics/opengl33/shaders/gl33/object_vs.glsl similarity index 100% rename from src/graphics/opengl/shaders/gl33/object_vs.glsl rename to src/graphics/opengl33/shaders/gl33/object_vs.glsl diff --git a/src/graphics/opengl/shaders/gl33/particle_fs.glsl b/src/graphics/opengl33/shaders/gl33/particle_fs.glsl similarity index 100% rename from src/graphics/opengl/shaders/gl33/particle_fs.glsl rename to src/graphics/opengl33/shaders/gl33/particle_fs.glsl diff --git a/src/graphics/opengl/shaders/gl33/particle_vs.glsl b/src/graphics/opengl33/shaders/gl33/particle_vs.glsl similarity index 100% rename from src/graphics/opengl/shaders/gl33/particle_vs.glsl rename to src/graphics/opengl33/shaders/gl33/particle_vs.glsl diff --git a/src/graphics/opengl/shaders/gl33/preamble.glsl b/src/graphics/opengl33/shaders/gl33/preamble.glsl similarity index 100% rename from src/graphics/opengl/shaders/gl33/preamble.glsl rename to src/graphics/opengl33/shaders/gl33/preamble.glsl diff --git a/src/graphics/opengl/shaders/gl33/shadow.glsl b/src/graphics/opengl33/shaders/gl33/shadow.glsl similarity index 100% rename from src/graphics/opengl/shaders/gl33/shadow.glsl rename to src/graphics/opengl33/shaders/gl33/shadow.glsl diff --git a/src/graphics/opengl/shaders/gl33/shadow_fs.glsl b/src/graphics/opengl33/shaders/gl33/shadow_fs.glsl similarity index 100% rename from src/graphics/opengl/shaders/gl33/shadow_fs.glsl rename to src/graphics/opengl33/shaders/gl33/shadow_fs.glsl diff --git a/src/graphics/opengl/shaders/gl33/shadow_vs.glsl b/src/graphics/opengl33/shaders/gl33/shadow_vs.glsl similarity index 100% rename from src/graphics/opengl/shaders/gl33/shadow_vs.glsl rename to src/graphics/opengl33/shaders/gl33/shadow_vs.glsl diff --git a/src/graphics/opengl/shaders/gl33/terrain_fs.glsl b/src/graphics/opengl33/shaders/gl33/terrain_fs.glsl similarity index 100% rename from src/graphics/opengl/shaders/gl33/terrain_fs.glsl rename to src/graphics/opengl33/shaders/gl33/terrain_fs.glsl diff --git a/src/graphics/opengl/shaders/gl33/terrain_vs.glsl b/src/graphics/opengl33/shaders/gl33/terrain_vs.glsl similarity index 100% rename from src/graphics/opengl/shaders/gl33/terrain_vs.glsl rename to src/graphics/opengl33/shaders/gl33/terrain_vs.glsl diff --git a/src/graphics/opengl/shaders/gl33/ui_fs.glsl b/src/graphics/opengl33/shaders/gl33/ui_fs.glsl similarity index 100% rename from src/graphics/opengl/shaders/gl33/ui_fs.glsl rename to src/graphics/opengl33/shaders/gl33/ui_fs.glsl diff --git a/src/graphics/opengl/shaders/gl33/ui_vs.glsl b/src/graphics/opengl33/shaders/gl33/ui_vs.glsl similarity index 100% rename from src/graphics/opengl/shaders/gl33/ui_vs.glsl rename to src/graphics/opengl33/shaders/gl33/ui_vs.glsl