diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 353d09ba..02688e25 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -144,10 +144,6 @@ add_library(colobotbase STATIC graphics/model/model_output.h graphics/model/model_shadow_spot.h graphics/model/model_triangle.h - graphics/opengl/gl14device.cpp - graphics/opengl/gl14device.h - graphics/opengl/gl21device.cpp - graphics/opengl/gl21device.h graphics/opengl/gl33device.cpp graphics/opengl/gl33device.h graphics/opengl/glframebuffer.cpp diff --git a/src/graphics/opengl/gl14device.cpp b/src/graphics/opengl/gl14device.cpp deleted file mode 100644 index 90f2e8f5..00000000 --- a/src/graphics/opengl/gl14device.cpp +++ /dev/null @@ -1,1829 +0,0 @@ -/* - * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2020, 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/gl14device.h" - -#include "common/config.h" - -#include "common/image.h" -#include "common/logger.h" - -#include "graphics/core/light.h" - -#include "graphics/engine/engine.h" - -#include "graphics/opengl/glframebuffer.h" - -#include "math/geometry.h" - - -#include - -#include - - -// Graphics module namespace -namespace Gfx -{ - -CGL14Device::CGL14Device(const DeviceConfig &config) - : m_config(config) -{} - -CGL14Device::~CGL14Device() -{ -} - -void CGL14Device::DebugHook() -{ - /* This function is only called here, so it can be used - * as a breakpoint when debugging using gDEBugger */ - glColor3i(0, 0, 0); -} - -void CGL14Device::DebugLights() -{ - Gfx::ColorHSV color(0.0, 1.0, 1.0); - - glLineWidth(3.0f); - glDisable(GL_LIGHTING); - glDepthMask(GL_FALSE); - glDisable(GL_BLEND); - - Math::Matrix saveWorldMat = m_worldMat; - m_worldMat.LoadIdentity(); - UpdateModelviewMatrix(); - - for (int i = 0; i < static_cast( m_lights.size() ); ++i) - { - color.h = static_cast(i) / static_cast(m_lights.size()); - if (m_lightsEnabled[i]) - { - const Light& l = m_lights[i]; - if (l.type == LIGHT_DIRECTIONAL) - { - Gfx::VertexCol v[2]; - v[0].coord = -Math::Normalize(l.direction) * 100.0f + Math::Vector(0.0f, 0.0f, 1.0f) * i; - v[0].color = HSV2RGB(color); - v[1].coord = Math::Normalize(l.direction) * 100.0f + Math::Vector(0.0f, 0.0f, 1.0f) * i; - v[1].color = HSV2RGB(color); - while (v[0].coord.y < 60.0f && v[0].coord.y < 60.0f) - { - v[0].coord.y += 10.0f; - v[1].coord.y += 10.0f; - } - DrawPrimitive(PRIMITIVE_LINES, v, 2); - - v[0].coord = v[1].coord + Math::Normalize(v[0].coord - v[1].coord) * 50.0f; - - glLineWidth(10.0f); - DrawPrimitive(PRIMITIVE_LINES, v, 2); - glLineWidth(3.0f); - } - else if (l.type == LIGHT_POINT) - { - Gfx::VertexCol v[8]; - for (int i = 0; i < 8; ++i) - v[i].color = HSV2RGB(color); - - v[0].coord = l.position + Math::Vector(-1.0f, -1.0f, -1.0f) * 4.0f; - v[1].coord = l.position + Math::Vector( 1.0f, -1.0f, -1.0f) * 4.0f; - v[2].coord = l.position + Math::Vector( 1.0f, 1.0f, -1.0f) * 4.0f; - v[3].coord = l.position + Math::Vector(-1.0f, 1.0f, -1.0f) * 4.0f; - v[4].coord = l.position + Math::Vector(-1.0f, -1.0f, -1.0f) * 4.0f; - DrawPrimitive(PRIMITIVE_LINE_STRIP, v, 5); - - v[0].coord = l.position + Math::Vector(-1.0f, -1.0f, 1.0f) * 4.0f; - v[1].coord = l.position + Math::Vector( 1.0f, -1.0f, 1.0f) * 4.0f; - v[2].coord = l.position + Math::Vector( 1.0f, 1.0f, 1.0f) * 4.0f; - v[3].coord = l.position + Math::Vector(-1.0f, 1.0f, 1.0f) * 4.0f; - v[4].coord = l.position + Math::Vector(-1.0f, -1.0f, 1.0f) * 4.0f; - DrawPrimitive(PRIMITIVE_LINE_STRIP, v, 5); - - v[0].coord = l.position + Math::Vector(-1.0f, -1.0f, -1.0f) * 4.0f; - v[1].coord = l.position + Math::Vector(-1.0f, -1.0f, 1.0f) * 4.0f; - v[2].coord = l.position + Math::Vector( 1.0f, -1.0f, -1.0f) * 4.0f; - v[3].coord = l.position + Math::Vector( 1.0f, -1.0f, 1.0f) * 4.0f; - v[4].coord = l.position + Math::Vector( 1.0f, 1.0f, -1.0f) * 4.0f; - v[5].coord = l.position + Math::Vector( 1.0f, 1.0f, 1.0f) * 4.0f; - v[6].coord = l.position + Math::Vector(-1.0f, 1.0f, -1.0f) * 4.0f; - v[7].coord = l.position + Math::Vector(-1.0f, 1.0f, 1.0f) * 4.0f; - DrawPrimitive(PRIMITIVE_LINES, v, 8); - } - else if (l.type == LIGHT_SPOT) - { - Gfx::VertexCol v[5]; - for (int i = 0; i < 5; ++i) - v[i].color = HSV2RGB(color); - - v[0].coord = l.position + Math::Vector(-1.0f, 0.0f, -1.0f) * 4.0f; - v[1].coord = l.position + Math::Vector( 1.0f, 0.0f, -1.0f) * 4.0f; - v[2].coord = l.position + Math::Vector( 1.0f, 0.0f, 1.0f) * 4.0f; - v[3].coord = l.position + Math::Vector(-1.0f, 0.0f, 1.0f) * 4.0f; - v[4].coord = l.position + Math::Vector(-1.0f, 0.0f, -1.0f) * 4.0f; - DrawPrimitive(PRIMITIVE_LINE_STRIP, v, 5); - - v[0].coord = l.position; - v[1].coord = l.position + Math::Normalize(l.direction) * 100.0f; - glEnable(GL_LINE_STIPPLE); - glLineStipple(3.0, 0xFF); - DrawPrimitive(PRIMITIVE_LINES, v, 2); - glDisable(GL_LINE_STIPPLE); - } - } - } - - glLineWidth(1.0f); - glEnable(GL_LIGHTING); - glDepthMask(GL_TRUE); - glEnable(GL_BLEND); - m_worldMat = saveWorldMat; - UpdateModelviewMatrix(); -} - -std::string CGL14Device::GetName() -{ - return std::string("OpenGL 1.4"); -} - -bool CGL14Device::Create() -{ - GetLogger()->Info("Creating CDevice - OpenGL 1.4\n"); - - if (!InitializeGLEW()) - { - m_errorMessage = "An error occurred while initializing GLEW."; - return false; - } - - // Extract OpenGL version - int glMajor = 1, glMinor = 1; - int glVersion = GetOpenGLVersion(glMajor, glMinor); - - if (glVersion < 13) - { - GetLogger()->Error("Unsupported OpenGL version: %d.%d\n", glMajor, glMinor); - GetLogger()->Error("OpenGL 1.3 or newer is required to use this engine.\n"); - m_errorMessage = "It seems your graphics card does not support OpenGL 1.3.\n"; - m_errorMessage += "Please make sure you have appropriate hardware and newest drivers installed.\n\n"; - m_errorMessage += GetHardwareInfo(); - return false; - } - - const char* version = reinterpret_cast(glGetString(GL_VERSION)); - const char* renderer = reinterpret_cast(glGetString(GL_RENDERER)); - - GetLogger()->Info("OpenGL %s\n", version); - GetLogger()->Info("%s\n", renderer); - - // Detect Shadow mapping support - if (glVersion >= 14) // Core depth texture+shadow, OpenGL 1.4+ - { - m_shadowMappingSupport = SMS_CORE; - m_capabilities.shadowMappingSupported = true; - GetLogger()->Info("Shadow mapping available (core)\n"); - } - else if (glewIsSupported("GL_ARB_depth_texture GL_ARB_shadow")) // ARB depth texture + shadow - { - m_shadowMappingSupport = SMS_ARB; - m_capabilities.shadowMappingSupported = true; - GetLogger()->Info("Shadow mapping available (ARB)\n"); - } - else // No Shadow mapping - { - m_shadowMappingSupport = SMS_NONE; - m_capabilities.shadowMappingSupported = false; - GetLogger()->Info("Shadow mapping not available\n"); - } - - // Detect support of anisotropic filtering - m_capabilities.anisotropySupported = glewIsSupported("GL_EXT_texture_filter_anisotropic"); - if (m_capabilities.anisotropySupported) - { - // Obtain maximum anisotropy level available - float level; - glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &level); - m_capabilities.maxAnisotropy = static_cast(level); - - GetLogger()->Info("Anisotropic filtering available\n"); - GetLogger()->Info("Maximum anisotropy: %d\n", m_capabilities.maxAnisotropy); - } - else - { - GetLogger()->Info("Anisotropic filtering not available\n"); - } - - // Read maximum sample count for MSAA - if(glewIsSupported("GL_EXT_framebuffer_multisample")) - { - m_capabilities.multisamplingSupported = true; - glGetIntegerv(GL_MAX_SAMPLES_EXT, &m_capabilities.maxSamples); - GetLogger()->Info("Multisampling supported, max samples: %d\n", m_capabilities.maxSamples); - } - else - { - m_capabilities.multisamplingSupported = false; - GetLogger()->Info("Multisampling not supported\n"); - } - - // check for glMultiDrawArrays() - if (glVersion >= 14) - m_multiDrawArrays = true; - - GetLogger()->Info("Auto-detecting VBO support\n"); - - // detecting VBO ARB extension - bool vboARB = glewIsSupported("GL_ARB_vertex_buffer_object"); - - // VBO is core OpenGL feature since 1.5 - // everything below 1.5 means no VBO support - if (glVersion >= 15) - { - GetLogger()->Info("Core VBO supported\n", glMajor, glMinor); - - // Set function pointers - m_glGenBuffers = glGenBuffers; - m_glDeleteBuffers = glDeleteBuffers; - m_glBindBuffer = glBindBuffer; - m_glBufferData = glBufferData; - m_glBufferSubData = glBufferSubData; - } - else if (vboARB) // VBO ARB extension available - { - GetLogger()->Info("ARB VBO supported\n"); - - // Set function pointers - m_glGenBuffers = glGenBuffersARB; - m_glDeleteBuffers = glDeleteBuffersARB; - m_glBindBuffer = glBindBufferARB; - m_glBufferData = glBufferDataARB; - m_glBufferSubData = glBufferSubDataARB; - } - else // no VBO support - { - m_errorMessage = "Your graphics card or drivers don't support OpenGL 1.5 or vertex buffer objects.\n" - "Ensure you have the latest graphics drivers for your graphics card.\n\n"; - GetLogger()->Error(m_errorMessage.c_str()); - m_errorMessage += GetHardwareInfo(); - return false; - } - - // This is mostly done in all modern hardware by default - // DirectX doesn't even allow the option to turn off perspective correction anymore - // So turn it on permanently - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); - - // To avoid problems with scaling & lighting - glEnable(GL_RESCALE_NORMAL); - //glEnable(GL_NORMALIZE); // this needs some testing - - // Minimal depth bias to avoid Z-fighting - //SetDepthBias(0.001f); - glAlphaFunc(GL_GREATER, 0.1f); - - // Set just to be sure - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glViewport(0, 0, m_config.size.x, m_config.size.y); - - int numLights = 0; - glGetIntegerv(GL_MAX_LIGHTS, &numLights); - - m_capabilities.maxLights = numLights; - - m_lights = std::vector(numLights, Light()); - m_lightsEnabled = std::vector (numLights, false); - - int maxTextures = 0; - glGetIntegerv(GL_MAX_TEXTURE_UNITS, &maxTextures); - GetLogger()->Info("Maximum texture units: %d\n", maxTextures); - - m_capabilities.multitexturingSupported = true; - m_capabilities.maxTextures = maxTextures; - - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_capabilities.maxTextureSize); - GetLogger()->Info("Maximum texture size: %d\n", m_capabilities.maxTextureSize); - - m_currentTextures = std::vector (maxTextures, Texture()); - m_texturesEnabled = std::vector (maxTextures, false); - m_textureStageParams = std::vector(maxTextures, TextureStageParams()); - m_remap = std::vector (maxTextures, 0); - - // default mapping - for (int i = 0; i < maxTextures; i++) - m_remap[i] = i; - - // special remapping for quality shadows - if (maxTextures >= 4) - { - m_remap[0] = 2; - m_remap[1] = 3; - m_remap[2] = 0; - m_remap[3] = 1; - - m_shadowQuality = true; - GetLogger()->Debug("Using quality shadows\n"); - } - else - { - m_shadowQuality = false; - GetLogger()->Debug("Using simple shadows\n"); - } - - // create white texture - glGenTextures(1, &m_whiteTexture); - glBindTexture(GL_TEXTURE_2D, m_whiteTexture); - int color = 0xFFFFFFFF; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &color); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glBindTexture(GL_TEXTURE_2D, 0); - - // create default framebuffer object - FramebufferParams framebufferParams; - - framebufferParams.width = m_config.size.x; - framebufferParams.height = m_config.size.y; - framebufferParams.depth = m_config.depthSize; - - m_framebuffers["default"] = MakeUnique(framebufferParams); - - m_framebufferSupport = DetectFramebufferSupport(); - if (m_framebufferSupport == FBS_ARB) - { - m_capabilities.framebufferSupported = true; - GetLogger()->Info("Framebuffer supported (ARB)\n"); - - glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &m_capabilities.maxRenderbufferSize); - GetLogger()->Info("Maximum renderbuffer size: %d\n", m_capabilities.maxRenderbufferSize); - } - else if (m_framebufferSupport == FBS_EXT) - { - m_capabilities.framebufferSupported = true; - GetLogger()->Info("Framebuffer supported (EXT)\n"); - - glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &m_capabilities.maxRenderbufferSize); - GetLogger()->Info("Maximum renderbuffer size: %d\n", m_capabilities.maxRenderbufferSize); - } - else - { - m_capabilities.framebufferSupported = false; - GetLogger()->Info("Framebuffer not supported\n"); - } - - GetLogger()->Info("CDevice created successfully\n"); - - return true; -} - -void CGL14Device::Destroy() -{ - // delete framebuffers - for (auto& framebuffer : m_framebuffers) - framebuffer.second->Destroy(); - - m_framebuffers.clear(); - - // Delete the remaining textures - // Should not be strictly necessary, but just in case - DestroyAllTextures(); - glDeleteTextures(1, &m_whiteTexture); - m_whiteTexture = 0; - - m_lights.clear(); - m_lightsEnabled.clear(); - - m_currentTextures.clear(); - m_texturesEnabled.clear(); - m_textureStageParams.clear(); -} - -void CGL14Device::ConfigChanged(const DeviceConfig& newConfig) -{ - m_config = newConfig; - - // Reset state - m_lighting = false; - - glViewport(0, 0, m_config.size.x, m_config.size.y); - - // create default framebuffer object - FramebufferParams framebufferParams; - - framebufferParams.width = m_config.size.x; - framebufferParams.height = m_config.size.y; - framebufferParams.depth = m_config.depthSize; - - m_framebuffers["default"] = MakeUnique(framebufferParams); -} - -void CGL14Device::BeginScene() -{ - Clear(); - - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(m_projectionMat.Array()); - - UpdateModelviewMatrix(); -} - -void CGL14Device::EndScene() -{ -#ifdef DEV_BUILD - int count = ClearGLErrors(); - - if (count > 0) - GetLogger()->Debug("OpenGL errors detected: %d\n", count); -#endif -} - -void CGL14Device::Clear() -{ - glDepthMask(GL_TRUE); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -} - -void CGL14Device::SetRenderMode(RenderMode mode) -{ - // nothing is done -} - -void CGL14Device::SetTransform(TransformType type, const Math::Matrix &matrix) -{ - if (type == TRANSFORM_WORLD) - { - m_worldMat = matrix; - UpdateModelviewMatrix(); - - m_combinedMatrixOutdated = true; - } - else if (type == TRANSFORM_VIEW) - { - m_viewMat = matrix; - UpdateModelviewMatrix(); - - m_combinedMatrixOutdated = true; - } - else if (type == TRANSFORM_PROJECTION) - { - m_projectionMat = matrix; - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(m_projectionMat.Array()); - - m_combinedMatrixOutdated = true; - } - else if (type == TRANSFORM_SHADOW) - { - m_shadowMatrix = matrix; - - glActiveTexture(GL_TEXTURE0 + m_remap[2]); - glMatrixMode(GL_TEXTURE); - glLoadMatrixf(m_shadowMatrix.Array()); - } - else - { - assert(false); - } -} - -void CGL14Device::UpdateModelviewMatrix() -{ - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glScalef(1.0f, 1.0f, -1.0f); - glMultMatrixf(m_viewMat.Array()); - glMultMatrixf(m_worldMat.Array()); - glGetFloatv(GL_MODELVIEW_MATRIX, m_modelviewMat.Array()); - - if (m_lighting) - { - UpdateLightPositions(); - } -} - -void CGL14Device::SetMaterial(const Material &material) -{ - m_material = material; - - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, m_material.ambient.Array()); - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, m_material.diffuse.Array()); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, m_material.specular.Array()); -} - -int CGL14Device::GetMaxLightCount() -{ - return m_lights.size(); -} - -void CGL14Device::SetLight(int index, const Light &light) -{ - assert(index >= 0); - assert(index < static_cast( m_lights.size() )); - - m_lights[index] = light; - - // Indexing from GL_LIGHT0 should always work - glLightfv(GL_LIGHT0 + index, GL_AMBIENT, const_cast(light.ambient.Array())); - glLightfv(GL_LIGHT0 + index, GL_DIFFUSE, const_cast(light.diffuse.Array())); - glLightfv(GL_LIGHT0 + index, GL_SPECULAR, const_cast(light.specular.Array())); - - glLightf(GL_LIGHT0 + index, GL_CONSTANT_ATTENUATION, light.attenuation0); - glLightf(GL_LIGHT0 + index, GL_LINEAR_ATTENUATION, light.attenuation1); - glLightf(GL_LIGHT0 + index, GL_QUADRATIC_ATTENUATION, light.attenuation2); - - if (light.type == LIGHT_SPOT) - { - glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, light.spotAngle * Math::RAD_TO_DEG); - glLightf(GL_LIGHT0 + index, GL_SPOT_EXPONENT, light.spotIntensity); - } - else - { - glLightf(GL_LIGHT0 + index, GL_SPOT_CUTOFF, 180.0f); - } - - UpdateLightPosition(index); -} - -void CGL14Device::UpdateLightPosition(int index) -{ - assert(index >= 0); - assert(index < static_cast( m_lights.size() )); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - - Light &light = m_lights[index]; - - if (light.type == LIGHT_POINT) - { - glLoadIdentity(); - glScalef(1.0f, 1.0f, -1.0f); - glMultMatrixf(m_viewMat.Array()); - - GLfloat position[4] = { light.position.x, light.position.y, light.position.z, 1.0f }; - glLightfv(GL_LIGHT0 + index, GL_POSITION, position); - } - else - { - glLoadIdentity(); - glScalef(1.0f, 1.0f, -1.0f); - Math::Matrix mat = m_viewMat; - mat.Set(1, 4, 0.0f); - mat.Set(2, 4, 0.0f); - mat.Set(3, 4, 0.0f); - glMultMatrixf(mat.Array()); - - if (light.type == LIGHT_SPOT) - { - GLfloat direction[4] = { -light.direction.x, -light.direction.y, -light.direction.z, 1.0f }; - glLightfv(GL_LIGHT0 + index, GL_SPOT_DIRECTION, direction); - } - else if (light.type == LIGHT_DIRECTIONAL) - { - GLfloat position[4] = { -light.direction.x, -light.direction.y, -light.direction.z, 0.0f }; - glLightfv(GL_LIGHT0 + index, GL_POSITION, position); - } - } - - glPopMatrix(); -} - -void CGL14Device::UpdateLightPositions() -{ - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - - // update spotlights and directional lights - glLoadIdentity(); - glScalef(1.0f, 1.0f, -1.0f); - Math::Matrix mat = m_viewMat; - mat.Set(1, 4, 0.0f); - mat.Set(2, 4, 0.0f); - mat.Set(3, 4, 0.0f); - glMultMatrixf(mat.Array()); - - int lightIndex = 0; - - for (const Light &light : m_lights) - { - if (m_lightsEnabled[lightIndex]) - { - if (light.type == LIGHT_SPOT) - { - GLfloat direction[4] = { -light.direction.x, -light.direction.y, -light.direction.z, 1.0f }; - glLightfv(GL_LIGHT0 + lightIndex, GL_SPOT_DIRECTION, direction); - } - else if (light.type == LIGHT_DIRECTIONAL) - { - GLfloat position[4] = { -light.direction.x, -light.direction.y, -light.direction.z, 0.0f }; - glLightfv(GL_LIGHT0 + lightIndex, GL_POSITION, position); - } - } - - lightIndex++; - } - - // update point lights - glLoadIdentity(); - glScalef(1.0f, 1.0f, -1.0f); - glMultMatrixf(m_viewMat.Array()); - - lightIndex = 0; - - for (const Light &light : m_lights) - { - if (m_lightsEnabled[lightIndex]) - { - if (light.type == LIGHT_POINT) - { - GLfloat position[4] = { light.position.x, light.position.y, light.position.z, 1.0f }; - glLightfv(GL_LIGHT0 + lightIndex, GL_POSITION, position); - } - } - - lightIndex++; - } - - glPopMatrix(); -} - -void CGL14Device::SetLightEnabled(int index, bool enabled) -{ - assert(index >= 0); - assert(index < static_cast( m_lights.size() )); - - m_lightsEnabled[index] = enabled; - - if (enabled) - glEnable(GL_LIGHT0 + index); - else - glDisable(GL_LIGHT0 + index); -} - -/** If image is invalid, returns invalid texture. - Otherwise, returns pointer to new Texture struct. - This struct must not be deleted in other way than through DeleteTexture() */ -Texture CGL14Device::CreateTexture(CImage *image, const TextureCreateParams ¶ms) -{ - ImageData *data = image->GetData(); - if (data == nullptr) - { - GetLogger()->Error("Invalid texture data\n"); - return Texture(); // invalid texture - } - - Math::IntPoint originalSize = image->GetSize(); - - if (params.padToNearestPowerOfTwo) - image->PadToNearestPowerOfTwo(); - - Texture tex = CreateTexture(data, params); - tex.originalSize = originalSize; - - return tex; -} - -Texture CGL14Device::CreateTexture(ImageData *data, const TextureCreateParams ¶ms) -{ - Texture result; - - result.size.x = data->surface->w; - result.size.y = data->surface->h; - - if (!Math::IsPowerOfTwo(result.size.x) || !Math::IsPowerOfTwo(result.size.y)) - GetLogger()->Warn("Creating non-power-of-2 texture (%dx%d)!\n", result.size.x, result.size.y); - - result.originalSize = result.size; - - // Use & enable 1st texture stage - glActiveTexture(GL_TEXTURE0 + m_remap[0]); - - glEnable(GL_TEXTURE_2D); - - glGenTextures(1, &result.id); - glBindTexture(GL_TEXTURE_2D, result.id); - - // Set texture parameters - GLint minF = GL_NEAREST, magF = GL_NEAREST; - int mipmapLevel = 1; - - switch (params.filter) - { - case TEX_FILTER_NEAREST: - minF = GL_NEAREST; - magF = GL_NEAREST; - break; - case TEX_FILTER_BILINEAR: - minF = GL_LINEAR; - magF = GL_LINEAR; - break; - case TEX_FILTER_TRILINEAR: - minF = GL_LINEAR_MIPMAP_LINEAR; - magF = GL_LINEAR; - mipmapLevel = CEngine::GetInstance().GetTextureMipmapLevel(); - break; - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minF); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magF); - - // Set mipmap level and automatic mipmap generation if neccesary - if (params.mipmap) - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmapLevel - 1); - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); - } - else - { - // Has to be set to 0 because no mipmaps are generated - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE); - } - - // Set anisotropy level if available - if (m_capabilities.anisotropySupported) - { - float level = Math::Min(m_capabilities.maxAnisotropy, CEngine::GetInstance().GetTextureAnisotropyLevel()); - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, level); - } - - PreparedTextureData texData = PrepareTextureData(data, params.format); - result.alpha = texData.alpha; - - glPixelStorei(GL_UNPACK_ROW_LENGTH, texData.actualSurface->pitch / texData.actualSurface->format->BytesPerPixel); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texData.actualSurface->w, texData.actualSurface->h, - 0, texData.sourceFormat, GL_UNSIGNED_BYTE, texData.actualSurface->pixels); - - SDL_FreeSurface(texData.convertedSurface); - - m_allTextures.insert(result); - - // Restore the previous state of 1st stage - glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id); - - if (! m_texturesEnabled[0]) - glDisable(GL_TEXTURE_2D); - - return result; -} - -Texture CGL14Device::CreateDepthTexture(int width, int height, int depth) -{ - Texture result; - - if (m_shadowMappingSupport == SMS_NONE) - { - result.id = 0; - return result; - } - - result.alpha = false; - result.size.x = width; - result.size.y = height; - - // Use & enable 1st texture stage - glActiveTexture(GL_TEXTURE0 + m_remap[0]); - - glGenTextures(1, &result.id); - glBindTexture(GL_TEXTURE_2D, result.id); - - GLuint format = GL_DEPTH_COMPONENT; - - switch (depth) - { - case 16: - format = GL_DEPTH_COMPONENT16; - break; - case 24: - format = GL_DEPTH_COMPONENT24; - break; - case 32: - format = GL_DEPTH_COMPONENT32; - break; - } - - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_INT, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - - float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color); - - glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id); - - return result; -} - -void CGL14Device::UpdateTexture(const Texture& texture, Math::IntPoint offset, ImageData* data, TexImgFormat format) -{ - // Use & enable 1st texture stage - glActiveTexture(GL_TEXTURE0 + m_remap[0]); - - glEnable(GL_TEXTURE_2D); - - glBindTexture(GL_TEXTURE_2D, texture.id); - - PreparedTextureData texData = PrepareTextureData(data, format); - - glPixelStorei(GL_UNPACK_ROW_LENGTH, texData.actualSurface->pitch / texData.actualSurface->format->BytesPerPixel); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - glTexSubImage2D(GL_TEXTURE_2D, 0, offset.x, offset.y, texData.actualSurface->w, texData.actualSurface->h, - texData.sourceFormat, GL_UNSIGNED_BYTE, texData.actualSurface->pixels); - - SDL_FreeSurface(texData.convertedSurface); -} - -void CGL14Device::DestroyTexture(const Texture &texture) -{ - // Unbind the texture if in use anywhere - for (int index = 0; index < static_cast( m_currentTextures.size() ); ++index) - { - if (m_currentTextures[index] == texture) - SetTexture(index, Texture()); // set to invalid texture - } - - auto it = m_allTextures.find(texture); - if (it != m_allTextures.end()) - { - glDeleteTextures(1, &texture.id); - m_allTextures.erase(it); - } -} - -void CGL14Device::DestroyAllTextures() -{ - // Unbind all texture stages - for (int index = 0; index < static_cast( m_currentTextures.size() ); ++index) - SetTexture(index, Texture()); - - for (auto it = m_allTextures.begin(); it != m_allTextures.end(); ++it) - glDeleteTextures(1, &(*it).id); - - m_allTextures.clear(); - - // recreate white texture - glActiveTexture(GL_TEXTURE0 + m_remap[0]); - - glDeleteTextures(1, &m_whiteTexture); - glGenTextures(1, &m_whiteTexture); - glBindTexture(GL_TEXTURE_2D, m_whiteTexture); - int color = 0xFFFFFFFF; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &color); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id); -} - -int CGL14Device::GetMaxTextureStageCount() -{ - return m_currentTextures.size(); -} - -/** - If \a texture is invalid, unbinds the given texture. - If valid, binds the texture and enables the given texture stage. - The setting is remembered, even if texturing is disabled at the moment. */ -void CGL14Device::SetTexture(int index, const Texture &texture) -{ - assert(index >= 0 && index < static_cast( m_currentTextures.size() )); - - bool same = m_currentTextures[index].id == texture.id; - - m_currentTextures[index] = texture; // remember the new value - - if (same) - return; // nothing to do - - glActiveTexture(GL_TEXTURE0 + m_remap[index]); - - glBindTexture(GL_TEXTURE_2D, texture.id); - - // Params need to be updated for the new bound texture - UpdateTextureParams(index); -} - -void CGL14Device::SetTexture(int index, unsigned int textureId) -{ - assert(index >= 0 && index < static_cast(m_currentTextures.size())); - - if (m_currentTextures[index].id == textureId) - return; // nothing to do - - m_currentTextures[index].id = textureId; - - glActiveTexture(GL_TEXTURE0 + m_remap[index]); - - glBindTexture(GL_TEXTURE_2D, textureId); - - // Params need to be updated for the new bound texture - UpdateTextureParams(index); -} - -void CGL14Device::SetTextureEnabled(int index, bool enabled) -{ - assert(index >= 0 && index < static_cast(m_currentTextures.size())); - - bool same = m_texturesEnabled[index] == enabled; - - m_texturesEnabled[index] = enabled; - - if (same) - return; // nothing to do - - glActiveTexture(GL_TEXTURE0 + m_remap[index]); - - if (enabled) - glEnable(GL_TEXTURE_2D); - else - glDisable(GL_TEXTURE_2D); -} - -/** - Sets the texture parameters for the given texture stage. - If the given texture was not set (bound) yet, nothing happens. - The settings are remembered, even if texturing is disabled at the moment. */ -void CGL14Device::SetTextureStageParams(int index, const TextureStageParams ¶ms) -{ - assert(index >= 0 && index < static_cast(m_currentTextures.size())); - - // Remember the settings - m_textureStageParams[index] = params; - - UpdateTextureParams(index); -} - -void CGL14Device::UpdateTextureParams(int index) -{ - assert(index >= 0 && index < static_cast(m_currentTextures.size())); - - // Don't actually do anything if texture not set - if (! m_currentTextures[index].Valid()) - return; - - const TextureStageParams ¶ms = m_textureStageParams[index]; - - glActiveTexture(GL_TEXTURE0 + m_remap[index]); - - if (params.wrapS == TEX_WRAP_CLAMP) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - else if (params.wrapS == TEX_WRAP_CLAMP_TO_BORDER) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - else if (params.wrapS == TEX_WRAP_REPEAT) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - else assert(false); - - if (params.wrapT == TEX_WRAP_CLAMP) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - else if (params.wrapT == TEX_WRAP_CLAMP_TO_BORDER) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - else if (params.wrapT == TEX_WRAP_REPEAT) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - else assert(false); - - glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, params.factor.Array()); - - // To save some trouble - if ( (params.colorOperation == TEX_MIX_OPER_DEFAULT) && - (params.alphaOperation == TEX_MIX_OPER_DEFAULT) ) - { - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - goto after_tex_operations; - } - - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - - // Only these modes of getting color & alpha are used - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); - - // Color operation - - if (params.colorOperation == TEX_MIX_OPER_DEFAULT) - { - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); - goto after_tex_color; - } - else if (params.colorOperation == TEX_MIX_OPER_REPLACE) - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE); - else if (params.colorOperation == TEX_MIX_OPER_MODULATE) - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); - else if (params.colorOperation == TEX_MIX_OPER_ADD) - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD); - else if (params.colorOperation == TEX_MIX_OPER_SUBTRACT) - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_SUBTRACT); - else assert(false); - - // Color arg1 - if (params.colorArg1 == TEX_MIX_ARG_TEXTURE) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE); - else if (params.colorArg1 == TEX_MIX_ARG_TEXTURE_0) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE0); - else if (params.colorArg1 == TEX_MIX_ARG_TEXTURE_1) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE1); - else if (params.colorArg1 == TEX_MIX_ARG_TEXTURE_2) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE2); - else if (params.colorArg1 == TEX_MIX_ARG_TEXTURE_3) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE3); - else if (params.colorArg1 == TEX_MIX_ARG_COMPUTED_COLOR) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); - else if (params.colorArg1 == TEX_MIX_ARG_SRC_COLOR) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR); - else if (params.colorArg1 == TEX_MIX_ARG_FACTOR) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_CONSTANT); - else assert(false); - - // Color arg2 - if (params.colorArg2 == TEX_MIX_ARG_TEXTURE) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE); - else if (params.colorArg2 == TEX_MIX_ARG_TEXTURE_0) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE0); - else if (params.colorArg2 == TEX_MIX_ARG_TEXTURE_1) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE1); - else if (params.colorArg2 == TEX_MIX_ARG_TEXTURE_2) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE2); - else if (params.colorArg2 == TEX_MIX_ARG_TEXTURE_3) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE3); - else if (params.colorArg2 == TEX_MIX_ARG_COMPUTED_COLOR) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PREVIOUS); - else if (params.colorArg2 == TEX_MIX_ARG_SRC_COLOR) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR); - else if (params.colorArg2 == TEX_MIX_ARG_FACTOR) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT); - else assert(false); - - -after_tex_color: - - // Alpha operation - if (params.alphaOperation == TEX_MIX_OPER_DEFAULT) - { - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE); - goto after_tex_operations; - } - else if (params.alphaOperation == TEX_MIX_OPER_REPLACE) - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); - else if (params.alphaOperation == TEX_MIX_OPER_MODULATE) - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); - else if (params.alphaOperation == TEX_MIX_OPER_ADD) - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD); - else if (params.alphaOperation == TEX_MIX_OPER_SUBTRACT) - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_SUBTRACT); - else assert(false); - - // Alpha arg1 - if (params.alphaArg1 == TEX_MIX_ARG_TEXTURE) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE); - else if (params.alphaArg1 == TEX_MIX_ARG_TEXTURE_0) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE0); - else if (params.alphaArg1 == TEX_MIX_ARG_TEXTURE_1) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE1); - else if (params.alphaArg1 == TEX_MIX_ARG_TEXTURE_2) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE2); - else if (params.alphaArg1 == TEX_MIX_ARG_TEXTURE_3) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE3); - else if (params.alphaArg1 == TEX_MIX_ARG_COMPUTED_COLOR) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); - else if (params.alphaArg1 == TEX_MIX_ARG_SRC_COLOR) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR); - else if (params.alphaArg1 == TEX_MIX_ARG_FACTOR) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_CONSTANT); - else assert(false); - - // Alpha arg2 - if (params.alphaArg2 == TEX_MIX_ARG_TEXTURE) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE); - else if (params.alphaArg2 == TEX_MIX_ARG_TEXTURE_0) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE0); - else if (params.alphaArg2 == TEX_MIX_ARG_TEXTURE_1) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE1); - else if (params.alphaArg2 == TEX_MIX_ARG_TEXTURE_2) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE2); - else if (params.alphaArg2 == TEX_MIX_ARG_TEXTURE_3) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE3); - else if (params.alphaArg2 == TEX_MIX_ARG_COMPUTED_COLOR) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PREVIOUS); - else if (params.alphaArg2 == TEX_MIX_ARG_SRC_COLOR) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR); - else if (params.alphaArg2 == TEX_MIX_ARG_FACTOR) - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_CONSTANT); - else assert(false); - -after_tex_operations: ; -} - -void CGL14Device::EnableShadows() -{ - // already enabled - if (m_shadowMapping) return; - - // shadow map unit - glActiveTexture(GL_TEXTURE0 + m_remap[2]); - glEnable(GL_TEXTURE_2D); - - glMatrixMode(GL_TEXTURE); - glLoadMatrixf(m_shadowMatrix.Array()); - - // enable texture coordinate generation - glEnable(GL_TEXTURE_GEN_S); - glEnable(GL_TEXTURE_GEN_T); - glEnable(GL_TEXTURE_GEN_R); - glEnable(GL_TEXTURE_GEN_Q); - - glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); - glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); - glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); - glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR); - - float plane1[] = { 1.0f, 0.0f, 0.0f, 0.0f }; - float plane2[] = { 0.0f, 1.0f, 0.0f, 0.0f }; - float plane3[] = { 0.0f, 0.0f, 1.0f, 0.0f }; - float plane4[] = { 0.0f, 0.0f, 0.0f, 1.0f }; - - glTexGenfv(GL_S, GL_EYE_PLANE, plane1); - glTexGenfv(GL_T, GL_EYE_PLANE, plane2); - glTexGenfv(GL_R, GL_EYE_PLANE, plane3); - glTexGenfv(GL_Q, GL_EYE_PLANE, plane4); - - // simple shadows - if (!m_shadowQuality) - { - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - } - // quality shadows - else - { - // texture environment settings - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - - float half[] = { 0.5f, 0.5f, 0.5f, 1.0f }; - glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, half); - - // color = 0.5 * (1.0 - shadow) - // = 0.5 for shadow = 0.0 - // = 0.0 for shadow = 1.0 - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); - - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR); - - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_CONSTANT); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); - - // alpha = previous - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); - - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - - - // combine unit - glActiveTexture(GL_TEXTURE0 + m_remap[3]); - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, m_whiteTexture); - - // texture enviromnent settings - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); - - // color = (1.0 - previous) * primary color - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); - - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR); - - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_PRIMARY_COLOR); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); - - // alpha = primary color - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); - - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PRIMARY_COLOR); - glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); - } - - m_shadowMapping = true; -} - -void CGL14Device::DisableShadows() -{ - // already disabled - if (!m_shadowMapping) return; - - glActiveTexture(GL_TEXTURE0 + m_remap[2]); - glDisable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); - - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - glDisable(GL_TEXTURE_GEN_R); - glDisable(GL_TEXTURE_GEN_Q); - - // quality shadows - if (m_shadowQuality) - { - glActiveTexture(GL_TEXTURE0 + m_remap[3]); - glDisable(GL_TEXTURE_2D); - } - - m_shadowMapping = false; -} - -void CGL14Device::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode wrapT) -{ - assert(index >= 0 && index < static_cast( m_currentTextures.size() )); - - // Remember the settings - m_textureStageParams[index].wrapS = wrapS; - m_textureStageParams[index].wrapT = wrapT; - - // Don't actually do anything if texture not set - if (! m_currentTextures[index].Valid()) - return; - - glActiveTexture(GL_TEXTURE0 + m_remap[index]); - - if (wrapS == TEX_WRAP_CLAMP) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - else if (wrapS == TEX_WRAP_CLAMP_TO_BORDER) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - else if (wrapS == TEX_WRAP_REPEAT) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - else assert(false); - - if (wrapT == TEX_WRAP_CLAMP) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - else if (wrapT == TEX_WRAP_CLAMP_TO_BORDER) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - else if (wrapT == TEX_WRAP_REPEAT) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - else assert(false); -} - -namespace -{ -void SetVertexAttributes(const Vertex* bufferBase, const std::vector& textureRemapping) -{ - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(Vertex), reinterpret_cast(bufferBase) + offsetof(Vertex, coord)); - - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, sizeof(Vertex), reinterpret_cast(bufferBase) + offsetof(Vertex, normal)); - - glClientActiveTexture(GL_TEXTURE0 + textureRemapping[1]); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTexture(GL_TEXTURE0 + textureRemapping[0]); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), reinterpret_cast(bufferBase) + offsetof(Vertex, texCoord)); - - glDisableClientState(GL_COLOR_ARRAY); -} - -void SetVertexAttributes(const VertexTex2* bufferBase, const std::vector& textureRemapping) -{ - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(bufferBase) + offsetof(VertexTex2, coord)); - - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(bufferBase) + offsetof(VertexTex2, normal)); - - glClientActiveTexture(GL_TEXTURE0 + textureRemapping[1]); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(bufferBase) + offsetof(VertexTex2, texCoord2)); - glClientActiveTexture(GL_TEXTURE0 + textureRemapping[0]); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(bufferBase) + offsetof(VertexTex2, texCoord)); - - glDisableClientState(GL_COLOR_ARRAY); -} - -void SetVertexAttributes(const VertexCol* bufferBase, const std::vector& textureRemapping) -{ - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(VertexCol), reinterpret_cast(bufferBase) + offsetof(VertexCol, coord)); - - glDisableClientState(GL_NORMAL_ARRAY); - - glClientActiveTexture(GL_TEXTURE0 + textureRemapping[1]); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTexture(GL_TEXTURE0 + textureRemapping[0]); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(4, GL_FLOAT, sizeof(VertexCol), reinterpret_cast(bufferBase) + offsetof(VertexCol, color)); -} -} // namespace - -void CGL14Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int vertexCount, - Color color) -{ - m_glBindBuffer(GL_ARRAY_BUFFER, 0); - SetVertexAttributes(vertices, m_remap); - glColor4fv(color.Array()); - - glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); -} - -void CGL14Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, - Color color) -{ - m_glBindBuffer(GL_ARRAY_BUFFER, 0); - SetVertexAttributes(vertices, m_remap); - glColor4fv(color.Array()); - - glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); -} - -void CGL14Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount) -{ - m_glBindBuffer(GL_ARRAY_BUFFER, 0); - SetVertexAttributes(vertices, m_remap); - - glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); -} - -void CGL14Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices, - int first[], int count[], int drawCount, Color color) -{ - m_glBindBuffer(GL_ARRAY_BUFFER, 0); - SetVertexAttributes(vertices, m_remap); - glColor4fv(color.Array()); - - GLenum t = TranslateGfxPrimitive(type); - - if (m_multiDrawArrays) - { - glMultiDrawArrays(t, first, count, drawCount); - } - else - { - for (int i = 0; i < drawCount; i++) - glDrawArrays(t, first[i], count[i]); - } -} - -void CGL14Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices, - int first[], int count[], int drawCount, Color color) -{ - m_glBindBuffer(GL_ARRAY_BUFFER, 0); - SetVertexAttributes(vertices, m_remap); - glColor4fv(color.Array()); - - GLenum t = TranslateGfxPrimitive(type); - - if (m_multiDrawArrays) - { - glMultiDrawArrays(t, first, count, drawCount); - } - else - { - for (int i = 0; i < drawCount; i++) - glDrawArrays(t, first[i], count[i]); - } -} - -void CGL14Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices, - int first[], int count[], int drawCount) -{ - m_glBindBuffer(GL_ARRAY_BUFFER, 0); - SetVertexAttributes(vertices, m_remap); - - GLenum t = TranslateGfxPrimitive(type); - - if (m_multiDrawArrays) - { - glMultiDrawArrays(t, first, count, drawCount); - } - else - { - for (int i = 0; i < drawCount; i++) - glDrawArrays(t, first[i], count[i]); - } -} - -template -unsigned int CGL14Device::CreateStaticBufferImpl(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) -{ - unsigned int id = ++m_lastVboId; - - VboObjectInfo info; - info.primitiveType = primitiveType; - info.vertexType = Vertex::VERTEX_TYPE; - info.vertexCount = vertexCount; - info.bufferId = 0; - - m_glGenBuffers(1, &info.bufferId); - m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); - m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW); - m_glBindBuffer(GL_ARRAY_BUFFER, 0); - - m_vboObjects[id] = info; - - return id; -} - -template -void CGL14Device::UpdateStaticBufferImpl(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) -{ - auto it = m_vboObjects.find(bufferId); - if (it == m_vboObjects.end()) - return; - - VboObjectInfo& info = (*it).second; - info.primitiveType = primitiveType; - info.vertexType = Vertex::VERTEX_TYPE; - info.vertexCount = vertexCount; - - m_glBindBuffer(GL_ARRAY_BUFFER, info.bufferId); - m_glBufferData(GL_ARRAY_BUFFER, vertexCount * sizeof(Vertex), vertices, GL_STATIC_DRAW); - m_glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -void CGL14Device::DrawStaticBuffer(unsigned int bufferId) -{ - auto it = m_vboObjects.find(bufferId); - if (it == m_vboObjects.end()) - return; - - m_glBindBuffer(GL_ARRAY_BUFFER, (*it).second.bufferId); - - if ((*it).second.vertexType == VERTEX_TYPE_NORMAL) - { - SetVertexAttributes(static_cast(nullptr), m_remap); - } - else if ((*it).second.vertexType == VERTEX_TYPE_TEX2) - { - SetVertexAttributes(static_cast(nullptr), m_remap); - } - else if ((*it).second.vertexType == VERTEX_TYPE_COL) - { - SetVertexAttributes(static_cast(nullptr), m_remap); - } - - GLenum mode = TranslateGfxPrimitive((*it).second.primitiveType); - - glDrawArrays(mode, 0, (*it).second.vertexCount); -} - -void CGL14Device::DestroyStaticBuffer(unsigned int bufferId) -{ - auto it = m_vboObjects.find(bufferId); - if (it == m_vboObjects.end()) - return; - - m_glDeleteBuffers(1, &(*it).second.bufferId); - - m_vboObjects.erase(it); -} - -/* Based on libwine's implementation */ - -int CGL14Device::ComputeSphereVisibility(const Math::Vector ¢er, float radius) -{ - if (m_combinedMatrixOutdated) - { - m_combinedMatrix = Math::MultiplyMatrices(m_projectionMat, m_modelviewMat); - m_combinedMatrixOutdated = false; - } - - Math::Matrix &m = m_combinedMatrix; - - Math::Vector vec[6]; - float originPlane[6]; - - // Left plane - vec[0].x = m.Get(4, 1) + m.Get(1, 1); - vec[0].y = m.Get(4, 2) + m.Get(1, 2); - vec[0].z = m.Get(4, 3) + m.Get(1, 3); - float l1 = vec[0].Length(); - vec[0].Normalize(); - originPlane[0] = (m.Get(4, 4) + m.Get(1, 4)) / l1; - - // Right plane - vec[1].x = m.Get(4, 1) - m.Get(1, 1); - vec[1].y = m.Get(4, 2) - m.Get(1, 2); - vec[1].z = m.Get(4, 3) - m.Get(1, 3); - float l2 = vec[1].Length(); - vec[1].Normalize(); - originPlane[1] = (m.Get(4, 4) - m.Get(1, 4)) / l2; - - // Bottom plane - vec[2].x = m.Get(4, 1) + m.Get(2, 1); - vec[2].y = m.Get(4, 2) + m.Get(2, 2); - vec[2].z = m.Get(4, 3) + m.Get(2, 3); - float l3 = vec[2].Length(); - vec[2].Normalize(); - originPlane[2] = (m.Get(4, 4) + m.Get(2, 4)) / l3; - - // Top plane - vec[3].x = m.Get(4, 1) - m.Get(2, 1); - vec[3].y = m.Get(4, 2) - m.Get(2, 2); - vec[3].z = m.Get(4, 3) - m.Get(2, 3); - float l4 = vec[3].Length(); - vec[3].Normalize(); - originPlane[3] = (m.Get(4, 4) - m.Get(2, 4)) / l4; - - // Front plane - vec[4].x = m.Get(4, 1) + m.Get(3, 1); - vec[4].y = m.Get(4, 2) + m.Get(3, 2); - vec[4].z = m.Get(4, 3) + m.Get(3, 3); - float l5 = vec[4].Length(); - vec[4].Normalize(); - originPlane[4] = (m.Get(4, 4) + m.Get(3, 4)) / l5; - - // Back plane - vec[5].x = m.Get(4, 1) - m.Get(3, 1); - vec[5].y = m.Get(4, 2) - m.Get(3, 2); - vec[5].z = m.Get(4, 3) - m.Get(3, 3); - float l6 = vec[5].Length(); - vec[5].Normalize(); - originPlane[5] = (m.Get(4, 4) - m.Get(3, 4)) / l6; - - int result = 0; - - if (InPlane(vec[0], originPlane[0], center, radius)) - result |= FRUSTUM_PLANE_LEFT; - if (InPlane(vec[1], originPlane[1], center, radius)) - result |= FRUSTUM_PLANE_RIGHT; - if (InPlane(vec[2], originPlane[2], center, radius)) - result |= FRUSTUM_PLANE_BOTTOM; - if (InPlane(vec[3], originPlane[3], center, radius)) - result |= FRUSTUM_PLANE_TOP; - if (InPlane(vec[4], originPlane[4], center, radius)) - result |= FRUSTUM_PLANE_FRONT; - if (InPlane(vec[5], originPlane[5], center, radius)) - result |= FRUSTUM_PLANE_BACK; - - return result; -} - -void CGL14Device::SetViewport(int x, int y, int width, int height) -{ - glViewport(x, y, width, height); -} - -void CGL14Device::SetRenderState(RenderState state, bool enabled) -{ - if (state == RENDER_STATE_DEPTH_WRITE) - { - glDepthMask(enabled ? GL_TRUE : GL_FALSE); - return; - } - else if (state == RENDER_STATE_LIGHTING) - { - m_lighting = enabled; - - if (enabled) - glEnable(GL_LIGHTING); - else - glDisable(GL_LIGHTING); - - if (enabled) - { - UpdateLightPositions(); - } - - return; - } - else if (state == RENDER_STATE_SHADOW_MAPPING) - { - if (enabled) - EnableShadows(); - else - DisableShadows(); - - return; - } - - GLenum flag = 0; - - switch (state) - { - case RENDER_STATE_BLENDING: flag = GL_BLEND; break; - case RENDER_STATE_FOG: flag = GL_FOG; break; - case RENDER_STATE_DEPTH_TEST: flag = GL_DEPTH_TEST; break; - case RENDER_STATE_ALPHA_TEST: flag = GL_ALPHA_TEST; break; - case RENDER_STATE_CULLING: flag = GL_CULL_FACE; break; - case RENDER_STATE_DEPTH_BIAS: flag = GL_POLYGON_OFFSET_FILL; break; - default: assert(false); break; - } - - if (enabled) - glEnable(flag); - else - glDisable(flag); -} - -void CGL14Device::SetColorMask(bool red, bool green, bool blue, bool alpha) -{ - glColorMask(red, green, blue, alpha); -} - -void CGL14Device::SetDepthTestFunc(CompFunc func) -{ - glDepthFunc(TranslateGfxCompFunc(func)); -} - -void CGL14Device::SetDepthBias(float factor, float units) -{ - glPolygonOffset(factor, units); -} - -void CGL14Device::SetAlphaTestFunc(CompFunc func, float refValue) -{ - glAlphaFunc(TranslateGfxCompFunc(func), refValue); -} - -void CGL14Device::SetBlendFunc(BlendFunc srcBlend, BlendFunc dstBlend) -{ - glBlendFunc(TranslateGfxBlendFunc(srcBlend), TranslateGfxBlendFunc(dstBlend)); -} - -void CGL14Device::SetClearColor(const Color &color) -{ - glClearColor(color.r, color.g, color.b, color.a); -} - -void CGL14Device::SetGlobalAmbient(const Color &color) -{ - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, color.Array()); -} - -void CGL14Device::SetFogParams(FogMode mode, const Color &color, float start, float end, float density) -{ - if (mode == FOG_LINEAR) glFogi(GL_FOG_MODE, GL_LINEAR); - else if (mode == FOG_EXP) glFogi(GL_FOG_MODE, GL_EXP); - else if (mode == FOG_EXP2) glFogi(GL_FOG_MODE, GL_EXP2); - else assert(false); - - glFogf(GL_FOG_START, start); - glFogf(GL_FOG_END, end); - glFogf(GL_FOG_DENSITY, density); - glFogfv(GL_FOG_COLOR, color.Array()); -} - -void CGL14Device::SetCullMode(CullMode mode) -{ - // Cull clockwise back faces, so front face is the opposite - // (assuming GL_CULL_FACE is GL_BACK) - if (mode == CULL_CW ) glFrontFace(GL_CCW); - else if (mode == CULL_CCW) glFrontFace(GL_CW); - else assert(false); -} - -void CGL14Device::SetShadeModel(ShadeModel model) -{ - if (model == SHADE_FLAT) glShadeModel(GL_FLAT); - else if (model == SHADE_SMOOTH) glShadeModel(GL_SMOOTH); - else assert(false); -} - -void CGL14Device::SetShadowColor(float value) -{ - // doesn't do anything because it can't -} - -void CGL14Device::SetFillMode(FillMode mode) -{ - if (mode == FILL_POINT) glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); - else if (mode == FILL_LINES) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - else if (mode == FILL_POLY) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - else assert(false); -} - -void CGL14Device::CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height) -{ - if (texture.id == 0) return; - - // Use & enable 1st texture stage - glActiveTexture(GL_TEXTURE0 + m_remap[0]); - - glBindTexture(GL_TEXTURE_2D, texture.id); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, x, y, width, height); - - // Restore previous texture - glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id); -} - -std::unique_ptr CGL14Device::GetFrameBufferPixels() const -{ - return GetGLFrameBufferPixels(m_config.size); -} - -CFramebuffer* CGL14Device::GetFramebuffer(std::string name) -{ - auto it = m_framebuffers.find(name); - if (it == m_framebuffers.end()) - return nullptr; - - return it->second.get(); -} - -CFramebuffer* CGL14Device::CreateFramebuffer(std::string name, const FramebufferParams& params) -{ - // existing framebuffer was found - if (m_framebuffers.find(name) != m_framebuffers.end()) - { - return nullptr; - } - - std::unique_ptr framebuffer; - - if (m_framebufferSupport == FBS_ARB) - framebuffer = MakeUnique(params); - else if (m_framebufferSupport == FBS_EXT) - framebuffer = MakeUnique(params); - else - return nullptr; - - if (!framebuffer->Create()) return nullptr; - - CFramebuffer* framebufferPtr = framebuffer.get(); - m_framebuffers[name] = std::move(framebuffer); - return framebufferPtr; -} - -void CGL14Device::DeleteFramebuffer(std::string name) -{ - // can't delete default framebuffer - if (name == "default") return; - - auto it = m_framebuffers.find(name); - if (it != m_framebuffers.end()) - { - it->second->Destroy(); - m_framebuffers.erase(it); - } -} - -bool CGL14Device::IsAnisotropySupported() -{ - return m_capabilities.anisotropySupported; -} - -int CGL14Device::GetMaxAnisotropyLevel() -{ - return m_capabilities.maxAnisotropy; -} - -int CGL14Device::GetMaxSamples() -{ - return m_capabilities.maxSamples; -} - -bool CGL14Device::IsShadowMappingSupported() -{ - return m_capabilities.shadowMappingSupported; -} - -int CGL14Device::GetMaxTextureSize() -{ - return m_capabilities.maxTextureSize; -} - -bool CGL14Device::IsFramebufferSupported() -{ - return m_capabilities.framebufferSupported; -} - -} // namespace Gfx diff --git a/src/graphics/opengl/gl14device.h b/src/graphics/opengl/gl14device.h deleted file mode 100644 index f0e7e950..00000000 --- a/src/graphics/opengl/gl14device.h +++ /dev/null @@ -1,307 +0,0 @@ -/* - * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2020, 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/opengl/gl14device.h - * \brief OpenGL implementation - CGL14Device class - */ - -#pragma once - -#include "graphics/core/device.h" - -#include "graphics/core/material.h" - -#include "graphics/opengl/glframebuffer.h" -#include "graphics/opengl/glutil.h" - -#include "math/matrix.h" - -#include -#include -#include -#include - - -// Graphics module namespace -namespace Gfx -{ - -enum ShadowMappingSupport -{ - SMS_NONE, //! No support for depth textures - SMS_ARB, //! ARB extension - SMS_CORE //! Core support -}; - -/** - \class CGL14Device - \brief Implementation of CDevice interface in OpenGL - - Provides the concrete implementation of 3D device in OpenGL. - - This class should be initialized (by calling Initialize() ) only after - setting the video mode by CApplication, once the OpenGL context is defined. - Because of that, CGL14DeviceConfig is outside the CDevice class and must be set - in CApplication. -*/ -class CGL14Device : public CDevice -{ -public: - CGL14Device(const DeviceConfig &config); - virtual ~CGL14Device(); - - void DebugHook() override; - void DebugLights() override; - - std::string GetName() override; - - bool Create() override; - void Destroy() override; - - void ConfigChanged(const DeviceConfig &newConfig) override; - - void BeginScene() override; - void EndScene() override; - - void Clear() override; - - void SetRenderMode(RenderMode mode) override; - - void SetTransform(TransformType type, const Math::Matrix &matrix) override; - - void SetMaterial(const Material &material) override; - - int GetMaxLightCount() override; - void SetLight(int index, const Light &light) override; - void SetLightEnabled(int index, bool enabled) override; - - Texture CreateTexture(CImage *image, const TextureCreateParams ¶ms) override; - Texture CreateTexture(ImageData *data, const TextureCreateParams ¶ms) override; - Texture CreateDepthTexture(int width, int height, int depth) override; - void UpdateTexture(const Texture& texture, Math::IntPoint offset, ImageData* data, TexImgFormat format) override; - void DestroyTexture(const Texture &texture) override; - void DestroyAllTextures() override; - - int GetMaxTextureStageCount() override; - void SetTexture(int index, const Texture &texture) override; - void SetTexture(int index, unsigned int textureId) override; - void SetTextureEnabled(int index, bool enabled) override; - - void SetTextureStageParams(int index, const TextureStageParams ¶ms) override; - - void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override; - - virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount, - Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; - virtual void DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, - Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; - virtual void DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount) override; - - virtual void DrawPrimitives(PrimitiveType type, const Vertex *vertices, - int first[], int count[], int drawCount, - Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; - virtual void DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices, - int first[], int count[], int drawCount, - Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; - virtual void DrawPrimitives(PrimitiveType type, const VertexCol *vertices, - int first[], int count[], int drawCount) override; - - unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) override - { - return CreateStaticBufferImpl(primitiveType, vertices, vertexCount); - } - unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) override - { - return CreateStaticBufferImpl(primitiveType, vertices, vertexCount); - } - unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) override - { - return CreateStaticBufferImpl(primitiveType, vertices, vertexCount); - } - void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) override - { - UpdateStaticBufferImpl(bufferId, primitiveType, vertices, vertexCount); - } - void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) override - { - UpdateStaticBufferImpl(bufferId, primitiveType, vertices, vertexCount); - } - void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) override - { - UpdateStaticBufferImpl(bufferId, primitiveType, vertices, vertexCount); - } - - void DrawStaticBuffer(unsigned int bufferId) override; - void DestroyStaticBuffer(unsigned int bufferId) override; - - int ComputeSphereVisibility(const Math::Vector ¢er, float radius) override; - - void SetViewport(int x, int y, int width, int height) override; - - void SetRenderState(RenderState state, bool enabled) override; - - void SetColorMask(bool red, bool green, bool blue, bool alpha) override; - - void SetDepthTestFunc(CompFunc func) override; - - void SetDepthBias(float factor, float units) override; - - void SetAlphaTestFunc(CompFunc func, float refValue) override; - - void SetBlendFunc(BlendFunc srcBlend, BlendFunc dstBlend) override; - - void SetClearColor(const Color &color) override; - - void SetGlobalAmbient(const Color &color) override; - - void SetFogParams(FogMode mode, const Color &color, float start, float end, float density) override; - - void SetCullMode(CullMode mode) override; - - void SetShadeModel(ShadeModel model) override; - - void SetShadowColor(float value) override; - - void SetFillMode(FillMode mode) override; - - void CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height) override; - - std::unique_ptr GetFrameBufferPixels() const override; - - CFramebuffer* GetFramebuffer(std::string name) override; - - CFramebuffer* CreateFramebuffer(std::string name, const FramebufferParams& params) override; - - void DeleteFramebuffer(std::string name) override; - - bool IsAnisotropySupported() override; - int GetMaxAnisotropyLevel() override; - - int GetMaxSamples() override; - - bool IsShadowMappingSupported() override; - - int GetMaxTextureSize() override; - - bool IsFramebufferSupported() override; - -private: - //! Updates internal modelview matrix - void UpdateModelviewMatrix(); - //! Updates position for given light based on transformation matrices - void UpdateLightPosition(int index); - //! Updates position for all lights based on transformation matrices - void UpdateLightPositions(); - //! Updates the texture params for given texture stage - void UpdateTextureParams(int index); - - //! Enables shadows - void EnableShadows(); - //! Disables shadows - void DisableShadows(); - - template - unsigned int CreateStaticBufferImpl(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount); - template - void UpdateStaticBufferImpl(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount); - -private: - //! Current config - DeviceConfig m_config; - - //! Current world matrix - Math::Matrix m_worldMat; - //! Current view matrix - Math::Matrix m_viewMat; - //! OpenGL modelview matrix = world matrix * view matrix - Math::Matrix m_modelviewMat; - //! Current projection matrix - Math::Matrix m_projectionMat; - //! Combined world-view-projection matrix - Math::Matrix m_combinedMatrix; - //! Current shadow matrix - Math::Matrix m_shadowMatrix; - //! true means that combined matrix is outdated - bool m_combinedMatrixOutdated = true; - - //! The current material - Material m_material; - - //! Whether lighting is enabled - bool m_lighting = false; - //! Current lights - std::vector m_lights; - //! Current lights enable status - std::vector m_lightsEnabled; - - //! Current textures; \c nullptr value means unassigned - std::vector m_currentTextures; - //! Current texture stages enable status - std::vector m_texturesEnabled; - //! Current texture params - std::vector m_textureStageParams; - //! Texture unit remap - std::vector m_remap; - - //! Set of all created textures - std::set m_allTextures; - //! White texture - GLuint m_whiteTexture = 0; - - //! Map of framebuffers - std::map> m_framebuffers; - - //! Info about static VBO buffers - struct VboObjectInfo - { - PrimitiveType primitiveType = {}; - unsigned int bufferId = 0; - VertexType vertexType = {}; - int vertexCount = 0; - }; - - //! Detected capabilities - //! Depth texture support - ShadowMappingSupport m_shadowMappingSupport = SMS_NONE; - //! glMultiDrawArrays() available - bool m_multiDrawArrays = false; - //! Framebuffer support - FramebufferSupport m_framebufferSupport = FBS_NONE; - //! Map of saved VBO objects - std::map m_vboObjects; - //! Last ID of VBO object - unsigned int m_lastVboId = 0; - - //! true means shadow mapping is enabled - bool m_shadowMapping = false; - //! true means that quality shadows are enabled - bool m_shadowQuality = true; - - - //! Pointers to OpenGL functions - PFNGLGENBUFFERSPROC m_glGenBuffers = nullptr; - PFNGLDELETEBUFFERSPROC m_glDeleteBuffers = nullptr; - PFNGLBINDBUFFERPROC m_glBindBuffer = nullptr; - PFNGLBUFFERDATAPROC m_glBufferData = nullptr; - PFNGLBUFFERSUBDATAPROC m_glBufferSubData = nullptr; -}; - - -} // namespace Gfx diff --git a/src/graphics/opengl/gl21device.cpp b/src/graphics/opengl/gl21device.cpp deleted file mode 100644 index e0782271..00000000 --- a/src/graphics/opengl/gl21device.cpp +++ /dev/null @@ -1,1654 +0,0 @@ -/* - * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2020, 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/gl21device.h" - -#include "common/config.h" - -#include "common/config_file.h" -#include "common/image.h" -#include "common/logger.h" - -#include "graphics/core/light.h" - -#include "graphics/engine/engine.h" - -#include "graphics/opengl/glframebuffer.h" - -#include "math/geometry.h" - - -#include -#include - -#include -#include - - -// Graphics module namespace -namespace Gfx -{ - -CGL21Device::CGL21Device(const DeviceConfig &config) - : m_config(config) -{} - - -CGL21Device::~CGL21Device() -{ -} - -void CGL21Device::DebugHook() -{ - /* This function is only called here, so it can be used - * as a breakpoint when debugging using gDEBugger */ - glColor3i(0, 0, 0); -} - -void CGL21Device::DebugLights() -{ - Gfx::ColorHSV color(0.0, 1.0, 1.0); - - glLineWidth(3.0f); - glDisable(GL_LIGHTING); - glDepthMask(GL_FALSE); - glDisable(GL_BLEND); - - Math::Matrix saveWorldMat = m_worldMat; - m_worldMat.LoadIdentity(); - SetTransform(TRANSFORM_WORLD, m_worldMat); - - for (int i = 0; i < static_cast( m_lights.size() ); ++i) - { - color.h = static_cast(i) / static_cast(m_lights.size()); - if (m_lightsEnabled[i]) - { - const Light& l = m_lights[i]; - if (l.type == LIGHT_DIRECTIONAL) - { - Gfx::VertexCol v[2]; - v[0].coord = -Math::Normalize(l.direction) * 100.0f + Math::Vector(0.0f, 0.0f, 1.0f) * i; - v[0].color = HSV2RGB(color); - v[1].coord = Math::Normalize(l.direction) * 100.0f + Math::Vector(0.0f, 0.0f, 1.0f) * i; - v[1].color = HSV2RGB(color); - while (v[0].coord.y < 60.0f && v[0].coord.y < 60.0f) - { - v[0].coord.y += 10.0f; - v[1].coord.y += 10.0f; - } - DrawPrimitive(PRIMITIVE_LINES, v, 2); - - v[0].coord = v[1].coord + Math::Normalize(v[0].coord - v[1].coord) * 50.0f; - - glLineWidth(10.0f); - DrawPrimitive(PRIMITIVE_LINES, v, 2); - glLineWidth(3.0f); - } - else if (l.type == LIGHT_POINT) - { - Gfx::VertexCol v[8]; - for (int i = 0; i < 8; ++i) - v[i].color = HSV2RGB(color); - - v[0].coord = l.position + Math::Vector(-1.0f, -1.0f, -1.0f) * 4.0f; - v[1].coord = l.position + Math::Vector( 1.0f, -1.0f, -1.0f) * 4.0f; - v[2].coord = l.position + Math::Vector( 1.0f, 1.0f, -1.0f) * 4.0f; - v[3].coord = l.position + Math::Vector(-1.0f, 1.0f, -1.0f) * 4.0f; - v[4].coord = l.position + Math::Vector(-1.0f, -1.0f, -1.0f) * 4.0f; - DrawPrimitive(PRIMITIVE_LINE_STRIP, v, 5); - - v[0].coord = l.position + Math::Vector(-1.0f, -1.0f, 1.0f) * 4.0f; - v[1].coord = l.position + Math::Vector( 1.0f, -1.0f, 1.0f) * 4.0f; - v[2].coord = l.position + Math::Vector( 1.0f, 1.0f, 1.0f) * 4.0f; - v[3].coord = l.position + Math::Vector(-1.0f, 1.0f, 1.0f) * 4.0f; - v[4].coord = l.position + Math::Vector(-1.0f, -1.0f, 1.0f) * 4.0f; - DrawPrimitive(PRIMITIVE_LINE_STRIP, v, 5); - - v[0].coord = l.position + Math::Vector(-1.0f, -1.0f, -1.0f) * 4.0f; - v[1].coord = l.position + Math::Vector(-1.0f, -1.0f, 1.0f) * 4.0f; - v[2].coord = l.position + Math::Vector( 1.0f, -1.0f, -1.0f) * 4.0f; - v[3].coord = l.position + Math::Vector( 1.0f, -1.0f, 1.0f) * 4.0f; - v[4].coord = l.position + Math::Vector( 1.0f, 1.0f, -1.0f) * 4.0f; - v[5].coord = l.position + Math::Vector( 1.0f, 1.0f, 1.0f) * 4.0f; - v[6].coord = l.position + Math::Vector(-1.0f, 1.0f, -1.0f) * 4.0f; - v[7].coord = l.position + Math::Vector(-1.0f, 1.0f, 1.0f) * 4.0f; - DrawPrimitive(PRIMITIVE_LINES, v, 8); - } - else if (l.type == LIGHT_SPOT) - { - Gfx::VertexCol v[5]; - for (int i = 0; i < 5; ++i) - v[i].color = HSV2RGB(color); - - v[0].coord = l.position + Math::Vector(-1.0f, 0.0f, -1.0f) * 4.0f; - v[1].coord = l.position + Math::Vector( 1.0f, 0.0f, -1.0f) * 4.0f; - v[2].coord = l.position + Math::Vector( 1.0f, 0.0f, 1.0f) * 4.0f; - v[3].coord = l.position + Math::Vector(-1.0f, 0.0f, 1.0f) * 4.0f; - v[4].coord = l.position + Math::Vector(-1.0f, 0.0f, -1.0f) * 4.0f; - DrawPrimitive(PRIMITIVE_LINE_STRIP, v, 5); - - v[0].coord = l.position; - v[1].coord = l.position + Math::Normalize(l.direction) * 100.0f; - glEnable(GL_LINE_STIPPLE); - glLineStipple(3.0, 0xFF); - DrawPrimitive(PRIMITIVE_LINES, v, 2); - glDisable(GL_LINE_STIPPLE); - } - } - } - - glLineWidth(1.0f); - glEnable(GL_LIGHTING); - glDepthMask(GL_TRUE); - glEnable(GL_BLEND); - - SetTransform(TRANSFORM_WORLD, saveWorldMat); - m_worldMat = saveWorldMat; -} - -std::string CGL21Device::GetName() -{ - return std::string("OpenGL 2.1"); -} - -bool CGL21Device::Create() -{ - GetLogger()->Info("Creating CDevice - OpenGL 2.1\n"); - - if (!InitializeGLEW()) - { - m_errorMessage = "An error occurred while initializing GLEW."; - return false; - } - - // Extract OpenGL version - int glMajor, glMinor; - int glVersion = GetOpenGLVersion(glMajor, glMinor); - - if (glVersion < 20) - { - GetLogger()->Error("Unsupported OpenGL version: %d.%d\n", glMajor, glMinor); - GetLogger()->Error("OpenGL 2.0 or newer is required to use this engine.\n"); - m_errorMessage = "It seems your graphics card does not support OpenGL 2.0.\n"; - m_errorMessage += "Please make sure you have appropriate hardware and newest drivers installed.\n"; - m_errorMessage += "(OpenGL 2.0 is roughly equivalent to Direct3D 9)\n\n"; - m_errorMessage += GetHardwareInfo(); - return false; - } - - const char* version = reinterpret_cast(glGetString(GL_VERSION)); - const char* renderer = reinterpret_cast(glGetString(GL_RENDERER)); - - GetLogger()->Info("OpenGL %s\n", version); - GetLogger()->Info("%s\n", renderer); - - // Detect support of anisotropic filtering - m_capabilities.anisotropySupported = glewIsSupported("GL_EXT_texture_filter_anisotropic"); - if (m_capabilities.anisotropySupported) - { - // Obtain maximum anisotropy level available - float level; - glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &level); - m_capabilities.maxAnisotropy = static_cast(level); - - GetLogger()->Info("Anisotropic filtering available\n"); - GetLogger()->Info("Maximum anisotropy: %d\n", m_capabilities.maxAnisotropy); - } - else - { - GetLogger()->Info("Anisotropic filtering not available\n"); - } - - // Read maximum sample count for MSAA - if(glewIsSupported("GL_EXT_framebuffer_multisample")) - { - m_capabilities.multisamplingSupported = true; - - glGetIntegerv(GL_MAX_SAMPLES_EXT, &m_capabilities.maxSamples); - GetLogger()->Info("Multisampling supported, max samples: %d\n", m_capabilities.maxSamples); - } - else - { - GetLogger()->Info("Multisampling not supported\n"); - } - - m_capabilities.shadowMappingSupported = true; - - // This is mostly done in all modern hardware by default - // DirectX doesn't even allow the option to turn off perspective correction anymore - // So turn it on permanently - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); - - // Set just to be sure - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - - glViewport(0, 0, m_config.size.x, m_config.size.y); - - // this is set in shader - int numLights = 4; - - m_lights = std::vector(numLights, Light()); - m_lightsEnabled = std::vector (numLights, false); - - m_capabilities.maxLights = numLights; - - int maxTextures = 0; - glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextures); - GetLogger()->Info("Maximum texture image units: %d\n", maxTextures); - - m_capabilities.multitexturingSupported = true; - m_capabilities.maxTextures = maxTextures; - - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_capabilities.maxTextureSize); - GetLogger()->Info("Maximum texture size: %d\n", m_capabilities.maxTextureSize); - - m_framebufferSupport = DetectFramebufferSupport(); - if (m_framebufferSupport == FBS_ARB) - { - m_capabilities.framebufferSupported = true; - GetLogger()->Info("Framebuffer supported (ARB)\n"); - - glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &m_capabilities.maxRenderbufferSize); - GetLogger()->Info("Maximum renderbuffer size: %d\n", m_capabilities.maxRenderbufferSize); - } - else if (m_framebufferSupport == FBS_EXT) - { - m_capabilities.framebufferSupported = true; - GetLogger()->Info("Framebuffer supported (EXT)\n"); - - glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &m_capabilities.maxRenderbufferSize); - GetLogger()->Info("Maximum renderbuffer size: %d\n", m_capabilities.maxRenderbufferSize); - } - else - { - m_capabilities.framebufferSupported = false; - GetLogger()->Info("Framebuffer not supported\n"); - } - - m_currentTextures = std::vector (maxTextures, Texture()); - m_texturesEnabled = std::vector (maxTextures, false); - m_textureStageParams = std::vector(maxTextures, TextureStageParams()); - - // Create shader program for normal rendering - GLint shaders[2]; - char filename[128]; - - strcpy(filename, "shaders/gl21/vs_normal.glsl"); - shaders[0] = LoadShader(GL_VERTEX_SHADER, filename); - if (shaders[0] == 0) - { - m_errorMessage = GetLastShaderError(); - GetLogger()->Error("Cound not create vertex shader from file '%s'\n", filename); - return false; - } - - strcpy(filename, "shaders/gl21/fs_normal.glsl"); - shaders[1] = LoadShader(GL_FRAGMENT_SHADER, filename); - if (shaders[1] == 0) - { - m_errorMessage = GetLastShaderError(); - GetLogger()->Error("Cound not create fragment shader from file '%s'\n", filename); - return false; - } - - m_normalProgram = LinkProgram(2, shaders); - if (m_normalProgram == 0) - { - m_errorMessage = GetLastShaderError(); - GetLogger()->Error("Cound not link shader program for normal rendering\n"); - return false; - } - - glDeleteShader(shaders[0]); - glDeleteShader(shaders[1]); - - // Create shader program for interface rendering - strcpy(filename, "shaders/gl21/vs_interface.glsl"); - shaders[0] = LoadShader(GL_VERTEX_SHADER, filename); - if (shaders[0] == 0) - { - m_errorMessage = GetLastShaderError(); - GetLogger()->Error("Cound not create vertex shader from file '%s'\n", filename); - return false; - } - - strcpy(filename, "shaders/gl21/fs_interface.glsl"); - shaders[1] = LoadShader(GL_FRAGMENT_SHADER, filename); - if (shaders[1] == 0) - { - m_errorMessage = GetLastShaderError(); - GetLogger()->Error("Cound not compile fragment shader from file '%s'\n", filename); - return false; - } - - m_interfaceProgram = LinkProgram(2, shaders); - if (m_interfaceProgram == 0) - { - m_errorMessage = GetLastShaderError(); - GetLogger()->Error("Cound not link shader program for interface rendering\n"); - return false; - } - - glDeleteShader(shaders[0]); - glDeleteShader(shaders[1]); - - // Create shader program for shadow rendering - strcpy(filename, "shaders/gl21/vs_shadow.glsl"); - shaders[0] = LoadShader(GL_VERTEX_SHADER, filename); - if (shaders[0] == 0) - { - m_errorMessage = GetLastShaderError(); - GetLogger()->Error("Cound not create vertex shader from file '%s'\n", filename); - return false; - } - - strcpy(filename, "shaders/gl21/fs_shadow.glsl"); - shaders[1] = LoadShader(GL_FRAGMENT_SHADER, filename); - if (shaders[1] == 0) - { - m_errorMessage = GetLastShaderError(); - GetLogger()->Error("Cound not compile fragment shader from file '%s'\n", filename); - return false; - } - - m_shadowProgram = LinkProgram(2, shaders); - if (m_shadowProgram == 0) - { - m_errorMessage = GetLastShaderError(); - GetLogger()->Error("Cound not link shader program for shadow rendering\n"); - return false; - } - - glDeleteShader(shaders[0]); - glDeleteShader(shaders[1]); - - // Obtain uniform locations from normal rendering program and initialize them - { - UniformLocations &uni = m_uniforms[0]; - - 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"); - uni.cameraPosition = glGetUniformLocation(m_normalProgram, "uni_CameraPosition"); - - 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.shadowTexelSize = glGetUniformLocation(m_normalProgram, "uni_ShadowTexelSize"); - uni.lightCount = glGetUniformLocation(m_normalProgram, "uni_LightCount"); - - uni.ambientColor = glGetUniformLocation(m_normalProgram, "uni_Material.ambient"); - uni.diffuseColor = glGetUniformLocation(m_normalProgram, "uni_Material.diffuse"); - uni.specularColor = glGetUniformLocation(m_normalProgram, "uni_Material.specular"); - - GLchar name[64]; - for (int i = 0; i < 8; i++) - { - 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); - } - - // 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()); - glUniform3f(uni.cameraPosition, 0.0f, 0.0f, 0.0f); - - 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); - glUniform1f(uni.shadowTexelSize, 0.5f); - - glUniform1i(uni.lightCount, 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 - FramebufferParams framebufferParams; - - framebufferParams.width = m_config.size.x; - framebufferParams.height = m_config.size.y; - framebufferParams.depth = m_config.depthSize; - - m_framebuffers["default"] = MakeUnique(framebufferParams); - - GetLogger()->Info("CDevice created successfully\n"); - - return true; -} - -void CGL21Device::Destroy() -{ - // Delete the remaining textures - // Should not be strictly necessary, but just in case - glUseProgram(0); - glDeleteProgram(m_normalProgram); - glDeleteProgram(m_interfaceProgram); - glDeleteProgram(m_shadowProgram); - - // delete framebuffers - for (auto& framebuffer : m_framebuffers) - framebuffer.second->Destroy(); - - m_framebuffers.clear(); - - DestroyAllTextures(); - - m_lights.clear(); - m_lightsEnabled.clear(); - - m_currentTextures.clear(); - m_texturesEnabled.clear(); - m_textureStageParams.clear(); -} - -void CGL21Device::ConfigChanged(const DeviceConfig& newConfig) -{ - m_config = newConfig; - - // Reset state - m_lighting = false; - m_updateLights = true; - - glViewport(0, 0, m_config.size.x, m_config.size.y); - - // create default framebuffer object - FramebufferParams framebufferParams; - - framebufferParams.width = m_config.size.x; - framebufferParams.height = m_config.size.y; - framebufferParams.depth = m_config.depthSize; - - m_framebuffers["default"] = MakeUnique(framebufferParams); -} - -void CGL21Device::BeginScene() -{ - Clear(); -} - -void CGL21Device::EndScene() -{ -#ifdef DEV_BUILD - CheckGLErrors(); -#endif -} - -void CGL21Device::Clear() -{ - glDepthMask(GL_TRUE); - 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(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); - - // normal transform - Math::Matrix normalMat = matrix; - - if (fabs(normalMat.Det()) > 1e-6) - normalMat = normalMat.Inverse(); - - glUniformMatrix4fv(m_uniforms[m_mode].normalMatrix, 1, GL_TRUE, normalMat.Array()); - } - else if (type == TRANSFORM_VIEW) - { - Math::Matrix scale; - Math::Vector cameraPosition; - scale.Set(3, 3, -1.0f); - m_viewMat = Math::MultiplyMatrices(scale, matrix); - - m_modelviewMat = Math::MultiplyMatrices(m_viewMat, m_worldMat); - m_combinedMatrix = Math::MultiplyMatrices(m_projectionMat, m_modelviewMat); - - glUniformMatrix4fv(m_uniforms[m_mode].viewMatrix, 1, GL_FALSE, m_viewMat.Array()); - - if (m_uniforms[m_mode].cameraPosition >= 0) - { - cameraPosition.LoadZero(); - cameraPosition = MatrixVectorMultiply(m_viewMat.Inverse(), cameraPosition); - glUniform3fv(m_uniforms[m_mode].cameraPosition, 1, cameraPosition.Array()); - } - } - else if (type == TRANSFORM_PROJECTION) - { - m_projectionMat = matrix; - - m_combinedMatrix = Math::MultiplyMatrices(m_projectionMat, m_modelviewMat); - - glUniformMatrix4fv(m_uniforms[m_mode].projectionMatrix, 1, GL_FALSE, m_projectionMat.Array()); - } - else if (type == TRANSFORM_SHADOW) - { - Math::Matrix temp = matrix; - glUniformMatrix4fv(m_uniforms[m_mode].shadowMatrix, 1, GL_FALSE, temp.Array()); - } - else - { - assert(false); - } -} - -void CGL21Device::SetMaterial(const Material &material) -{ - m_material = material; - - 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() -{ - return m_lights.size(); -} - -void CGL21Device::SetLight(int index, const Light &light) -{ - assert(index >= 0); - assert(index < static_cast( m_lights.size() )); - - m_lights[index] = light; - - m_updateLights = true; -} - -void CGL21Device::SetLightEnabled(int index, bool enabled) -{ - assert(index >= 0); - assert(index < static_cast( m_lights.size() )); - - m_lightsEnabled[index] = enabled; - - m_updateLights = true; -} - -/** If image is invalid, returns invalid texture. - Otherwise, returns pointer to new Texture struct. - This struct must not be deleted in other way than through DeleteTexture() */ -Texture CGL21Device::CreateTexture(CImage *image, const TextureCreateParams ¶ms) -{ - ImageData *data = image->GetData(); - if (data == nullptr) - { - GetLogger()->Error("Invalid texture data\n"); - return Texture(); // invalid texture - } - - Math::IntPoint originalSize = image->GetSize(); - - if (params.padToNearestPowerOfTwo) - image->PadToNearestPowerOfTwo(); - - Texture tex = CreateTexture(data, params); - tex.originalSize = originalSize; - - return tex; -} - -Texture CGL21Device::CreateTexture(ImageData *data, const TextureCreateParams ¶ms) -{ - Texture result; - - result.size.x = data->surface->w; - result.size.y = data->surface->h; - - if (!Math::IsPowerOfTwo(result.size.x) || !Math::IsPowerOfTwo(result.size.y)) - GetLogger()->Warn("Creating non-power-of-2 texture (%dx%d)!\n", result.size.x, result.size.y); - - result.originalSize = result.size; - - glGenTextures(1, &result.id); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, result.id); - - glEnable(GL_TEXTURE_2D); - - // Set texture parameters - GLint minF = GL_NEAREST, magF = GL_NEAREST; - int mipmapLevel = 1; - - switch (params.filter) - { - case TEX_FILTER_NEAREST: - minF = GL_NEAREST; - magF = GL_NEAREST; - break; - case TEX_FILTER_BILINEAR: - minF = GL_LINEAR; - magF = GL_LINEAR; - break; - case TEX_FILTER_TRILINEAR: - minF = GL_LINEAR_MIPMAP_LINEAR; - magF = GL_LINEAR; - mipmapLevel = CEngine::GetInstance().GetTextureMipmapLevel(); - break; - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minF); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magF); - - // Set mipmap level and automatic mipmap generation if neccesary - if (params.mipmap) - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, mipmapLevel - 1); - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); - } - else - { - // Has to be set to 0 because no mipmaps are generated - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE); - } - - // Set anisotropy level if available - if (m_capabilities.anisotropySupported) - { - float level = Math::Min(m_capabilities.maxAnisotropy, CEngine::GetInstance().GetTextureAnisotropyLevel()); - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, level); - } - - PreparedTextureData texData = PrepareTextureData(data, params.format); - result.alpha = texData.alpha; - - glPixelStorei(GL_UNPACK_ROW_LENGTH, texData.actualSurface->pitch / texData.actualSurface->format->BytesPerPixel); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texData.actualSurface->w, texData.actualSurface->h, - 0, texData.sourceFormat, GL_UNSIGNED_BYTE, texData.actualSurface->pixels); - - SDL_FreeSurface(texData.convertedSurface); - - m_allTextures.insert(result); - - // Restore the previous state of 1st stage - glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id); - - if (! m_texturesEnabled[0]) - glDisable(GL_TEXTURE_2D); - - return result; -} - -Texture CGL21Device::CreateDepthTexture(int width, int height, int depth) -{ - Texture result; - - result.alpha = false; - result.size.x = width; - result.size.y = height; - - // Use & enable 1st texture stage - glActiveTexture(GL_TEXTURE0); - - glGenTextures(1, &result.id); - glBindTexture(GL_TEXTURE_2D, result.id); - - GLuint format = GL_DEPTH_COMPONENT; - - switch (depth) - { - case 16: - format = GL_DEPTH_COMPONENT16; - break; - case 24: - format = GL_DEPTH_COMPONENT24; - break; - case 32: - format = GL_DEPTH_COMPONENT32; - break; - } - - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, GL_DEPTH_COMPONENT, GL_INT, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); - - float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, color); - - glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id); - - return result; -} - -void CGL21Device::UpdateTexture(const Texture& texture, Math::IntPoint offset, ImageData* data, TexImgFormat format) -{ - glActiveTexture(GL_TEXTURE0); - glEnable(GL_TEXTURE_2D); - - glBindTexture(GL_TEXTURE_2D, texture.id); - - PreparedTextureData texData = PrepareTextureData(data, format); - - glPixelStorei(GL_UNPACK_ROW_LENGTH, texData.actualSurface->pitch / texData.actualSurface->format->BytesPerPixel); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - glTexSubImage2D(GL_TEXTURE_2D, 0, offset.x, offset.y, texData.actualSurface->w, texData.actualSurface->h, - texData.sourceFormat, GL_UNSIGNED_BYTE, texData.actualSurface->pixels); - - SDL_FreeSurface(texData.convertedSurface); -} - -void CGL21Device::DestroyTexture(const Texture &texture) -{ - // Unbind the texture if in use anywhere - for (int index = 0; index < static_cast( m_currentTextures.size() ); ++index) - { - if (m_currentTextures[index] == texture) - SetTexture(index, Texture()); // set to invalid texture - } - - auto it = m_allTextures.find(texture); - if (it != m_allTextures.end()) - { - glDeleteTextures(1, &texture.id); - m_allTextures.erase(it); - } -} - -void CGL21Device::DestroyAllTextures() -{ - // Unbind all texture stages - for (int index = 0; index < static_cast( m_currentTextures.size() ); ++index) - SetTexture(index, Texture()); - - for (auto it = m_allTextures.begin(); it != m_allTextures.end(); ++it) - glDeleteTextures(1, &(*it).id); - - m_allTextures.clear(); -} - -int CGL21Device::GetMaxTextureStageCount() -{ - return m_currentTextures.size(); -} - -/** - If \a texture is invalid, unbinds the given texture. - If valid, binds the texture and enables the given texture stage. - The setting is remembered, even if texturing is disabled at the moment. */ -void CGL21Device::SetTexture(int index, const Texture &texture) -{ - assert(index >= 0 && index < static_cast( m_currentTextures.size() )); - - bool same = m_currentTextures[index].id == texture.id; - - m_currentTextures[index] = texture; // remember the new value - - if (same) - return; // nothing to do - - glActiveTexture(GL_TEXTURE0 + index); - - glBindTexture(GL_TEXTURE_2D, texture.id); - - // Params need to be updated for the new bound texture - UpdateTextureState(index); - UpdateTextureParams(index); -} - -void CGL21Device::SetTexture(int index, unsigned int textureId) -{ - assert(index >= 0 && index < static_cast( m_currentTextures.size() )); - - if (m_currentTextures[index].id == textureId) - return; // nothing to do - - m_currentTextures[index].id = textureId; - - glActiveTexture(GL_TEXTURE0 + index); - - glBindTexture(GL_TEXTURE_2D, textureId); - - // Params need to be updated for the new bound texture - UpdateTextureState(index); - UpdateTextureParams(index); -} - -void CGL21Device::SetTextureEnabled(int index, bool enabled) -{ - assert(index >= 0 && index < static_cast( m_currentTextures.size() )); - - bool same = m_texturesEnabled[index] == enabled; - - m_texturesEnabled[index] = enabled; - - if (same) - return; // nothing to do - - UpdateTextureState(index); -} - -void CGL21Device::UpdateTextureState(int index) -{ - bool enabled = m_texturesEnabled[index] && (m_currentTextures[index].id != 0); - glUniform1i(m_uniforms[m_mode].textureEnabled[index], enabled ? 1 : 0); -} - -void CGL21Device::UpdateLights() -{ - m_updateLights = false; - - // If not in normal rendering mode, return immediately - if (m_mode != 0) return; - - // Lighting enabled - if (m_lighting) - { - int index = 0; - - // Iterate all lights - for (unsigned int i = 0; i < m_lights.size(); i++) - { - // If disabled, ignore and continue - if (!m_lightsEnabled[i]) continue; - - // If not directional, ignore and continue - if (m_lights[i].type != LIGHT_DIRECTIONAL) continue; - - Light &light = m_lights[i]; - LightLocations &uni = m_uniforms[m_mode].lights[index]; - - glUniform4fv(uni.ambient, 1, light.ambient.Array()); - glUniform4fv(uni.diffuse, 1, light.diffuse.Array()); - glUniform4fv(uni.specular, 1, light.specular.Array()); - - glUniform4f(uni.position, -light.direction.x, -light.direction.y, -light.direction.z, 0.0f); - - index++; - } - - glUniform1i(m_uniforms[m_mode].lightCount, index); - } - // Lighting disabled - else - { - glUniform1i(m_uniforms[m_mode].lightCount, 0); - } -} - -inline void CGL21Device::BindVBO(GLuint vbo) -{ - if (m_currentVBO == vbo) return; - - glBindBuffer(GL_ARRAY_BUFFER, vbo); - m_currentVBO = vbo; -} - -inline void CGL21Device::BindTexture(int index, GLuint texture) -{ - glActiveTexture(GL_TEXTURE0 + index); - glBindTexture(GL_TEXTURE_2D, texture); -} - -/** - Sets the texture parameters for the given texture stage. - If the given texture was not set (bound) yet, nothing happens. - The settings are remembered, even if texturing is disabled at the moment. */ -void CGL21Device::SetTextureStageParams(int index, const TextureStageParams ¶ms) -{ - assert(index >= 0 && index < static_cast( m_currentTextures.size() )); - - // Remember the settings - m_textureStageParams[index] = params; - - UpdateTextureParams(index); -} - -void CGL21Device::UpdateTextureParams(int index) -{ - assert(index >= 0 && index < static_cast( m_currentTextures.size() )); - - // Don't actually do anything if texture not set - if (! m_currentTextures[index].Valid()) - return; - - const TextureStageParams ¶ms = m_textureStageParams[index]; - - glActiveTexture(GL_TEXTURE0 + index); - - if (params.wrapS == TEX_WRAP_CLAMP) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - else if (params.wrapS == TEX_WRAP_CLAMP_TO_BORDER) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - else if (params.wrapS == TEX_WRAP_REPEAT) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - else assert(false); - - if (params.wrapT == TEX_WRAP_CLAMP) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - else if (params.wrapT == TEX_WRAP_CLAMP_TO_BORDER) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - else if (params.wrapT == TEX_WRAP_REPEAT) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - else assert(false); -} - -void CGL21Device::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode wrapT) -{ - assert(index >= 0 && index < static_cast( m_currentTextures.size() )); - - // Remember the settings - m_textureStageParams[index].wrapS = wrapS; - m_textureStageParams[index].wrapT = wrapT; - - // Don't actually do anything if texture not set - if (! m_currentTextures[index].Valid()) - return; - - glActiveTexture(GL_TEXTURE0 + index); - - if (wrapS == TEX_WRAP_CLAMP) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - else if (wrapS == TEX_WRAP_CLAMP_TO_BORDER) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - else if (wrapS == TEX_WRAP_REPEAT) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - else assert(false); - - if (wrapT == TEX_WRAP_CLAMP) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - else if (wrapT == TEX_WRAP_CLAMP_TO_BORDER) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - else if (wrapT == TEX_WRAP_REPEAT) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - else assert(false); -} - -namespace -{ -void SetVertexAttributes(const Vertex* bufferBase) -{ - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(Vertex), reinterpret_cast(bufferBase) + offsetof(Vertex, coord)); - - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, sizeof(Vertex), reinterpret_cast(bufferBase) + offsetof(Vertex, normal)); - - glClientActiveTexture(GL_TEXTURE1); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTexture(GL_TEXTURE0); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), reinterpret_cast(bufferBase) + offsetof(Vertex, texCoord)); - - glDisableClientState(GL_COLOR_ARRAY); -} - -void SetVertexAttributes(const VertexTex2* bufferBase) -{ - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(bufferBase) + offsetof(VertexTex2, coord)); - - glEnableClientState(GL_NORMAL_ARRAY); - glNormalPointer(GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(bufferBase) + offsetof(VertexTex2, normal)); - - glClientActiveTexture(GL_TEXTURE1); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(bufferBase) + offsetof(VertexTex2, texCoord2)); - glClientActiveTexture(GL_TEXTURE0); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glTexCoordPointer(2, GL_FLOAT, sizeof(VertexTex2), reinterpret_cast(bufferBase) + offsetof(VertexTex2, texCoord)); - - glDisableClientState(GL_COLOR_ARRAY); -} - -void SetVertexAttributes(const VertexCol* bufferBase) -{ - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, sizeof(VertexCol), reinterpret_cast(bufferBase) + offsetof(VertexCol, coord)); - - glDisableClientState(GL_NORMAL_ARRAY); - - glClientActiveTexture(GL_TEXTURE1); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTexture(GL_TEXTURE0); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(4, GL_FLOAT, sizeof(VertexCol), reinterpret_cast(bufferBase) + offsetof(VertexCol, color)); -} -} // namespace - -void CGL21Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int vertexCount, - Color color) -{ - if (m_updateLights) UpdateLights(); - - BindVBO(0); - SetVertexAttributes(vertices); - glColor4fv(color.Array()); - - glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); -} - -void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, - Color color) -{ - if (m_updateLights) UpdateLights(); - - BindVBO(0); - SetVertexAttributes(vertices); - glColor4fv(color.Array()); - - glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); -} - -void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount) -{ - if (m_updateLights) UpdateLights(); - - BindVBO(0); - SetVertexAttributes(vertices); - glDrawArrays(TranslateGfxPrimitive(type), 0, vertexCount); -} - -void CGL21Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices, - int first[], int count[], int drawCount, Color color) -{ - if (m_updateLights) UpdateLights(); - - BindVBO(0); - SetVertexAttributes(vertices); - glColor4fv(color.Array()); - - glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount); -} - -void CGL21Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices, - int first[], int count[], int drawCount, Color color) -{ - if (m_updateLights) UpdateLights(); - - BindVBO(0); - SetVertexAttributes(vertices); - glColor4fv(color.Array()); - - glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount); -} - -void CGL21Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices, - int first[], int count[], int drawCount) -{ - if (m_updateLights) UpdateLights(); - - BindVBO(0); - SetVertexAttributes(vertices); - - glMultiDrawArrays(TranslateGfxPrimitive(type), first, count, drawCount); -} - - -template -unsigned int CGL21Device::CreateStaticBufferImpl(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) -{ - unsigned int id = ++m_lastVboId; - - VboObjectInfo info; - info.primitiveType = primitiveType; - info.vertexType = Vertex::VERTEX_TYPE; - info.vertexCount = vertexCount; - info.bufferId = 0; - info.size = vertexCount * sizeof(Vertex); - - glGenBuffers(1, &info.bufferId); - BindVBO(info.bufferId); - glBufferData(GL_ARRAY_BUFFER, info.size, vertices, GL_STATIC_DRAW); - - m_vboObjects[id] = info; - - return id; -} - -template -void CGL21Device::UpdateStaticBufferImpl(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) -{ - auto it = m_vboObjects.find(bufferId); - if (it == m_vboObjects.end()) - return; - - int newSize = vertexCount * sizeof(Vertex); - - VboObjectInfo& info = (*it).second; - info.primitiveType = primitiveType; - info.vertexType = Vertex::VERTEX_TYPE; - info.vertexCount = vertexCount; - - BindVBO(info.bufferId); - - if (info.size < newSize) - { - glBufferData(GL_ARRAY_BUFFER, newSize, vertices, GL_STATIC_DRAW); - info.size = newSize; - } - else - { - glBufferSubData(GL_ARRAY_BUFFER, 0, newSize, vertices); - } -} - -void CGL21Device::DrawStaticBuffer(unsigned int bufferId) -{ - auto it = m_vboObjects.find(bufferId); - if (it == m_vboObjects.end()) - return; - - if (m_updateLights) UpdateLights(); - - BindVBO((*it).second.bufferId); - - if ((*it).second.vertexType == VERTEX_TYPE_NORMAL) - { - SetVertexAttributes(static_cast(nullptr)); - } - else if ((*it).second.vertexType == VERTEX_TYPE_TEX2) - { - SetVertexAttributes(static_cast(nullptr)); - } - else if ((*it).second.vertexType == VERTEX_TYPE_COL) - { - SetVertexAttributes(static_cast(nullptr)); - } - - GLenum mode = TranslateGfxPrimitive((*it).second.primitiveType); - - glDrawArrays(mode, 0, (*it).second.vertexCount); -} - -void CGL21Device::DestroyStaticBuffer(unsigned int bufferId) -{ - auto it = m_vboObjects.find(bufferId); - if (it == m_vboObjects.end()) - return; - - if (m_currentVBO == (*it).second.bufferId) - BindVBO(0); - - glDeleteBuffers(1, &(*it).second.bufferId); - - m_vboObjects.erase(it); -} - -/* Based on libwine's implementation */ - -int CGL21Device::ComputeSphereVisibility(const Math::Vector ¢er, float radius) -{ - Math::Matrix &m = m_combinedMatrix; - - Math::Vector vec[6]; - float originPlane[6]; - - // Left plane - vec[0].x = m.Get(4, 1) + m.Get(1, 1); - vec[0].y = m.Get(4, 2) + m.Get(1, 2); - vec[0].z = m.Get(4, 3) + m.Get(1, 3); - float l1 = vec[0].Length(); - vec[0].Normalize(); - originPlane[0] = (m.Get(4, 4) + m.Get(1, 4)) / l1; - - // Right plane - vec[1].x = m.Get(4, 1) - m.Get(1, 1); - vec[1].y = m.Get(4, 2) - m.Get(1, 2); - vec[1].z = m.Get(4, 3) - m.Get(1, 3); - float l2 = vec[1].Length(); - vec[1].Normalize(); - originPlane[1] = (m.Get(4, 4) - m.Get(1, 4)) / l2; - - // Bottom plane - vec[2].x = m.Get(4, 1) + m.Get(2, 1); - vec[2].y = m.Get(4, 2) + m.Get(2, 2); - vec[2].z = m.Get(4, 3) + m.Get(2, 3); - float l3 = vec[2].Length(); - vec[2].Normalize(); - originPlane[2] = (m.Get(4, 4) + m.Get(2, 4)) / l3; - - // Top plane - vec[3].x = m.Get(4, 1) - m.Get(2, 1); - vec[3].y = m.Get(4, 2) - m.Get(2, 2); - vec[3].z = m.Get(4, 3) - m.Get(2, 3); - float l4 = vec[3].Length(); - vec[3].Normalize(); - originPlane[3] = (m.Get(4, 4) - m.Get(2, 4)) / l4; - - // Front plane - vec[4].x = m.Get(4, 1) + m.Get(3, 1); - vec[4].y = m.Get(4, 2) + m.Get(3, 2); - vec[4].z = m.Get(4, 3) + m.Get(3, 3); - float l5 = vec[4].Length(); - vec[4].Normalize(); - originPlane[4] = (m.Get(4, 4) + m.Get(3, 4)) / l5; - - // Back plane - vec[5].x = m.Get(4, 1) - m.Get(3, 1); - vec[5].y = m.Get(4, 2) - m.Get(3, 2); - vec[5].z = m.Get(4, 3) - m.Get(3, 3); - float l6 = vec[5].Length(); - vec[5].Normalize(); - originPlane[5] = (m.Get(4, 4) - m.Get(3, 4)) / l6; - - int result = 0; - - if (InPlane(vec[0], originPlane[0], center, radius)) - result |= FRUSTUM_PLANE_LEFT; - if (InPlane(vec[1], originPlane[1], center, radius)) - result |= FRUSTUM_PLANE_RIGHT; - if (InPlane(vec[2], originPlane[2], center, radius)) - result |= FRUSTUM_PLANE_BOTTOM; - if (InPlane(vec[3], originPlane[3], center, radius)) - result |= FRUSTUM_PLANE_TOP; - if (InPlane(vec[4], originPlane[4], center, radius)) - result |= FRUSTUM_PLANE_FRONT; - if (InPlane(vec[5], originPlane[5], center, radius)) - result |= FRUSTUM_PLANE_BACK; - - return result; -} - -void CGL21Device::SetViewport(int x, int y, int width, int height) -{ - glViewport(x, y, width, height); -} - -void CGL21Device::SetRenderState(RenderState state, bool enabled) -{ - if (state == RENDER_STATE_DEPTH_WRITE) - { - glDepthMask(enabled ? GL_TRUE : GL_FALSE); - return; - } - else if (state == RENDER_STATE_LIGHTING) - { - if (m_lighting == enabled) return; - - m_lighting = enabled; - - m_updateLights = true; - - return; - } - else if (state == RENDER_STATE_ALPHA_TEST) - { - glUniform1i(m_uniforms[m_mode].alphaTestEnabled, enabled ? 1 : 0); - - return; - } - else if (state == RENDER_STATE_FOG) - { - glUniform1i(m_uniforms[m_mode].fogEnabled, enabled ? 1 : 0); - - return; - } - else if (state == RENDER_STATE_SHADOW_MAPPING) - { - glUniform1f(m_uniforms[m_mode].shadowTexelSize, 1.0/m_currentTextures[TEXTURE_SHADOW].size.x); - SetTextureEnabled(TEXTURE_SHADOW, enabled); - - return; - } - - GLenum flag = 0; - - switch (state) - { - case RENDER_STATE_BLENDING: flag = GL_BLEND; break; - case RENDER_STATE_DEPTH_TEST: flag = GL_DEPTH_TEST; break; - case RENDER_STATE_CULLING: flag = GL_CULL_FACE; break; - case RENDER_STATE_DEPTH_BIAS: flag = GL_POLYGON_OFFSET_FILL; break; - default: assert(false); break; - } - - if (enabled) - glEnable(flag); - else - glDisable(flag); -} - -void CGL21Device::SetColorMask(bool red, bool green, bool blue, bool alpha) -{ - glColorMask(red, green, blue, alpha); -} - -void CGL21Device::SetDepthTestFunc(CompFunc func) -{ - glDepthFunc(TranslateGfxCompFunc(func)); -} - -void CGL21Device::SetDepthBias(float factor, float units) -{ - glPolygonOffset(factor, units); -} - -void CGL21Device::SetAlphaTestFunc(CompFunc func, float refValue) -{ - glUniform1f(m_uniforms[m_mode].alphaReference, refValue); -} - -void CGL21Device::SetBlendFunc(BlendFunc srcBlend, BlendFunc dstBlend) -{ - glBlendFunc(TranslateGfxBlendFunc(srcBlend), TranslateGfxBlendFunc(dstBlend)); -} - -void CGL21Device::SetClearColor(const Color &color) -{ - glClearColor(color.r, color.g, color.b, color.a); -} - -void CGL21Device::SetGlobalAmbient(const Color &color) -{ - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, color.Array()); -} - -void CGL21Device::SetFogParams(FogMode mode, const Color &color, float start, float end, float density) -{ - 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); - else if (mode == FOG_EXP) glFogi(GL_FOG_MODE, GL_EXP); - else if (mode == FOG_EXP2) glFogi(GL_FOG_MODE, GL_EXP2); - else assert(false); - - glFogf(GL_FOG_START, start); - glFogf(GL_FOG_END, end); - glFogf(GL_FOG_DENSITY, density); - glFogfv(GL_FOG_COLOR, color.Array()); - // */ -} - -void CGL21Device::SetCullMode(CullMode mode) -{ - // Cull clockwise back faces, so front face is the opposite - // (assuming GL_CULL_FACE is GL_BACK) - if (mode == CULL_CW ) glFrontFace(GL_CCW); - else if (mode == CULL_CCW) glFrontFace(GL_CW); - else assert(false); -} - -void CGL21Device::SetShadeModel(ShadeModel model) -{ - if (model == SHADE_FLAT) glShadeModel(GL_FLAT); - else if (model == SHADE_SMOOTH) glShadeModel(GL_SMOOTH); - else assert(false); -} - -void CGL21Device::SetShadowColor(float value) -{ - glUniform1f(m_uniforms[m_mode].shadowColor, value); -} - -void CGL21Device::SetFillMode(FillMode mode) -{ - if (mode == FILL_POINT) glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); - else if (mode == FILL_LINES) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - else if (mode == FILL_POLY) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - else assert(false); -} - -void CGL21Device::CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height) -{ - if (texture.id == 0) return; - - // Use & enable 1st texture stage - glActiveTexture(GL_TEXTURE0); - - glBindTexture(GL_TEXTURE_2D, texture.id); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, x, y, width, height); - - // Restore previous texture - glBindTexture(GL_TEXTURE_2D, m_currentTextures[0].id); -} - -std::unique_ptr CGL21Device::GetFrameBufferPixels() const -{ - return GetGLFrameBufferPixels(m_config.size); -} - -CFramebuffer* CGL21Device::GetFramebuffer(std::string name) -{ - auto it = m_framebuffers.find(name); - if (it == m_framebuffers.end()) - return nullptr; - - return it->second.get(); -} - -CFramebuffer* CGL21Device::CreateFramebuffer(std::string name, const FramebufferParams& params) -{ - // existing framebuffer was found - if (m_framebuffers.find(name) != m_framebuffers.end()) - { - return nullptr; - } - - std::unique_ptr framebuffer; - - if (m_framebufferSupport == FBS_ARB) - framebuffer = MakeUnique(params); - else if (m_framebufferSupport == FBS_EXT) - framebuffer = MakeUnique(params); - else - return nullptr; - - if (!framebuffer->Create()) return nullptr; - - CFramebuffer* framebufferPtr = framebuffer.get(); - m_framebuffers[name] = std::move(framebuffer); - return framebufferPtr; -} - -void CGL21Device::DeleteFramebuffer(std::string name) -{ - // can't delete default framebuffer - if (name == "default") return; - - auto it = m_framebuffers.find(name); - if (it != m_framebuffers.end()) - { - it->second->Destroy(); - m_framebuffers.erase(it); - } -} - -bool CGL21Device::IsAnisotropySupported() -{ - return m_capabilities.anisotropySupported; -} - -int CGL21Device::GetMaxAnisotropyLevel() -{ - return m_capabilities.maxAnisotropy; -} - -int CGL21Device::GetMaxSamples() -{ - return m_capabilities.maxSamples; -} - -bool CGL21Device::IsShadowMappingSupported() -{ - return m_capabilities.shadowMappingSupported; -} - -int CGL21Device::GetMaxTextureSize() -{ - return m_capabilities.maxTextureSize; -} - -bool CGL21Device::IsFramebufferSupported() -{ - return m_capabilities.framebufferSupported; -} - -} // namespace Gfx diff --git a/src/graphics/opengl/gl21device.h b/src/graphics/opengl/gl21device.h deleted file mode 100644 index 52af3f04..00000000 --- a/src/graphics/opengl/gl21device.h +++ /dev/null @@ -1,287 +0,0 @@ -/* - * This file is part of the Colobot: Gold Edition source code - * Copyright (C) 2001-2020, 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/opengl/gl21device.h - * \brief OpenGL implementation - CGL21Device class - */ - -#pragma once - -#include "graphics/core/device.h" - -#include "graphics/core/material.h" - -#include "graphics/opengl/glutil.h" - -#include "math/matrix.h" - -#include -#include -#include -#include - - -// Graphics module namespace -namespace Gfx -{ - -/** - \class CGL21Device - \brief Implementation of CDevice interface in OpenGL - - Provides the concrete implementation of 3D device in OpenGL. - - This class should be initialized (by calling Initialize() ) only after - setting the video mode by CApplication, once the OpenGL context is defined. - Because of that, CGL21DeviceConfig is outside the CDevice class and must be set - in CApplication. -*/ -class CGL21Device : public CDevice -{ -public: - CGL21Device(const DeviceConfig &config); - virtual ~CGL21Device(); - - void DebugHook() override; - void DebugLights() override; - - std::string GetName() override; - - bool Create() override; - void Destroy() override; - - void ConfigChanged(const DeviceConfig &newConfig) override; - - void BeginScene() override; - void EndScene() override; - - void Clear() override; - - void SetRenderMode(RenderMode mode) override; - - void SetTransform(TransformType type, const Math::Matrix &matrix) override; - - void SetMaterial(const Material &material) override; - - int GetMaxLightCount() override; - void SetLight(int index, const Light &light) override; - void SetLightEnabled(int index, bool enabled) override; - - Texture CreateTexture(CImage *image, const TextureCreateParams ¶ms) override; - Texture CreateTexture(ImageData *data, const TextureCreateParams ¶ms) override; - Texture CreateDepthTexture(int width, int height, int depth) override; - void UpdateTexture(const Texture& texture, Math::IntPoint offset, ImageData* data, TexImgFormat format) override; - void DestroyTexture(const Texture &texture) override; - void DestroyAllTextures() override; - - int GetMaxTextureStageCount() override; - void SetTexture(int index, const Texture &texture) override; - void SetTexture(int index, unsigned int textureId) override; - void SetTextureEnabled(int index, bool enabled) override; - - void SetTextureStageParams(int index, const TextureStageParams ¶ms) override; - - void SetTextureStageWrap(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT) override; - - virtual void DrawPrimitive(PrimitiveType type, const Vertex *vertices , int vertexCount, - Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; - virtual void DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount, - Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; - virtual void DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount) override; - - virtual void DrawPrimitives(PrimitiveType type, const Vertex *vertices, - int first[], int count[], int drawCount, - Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; - virtual void DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices, - int first[], int count[], int drawCount, - Color color = Color(1.0f, 1.0f, 1.0f, 1.0f)) override; - virtual void DrawPrimitives(PrimitiveType type, const VertexCol *vertices, - int first[], int count[], int drawCount) override; - - unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) override - { - return CreateStaticBufferImpl(primitiveType, vertices, vertexCount); - } - unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) override - { - return CreateStaticBufferImpl(primitiveType, vertices, vertexCount); - } - unsigned int CreateStaticBuffer(PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) override - { - return CreateStaticBufferImpl(primitiveType, vertices, vertexCount); - } - void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount) override - { - UpdateStaticBufferImpl(bufferId, primitiveType, vertices, vertexCount); - } - void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexTex2* vertices, int vertexCount) override - { - UpdateStaticBufferImpl(bufferId, primitiveType, vertices, vertexCount); - } - void UpdateStaticBuffer(unsigned int bufferId, PrimitiveType primitiveType, const VertexCol* vertices, int vertexCount) override - { - UpdateStaticBufferImpl(bufferId, primitiveType, vertices, vertexCount); - } - void DrawStaticBuffer(unsigned int bufferId) override; - void DestroyStaticBuffer(unsigned int bufferId) override; - - int ComputeSphereVisibility(const Math::Vector ¢er, float radius) override; - - void SetViewport(int x, int y, int width, int height) override; - - void SetRenderState(RenderState state, bool enabled) override; - - void SetColorMask(bool red, bool green, bool blue, bool alpha) override; - - void SetDepthTestFunc(CompFunc func) override; - - void SetDepthBias(float factor, float units) override; - - void SetAlphaTestFunc(CompFunc func, float refValue) override; - - void SetBlendFunc(BlendFunc srcBlend, BlendFunc dstBlend) override; - - void SetClearColor(const Color &color) override; - - void SetGlobalAmbient(const Color &color) override; - - void SetFogParams(FogMode mode, const Color &color, float start, float end, float density) override; - - void SetCullMode(CullMode mode) override; - - void SetShadeModel(ShadeModel model) override; - - void SetShadowColor(float value) override; - - void SetFillMode(FillMode mode) override; - - void CopyFramebufferToTexture(Texture& texture, int xOffset, int yOffset, int x, int y, int width, int height) override; - - std::unique_ptr GetFrameBufferPixels() const override; - - CFramebuffer* GetFramebuffer(std::string name) override; - - CFramebuffer* CreateFramebuffer(std::string name, const FramebufferParams& params) override; - - void DeleteFramebuffer(std::string name) override; - - bool IsAnisotropySupported() override; - int GetMaxAnisotropyLevel() override; - - int GetMaxSamples() override; - - bool IsShadowMappingSupported() override; - - int GetMaxTextureSize() override; - - bool IsFramebufferSupported() override; - -private: - //! Updates the texture params for given texture stage - void UpdateTextureParams(int index); - //! Updates texture state - void UpdateTextureState(int index); - //! Update light parameters - void UpdateLights(); - //! Binds VBO - inline void BindVBO(GLuint vbo); - //! Binds texture - inline void BindTexture(int index, GLuint texture); - - template - unsigned int CreateStaticBufferImpl(PrimitiveType primitiveType, const Vertex* vertices, int vertexCount); - template - void UpdateStaticBufferImpl(unsigned int bufferId, PrimitiveType primitiveType, const Vertex* vertices, int vertexCount); - -private: - //! Current config - DeviceConfig m_config; - - //! Current world matrix - Math::Matrix m_worldMat; - //! Current view matrix - Math::Matrix m_viewMat; - //! OpenGL modelview matrix = world matrix * view matrix - Math::Matrix m_modelviewMat; - //! Current projection matrix - Math::Matrix m_projectionMat; - //! Combined world-view-projection matrix - Math::Matrix m_combinedMatrix; - - //! The current material - Material m_material; - - //! Whether lighting is enabled - bool m_lighting = false; - //! true means that lights need to be updated - bool m_updateLights = false; - //! Current lights - std::vector m_lights; - //! Current lights enable status - std::vector m_lightsEnabled; - - //! Current textures; \c nullptr value means unassigned - std::vector m_currentTextures; - //! Current texture stages enable status - std::vector m_texturesEnabled; - //! Current texture params - std::vector m_textureStageParams; - - //! Set of all created textures - std::set m_allTextures; - - //! Map of framebuffers - std::map> m_framebuffers; - - //! Info about static VBO buffers - struct VboObjectInfo - { - PrimitiveType primitiveType = {}; - unsigned int bufferId = 0; - VertexType vertexType = {}; - int vertexCount = 0; - int size = 0; - }; - - //! Detected capabilities - //! Framebuffer support - FramebufferSupport m_framebufferSupport = FBS_NONE; - //! Map of saved VBO objects - std::map m_vboObjects; - //! Last ID of VBO object - unsigned int m_lastVboId = 0; - //! Currently bound VBO - GLuint m_currentVBO = 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; - - //! Uniform locations - UniformLocations m_uniforms[3]; - //! Current mode - int m_mode = 0; -}; - - -} // namespace Gfx diff --git a/src/graphics/opengl/glutil.cpp b/src/graphics/opengl/glutil.cpp index fabce21c..97ccdd4c 100644 --- a/src/graphics/opengl/glutil.cpp +++ b/src/graphics/opengl/glutil.cpp @@ -23,8 +23,6 @@ #include "common/logger.h" #include "common/make_unique.h" -#include "graphics/opengl/gl14device.h" -#include "graphics/opengl/gl21device.h" #include "graphics/opengl/gl33device.h" #include @@ -71,18 +69,14 @@ FramebufferSupport DetectFramebufferSupport() std::unique_ptr CreateDevice(const DeviceConfig &config, const std::string& name) { - if (name == "default") return MakeUnique(config); - else if (name == "opengl") return MakeUnique(config); - else if (name == "gl14") return MakeUnique(config); - else if (name == "gl21") return MakeUnique(config); + if (name == "default") return MakeUnique(config); + else if (name == "opengl") return MakeUnique(config); else if (name == "gl33") return MakeUnique(config); else if (name == "auto") { int version = GetOpenGLVersion(); - if (version >= 33) return MakeUnique(config); - else if (version >= 21) return MakeUnique(config); - else return MakeUnique(config); + if (version >= 33) return MakeUnique(config); } return nullptr; diff --git a/src/graphics/opengl/shaders/CMakeLists.txt b/src/graphics/opengl/shaders/CMakeLists.txt index 716a9655..99258036 100644 --- a/src/graphics/opengl/shaders/CMakeLists.txt +++ b/src/graphics/opengl/shaders/CMakeLists.txt @@ -1,2 +1 @@ -install(DIRECTORY gl21 DESTINATION ${COLOBOT_INSTALL_DATA_DIR}/shaders) install(DIRECTORY gl33 DESTINATION ${COLOBOT_INSTALL_DATA_DIR}/shaders) diff --git a/src/graphics/opengl/shaders/gl21/fs_interface.glsl b/src/graphics/opengl/shaders/gl21/fs_interface.glsl deleted file mode 100644 index ef15cde3..00000000 --- a/src/graphics/opengl/shaders/gl21/fs_interface.glsl +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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/gl21/fs_normal.glsl b/src/graphics/opengl/shaders/gl21/fs_normal.glsl deleted file mode 100644 index 1aeffcbe..00000000 --- a/src/graphics/opengl/shaders/gl21/fs_normal.glsl +++ /dev/null @@ -1,146 +0,0 @@ -/* - * 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 - NORMAL MODE -#version 120 - -#define CONFIG_QUALITY_SHADOWS 1 - -uniform sampler2D uni_PrimaryTexture; -uniform sampler2D uni_SecondaryTexture; -uniform sampler2DShadow uni_ShadowTexture; - -uniform bool uni_TextureEnabled[3]; - -uniform bool uni_AlphaTestEnabled; -uniform float uni_AlphaReference; - -uniform bool uni_FogEnabled; -uniform vec2 uni_FogRange; -uniform vec4 uni_FogColor; - -uniform float uni_ShadowColor; -uniform float uni_ShadowTexelSize; - -struct LightParams -{ - vec4 Position; - vec4 Ambient; - vec4 Diffuse; - vec4 Specular; -}; - -struct Material -{ - vec4 ambient; - vec4 diffuse; - vec4 specular; -}; - -uniform Material uni_Material; - -uniform int uni_LightCount; -uniform LightParams uni_Light[4]; - -varying vec3 pass_CameraDirection; -varying float pass_Distance; -varying vec4 pass_Color; -varying vec3 pass_Normal; -varying vec2 pass_TexCoord0; -varying vec2 pass_TexCoord1; -varying vec3 pass_TexCoord2; - -const vec3 const_LightDirection = vec3(1.0f, 2.0f, -1.0f); - -void main() -{ - vec4 color = pass_Color; - - if (uni_LightCount > 0) - { - vec4 ambient = vec4(0.0f); - vec4 diffuse = vec4(0.0f); - vec4 specular = vec4(0.0f); - - vec3 normal = normalize(pass_Normal); - vec3 camera = normalize(pass_CameraDirection); - - for (int i = 0; i < uni_LightCount; i++) - { - LightParams light = uni_Light[i]; - - vec3 lightDirection = light.Position.xyz; - vec3 reflectAxis = normalize(normalize(lightDirection) + camera); - - float diffuseComponent = clamp(dot(normal, lightDirection), 0.0f, 1.0f); - float specularComponent = pow(clamp(dot(normal, reflectAxis), 0.0f, 1.0f), 10.0f); - - ambient += light.Ambient; - diffuse += diffuseComponent * light.Diffuse; - specular += specularComponent * light.Specular; - } - - float shadow = 1.0f; - - if (uni_TextureEnabled[2]) - { -#ifdef CONFIG_QUALITY_SHADOWS - float value = (1.0f / 5.0f) * (shadow2D(uni_ShadowTexture, pass_TexCoord2).x - + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( uni_ShadowTexelSize, 0.0f, 0.0f)).x - + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3(-uni_ShadowTexelSize, 0.0f, 0.0f)).x - + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( 0.0f, uni_ShadowTexelSize, 0.0f)).x - + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( 0.0f, -uni_ShadowTexelSize, 0.0f)).x); - - shadow = mix(uni_ShadowColor, 1.0f, value); -#else - shadow = mix(uni_ShadowColor, 1.0f, shadow2D(uni_ShadowTexture, pass_TexCoord2).x); -#endif - } - - vec4 result = ambient * uni_Material.ambient - + diffuse * uni_Material.diffuse * shadow - + specular * uni_Material.specular * shadow; - - color = clamp(vec4(result.rgb, 1.0f), 0.0f, 1.0f); - } - - if (uni_TextureEnabled[0]) - { - color = color * texture2D(uni_PrimaryTexture, pass_TexCoord0); - } - - if (uni_TextureEnabled[1]) - { - color = color * texture2D(uni_SecondaryTexture, pass_TexCoord1); - } - - if (uni_FogEnabled) - { - float interpolate = (pass_Distance - uni_FogRange.x) / (uni_FogRange.y - uni_FogRange.x); - - color = mix(color, uni_FogColor, clamp(interpolate, 0.0f, 1.0f)); - } - - if (uni_AlphaTestEnabled) - { - if(color.a < uni_AlphaReference) - discard; - } - - gl_FragColor = color; -} diff --git a/src/graphics/opengl/shaders/gl21/fs_shadow.glsl b/src/graphics/opengl/shaders/gl21/fs_shadow.glsl deleted file mode 100644 index 7b35925b..00000000 --- a/src/graphics/opengl/shaders/gl21/fs_shadow.glsl +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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/gl21/vs_interface.glsl b/src/graphics/opengl/shaders/gl21/vs_interface.glsl deleted file mode 100644 index e4b75c97..00000000 --- a/src/graphics/opengl/shaders/gl21/vs_interface.glsl +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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/gl21/vs_normal.glsl b/src/graphics/opengl/shaders/gl21/vs_normal.glsl deleted file mode 100644 index 41141c4b..00000000 --- a/src/graphics/opengl/shaders/gl21/vs_normal.glsl +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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 - NORMAL MODE -#version 120 - -uniform mat4 uni_ProjectionMatrix; -uniform mat4 uni_ViewMatrix; -uniform mat4 uni_ModelMatrix; -uniform mat4 uni_ShadowMatrix; -uniform mat4 uni_NormalMatrix; -uniform vec3 uni_CameraPosition; - -varying vec3 pass_CameraDirection; -varying float pass_Distance; -varying vec4 pass_Color; -varying vec3 pass_Normal; -varying vec2 pass_TexCoord0; -varying vec2 pass_TexCoord1; -varying vec3 pass_TexCoord2; - -void main() -{ - vec4 position = uni_ModelMatrix * gl_Vertex; - vec4 eyeSpace = uni_ViewMatrix * position; - vec4 shadowCoord = uni_ShadowMatrix * position; - - gl_Position = uni_ProjectionMatrix * eyeSpace; - - pass_CameraDirection = uni_CameraPosition - position.xyz; - pass_Color = gl_Color; - pass_Normal = normalize((uni_NormalMatrix * vec4(gl_Normal, 0.0f)).xyz); - pass_Distance = abs(eyeSpace.z / eyeSpace.w); - pass_TexCoord0 = gl_MultiTexCoord0.st; - pass_TexCoord1 = gl_MultiTexCoord1.st; - pass_TexCoord2 = shadowCoord.xyz / shadowCoord.w; -} diff --git a/src/graphics/opengl/shaders/gl21/vs_shadow.glsl b/src/graphics/opengl/shaders/gl21/vs_shadow.glsl deleted file mode 100644 index c3ed0147..00000000 --- a/src/graphics/opengl/shaders/gl21/vs_shadow.glsl +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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; -}