diff --git a/CMakeLists.txt b/CMakeLists.txt index 678da7b58..fab196650 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1686,7 +1686,9 @@ if(CLIENT) add_library(${TARGET_STEAMAPI} ${STEAMAPI_KIND} ${STEAMAPI_SRC}) list(APPEND TARGETS_OWN ${TARGET_STEAMAPI}) - set_src(ENGINE_CLIENT GLOB src/engine/client + set_src(ENGINE_CLIENT GLOB_RECURSE src/engine/client + backend/backend_opengl.cpp + backend/backend_opengl3.cpp backend_sdl.cpp backend_sdl.h blocklist_driver.cpp diff --git a/data/shader/text.frag b/data/shader/text.frag index 8254a3f8a..47aa8d6cd 100644 --- a/data/shader/text.frag +++ b/data/shader/text.frag @@ -10,12 +10,12 @@ noperspective in vec4 outVertColor; out vec4 FragClr; void main() { - vec4 textColor = gVertColor * outVertColor * texture(gTextSampler, texCoord); - vec4 textOutlineTex = gVertOutlineColor * texture(gTextOutlineSampler, texCoord); - + vec4 textColor = gVertColor * outVertColor * vec4(1.0, 1.0, 1.0, texture(gTextSampler, texCoord).r); + vec4 textOutlineTex = gVertOutlineColor * vec4(1.0, 1.0, 1.0, texture(gTextOutlineSampler, texCoord).r); + // ratio between the two textures float OutlineBlend = (1.0 - textColor.a); - + // since the outline is always black, or even if it has decent colors, it can be just added to the actual color // without loosing any or too much color diff --git a/data/shader/tile.vert b/data/shader/tile.vert index ba6ed9a25..0d3a4cfa7 100644 --- a/data/shader/tile.vert +++ b/data/shader/tile.vert @@ -24,14 +24,14 @@ void main() vec4 VertPos = vec4(inVertex, 0.0, 1.0); int XCount = gl_InstanceID - (int(gl_InstanceID/gJumpIndex) * gJumpIndex); int YCount = (int(gl_InstanceID/gJumpIndex)); - VertPos.x += gOffset.x + gDir.x * XCount; - VertPos.y += gOffset.y + gDir.y * YCount; + VertPos.x += gOffset.x + gDir.x * float(XCount); + VertPos.y += gOffset.y + gDir.y * float(YCount); gl_Position = vec4(gPos * VertPos, 0.0, 1.0); #elif defined(TW_TILE_BORDER_LINE) vec4 VertPos = vec4(inVertex.x + gOffset.x, inVertex.y + gOffset.y, 0.0, 1.0); - VertPos.x += gDir.x * gl_InstanceID; - VertPos.y += gDir.y * gl_InstanceID; + VertPos.x += gDir.x * float(gl_InstanceID); + VertPos.y += gDir.y * float(gl_InstanceID); gl_Position = vec4(gPos * VertPos, 0.0, 1.0); #else diff --git a/src/base/detect.h b/src/base/detect.h index 19a2386d4..f2926f661 100644 --- a/src/base/detect.h +++ b/src/base/detect.h @@ -51,6 +51,7 @@ #define CONF_FAMILY_STRING "unix" #define CONF_PLATFORM_LINUX 1 #define PLATFORM_STRING "linux" +#define CONF_BACKEND_OPENGL_ES 1 #endif #if defined(__GNU__) || defined(__gnu__) diff --git a/src/engine/client/backend/backend_opengl.cpp b/src/engine/client/backend/backend_opengl.cpp new file mode 100644 index 000000000..b0cbf7d33 --- /dev/null +++ b/src/engine/client/backend/backend_opengl.cpp @@ -0,0 +1,2279 @@ +#include + +#include + +#ifndef CONF_BACKEND_OPENGL_ES +#include +#else +#define GL_GLEXT_PROTOTYPES 1 +#include "SDL_opengles2.h" +#include +#include +#define glOrtho glOrthof +#define GL_TEXTURE_2D_ARRAY_EXT GL_TEXTURE_2D_ARRAY +// GLES doesnt support GL_QUADS, but the code is also never executed +#define GL_QUADS GL_TRIANGLES +#endif + +#include +#include + +#include + +// ------------ CCommandProcessorFragment_OpenGL +bool CCommandProcessorFragment_OpenGL::Texture2DTo3D(void *pImageBuffer, int ImageWidth, int ImageHeight, int ImageColorChannelCount, int SplitCountWidth, int SplitCountHeight, void *pTarget3DImageData, int &Target3DImageWidth, int &Target3DImageHeight) +{ + Target3DImageWidth = ImageWidth / SplitCountWidth; + Target3DImageHeight = ImageHeight / SplitCountHeight; + + size_t FullImageWidth = (size_t)ImageWidth * ImageColorChannelCount; + + for(int Y = 0; Y < SplitCountHeight; ++Y) + { + for(int X = 0; X < SplitCountWidth; ++X) + { + for(int Y3D = 0; Y3D < Target3DImageHeight; ++Y3D) + { + int DepthIndex = X + Y * SplitCountWidth; + + size_t TargetImageFullWidth = (size_t)Target3DImageWidth * ImageColorChannelCount; + size_t TargetImageFullSize = (size_t)TargetImageFullWidth * Target3DImageHeight; + ptrdiff_t ImageOffset = (ptrdiff_t)(((size_t)Y * FullImageWidth * (size_t)Target3DImageHeight) + ((size_t)Y3D * FullImageWidth) + ((size_t)X * TargetImageFullWidth)); + ptrdiff_t TargetImageOffset = (ptrdiff_t)(TargetImageFullSize * (size_t)DepthIndex + ((size_t)Y3D * TargetImageFullWidth)); + mem_copy(((uint8_t *)pTarget3DImageData) + TargetImageOffset, ((uint8_t *)pImageBuffer) + (ptrdiff_t)(ImageOffset), TargetImageFullWidth); + } + } + } + + return true; +} + +int CCommandProcessorFragment_OpenGL::TexFormatToOpenGLFormat(int TexFormat) +{ + if(TexFormat == CCommandBuffer::TEXFORMAT_RGB) + return GL_RGB; + if(TexFormat == CCommandBuffer::TEXFORMAT_ALPHA) + return GL_ALPHA; + if(TexFormat == CCommandBuffer::TEXFORMAT_RGBA) + return GL_RGBA; + return GL_RGBA; +} + +int CCommandProcessorFragment_OpenGL::TexFormatToImageColorChannelCount(int TexFormat) +{ + if(TexFormat == CCommandBuffer::TEXFORMAT_RGB) + return 3; + if(TexFormat == CCommandBuffer::TEXFORMAT_ALPHA) + return 1; + if(TexFormat == CCommandBuffer::TEXFORMAT_RGBA) + return 4; + return 4; +} + +void *CCommandProcessorFragment_OpenGL::Resize(int Width, int Height, int NewWidth, int NewHeight, int Format, const unsigned char *pData) +{ + int Bpp = TexFormatToImageColorChannelCount(Format); + + return ResizeImage((const uint8_t *)pData, Width, Height, NewWidth, NewHeight, Bpp); +} + +bool CCommandProcessorFragment_OpenGL::IsTexturedState(const CCommandBuffer::SState &State) +{ + return State.m_Texture >= 0 && State.m_Texture < (int)m_Textures.size(); +} + +void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &State, bool Use2DArrayTextures) +{ + // blend + switch(State.m_BlendMode) + { + case CCommandBuffer::BLEND_NONE: + glDisable(GL_BLEND); + break; + case CCommandBuffer::BLEND_ALPHA: + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + case CCommandBuffer::BLEND_ADDITIVE: + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + break; + default: + dbg_msg("render", "unknown blendmode %d\n", State.m_BlendMode); + }; + m_LastBlendMode = State.m_BlendMode; + + // clip + if(State.m_ClipEnable) + { + glScissor(State.m_ClipX, State.m_ClipY, State.m_ClipW, State.m_ClipH); + glEnable(GL_SCISSOR_TEST); + m_LastClipEnable = true; + } + else if(m_LastClipEnable) + { + // Don't disable it always + glDisable(GL_SCISSOR_TEST); + m_LastClipEnable = false; + } + + glDisable(GL_TEXTURE_2D); + if(!m_HasShaders) + { + if(m_Has3DTextures) + glDisable(GL_TEXTURE_3D); + if(m_Has2DArrayTextures) + { + glDisable(m_2DArrayTarget); + } + } + + if(m_HasShaders && IsNewApi()) + { + glBindSampler(0, 0); + } + + // texture + if(IsTexturedState(State)) + { + if(!Use2DArrayTextures) + { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, m_Textures[State.m_Texture].m_Tex); + + if(m_Textures[State.m_Texture].m_LastWrapMode != State.m_WrapMode) + { + switch(State.m_WrapMode) + { + case CCommandBuffer::WRAP_REPEAT: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + break; + case CCommandBuffer::WRAP_CLAMP: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + break; + default: + dbg_msg("render", "unknown wrapmode %d\n", State.m_WrapMode); + }; + m_Textures[State.m_Texture].m_LastWrapMode = State.m_WrapMode; + } + } + else + { + if(m_Has2DArrayTextures) + { + if(!m_HasShaders) + glEnable(m_2DArrayTarget); + glBindTexture(m_2DArrayTarget, m_Textures[State.m_Texture].m_Tex2DArray); + } + else if(m_Has3DTextures) + { + if(!m_HasShaders) + glEnable(GL_TEXTURE_3D); + glBindTexture(GL_TEXTURE_3D, m_Textures[State.m_Texture].m_Tex2DArray); + } + else + { + dbg_msg("opengl", "Error: this call should not happen."); + } + } + } + + // screen mapping + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(State.m_ScreenTL.x, State.m_ScreenBR.x, State.m_ScreenBR.y, State.m_ScreenTL.y, -10.0f, 10.f); +} + +static void ParseVersionString(EBackendType BackendType, const char *pStr, int &VersionMajor, int &VersionMinor, int &VersionPatch) +{ + if(pStr) + { + // if backend is GLES, it starts with "OpenGL ES " or OpenGL ES-CM for older contexts, rest is the same + if(BackendType == BACKEND_TYPE_OPENGL_ES) + { + int StrLenGLES = str_length("OpenGL ES "); + int StrLenGLESCM = str_length("OpenGL ES-CM "); + if(str_comp_num(pStr, "OpenGL ES ", StrLenGLES) == 0) + pStr += StrLenGLES; + else if(str_comp_num(pStr, "OpenGL ES-CM ", StrLenGLESCM) == 0) + pStr += StrLenGLESCM; + } + + char aCurNumberStr[32]; + size_t CurNumberStrLen = 0; + size_t TotalNumbersPassed = 0; + int aNumbers[3] = {0}; + bool LastWasNumber = false; + while(*pStr && TotalNumbersPassed < 3) + { + if(*pStr >= '0' && *pStr <= '9') + { + aCurNumberStr[CurNumberStrLen++] = (char)*pStr; + LastWasNumber = true; + } + else if(LastWasNumber && (*pStr == '.' || *pStr == ' ' || *pStr == '\0')) + { + int CurNumber = 0; + if(CurNumberStrLen > 0) + { + aCurNumberStr[CurNumberStrLen] = 0; + CurNumber = str_toint(aCurNumberStr); + aNumbers[TotalNumbersPassed++] = CurNumber; + CurNumberStrLen = 0; + } + + LastWasNumber = false; + + if(*pStr != '.') + break; + } + else + { + break; + } + + ++pStr; + } + + VersionMajor = aNumbers[0]; + VersionMinor = aNumbers[1]; + VersionPatch = aNumbers[2]; + } +} + +#ifndef CONF_BACKEND_OPENGL_ES +static const char *GetGLErrorName(GLenum Type) +{ + if(Type == GL_DEBUG_TYPE_ERROR) + return "ERROR"; + else if(Type == GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR) + return "DEPRECATED BEHAVIOR"; + else if(Type == GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR) + return "UNDEFINED BEHAVIOR"; + else if(Type == GL_DEBUG_TYPE_PORTABILITY) + return "PORTABILITY"; + else if(Type == GL_DEBUG_TYPE_PERFORMANCE) + return "PERFORMANCE"; + else if(Type == GL_DEBUG_TYPE_OTHER) + return "OTHER"; + else if(Type == GL_DEBUG_TYPE_MARKER) + return "MARKER"; + else if(Type == GL_DEBUG_TYPE_PUSH_GROUP) + return "PUSH_GROUP"; + else if(Type == GL_DEBUG_TYPE_POP_GROUP) + return "POP_GROUP"; + return "UNKNOWN"; +}; + +static const char *GetGLSeverity(GLenum Type) +{ + if(Type == GL_DEBUG_SEVERITY_HIGH) + return "high"; // All OpenGL Errors, shader compilation/linking errors, or highly-dangerous undefined behavior + else if(Type == GL_DEBUG_SEVERITY_MEDIUM) + return "medium"; // Major performance warnings, shader compilation/linking warnings, or the use of deprecated functionality + else if(Type == GL_DEBUG_SEVERITY_LOW) + return "low"; // Redundant state change performance warning, or unimportant undefined behavior + else if(Type == GL_DEBUG_SEVERITY_NOTIFICATION) + return "notification"; // Anything that isn't an error or performance issue. + + return "unknown"; +} + +static void GLAPIENTRY +GfxOpenGLMessageCallback(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar *message, + const void *userParam) +{ + dbg_msg("gfx", "[%s] (importance: %s) %s", GetGLErrorName(type), GetGLSeverity(severity), message); +} +#endif + +void CCommandProcessorFragment_OpenGL::InitOpenGL(const SCommand_Init *pCommand) +{ + m_IsOpenGLES = pCommand->m_RequestedBackend == BACKEND_TYPE_OPENGL_ES; + + // set some default settings + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + + if(!IsNewApi()) + glAlphaFunc(GL_GREATER, 0); + glEnable(GL_ALPHA_TEST); + glDepthMask(0); + +#ifndef CONF_BACKEND_OPENGL_ES + if(g_Config.m_DbgGfx) + { + if(GLEW_KHR_debug || GLEW_ARB_debug_output) + { + // During init, enable debug output + if(GLEW_KHR_debug) + { + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallback(GfxOpenGLMessageCallback, 0); + } + else if(GLEW_ARB_debug_output) + { + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); + glDebugMessageCallbackARB(GfxOpenGLMessageCallback, 0); + } + dbg_msg("gfx", "Enabled OpenGL debug mode"); + } + else + dbg_msg("gfx", "Requested OpenGL debug mode, but the driver does not support the required extension"); + } +#endif + + const char *pVendorString = (const char *)glGetString(GL_VENDOR); + dbg_msg("opengl", "Vendor string: %s", pVendorString); + + // check what this context can do + const char *pVersionString = (const char *)glGetString(GL_VERSION); + dbg_msg("opengl", "Version string: %s", pVersionString); + + const char *pRendererString = (const char *)glGetString(GL_RENDERER); + + str_copy(pCommand->m_pVendorString, pVendorString, gs_GPUInfoStringSize); + str_copy(pCommand->m_pVersionString, pVersionString, gs_GPUInfoStringSize); + str_copy(pCommand->m_pRendererString, pRendererString, gs_GPUInfoStringSize); + + // parse version string + ParseVersionString(pCommand->m_RequestedBackend, pVersionString, pCommand->m_pCapabilities->m_ContextMajor, pCommand->m_pCapabilities->m_ContextMinor, pCommand->m_pCapabilities->m_ContextPatch); + + *pCommand->m_pInitError = 0; + + int BlocklistMajor = -1, BlocklistMinor = -1, BlocklistPatch = -1; + const char *pErrString = ParseBlocklistDriverVersions(pVendorString, pVersionString, BlocklistMajor, BlocklistMinor, BlocklistPatch); + //if the driver is buggy, and the requested GL version is the default, fallback + if(pErrString != NULL && pCommand->m_RequestedMajor == 3 && pCommand->m_RequestedMinor == 0 && pCommand->m_RequestedPatch == 0) + { + // if not already in the error state, set the GL version + if(g_Config.m_GfxDriverIsBlocked == 0) + { + // fallback to known good GL version + pCommand->m_pCapabilities->m_ContextMajor = BlocklistMajor; + pCommand->m_pCapabilities->m_ContextMinor = BlocklistMinor; + pCommand->m_pCapabilities->m_ContextPatch = BlocklistPatch; + + // set backend error string + *pCommand->m_pErrStringPtr = pErrString; + *pCommand->m_pInitError = -2; + + g_Config.m_GfxDriverIsBlocked = 1; + } + } + // if the driver was in a blocked error state, but is not anymore, reset all config variables + else if(pErrString == NULL && g_Config.m_GfxDriverIsBlocked == 1) + { + pCommand->m_pCapabilities->m_ContextMajor = 3; + pCommand->m_pCapabilities->m_ContextMinor = 0; + pCommand->m_pCapabilities->m_ContextPatch = 0; + + // tell the caller to reinitialize the context + *pCommand->m_pInitError = -2; + + g_Config.m_GfxDriverIsBlocked = 0; + } + + int MajorV = pCommand->m_pCapabilities->m_ContextMajor; + + if(pCommand->m_RequestedBackend == BACKEND_TYPE_OPENGL) + { +#ifndef CONF_BACKEND_OPENGL_ES + int MinorV = pCommand->m_pCapabilities->m_ContextMinor; + if(*pCommand->m_pInitError == 0) + { + if(MajorV < pCommand->m_RequestedMajor) + { + *pCommand->m_pInitError = -2; + } + else if(MajorV == pCommand->m_RequestedMajor) + { + if(MinorV < pCommand->m_RequestedMinor) + { + *pCommand->m_pInitError = -2; + } + else if(MinorV == pCommand->m_RequestedMinor) + { + int PatchV = pCommand->m_pCapabilities->m_ContextPatch; + if(PatchV < pCommand->m_RequestedPatch) + { + *pCommand->m_pInitError = -2; + } + } + } + } + + if(*pCommand->m_pInitError == 0) + { + MajorV = pCommand->m_RequestedMajor; + MinorV = pCommand->m_RequestedMinor; + + pCommand->m_pCapabilities->m_2DArrayTexturesAsExtension = false; + pCommand->m_pCapabilities->m_NPOTTextures = true; + + if(MajorV >= 4 || (MajorV == 3 && MinorV == 3)) + { + pCommand->m_pCapabilities->m_TileBuffering = true; + pCommand->m_pCapabilities->m_QuadBuffering = true; + pCommand->m_pCapabilities->m_TextBuffering = true; + pCommand->m_pCapabilities->m_QuadContainerBuffering = true; + pCommand->m_pCapabilities->m_ShaderSupport = true; + + pCommand->m_pCapabilities->m_MipMapping = true; + pCommand->m_pCapabilities->m_3DTextures = true; + pCommand->m_pCapabilities->m_2DArrayTextures = true; + } + else if(MajorV == 3) + { + pCommand->m_pCapabilities->m_MipMapping = true; + // check for context native 2D array texture size + pCommand->m_pCapabilities->m_3DTextures = false; + pCommand->m_pCapabilities->m_2DArrayTextures = false; + pCommand->m_pCapabilities->m_ShaderSupport = true; + + int TextureLayers = 0; + glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &TextureLayers); + if(TextureLayers >= 256) + { + pCommand->m_pCapabilities->m_2DArrayTextures = true; + } + + int Texture3DSize = 0; + glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &Texture3DSize); + if(Texture3DSize >= 256) + { + pCommand->m_pCapabilities->m_3DTextures = true; + } + + if(!pCommand->m_pCapabilities->m_3DTextures && !pCommand->m_pCapabilities->m_2DArrayTextures) + { + *pCommand->m_pInitError = -2; + pCommand->m_pCapabilities->m_ContextMajor = 1; + pCommand->m_pCapabilities->m_ContextMinor = 5; + pCommand->m_pCapabilities->m_ContextPatch = 0; + } + + pCommand->m_pCapabilities->m_TileBuffering = pCommand->m_pCapabilities->m_2DArrayTextures || pCommand->m_pCapabilities->m_3DTextures; + pCommand->m_pCapabilities->m_QuadBuffering = false; + pCommand->m_pCapabilities->m_TextBuffering = false; + pCommand->m_pCapabilities->m_QuadContainerBuffering = false; + } + else if(MajorV == 2) + { + pCommand->m_pCapabilities->m_MipMapping = true; + // check for context extension: 2D array texture and its max size + pCommand->m_pCapabilities->m_3DTextures = false; + pCommand->m_pCapabilities->m_2DArrayTextures = false; + + pCommand->m_pCapabilities->m_ShaderSupport = false; + if(MinorV >= 1) + pCommand->m_pCapabilities->m_ShaderSupport = true; + + int Texture3DSize = 0; + glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &Texture3DSize); + if(Texture3DSize >= 256) + { + pCommand->m_pCapabilities->m_3DTextures = true; + } + + // check for array texture extension + if(pCommand->m_pCapabilities->m_ShaderSupport && GLEW_EXT_texture_array) + { + int TextureLayers = 0; + glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS_EXT, &TextureLayers); + if(TextureLayers >= 256) + { + pCommand->m_pCapabilities->m_2DArrayTextures = true; + pCommand->m_pCapabilities->m_2DArrayTexturesAsExtension = true; + } + } + + pCommand->m_pCapabilities->m_TileBuffering = pCommand->m_pCapabilities->m_2DArrayTextures || pCommand->m_pCapabilities->m_3DTextures; + pCommand->m_pCapabilities->m_QuadBuffering = false; + pCommand->m_pCapabilities->m_TextBuffering = false; + pCommand->m_pCapabilities->m_QuadContainerBuffering = false; + + if(GLEW_ARB_texture_non_power_of_two || pCommand->m_GlewMajor > 2) + pCommand->m_pCapabilities->m_NPOTTextures = true; + else + { + pCommand->m_pCapabilities->m_NPOTTextures = false; + } + + if(!pCommand->m_pCapabilities->m_NPOTTextures || (!pCommand->m_pCapabilities->m_3DTextures && !pCommand->m_pCapabilities->m_2DArrayTextures)) + { + *pCommand->m_pInitError = -2; + pCommand->m_pCapabilities->m_ContextMajor = 1; + pCommand->m_pCapabilities->m_ContextMinor = 5; + pCommand->m_pCapabilities->m_ContextPatch = 0; + } + } + else if(MajorV < 2) + { + pCommand->m_pCapabilities->m_TileBuffering = false; + pCommand->m_pCapabilities->m_QuadBuffering = false; + pCommand->m_pCapabilities->m_TextBuffering = false; + pCommand->m_pCapabilities->m_QuadContainerBuffering = false; + pCommand->m_pCapabilities->m_ShaderSupport = false; + + pCommand->m_pCapabilities->m_MipMapping = false; + pCommand->m_pCapabilities->m_3DTextures = false; + pCommand->m_pCapabilities->m_2DArrayTextures = false; + pCommand->m_pCapabilities->m_NPOTTextures = false; + } + } +#endif + } + else if(pCommand->m_RequestedBackend == BACKEND_TYPE_OPENGL_ES) + { + if(MajorV < 3) + { + pCommand->m_pCapabilities->m_TileBuffering = false; + pCommand->m_pCapabilities->m_QuadBuffering = false; + pCommand->m_pCapabilities->m_TextBuffering = false; + pCommand->m_pCapabilities->m_QuadContainerBuffering = false; + pCommand->m_pCapabilities->m_ShaderSupport = false; + + pCommand->m_pCapabilities->m_MipMapping = false; + pCommand->m_pCapabilities->m_3DTextures = false; + pCommand->m_pCapabilities->m_2DArrayTextures = false; + pCommand->m_pCapabilities->m_NPOTTextures = false; + } + else + { + pCommand->m_pCapabilities->m_TileBuffering = true; + pCommand->m_pCapabilities->m_QuadBuffering = true; + pCommand->m_pCapabilities->m_TextBuffering = true; + pCommand->m_pCapabilities->m_QuadContainerBuffering = true; + pCommand->m_pCapabilities->m_ShaderSupport = true; + + pCommand->m_pCapabilities->m_MipMapping = true; + pCommand->m_pCapabilities->m_3DTextures = true; + pCommand->m_pCapabilities->m_2DArrayTextures = true; + pCommand->m_pCapabilities->m_NPOTTextures = true; + } + } +} + +void CCommandProcessorFragment_OpenGL::Cmd_Init(const SCommand_Init *pCommand) +{ + InitOpenGL(pCommand); + + m_pTextureMemoryUsage = pCommand->m_pTextureMemoryUsage; + m_pTextureMemoryUsage->store(0, std::memory_order_relaxed); + m_MaxTexSize = -1; + + m_OpenGLTextureLodBIAS = 0; + + m_Has2DArrayTextures = pCommand->m_pCapabilities->m_2DArrayTextures; + if(pCommand->m_pCapabilities->m_2DArrayTexturesAsExtension) + { + m_Has2DArrayTexturesAsExtension = true; + m_2DArrayTarget = GL_TEXTURE_2D_ARRAY_EXT; + } + else + { + m_Has2DArrayTexturesAsExtension = false; + m_2DArrayTarget = GL_TEXTURE_2D_ARRAY; + } + + m_Has3DTextures = pCommand->m_pCapabilities->m_3DTextures; + m_HasMipMaps = pCommand->m_pCapabilities->m_MipMapping; + m_HasNPOTTextures = pCommand->m_pCapabilities->m_NPOTTextures; + + m_LastBlendMode = CCommandBuffer::BLEND_ALPHA; + m_LastClipEnable = false; +} + +void CCommandProcessorFragment_OpenGL::Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand) +{ + glBindTexture(GL_TEXTURE_2D, m_Textures[pCommand->m_Slot].m_Tex); + + void *pTexData = pCommand->m_pData; + int Width = pCommand->m_Width; + int Height = pCommand->m_Height; + int X = pCommand->m_X; + int Y = pCommand->m_Y; + + if(!m_HasNPOTTextures) + { + float ResizeW = m_Textures[pCommand->m_Slot].m_ResizeWidth; + float ResizeH = m_Textures[pCommand->m_Slot].m_ResizeHeight; + if(ResizeW > 0 && ResizeH > 0) + { + int ResizedW = (int)(Width * ResizeW); + int ResizedH = (int)(Height * ResizeH); + + void *pTmpData = Resize(Width, Height, ResizedW, ResizedH, pCommand->m_Format, static_cast(pTexData)); + free(pTexData); + pTexData = pTmpData; + + Width = ResizedW; + Height = ResizedH; + } + } + + if(m_Textures[pCommand->m_Slot].m_RescaleCount > 0) + { + int OldWidth = Width; + int OldHeight = Height; + for(int i = 0; i < m_Textures[pCommand->m_Slot].m_RescaleCount; ++i) + { + Width >>= 1; + Height >>= 1; + + X /= 2; + Y /= 2; + } + + void *pTmpData = Resize(OldWidth, OldHeight, Width, Height, pCommand->m_Format, static_cast(pTexData)); + free(pTexData); + pTexData = pTmpData; + } + + glTexSubImage2D(GL_TEXTURE_2D, 0, X, Y, Width, Height, + TexFormatToOpenGLFormat(pCommand->m_Format), GL_UNSIGNED_BYTE, pTexData); + free(pTexData); +} + +void CCommandProcessorFragment_OpenGL::DestroyTexture(int Slot) +{ + m_pTextureMemoryUsage->store(m_pTextureMemoryUsage->load(std::memory_order_relaxed) - m_Textures[Slot].m_MemSize, std::memory_order_relaxed); + + if(m_Textures[Slot].m_Tex != 0) + { + glDeleteTextures(1, &m_Textures[Slot].m_Tex); + } + + if(m_Textures[Slot].m_Tex2DArray != 0) + { + glDeleteTextures(1, &m_Textures[Slot].m_Tex2DArray); + } + + if(IsNewApi()) + { + if(m_Textures[Slot].m_Sampler != 0) + { + glDeleteSamplers(1, &m_Textures[Slot].m_Sampler); + } + if(m_Textures[Slot].m_Sampler2DArray != 0) + { + glDeleteSamplers(1, &m_Textures[Slot].m_Sampler2DArray); + } + } + + m_Textures[Slot].m_Tex = 0; + m_Textures[Slot].m_Sampler = 0; + m_Textures[Slot].m_Tex2DArray = 0; + m_Textures[Slot].m_Sampler2DArray = 0; + m_Textures[Slot].m_LastWrapMode = CCommandBuffer::WRAP_REPEAT; +} + +void CCommandProcessorFragment_OpenGL::Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand) +{ + DestroyTexture(pCommand->m_Slot); +} + +void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand) +{ + int Width = pCommand->m_Width; + int Height = pCommand->m_Height; + void *pTexData = pCommand->m_pData; + + if(m_MaxTexSize == -1) + { + // fix the alignment to allow even 1byte changes, e.g. for alpha components + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_MaxTexSize); + } + + if(pCommand->m_Slot >= (int)m_Textures.size()) + m_Textures.resize(m_Textures.size() * 2); + + m_Textures[pCommand->m_Slot].m_ResizeWidth = -1.f; + m_Textures[pCommand->m_Slot].m_ResizeHeight = -1.f; + + if(!m_HasNPOTTextures) + { + int PowerOfTwoWidth = HighestBit(Width); + int PowerOfTwoHeight = HighestBit(Height); + if(Width != PowerOfTwoWidth || Height != PowerOfTwoHeight) + { + void *pTmpData = Resize(Width, Height, PowerOfTwoWidth, PowerOfTwoHeight, pCommand->m_Format, static_cast(pTexData)); + free(pTexData); + pTexData = pTmpData; + + m_Textures[pCommand->m_Slot].m_ResizeWidth = (float)PowerOfTwoWidth / (float)Width; + m_Textures[pCommand->m_Slot].m_ResizeHeight = (float)PowerOfTwoHeight / (float)Height; + + Width = PowerOfTwoWidth; + Height = PowerOfTwoHeight; + } + } + + int RescaleCount = 0; + if(pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGBA || pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGB || pCommand->m_Format == CCommandBuffer::TEXFORMAT_ALPHA) + { + int OldWidth = Width; + int OldHeight = Height; + bool NeedsResize = false; + + if(Width > m_MaxTexSize || Height > m_MaxTexSize) + { + do + { + Width >>= 1; + Height >>= 1; + ++RescaleCount; + } while(Width > m_MaxTexSize || Height > m_MaxTexSize); + NeedsResize = true; + } + else if(pCommand->m_Format != CCommandBuffer::TEXFORMAT_ALPHA && (Width > 16 && Height > 16 && (pCommand->m_Flags & CCommandBuffer::TEXFLAG_QUALITY) == 0)) + { + Width >>= 1; + Height >>= 1; + ++RescaleCount; + NeedsResize = true; + } + + if(NeedsResize) + { + void *pTmpData = Resize(OldWidth, OldHeight, Width, Height, pCommand->m_Format, static_cast(pTexData)); + free(pTexData); + pTexData = pTmpData; + } + } + m_Textures[pCommand->m_Slot].m_Width = Width; + m_Textures[pCommand->m_Slot].m_Height = Height; + m_Textures[pCommand->m_Slot].m_RescaleCount = RescaleCount; + + int Oglformat = TexFormatToOpenGLFormat(pCommand->m_Format); + int StoreOglformat = TexFormatToOpenGLFormat(pCommand->m_StoreFormat); + + if((pCommand->m_Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0) + { + glGenTextures(1, &m_Textures[pCommand->m_Slot].m_Tex); + glBindTexture(GL_TEXTURE_2D, m_Textures[pCommand->m_Slot].m_Tex); + } + + if(pCommand->m_Flags & CCommandBuffer::TEXFLAG_NOMIPMAPS || !m_HasMipMaps) + { + if((pCommand->m_Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, StoreOglformat, Width, Height, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData); + } + } + else + { + if((pCommand->m_Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); + +#ifndef CONF_BACKEND_OPENGL_ES + if(m_OpenGLTextureLodBIAS != 0 && !m_IsOpenGLES) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f)); +#endif + + glTexImage2D(GL_TEXTURE_2D, 0, StoreOglformat, Width, Height, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData); + } + + int Flag2DArrayTexture = (CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE | CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE_SINGLE_LAYER); + int Flag3DTexture = (CCommandBuffer::TEXFLAG_TO_3D_TEXTURE | CCommandBuffer::TEXFLAG_TO_3D_TEXTURE_SINGLE_LAYER); + if((pCommand->m_Flags & (Flag2DArrayTexture | Flag3DTexture)) != 0) + { + bool Is3DTexture = (pCommand->m_Flags & Flag3DTexture) != 0; + + glGenTextures(1, &m_Textures[pCommand->m_Slot].m_Tex2DArray); + + GLenum Target = GL_TEXTURE_3D; + + if(Is3DTexture) + { + Target = GL_TEXTURE_3D; + } + else + { + Target = m_2DArrayTarget; + } + + glBindTexture(Target, m_Textures[pCommand->m_Slot].m_Tex2DArray); + + if(IsNewApi()) + { + glGenSamplers(1, &m_Textures[pCommand->m_Slot].m_Sampler2DArray); + glBindSampler(0, m_Textures[pCommand->m_Slot].m_Sampler2DArray); + } + + glTexParameteri(Target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + if(Is3DTexture) + { + glTexParameteri(Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + if(IsNewApi()) + glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + else + { + glTexParameteri(Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(Target, GL_GENERATE_MIPMAP, GL_TRUE); + if(IsNewApi()) + glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + } + + glTexParameteri(Target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(Target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(Target, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT); + +#ifndef CONF_BACKEND_OPENGL_ES + if(m_OpenGLTextureLodBIAS != 0 && !m_IsOpenGLES) + glTexParameterf(Target, GL_TEXTURE_LOD_BIAS, ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f)); +#endif + + if(IsNewApi()) + { + glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT); + +#ifndef CONF_BACKEND_OPENGL_ES + if(m_OpenGLTextureLodBIAS != 0 && !m_IsOpenGLES) + glSamplerParameterf(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_LOD_BIAS, ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f)); +#endif + + glBindSampler(0, 0); + } + + int ImageColorChannels = TexFormatToImageColorChannelCount(pCommand->m_Format); + + uint8_t *p3DImageData = NULL; + + bool IsSingleLayer = (pCommand->m_Flags & (CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE_SINGLE_LAYER | CCommandBuffer::TEXFLAG_TO_3D_TEXTURE_SINGLE_LAYER)) != 0; + + if(!IsSingleLayer) + p3DImageData = (uint8_t *)malloc((size_t)ImageColorChannels * Width * Height); + int Image3DWidth, Image3DHeight; + + int ConvertWidth = Width; + int ConvertHeight = Height; + + if(!IsSingleLayer) + { + if(ConvertWidth == 0 || (ConvertWidth % 16) != 0 || ConvertHeight == 0 || (ConvertHeight % 16) != 0) + { + dbg_msg("gfx", "3D/2D array texture was resized"); + int NewWidth = maximum(HighestBit(ConvertWidth), 16); + int NewHeight = maximum(HighestBit(ConvertHeight), 16); + uint8_t *pNewTexData = (uint8_t *)Resize(ConvertWidth, ConvertHeight, NewWidth, NewHeight, pCommand->m_Format, (const uint8_t *)pTexData); + + ConvertWidth = NewWidth; + ConvertHeight = NewHeight; + + free(pTexData); + pTexData = pNewTexData; + } + } + + if(IsSingleLayer || (Texture2DTo3D(pTexData, ConvertWidth, ConvertHeight, ImageColorChannels, 16, 16, p3DImageData, Image3DWidth, Image3DHeight))) + { + if(IsSingleLayer) + { + glTexImage3D(Target, 0, StoreOglformat, ConvertWidth, ConvertHeight, 1, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData); + } + else + { + glTexImage3D(Target, 0, StoreOglformat, Image3DWidth, Image3DHeight, 256, 0, Oglformat, GL_UNSIGNED_BYTE, p3DImageData); + } + } + + if(!IsSingleLayer) + free(p3DImageData); + } + } + + // This is the initial value for the wrap modes + m_Textures[pCommand->m_Slot].m_LastWrapMode = CCommandBuffer::WRAP_REPEAT; + + // calculate memory usage + m_Textures[pCommand->m_Slot].m_MemSize = Width * Height * pCommand->m_PixelSize; + while(Width > 2 && Height > 2) + { + Width >>= 1; + Height >>= 1; + m_Textures[pCommand->m_Slot].m_MemSize += Width * Height * pCommand->m_PixelSize; + } + m_pTextureMemoryUsage->store(m_pTextureMemoryUsage->load(std::memory_order_relaxed) + m_Textures[pCommand->m_Slot].m_MemSize, std::memory_order_relaxed); + + free(pTexData); +} + +void CCommandProcessorFragment_OpenGL::Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand) +{ + glClearColor(pCommand->m_Color.r, pCommand->m_Color.g, pCommand->m_Color.b, 0.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +void CCommandProcessorFragment_OpenGL::Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand) +{ + SetState(pCommand->m_State); + + glVertexPointer(2, GL_FLOAT, sizeof(CCommandBuffer::SVertex), (char *)pCommand->m_pVertices); + glTexCoordPointer(2, GL_FLOAT, sizeof(CCommandBuffer::SVertex), (char *)pCommand->m_pVertices + sizeof(float) * 2); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(CCommandBuffer::SVertex), (char *)pCommand->m_pVertices + sizeof(float) * 4); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + switch(pCommand->m_PrimType) + { + case CCommandBuffer::PRIMTYPE_QUADS: +#ifndef CONF_BACKEND_OPENGL_ES + glDrawArrays(GL_QUADS, 0, pCommand->m_PrimCount * 4); +#endif + break; + case CCommandBuffer::PRIMTYPE_LINES: + glDrawArrays(GL_LINES, 0, pCommand->m_PrimCount * 2); + break; + case CCommandBuffer::PRIMTYPE_TRIANGLES: + glDrawArrays(GL_TRIANGLES, 0, pCommand->m_PrimCount * 3); + break; + default: + dbg_msg("render", "unknown primtype %d\n", pCommand->m_PrimType); + }; +} + +void CCommandProcessorFragment_OpenGL::Cmd_Screenshot(const CCommandBuffer::SCommand_Screenshot *pCommand) +{ + // fetch image data + GLint aViewport[4] = {0, 0, 0, 0}; + glGetIntegerv(GL_VIEWPORT, aViewport); + + int w = aViewport[2]; + int h = aViewport[3]; + + // we allocate one more row to use when we are flipping the texture + unsigned char *pPixelData = (unsigned char *)malloc((size_t)w * (h + 1) * 3); + unsigned char *pTempRow = pPixelData + w * h * 3; + + // fetch the pixels + GLint Alignment; + glGetIntegerv(GL_PACK_ALIGNMENT, &Alignment); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, pPixelData); + glPixelStorei(GL_PACK_ALIGNMENT, Alignment); + + // flip the pixel because opengl works from bottom left corner + for(int y = 0; y < h / 2; y++) + { + mem_copy(pTempRow, pPixelData + y * w * 3, w * 3); + mem_copy(pPixelData + y * w * 3, pPixelData + (h - y - 1) * w * 3, w * 3); + mem_copy(pPixelData + (h - y - 1) * w * 3, pTempRow, w * 3); + } + + // fill in the information + pCommand->m_pImage->m_Width = w; + pCommand->m_pImage->m_Height = h; + pCommand->m_pImage->m_Format = CImageInfo::FORMAT_RGB; + pCommand->m_pImage->m_pData = pPixelData; +} + +CCommandProcessorFragment_OpenGL::CCommandProcessorFragment_OpenGL() +{ + m_Textures.resize(CCommandBuffer::MAX_TEXTURES); + m_HasShaders = false; +} + +bool CCommandProcessorFragment_OpenGL::RunCommand(const CCommandBuffer::SCommand *pBaseCommand) +{ + switch(pBaseCommand->m_Cmd) + { + case CCommandProcessorFragment_OpenGL::CMD_INIT: + Cmd_Init(static_cast(pBaseCommand)); + break; + case CCommandProcessorFragment_OpenGL::CMD_SHUTDOWN: + Cmd_Shutdown(static_cast(pBaseCommand)); + break; + case CCommandBuffer::CMD_TEXTURE_CREATE: + Cmd_Texture_Create(static_cast(pBaseCommand)); + break; + case CCommandBuffer::CMD_TEXTURE_DESTROY: + Cmd_Texture_Destroy(static_cast(pBaseCommand)); + break; + case CCommandBuffer::CMD_TEXTURE_UPDATE: + Cmd_Texture_Update(static_cast(pBaseCommand)); + break; + case CCommandBuffer::CMD_CLEAR: + Cmd_Clear(static_cast(pBaseCommand)); + break; + case CCommandBuffer::CMD_RENDER: + Cmd_Render(static_cast(pBaseCommand)); + break; + case CCommandBuffer::CMD_RENDER_TEX3D: + Cmd_RenderTex3D(static_cast(pBaseCommand)); + break; + case CCommandBuffer::CMD_SCREENSHOT: + Cmd_Screenshot(static_cast(pBaseCommand)); + break; + + case CCommandBuffer::CMD_CREATE_BUFFER_OBJECT: Cmd_CreateBufferObject(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_UPDATE_BUFFER_OBJECT: Cmd_UpdateBufferObject(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_RECREATE_BUFFER_OBJECT: Cmd_RecreateBufferObject(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_COPY_BUFFER_OBJECT: Cmd_CopyBufferObject(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_DELETE_BUFFER_OBJECT: Cmd_DeleteBufferObject(static_cast(pBaseCommand)); break; + + case CCommandBuffer::CMD_CREATE_BUFFER_CONTAINER: Cmd_CreateBufferContainer(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_UPDATE_BUFFER_CONTAINER: Cmd_UpdateBufferContainer(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_DELETE_BUFFER_CONTAINER: Cmd_DeleteBufferContainer(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_INDICES_REQUIRED_NUM_NOTIFY: Cmd_IndicesRequiredNumNotify(static_cast(pBaseCommand)); break; + + case CCommandBuffer::CMD_RENDER_TILE_LAYER: Cmd_RenderTileLayer(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_RENDER_BORDER_TILE: Cmd_RenderBorderTile(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_RENDER_BORDER_TILE_LINE: Cmd_RenderBorderTileLine(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_RENDER_QUAD_LAYER: Cmd_RenderQuadLayer(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_RENDER_TEXT: Cmd_RenderText(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_RENDER_TEXT_STREAM: Cmd_RenderTextStream(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_RENDER_QUAD_CONTAINER: Cmd_RenderQuadContainer(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_RENDER_QUAD_CONTAINER_EX: Cmd_RenderQuadContainerEx(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_RENDER_QUAD_CONTAINER_SPRITE_MULTIPLE: Cmd_RenderQuadContainerAsSpriteMultiple(static_cast(pBaseCommand)); break; + default: return false; + } + + return true; +} + +// ------------ CCommandProcessorFragment_OpenGL2 + +void CCommandProcessorFragment_OpenGL2::UseProgram(CGLSLTWProgram *pProgram) +{ + pProgram->UseProgram(); +} + +bool CCommandProcessorFragment_OpenGL2::IsAndUpdateTextureSlotBound(int IDX, int Slot, bool Is2DArray) +{ + if(m_TextureSlotBoundToUnit[IDX].m_TextureSlot == Slot && m_TextureSlotBoundToUnit[IDX].m_Is2DArray == Is2DArray) + return true; + else + { + //the texture slot uses this index now + m_TextureSlotBoundToUnit[IDX].m_TextureSlot = Slot; + m_TextureSlotBoundToUnit[IDX].m_Is2DArray = Is2DArray; + return false; + } +} + +void CCommandProcessorFragment_OpenGL2::SetState(const CCommandBuffer::SState &State, CGLSLTWProgram *pProgram, bool Use2DArrayTextures) +{ + if(m_LastBlendMode == CCommandBuffer::BLEND_NONE) + { + m_LastBlendMode = CCommandBuffer::BLEND_ALPHA; + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + if(State.m_BlendMode != m_LastBlendMode && State.m_BlendMode != CCommandBuffer::BLEND_NONE) + { + // blend + switch(State.m_BlendMode) + { + case CCommandBuffer::BLEND_NONE: + // We don't really need this anymore + //glDisable(GL_BLEND); + break; + case CCommandBuffer::BLEND_ALPHA: + //glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + case CCommandBuffer::BLEND_ADDITIVE: + //glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + break; + default: + dbg_msg("render", "unknown blendmode %d\n", State.m_BlendMode); + }; + + m_LastBlendMode = State.m_BlendMode; + } + + // clip + if(State.m_ClipEnable) + { + glScissor(State.m_ClipX, State.m_ClipY, State.m_ClipW, State.m_ClipH); + glEnable(GL_SCISSOR_TEST); + m_LastClipEnable = true; + } + else if(m_LastClipEnable) + { + // Don't disable it always + glDisable(GL_SCISSOR_TEST); + m_LastClipEnable = false; + } + + if(!IsNewApi()) + { + glDisable(GL_TEXTURE_2D); + if(!m_HasShaders) + { + if(m_Has3DTextures) + glDisable(GL_TEXTURE_3D); + if(m_Has2DArrayTextures) + { + glDisable(m_2DArrayTarget); + } + } + } + + // texture + if(IsTexturedState(State)) + { + int Slot = 0; + if(m_UseMultipleTextureUnits) + { + Slot = State.m_Texture % m_MaxTextureUnits; + if(!IsAndUpdateTextureSlotBound(Slot, State.m_Texture, Use2DArrayTextures)) + { + glActiveTexture(GL_TEXTURE0 + Slot); + if(!Use2DArrayTextures) + { + glBindTexture(GL_TEXTURE_2D, m_Textures[State.m_Texture].m_Tex); + if(IsNewApi()) + glBindSampler(Slot, m_Textures[State.m_Texture].m_Sampler); + } + else + { + glBindTexture(GL_TEXTURE_2D_ARRAY, m_Textures[State.m_Texture].m_Tex2DArray); + if(IsNewApi()) + glBindSampler(Slot, m_Textures[State.m_Texture].m_Sampler2DArray); + } + } + } + else + { + Slot = 0; + if(!Use2DArrayTextures) + { + if(!IsNewApi() && !m_HasShaders) + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, m_Textures[State.m_Texture].m_Tex); + if(IsNewApi()) + glBindSampler(Slot, m_Textures[State.m_Texture].m_Sampler); + } + else + { + if(!m_Has2DArrayTextures) + { + if(!IsNewApi() && !m_HasShaders) + glEnable(GL_TEXTURE_3D); + glBindTexture(GL_TEXTURE_3D, m_Textures[State.m_Texture].m_Tex2DArray); + if(IsNewApi()) + glBindSampler(Slot, m_Textures[State.m_Texture].m_Sampler2DArray); + } + else + { + if(!IsNewApi() && !m_HasShaders) + glEnable(m_2DArrayTarget); + glBindTexture(m_2DArrayTarget, m_Textures[State.m_Texture].m_Tex2DArray); + if(IsNewApi()) + glBindSampler(Slot, m_Textures[State.m_Texture].m_Sampler2DArray); + } + } + } + + if(pProgram->m_LastTextureSampler != Slot) + { + pProgram->SetUniform(pProgram->m_LocTextureSampler, Slot); + pProgram->m_LastTextureSampler = Slot; + } + + if(m_Textures[State.m_Texture].m_LastWrapMode != State.m_WrapMode && !Use2DArrayTextures) + { + switch(State.m_WrapMode) + { + case CCommandBuffer::WRAP_REPEAT: + if(IsNewApi()) + { + glSamplerParameteri(m_Textures[State.m_Texture].m_Sampler, GL_TEXTURE_WRAP_S, GL_REPEAT); + glSamplerParameteri(m_Textures[State.m_Texture].m_Sampler, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + break; + case CCommandBuffer::WRAP_CLAMP: + if(IsNewApi()) + { + glSamplerParameteri(m_Textures[State.m_Texture].m_Sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glSamplerParameteri(m_Textures[State.m_Texture].m_Sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + break; + default: + dbg_msg("render", "unknown wrapmode %d\n", State.m_WrapMode); + }; + m_Textures[State.m_Texture].m_LastWrapMode = State.m_WrapMode; + } + } + + if(pProgram->m_LastScreen[0] != State.m_ScreenTL.x || pProgram->m_LastScreen[1] != State.m_ScreenTL.y || pProgram->m_LastScreen[2] != State.m_ScreenBR.x || pProgram->m_LastScreen[3] != State.m_ScreenBR.y) + { + pProgram->m_LastScreen[0] = State.m_ScreenTL.x; + pProgram->m_LastScreen[1] = State.m_ScreenTL.y; + pProgram->m_LastScreen[2] = State.m_ScreenBR.x; + pProgram->m_LastScreen[3] = State.m_ScreenBR.y; + // screen mapping + // orthographic projection matrix + // the z coordinate is the same for every vertex, so just ignore the z coordinate and set it in the shaders + float m[2 * 4] = { + 2.f / (State.m_ScreenBR.x - State.m_ScreenTL.x), 0, 0, -((State.m_ScreenBR.x + State.m_ScreenTL.x) / (State.m_ScreenBR.x - State.m_ScreenTL.x)), + 0, (2.f / (State.m_ScreenTL.y - State.m_ScreenBR.y)), 0, -((State.m_ScreenTL.y + State.m_ScreenBR.y) / (State.m_ScreenTL.y - State.m_ScreenBR.y)), + //0, 0, -(2.f/(9.f)), -((11.f)/(9.f)), + //0, 0, 0, 1.0f + }; + + // transpose bcs of column-major order of opengl + glUniformMatrix4x2fv(pProgram->m_LocPos, 1, true, (float *)&m); + } +} + +bool CCommandProcessorFragment_OpenGL2::DoAnalyzeStep(size_t StepN, size_t CheckCount, size_t VerticesCount, uint8_t aFakeTexture[], size_t SingleImageSize) +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + int Slot = 0; + if(m_HasShaders) + { + CGLSLTWProgram *pProgram = m_pPrimitive3DProgramTextured; + if(StepN == 1) + pProgram = m_pTileProgramTextured; + UseProgram(pProgram); + + pProgram->SetUniform(pProgram->m_LocTextureSampler, Slot); + + if(StepN == 1) + { + float aColor[4] = {1.f, 1.f, 1.f, 1.f}; + pProgram->SetUniformVec4(((CGLSLTileProgram *)pProgram)->m_LocColor, 1, aColor); + } + + float m[2 * 4] = { + 1, 0, 0, 0, + 0, 1, 0, 0}; + + // transpose bcs of column-major order of opengl + glUniformMatrix4x2fv(pProgram->m_LocPos, 1, true, (float *)&m); + } + else + { + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-1, 1, -1, 1, -10.0f, 10.f); + } + + GLuint BufferID = 0; + if(StepN == 1 && m_HasShaders) + { + glGenBuffers(1, &BufferID); + glBindBuffer(GL_ARRAY_BUFFER, BufferID); + glBufferData(GL_ARRAY_BUFFER, VerticesCount * sizeof((m_aStreamVertices[0])), m_aStreamVertices, GL_STATIC_DRAW); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, false, sizeof((m_aStreamVertices[0])), 0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, false, sizeof((m_aStreamVertices[0])), (GLvoid *)(sizeof(vec4) + sizeof(vec2))); + } + else + { + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glVertexPointer(2, GL_FLOAT, sizeof(m_aStreamVertices[0]), m_aStreamVertices); + glColorPointer(4, GL_FLOAT, sizeof(m_aStreamVertices[0]), (uint8_t *)m_aStreamVertices + (ptrdiff_t)(sizeof(vec2))); + glTexCoordPointer(3, GL_FLOAT, sizeof(m_aStreamVertices[0]), (uint8_t *)m_aStreamVertices + (ptrdiff_t)(sizeof(vec2) + sizeof(vec4))); + } + + glDrawArrays(GL_QUADS, 0, VerticesCount); + + if(StepN == 1 && m_HasShaders) + { + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glDeleteBuffers(1, &BufferID); + } + else + { + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + + if(m_HasShaders) + { + glUseProgram(0); + } + + glFinish(); + + GLint aViewport[4] = {0, 0, 0, 0}; + glGetIntegerv(GL_VIEWPORT, aViewport); + + int w = aViewport[2]; + int h = aViewport[3]; + + size_t PixelDataSize = (size_t)w * h * 3; + if(PixelDataSize == 0) + return false; + uint8_t *pPixelData = (uint8_t *)malloc(PixelDataSize); + + // fetch the pixels + GLint Alignment; + glGetIntegerv(GL_PACK_ALIGNMENT, &Alignment); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, pPixelData); + glPixelStorei(GL_PACK_ALIGNMENT, Alignment); + + // now analyse the image data + bool CheckFailed = false; + int WidthTile = w / 16; + int HeightTile = h / 16; + int StartX = WidthTile / 2; + int StartY = HeightTile / 2; + for(size_t d = 0; d < CheckCount; ++d) + { + int CurX = (int)d % 16; + int CurY = (int)d / 16; + + int CheckX = StartX + CurX * WidthTile; + int CheckY = StartY + CurY * HeightTile; + + ptrdiff_t OffsetPixelData = (CheckY * (w * 3)) + (CheckX * 3); + ptrdiff_t OffsetFakeTexture = SingleImageSize * d; + OffsetPixelData = clamp(OffsetPixelData, 0, (ptrdiff_t)PixelDataSize); + OffsetFakeTexture = clamp(OffsetFakeTexture, 0, (ptrdiff_t)(SingleImageSize * CheckCount)); + uint8_t *pPixel = pPixelData + OffsetPixelData; + uint8_t *pPixelTex = aFakeTexture + OffsetFakeTexture; + for(size_t i = 0; i < 3; ++i) + { + if((pPixel[i] < pPixelTex[i] - 25) || (pPixel[i] > pPixelTex[i] + 25)) + { + CheckFailed = true; + break; + } + } + } + + free(pPixelData); + return !CheckFailed; +} + +bool CCommandProcessorFragment_OpenGL2::IsTileMapAnalysisSucceeded() +{ + glClearColor(0, 0, 0, 1); + + // create fake texture 1024x1024 + const size_t ImageWidth = 1024; + const size_t ImageHeight = 1024; + uint8_t *pFakeTexture = (uint8_t *)malloc(sizeof(uint8_t) * ImageWidth * ImageHeight * 4); + // fill by colors stepping by 50 => (255 / 50 ~ 5) => 5 times 3(color channels) = 5 ^ 3 = 125 possibilities to check + size_t CheckCount = 5 * 5 * 5; + // always fill 4 pixels of the texture, so the sampling is accurate + int aCurColor[4] = {25, 25, 25, 255}; + const size_t SingleImageWidth = 64; + const size_t SingleImageHeight = 64; + size_t SingleImageSize = SingleImageWidth * SingleImageHeight * 4; + for(size_t d = 0; d < CheckCount; ++d) + { + uint8_t *pCurFakeTexture = pFakeTexture + (ptrdiff_t)(SingleImageSize * d); + + uint8_t aCurColorUint8[SingleImageWidth * SingleImageHeight * 4]; + for(size_t y = 0; y < SingleImageHeight; ++y) + { + for(size_t x = 0; x < SingleImageWidth; ++x) + { + for(size_t i = 0; i < 4; ++i) + { + aCurColorUint8[(y * SingleImageWidth * 4) + (x * 4) + i] = (uint8_t)aCurColor[i]; + } + } + } + mem_copy(pCurFakeTexture, aCurColorUint8, sizeof(aCurColorUint8)); + + aCurColor[2] += 50; + if(aCurColor[2] > 225) + { + aCurColor[2] -= 250; + aCurColor[1] += 50; + } + if(aCurColor[1] > 225) + { + aCurColor[1] -= 250; + aCurColor[0] += 50; + } + if(aCurColor[0] > 225) + { + break; + } + } + + // upload the texture + GLuint FakeTexture; + glGenTextures(1, &FakeTexture); + + GLenum Target = GL_TEXTURE_3D; + if(m_Has2DArrayTextures) + { + Target = m_2DArrayTarget; + } + + glBindTexture(Target, FakeTexture); + glTexParameteri(Target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + if(!m_Has2DArrayTextures) + { + glTexParameteri(Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + else + { + glTexParameteri(Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(Target, GL_GENERATE_MIPMAP, GL_TRUE); + } + + glTexParameteri(Target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(Target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(Target, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT); + + glTexImage3D(Target, 0, GL_RGBA, ImageWidth / 16, ImageHeight / 16, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, pFakeTexture); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable(GL_SCISSOR_TEST); + + if(!m_HasShaders) + { + glDisable(GL_TEXTURE_2D); + if(m_Has3DTextures) + glDisable(GL_TEXTURE_3D); + if(m_Has2DArrayTextures) + { + glDisable(m_2DArrayTarget); + } + + if(!m_Has2DArrayTextures) + { + glEnable(GL_TEXTURE_3D); + glBindTexture(GL_TEXTURE_3D, FakeTexture); + } + else + { + glEnable(m_2DArrayTarget); + glBindTexture(m_2DArrayTarget, FakeTexture); + } + } + + static_assert(sizeof(m_aStreamVertices) / sizeof(m_aStreamVertices[0]) >= 256 * 4, "Keep the number of stream vertices >= 256 * 4."); + + size_t VertexCount = 0; + for(size_t i = 0; i < CheckCount; ++i) + { + float XPos = (float)(i % 16); + float YPos = (float)(i / 16); + + GL_SVertexTex3D *pVertex = &m_aStreamVertices[VertexCount++]; + GL_SVertexTex3D *pVertexBefore = pVertex; + pVertex->m_Pos.x = XPos / 16.f; + pVertex->m_Pos.y = YPos / 16.f; + pVertex->m_Color.r = 1; + pVertex->m_Color.g = 1; + pVertex->m_Color.b = 1; + pVertex->m_Color.a = 1; + pVertex->m_Tex.u = 0; + pVertex->m_Tex.v = 0; + + pVertex = &m_aStreamVertices[VertexCount++]; + pVertex->m_Pos.x = XPos / 16.f + 1.f / 16.f; + pVertex->m_Pos.y = YPos / 16.f; + pVertex->m_Color.r = 1; + pVertex->m_Color.g = 1; + pVertex->m_Color.b = 1; + pVertex->m_Color.a = 1; + pVertex->m_Tex.u = 1; + pVertex->m_Tex.v = 0; + + pVertex = &m_aStreamVertices[VertexCount++]; + pVertex->m_Pos.x = XPos / 16.f + 1.f / 16.f; + pVertex->m_Pos.y = YPos / 16.f + 1.f / 16.f; + pVertex->m_Color.r = 1; + pVertex->m_Color.g = 1; + pVertex->m_Color.b = 1; + pVertex->m_Color.a = 1; + pVertex->m_Tex.u = 1; + pVertex->m_Tex.v = 1; + + pVertex = &m_aStreamVertices[VertexCount++]; + pVertex->m_Pos.x = XPos / 16.f; + pVertex->m_Pos.y = YPos / 16.f + 1.f / 16.f; + pVertex->m_Color.r = 1; + pVertex->m_Color.g = 1; + pVertex->m_Color.b = 1; + pVertex->m_Color.a = 1; + pVertex->m_Tex.u = 0; + pVertex->m_Tex.v = 1; + + for(size_t n = 0; n < 4; ++n) + { + pVertexBefore[n].m_Pos.x *= 2; + pVertexBefore[n].m_Pos.x -= 1; + pVertexBefore[n].m_Pos.y *= 2; + pVertexBefore[n].m_Pos.y -= 1; + if(m_Has2DArrayTextures) + { + pVertexBefore[n].m_Tex.w = i; + } + else + { + pVertexBefore[n].m_Tex.w = (i + 0.5f) / 256.f; + } + } + } + + //everything build up, now do the analyze steps + bool NoError = DoAnalyzeStep(0, CheckCount, VertexCount, pFakeTexture, SingleImageSize); + if(NoError && m_HasShaders) + NoError &= DoAnalyzeStep(1, CheckCount, VertexCount, pFakeTexture, SingleImageSize); + + glDeleteTextures(1, &FakeTexture); + free(pFakeTexture); + + return NoError; +} + +void CCommandProcessorFragment_OpenGL2::Cmd_Init(const SCommand_Init *pCommand) +{ + CCommandProcessorFragment_OpenGL::Cmd_Init(pCommand); + + m_OpenGLTextureLodBIAS = g_Config.m_GfxOpenGLTextureLODBIAS; + + m_HasShaders = pCommand->m_pCapabilities->m_ShaderSupport; + + bool HasAllFunc = true; +#ifndef CONF_BACKEND_OPENGL_ES + if(m_HasShaders) + { + HasAllFunc &= (glUniformMatrix4x2fv != NULL) && (glGenBuffers != NULL); + HasAllFunc &= (glBindBuffer != NULL) && (glBufferData != NULL); + HasAllFunc &= (glEnableVertexAttribArray != NULL) && (glVertexAttribPointer != NULL); + HasAllFunc &= (glDisableVertexAttribArray != NULL) && (glDeleteBuffers != NULL); + HasAllFunc &= (glUseProgram != NULL) && (glTexImage3D != NULL); + HasAllFunc &= (glBindAttribLocation != NULL) && (glTexImage3D != NULL); + HasAllFunc &= (glBufferSubData != NULL) && (glGetUniformLocation != NULL); + HasAllFunc &= (glUniform1i != NULL) && (glUniform1f != NULL); + HasAllFunc &= (glUniform1ui != NULL) && (glUniform1i != NULL); + HasAllFunc &= (glUniform1fv != NULL) && (glUniform2fv != NULL); + HasAllFunc &= (glUniform4fv != NULL) && (glGetAttachedShaders != NULL); + HasAllFunc &= (glGetProgramInfoLog != NULL) && (glGetProgramiv != NULL); + HasAllFunc &= (glLinkProgram != NULL) && (glDetachShader != NULL); + HasAllFunc &= (glAttachShader != NULL) && (glDeleteProgram != NULL); + HasAllFunc &= (glCreateProgram != NULL) && (glShaderSource != NULL); + HasAllFunc &= (glCompileShader != NULL) && (glGetShaderiv != NULL); + HasAllFunc &= (glGetShaderInfoLog != NULL) && (glDeleteShader != NULL); + HasAllFunc &= (glCreateShader != NULL); + } +#endif + + bool AnalysisCorrect = true; + if(HasAllFunc) + { + if(m_HasShaders) + { + m_pTileProgram = new CGLSLTileProgram; + m_pTileProgramTextured = new CGLSLTileProgram; + m_pPrimitive3DProgram = new CGLSLPrimitiveProgram; + m_pPrimitive3DProgramTextured = new CGLSLPrimitiveProgram; + + CGLSLCompiler ShaderCompiler(g_Config.m_GfxOpenGLMajor, g_Config.m_GfxOpenGLMinor, g_Config.m_GfxOpenGLPatch, m_IsOpenGLES, m_OpenGLTextureLodBIAS / 1000.0f); + ShaderCompiler.SetHasTextureArray(pCommand->m_pCapabilities->m_2DArrayTextures); + + if(pCommand->m_pCapabilities->m_2DArrayTextures) + ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY); + else + ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D); + { + CGLSL PrimitiveVertexShader; + CGLSL PrimitiveFragmentShader; + PrimitiveVertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/pipeline.vert", GL_VERTEX_SHADER); + PrimitiveFragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/pipeline.frag", GL_FRAGMENT_SHADER); + + m_pPrimitive3DProgram->CreateProgram(); + m_pPrimitive3DProgram->AddShader(&PrimitiveVertexShader); + m_pPrimitive3DProgram->AddShader(&PrimitiveFragmentShader); + m_pPrimitive3DProgram->LinkProgram(); + + UseProgram(m_pPrimitive3DProgram); + + m_pPrimitive3DProgram->m_LocPos = m_pPrimitive3DProgram->GetUniformLoc("gPos"); + } + + if(pCommand->m_pCapabilities->m_2DArrayTextures) + ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY); + else + ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D); + { + CGLSL PrimitiveVertexShader; + CGLSL PrimitiveFragmentShader; + ShaderCompiler.AddDefine("TW_TEXTURED", ""); + if(!pCommand->m_pCapabilities->m_2DArrayTextures) + ShaderCompiler.AddDefine("TW_3D_TEXTURED", ""); + PrimitiveVertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/pipeline.vert", GL_VERTEX_SHADER); + PrimitiveFragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/pipeline.frag", GL_FRAGMENT_SHADER); + ShaderCompiler.ClearDefines(); + + m_pPrimitive3DProgramTextured->CreateProgram(); + m_pPrimitive3DProgramTextured->AddShader(&PrimitiveVertexShader); + m_pPrimitive3DProgramTextured->AddShader(&PrimitiveFragmentShader); + m_pPrimitive3DProgramTextured->LinkProgram(); + + UseProgram(m_pPrimitive3DProgramTextured); + + m_pPrimitive3DProgramTextured->m_LocPos = m_pPrimitive3DProgramTextured->GetUniformLoc("gPos"); + m_pPrimitive3DProgramTextured->m_LocTextureSampler = m_pPrimitive3DProgramTextured->GetUniformLoc("gTextureSampler"); + } + if(pCommand->m_pCapabilities->m_2DArrayTextures) + ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY); + else + ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D); + { + CGLSL VertexShader; + CGLSL FragmentShader; + VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.vert", GL_VERTEX_SHADER); + FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.frag", GL_FRAGMENT_SHADER); + + m_pTileProgram->CreateProgram(); + m_pTileProgram->AddShader(&VertexShader); + m_pTileProgram->AddShader(&FragmentShader); + + glBindAttribLocation(m_pTileProgram->GetProgramID(), 0, "inVertex"); + + m_pTileProgram->LinkProgram(); + + UseProgram(m_pTileProgram); + + m_pTileProgram->m_LocPos = m_pTileProgram->GetUniformLoc("gPos"); + m_pTileProgram->m_LocColor = m_pTileProgram->GetUniformLoc("gVertColor"); + } + if(pCommand->m_pCapabilities->m_2DArrayTextures) + ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY); + else + ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D); + { + CGLSL VertexShader; + CGLSL FragmentShader; + ShaderCompiler.AddDefine("TW_TILE_TEXTURED", ""); + if(!pCommand->m_pCapabilities->m_2DArrayTextures) + ShaderCompiler.AddDefine("TW_TILE_3D_TEXTURED", ""); + VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.vert", GL_VERTEX_SHADER); + FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.frag", GL_FRAGMENT_SHADER); + ShaderCompiler.ClearDefines(); + + m_pTileProgramTextured->CreateProgram(); + m_pTileProgramTextured->AddShader(&VertexShader); + m_pTileProgramTextured->AddShader(&FragmentShader); + + glBindAttribLocation(m_pTileProgram->GetProgramID(), 0, "inVertex"); + glBindAttribLocation(m_pTileProgram->GetProgramID(), 1, "inVertexTexCoord"); + + m_pTileProgramTextured->LinkProgram(); + + UseProgram(m_pTileProgramTextured); + + m_pTileProgramTextured->m_LocPos = m_pTileProgramTextured->GetUniformLoc("gPos"); + m_pTileProgramTextured->m_LocTextureSampler = m_pTileProgramTextured->GetUniformLoc("gTextureSampler"); + m_pTileProgramTextured->m_LocColor = m_pTileProgramTextured->GetUniformLoc("gVertColor"); + } + + glUseProgram(0); + } + + if(g_Config.m_Gfx3DTextureAnalysisDone == 0) + { + AnalysisCorrect = IsTileMapAnalysisSucceeded(); + if(AnalysisCorrect) + { + g_Config.m_Gfx3DTextureAnalysisDone = 1; + } + } + } + + if(!AnalysisCorrect || !HasAllFunc) + { + // downgrade to opengl 1.5 + *pCommand->m_pInitError = -2; + pCommand->m_pCapabilities->m_ContextMajor = 1; + pCommand->m_pCapabilities->m_ContextMinor = 5; + pCommand->m_pCapabilities->m_ContextPatch = 0; + } +} + +void CCommandProcessorFragment_OpenGL2::Cmd_RenderTex3D(const CCommandBuffer::SCommand_RenderTex3D *pCommand) +{ + if(m_HasShaders) + { + CGLSLPrimitiveProgram *pProgram = NULL; + if(IsTexturedState(pCommand->m_State)) + { + pProgram = m_pPrimitive3DProgramTextured; + } + else + pProgram = m_pPrimitive3DProgram; + + UseProgram(pProgram); + + SetState(pCommand->m_State, pProgram, true); + } + else + { + CCommandProcessorFragment_OpenGL::SetState(pCommand->m_State, true); + } + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glVertexPointer(2, GL_FLOAT, sizeof(pCommand->m_pVertices[0]), pCommand->m_pVertices); + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(pCommand->m_pVertices[0]), (uint8_t *)pCommand->m_pVertices + (ptrdiff_t)(sizeof(vec2))); + glTexCoordPointer(3, GL_FLOAT, sizeof(pCommand->m_pVertices[0]), (uint8_t *)pCommand->m_pVertices + (ptrdiff_t)(sizeof(vec2) + sizeof(unsigned char) * 4)); + + switch(pCommand->m_PrimType) + { + case CCommandBuffer::PRIMTYPE_QUADS: + glDrawArrays(GL_QUADS, 0, pCommand->m_PrimCount * 4); + break; + case CCommandBuffer::PRIMTYPE_TRIANGLES: + glDrawArrays(GL_TRIANGLES, 0, pCommand->m_PrimCount * 3); + break; + default: + dbg_msg("render", "unknown primtype %d\n", pCommand->m_PrimType); + }; + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + if(m_HasShaders) + { + glUseProgram(0); + } +} + +void CCommandProcessorFragment_OpenGL2::Cmd_CreateBufferObject(const CCommandBuffer::SCommand_CreateBufferObject *pCommand) +{ + void *pUploadData = pCommand->m_pUploadData; + int Index = pCommand->m_BufferIndex; + //create necessary space + if((size_t)Index >= m_BufferObjectIndices.size()) + { + for(int i = m_BufferObjectIndices.size(); i < Index + 1; ++i) + { + m_BufferObjectIndices.push_back(SBufferObject(0)); + } + } + + GLuint VertBufferID = 0; + + if(m_HasShaders) + { + glGenBuffers(1, &VertBufferID); + glBindBuffer(GL_COPY_WRITE_BUFFER, VertBufferID); + glBufferData(GL_COPY_WRITE_BUFFER, (GLsizeiptr)(pCommand->m_DataSize), pUploadData, GL_STATIC_DRAW); + glBindBuffer(GL_COPY_WRITE_BUFFER, 0); + } + + SBufferObject &BufferObject = m_BufferObjectIndices[Index]; + BufferObject.m_BufferObjectID = VertBufferID; + BufferObject.m_DataSize = pCommand->m_DataSize; + BufferObject.m_pData = malloc(pCommand->m_DataSize); + if(pUploadData) + mem_copy(BufferObject.m_pData, pUploadData, pCommand->m_DataSize); + + if(pCommand->m_DeletePointer) + free(pUploadData); +} + +void CCommandProcessorFragment_OpenGL2::Cmd_RecreateBufferObject(const CCommandBuffer::SCommand_RecreateBufferObject *pCommand) +{ + void *pUploadData = pCommand->m_pUploadData; + int Index = pCommand->m_BufferIndex; + SBufferObject &BufferObject = m_BufferObjectIndices[Index]; + + if(m_HasShaders) + { + glBindBuffer(GL_COPY_WRITE_BUFFER, BufferObject.m_BufferObjectID); + glBufferData(GL_COPY_WRITE_BUFFER, (GLsizeiptr)(pCommand->m_DataSize), pUploadData, GL_STATIC_DRAW); + glBindBuffer(GL_COPY_WRITE_BUFFER, 0); + } + + BufferObject.m_DataSize = pCommand->m_DataSize; + if(BufferObject.m_pData) + free(BufferObject.m_pData); + BufferObject.m_pData = malloc(pCommand->m_DataSize); + if(pUploadData) + mem_copy(BufferObject.m_pData, pUploadData, pCommand->m_DataSize); + + if(pCommand->m_DeletePointer) + free(pUploadData); +} + +void CCommandProcessorFragment_OpenGL2::Cmd_UpdateBufferObject(const CCommandBuffer::SCommand_UpdateBufferObject *pCommand) +{ + void *pUploadData = pCommand->m_pUploadData; + int Index = pCommand->m_BufferIndex; + SBufferObject &BufferObject = m_BufferObjectIndices[Index]; + + if(m_HasShaders) + { + glBindBuffer(GL_COPY_WRITE_BUFFER, BufferObject.m_BufferObjectID); + glBufferSubData(GL_COPY_WRITE_BUFFER, (GLintptr)(pCommand->m_pOffset), (GLsizeiptr)(pCommand->m_DataSize), pUploadData); + glBindBuffer(GL_COPY_WRITE_BUFFER, 0); + } + + if(pUploadData) + mem_copy(((uint8_t *)BufferObject.m_pData) + (ptrdiff_t)pCommand->m_pOffset, pUploadData, pCommand->m_DataSize); + + if(pCommand->m_DeletePointer) + free(pUploadData); +} + +void CCommandProcessorFragment_OpenGL2::Cmd_CopyBufferObject(const CCommandBuffer::SCommand_CopyBufferObject *pCommand) +{ + int WriteIndex = pCommand->m_WriteBufferIndex; + int ReadIndex = pCommand->m_ReadBufferIndex; + + SBufferObject &ReadBufferObject = m_BufferObjectIndices[ReadIndex]; + SBufferObject &WriteBufferObject = m_BufferObjectIndices[WriteIndex]; + + mem_copy(((uint8_t *)WriteBufferObject.m_pData) + (ptrdiff_t)pCommand->m_pWriteOffset, ((uint8_t *)ReadBufferObject.m_pData) + (ptrdiff_t)pCommand->m_pReadOffset, pCommand->m_CopySize); + + if(m_HasShaders) + { + glBindBuffer(GL_COPY_WRITE_BUFFER, WriteBufferObject.m_BufferObjectID); + glBufferSubData(GL_COPY_WRITE_BUFFER, (GLintptr)(pCommand->m_pWriteOffset), (GLsizeiptr)(pCommand->m_CopySize), ((uint8_t *)WriteBufferObject.m_pData) + (ptrdiff_t)pCommand->m_pWriteOffset); + glBindBuffer(GL_COPY_WRITE_BUFFER, 0); + } +} + +void CCommandProcessorFragment_OpenGL2::Cmd_DeleteBufferObject(const CCommandBuffer::SCommand_DeleteBufferObject *pCommand) +{ + int Index = pCommand->m_BufferIndex; + SBufferObject &BufferObject = m_BufferObjectIndices[Index]; + + if(m_HasShaders) + { + glDeleteBuffers(1, &BufferObject.m_BufferObjectID); + } + + if(BufferObject.m_pData) + { + free(BufferObject.m_pData); + BufferObject.m_pData = NULL; + } +} + +void CCommandProcessorFragment_OpenGL2::Cmd_CreateBufferContainer(const CCommandBuffer::SCommand_CreateBufferContainer *pCommand) +{ + int Index = pCommand->m_BufferContainerIndex; + //create necessary space + if((size_t)Index >= m_BufferContainers.size()) + { + for(int i = m_BufferContainers.size(); i < Index + 1; ++i) + { + SBufferContainer Container; + Container.m_ContainerInfo.m_Stride = 0; + m_BufferContainers.push_back(Container); + } + } + + SBufferContainer &BufferContainer = m_BufferContainers[Index]; + + for(int i = 0; i < pCommand->m_AttrCount; ++i) + { + SBufferContainerInfo::SAttribute &Attr = pCommand->m_Attributes[i]; + BufferContainer.m_ContainerInfo.m_Attributes.push_back(Attr); + } + + BufferContainer.m_ContainerInfo.m_Stride = pCommand->m_Stride; +} + +void CCommandProcessorFragment_OpenGL2::Cmd_UpdateBufferContainer(const CCommandBuffer::SCommand_UpdateBufferContainer *pCommand) +{ + SBufferContainer &BufferContainer = m_BufferContainers[pCommand->m_BufferContainerIndex]; + + BufferContainer.m_ContainerInfo.m_Attributes.clear(); + + for(int i = 0; i < pCommand->m_AttrCount; ++i) + { + SBufferContainerInfo::SAttribute &Attr = pCommand->m_Attributes[i]; + BufferContainer.m_ContainerInfo.m_Attributes.push_back(Attr); + } + + BufferContainer.m_ContainerInfo.m_Stride = pCommand->m_Stride; +} + +void CCommandProcessorFragment_OpenGL2::Cmd_DeleteBufferContainer(const CCommandBuffer::SCommand_DeleteBufferContainer *pCommand) +{ + SBufferContainer &BufferContainer = m_BufferContainers[pCommand->m_BufferContainerIndex]; + + if(pCommand->m_DestroyAllBO) + { + for(size_t i = 0; i < BufferContainer.m_ContainerInfo.m_Attributes.size(); ++i) + { + int VertBufferID = BufferContainer.m_ContainerInfo.m_Attributes[i].m_VertBufferBindingIndex; + if(VertBufferID != -1) + { + for(auto &Attribute : BufferContainer.m_ContainerInfo.m_Attributes) + { + // set all equal ids to zero to not double delete + if(VertBufferID == Attribute.m_VertBufferBindingIndex) + { + Attribute.m_VertBufferBindingIndex = -1; + } + } + + if(m_HasShaders) + { + glDeleteBuffers(1, &m_BufferObjectIndices[VertBufferID].m_BufferObjectID); + } + + if(m_BufferObjectIndices[VertBufferID].m_pData) + { + free(m_BufferObjectIndices[VertBufferID].m_pData); + m_BufferObjectIndices[VertBufferID].m_pData = NULL; + } + } + } + } + + BufferContainer.m_ContainerInfo.m_Attributes.clear(); +} + +void CCommandProcessorFragment_OpenGL2::Cmd_IndicesRequiredNumNotify(const CCommandBuffer::SCommand_IndicesRequiredNumNotify *pCommand) +{ +} + +void CCommandProcessorFragment_OpenGL2::RenderBorderTileEmulation(SBufferContainer &BufferContainer, const CCommandBuffer::SState &State, const float *pColor, const char *pBuffOffset, unsigned int DrawNum, const float *pOffset, const float *pDir, int JumpIndex) +{ + if(m_HasShaders) + { + CGLSLPrimitiveProgram *pProgram = NULL; + if(IsTexturedState(State)) + { + pProgram = m_pPrimitive3DProgramTextured; + } + else + pProgram = m_pPrimitive3DProgram; + + UseProgram(pProgram); + + SetState(State, pProgram, true); + } + else + { + CCommandProcessorFragment_OpenGL::SetState(State, true); + } + + bool IsTextured = BufferContainer.m_ContainerInfo.m_Attributes.size() == 2; + + SBufferObject &BufferObject = m_BufferObjectIndices[(size_t)BufferContainer.m_ContainerInfo.m_Attributes[0].m_VertBufferBindingIndex]; + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + if(IsTextured) + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glVertexPointer(2, GL_FLOAT, sizeof(m_aStreamVertices[0]), m_aStreamVertices); + glColorPointer(4, GL_FLOAT, sizeof(m_aStreamVertices[0]), (uint8_t *)m_aStreamVertices + (ptrdiff_t)(sizeof(vec2))); + if(IsTextured) + glTexCoordPointer(3, GL_FLOAT, sizeof(m_aStreamVertices[0]), (uint8_t *)m_aStreamVertices + (ptrdiff_t)(sizeof(vec2) + sizeof(vec4))); + + size_t VertexCount = 0; + for(size_t i = 0; i < DrawNum; ++i) + { + GLint RealOffset = (GLint)((((size_t)(uintptr_t)(pBuffOffset)) / (6 * sizeof(unsigned int))) * 4); + size_t SingleVertSize = (sizeof(vec2) + (IsTextured ? sizeof(vec3) : 0)); + size_t CurBufferOffset = (RealOffset)*SingleVertSize; + + for(size_t n = 0; n < 4; ++n) + { + int XCount = i - (int(i / JumpIndex) * JumpIndex); + int YCount = (int(i / JumpIndex)); + + ptrdiff_t VertOffset = (ptrdiff_t)(CurBufferOffset + (n * SingleVertSize)); + vec2 *pPos = (vec2 *)((uint8_t *)BufferObject.m_pData + VertOffset); + + GL_SVertexTex3D &Vertex = m_aStreamVertices[VertexCount++]; + mem_copy(&Vertex.m_Pos, pPos, sizeof(vec2)); + mem_copy(&Vertex.m_Color, pColor, sizeof(vec4)); + if(IsTextured) + { + vec3 *pTex = (vec3 *)((uint8_t *)BufferObject.m_pData + VertOffset + (ptrdiff_t)sizeof(vec2)); + mem_copy(&Vertex.m_Tex, pTex, sizeof(vec3)); + } + + Vertex.m_Pos.x += pOffset[0] + pDir[0] * XCount; + Vertex.m_Pos.y += pOffset[1] + pDir[1] * YCount; + + if(VertexCount >= sizeof(m_aStreamVertices) / sizeof(m_aStreamVertices[0])) + { + glDrawArrays(GL_QUADS, 0, VertexCount); + VertexCount = 0; + } + } + } + if(VertexCount > 0) + glDrawArrays(GL_QUADS, 0, VertexCount); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + + if(IsTextured) + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + if(m_HasShaders) + { + glUseProgram(0); + } +} + +void CCommandProcessorFragment_OpenGL2::RenderBorderTileLineEmulation(SBufferContainer &BufferContainer, const CCommandBuffer::SState &State, const float *pColor, const char *pBuffOffset, unsigned int IndexDrawNum, unsigned int DrawNum, const float *pOffset, const float *pDir) +{ + if(m_HasShaders) + { + CGLSLPrimitiveProgram *pProgram = NULL; + if(IsTexturedState(State)) + { + pProgram = m_pPrimitive3DProgramTextured; + } + else + pProgram = m_pPrimitive3DProgram; + + UseProgram(pProgram); + + SetState(State, pProgram, true); + } + else + { + CCommandProcessorFragment_OpenGL::SetState(State, true); + } + + bool IsTextured = BufferContainer.m_ContainerInfo.m_Attributes.size() == 2; + + SBufferObject &BufferObject = m_BufferObjectIndices[(size_t)BufferContainer.m_ContainerInfo.m_Attributes[0].m_VertBufferBindingIndex]; + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + if(IsTextured) + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glVertexPointer(2, GL_FLOAT, sizeof(m_aStreamVertices[0]), m_aStreamVertices); + glColorPointer(4, GL_FLOAT, sizeof(m_aStreamVertices[0]), (uint8_t *)m_aStreamVertices + (ptrdiff_t)(sizeof(vec2))); + if(IsTextured) + glTexCoordPointer(3, GL_FLOAT, sizeof(m_aStreamVertices[0]), (uint8_t *)m_aStreamVertices + (ptrdiff_t)(sizeof(vec2) + sizeof(vec4))); + + size_t VertexCount = 0; + for(size_t i = 0; i < DrawNum; ++i) + { + GLint RealOffset = (GLint)((((size_t)(uintptr_t)(pBuffOffset)) / (6 * sizeof(unsigned int))) * 4); + size_t SingleVertSize = (sizeof(vec2) + (IsTextured ? sizeof(vec3) : 0)); + size_t CurBufferOffset = (RealOffset)*SingleVertSize; + size_t VerticesPerLine = (size_t)IndexDrawNum / 6; + + for(size_t n = 0; n < 4 * (size_t)VerticesPerLine; ++n) + { + ptrdiff_t VertOffset = (ptrdiff_t)(CurBufferOffset + (n * SingleVertSize)); + vec2 *pPos = (vec2 *)((uint8_t *)BufferObject.m_pData + VertOffset); + + GL_SVertexTex3D &Vertex = m_aStreamVertices[VertexCount++]; + mem_copy(&Vertex.m_Pos, pPos, sizeof(vec2)); + mem_copy(&Vertex.m_Color, pColor, sizeof(vec4)); + if(IsTextured) + { + vec3 *pTex = (vec3 *)((uint8_t *)BufferObject.m_pData + VertOffset + (ptrdiff_t)sizeof(vec2)); + mem_copy(&Vertex.m_Tex, pTex, sizeof(vec3)); + } + + Vertex.m_Pos.x += pOffset[0] + pDir[0] * i; + Vertex.m_Pos.y += pOffset[1] + pDir[1] * i; + + if(VertexCount >= sizeof(m_aStreamVertices) / sizeof(m_aStreamVertices[0])) + { + glDrawArrays(GL_QUADS, 0, VertexCount); + VertexCount = 0; + } + } + } + if(VertexCount > 0) + glDrawArrays(GL_QUADS, 0, VertexCount); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + + if(IsTextured) + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + if(m_HasShaders) + { + glUseProgram(0); + } +} + +void CCommandProcessorFragment_OpenGL2::Cmd_RenderBorderTile(const CCommandBuffer::SCommand_RenderBorderTile *pCommand) +{ + int Index = pCommand->m_BufferContainerIndex; + //if space not there return + if((size_t)Index >= m_BufferContainers.size()) + return; + + SBufferContainer &BufferContainer = m_BufferContainers[Index]; + + RenderBorderTileEmulation(BufferContainer, pCommand->m_State, (float *)&pCommand->m_Color, pCommand->m_pIndicesOffset, pCommand->m_DrawNum, pCommand->m_Offset, pCommand->m_Dir, pCommand->m_JumpIndex); +} + +void CCommandProcessorFragment_OpenGL2::Cmd_RenderBorderTileLine(const CCommandBuffer::SCommand_RenderBorderTileLine *pCommand) +{ + int Index = pCommand->m_BufferContainerIndex; + //if space not there return + if((size_t)Index >= m_BufferContainers.size()) + return; + + SBufferContainer &BufferContainer = m_BufferContainers[Index]; + + RenderBorderTileLineEmulation(BufferContainer, pCommand->m_State, (float *)&pCommand->m_Color, pCommand->m_pIndicesOffset, pCommand->m_IndexDrawNum, pCommand->m_DrawNum, pCommand->m_Offset, pCommand->m_Dir); +} + +void CCommandProcessorFragment_OpenGL2::Cmd_RenderTileLayer(const CCommandBuffer::SCommand_RenderTileLayer *pCommand) +{ + int Index = pCommand->m_BufferContainerIndex; + //if space not there return + if((size_t)Index >= m_BufferContainers.size()) + return; + + SBufferContainer &BufferContainer = m_BufferContainers[Index]; + + if(pCommand->m_IndicesDrawNum == 0) + { + return; //nothing to draw + } + + if(m_HasShaders) + { + CGLSLTileProgram *pProgram = NULL; + if(IsTexturedState(pCommand->m_State)) + { + pProgram = m_pTileProgramTextured; + } + else + pProgram = m_pTileProgram; + + UseProgram(pProgram); + + SetState(pCommand->m_State, pProgram, true); + pProgram->SetUniformVec4(pProgram->m_LocColor, 1, (float *)&pCommand->m_Color); + } + else + { + CCommandProcessorFragment_OpenGL::SetState(pCommand->m_State, true); + } + + bool IsTextured = BufferContainer.m_ContainerInfo.m_Attributes.size() == 2; + + SBufferObject &BufferObject = m_BufferObjectIndices[(size_t)BufferContainer.m_ContainerInfo.m_Attributes[0].m_VertBufferBindingIndex]; + if(m_HasShaders) + glBindBuffer(GL_ARRAY_BUFFER, BufferObject.m_BufferObjectID); + + if(!m_HasShaders) + { + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + + if(IsTextured) + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + } + + if(m_HasShaders) + { + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, false, BufferContainer.m_ContainerInfo.m_Stride, BufferContainer.m_ContainerInfo.m_Attributes[0].m_pOffset); + if(IsTextured) + { + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 3, GL_FLOAT, false, BufferContainer.m_ContainerInfo.m_Stride, BufferContainer.m_ContainerInfo.m_Attributes[1].m_pOffset); + } + + for(int i = 0; i < pCommand->m_IndicesDrawNum; ++i) + { + size_t RealDrawCount = (pCommand->m_pDrawCount[i] / 6) * 4; + GLint RealOffset = (GLint)((((size_t)(uintptr_t)(pCommand->m_pIndicesOffsets[i])) / (6 * sizeof(unsigned int))) * 4); + glDrawArrays(GL_QUADS, RealOffset, RealDrawCount); + } + } + else + { + glVertexPointer(2, GL_FLOAT, sizeof(m_aStreamVertices[0]), m_aStreamVertices); + glColorPointer(4, GL_FLOAT, sizeof(m_aStreamVertices[0]), (uint8_t *)m_aStreamVertices + (ptrdiff_t)(sizeof(vec2))); + if(IsTextured) + glTexCoordPointer(3, GL_FLOAT, sizeof(m_aStreamVertices[0]), (uint8_t *)m_aStreamVertices + (ptrdiff_t)(sizeof(vec2) + sizeof(vec4))); + + size_t VertexCount = 0; + for(int i = 0; i < pCommand->m_IndicesDrawNum; ++i) + { + size_t RealDrawCount = (pCommand->m_pDrawCount[i] / 6) * 4; + GLint RealOffset = (GLint)((((size_t)(uintptr_t)(pCommand->m_pIndicesOffsets[i])) / (6 * sizeof(unsigned int))) * 4); + size_t SingleVertSize = (sizeof(vec2) + (IsTextured ? sizeof(vec3) : 0)); + size_t CurBufferOffset = RealOffset * SingleVertSize; + + for(size_t n = 0; n < RealDrawCount; ++n) + { + ptrdiff_t VertOffset = (ptrdiff_t)(CurBufferOffset + (n * SingleVertSize)); + vec2 *pPos = (vec2 *)((uint8_t *)BufferObject.m_pData + VertOffset); + GL_SVertexTex3D &Vertex = m_aStreamVertices[VertexCount++]; + mem_copy(&Vertex.m_Pos, pPos, sizeof(vec2)); + mem_copy(&Vertex.m_Color, &pCommand->m_Color, sizeof(vec4)); + if(IsTextured) + { + vec3 *pTex = (vec3 *)((uint8_t *)BufferObject.m_pData + VertOffset + (ptrdiff_t)sizeof(vec2)); + mem_copy(&Vertex.m_Tex, pTex, sizeof(vec3)); + } + + if(VertexCount >= sizeof(m_aStreamVertices) / sizeof(m_aStreamVertices[0])) + { + glDrawArrays(GL_QUADS, 0, VertexCount); + VertexCount = 0; + } + } + } + if(VertexCount > 0) + glDrawArrays(GL_QUADS, 0, VertexCount); + } + + if(!m_HasShaders) + { + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + + if(IsTextured) + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + else + { + glDisableVertexAttribArray(0); + if(IsTextured) + glDisableVertexAttribArray(1); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glUseProgram(0); + } +} diff --git a/src/engine/client/backend/backend_opengl3.cpp b/src/engine/client/backend/backend_opengl3.cpp new file mode 100644 index 000000000..5ce8a5866 --- /dev/null +++ b/src/engine/client/backend/backend_opengl3.cpp @@ -0,0 +1,1613 @@ +#include + +#include + +#ifndef CONF_BACKEND_OPENGL_ES +#include +#else +#define GL_GLEXT_PROTOTYPES 1 +#include "SDL_opengles2.h" +#include +#endif + +#include +#include + +#include + +// ------------ CCommandProcessorFragment_OpenGL3_3 +int CCommandProcessorFragment_OpenGL3_3::TexFormatToNewOpenGLFormat(int TexFormat) +{ + if(TexFormat == CCommandBuffer::TEXFORMAT_RGB) + return GL_RGB; + if(TexFormat == CCommandBuffer::TEXFORMAT_ALPHA) + return GL_RED; + if(TexFormat == CCommandBuffer::TEXFORMAT_RGBA) + return GL_RGBA; + return GL_RGBA; +} + +void CCommandProcessorFragment_OpenGL3_3::UseProgram(CGLSLTWProgram *pProgram) +{ + if(m_LastProgramID != pProgram->GetProgramID()) + { + pProgram->UseProgram(); + m_LastProgramID = pProgram->GetProgramID(); + } +} + +void CCommandProcessorFragment_OpenGL3_3::InitPrimExProgram(CGLSLPrimitiveExProgram *pProgram, CGLSLCompiler *pCompiler, IStorage *pStorage, bool Textured, bool Rotationless) +{ + CGLSL PrimitiveVertexShader; + CGLSL PrimitiveFragmentShader; + if(Textured) + pCompiler->AddDefine("TW_TEXTURED", ""); + if(Rotationless) + pCompiler->AddDefine("TW_ROTATIONLESS", ""); + PrimitiveVertexShader.LoadShader(pCompiler, pStorage, "shader/primex.vert", GL_VERTEX_SHADER); + PrimitiveFragmentShader.LoadShader(pCompiler, pStorage, "shader/primex.frag", GL_FRAGMENT_SHADER); + if(Textured || Rotationless) + pCompiler->ClearDefines(); + + pProgram->CreateProgram(); + pProgram->AddShader(&PrimitiveVertexShader); + pProgram->AddShader(&PrimitiveFragmentShader); + pProgram->LinkProgram(); + + UseProgram(pProgram); + + pProgram->m_LocPos = pProgram->GetUniformLoc("gPos"); + pProgram->m_LocTextureSampler = pProgram->GetUniformLoc("gTextureSampler"); + pProgram->m_LocRotation = pProgram->GetUniformLoc("gRotation"); + pProgram->m_LocCenter = pProgram->GetUniformLoc("gCenter"); + pProgram->m_LocVertciesColor = pProgram->GetUniformLoc("gVerticesColor"); + + pProgram->SetUniform(pProgram->m_LocRotation, 0.0f); + float Center[2] = {0.f, 0.f}; + pProgram->SetUniformVec2(pProgram->m_LocCenter, 1, Center); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_Init(const SCommand_Init *pCommand) +{ + InitOpenGL(pCommand); + + m_OpenGLTextureLodBIAS = g_Config.m_GfxOpenGLTextureLODBIAS; + + m_UseMultipleTextureUnits = g_Config.m_GfxEnableTextureUnitOptimization; + if(!m_UseMultipleTextureUnits) + { + glActiveTexture(GL_TEXTURE0); + } + + m_Has2DArrayTextures = true; + m_Has2DArrayTexturesAsExtension = false; + m_2DArrayTarget = GL_TEXTURE_2D_ARRAY; + m_Has3DTextures = false; + m_HasMipMaps = true; + m_HasNPOTTextures = true; + m_HasShaders = true; + + m_pTextureMemoryUsage = pCommand->m_pTextureMemoryUsage; + m_pTextureMemoryUsage->store(0, std::memory_order_relaxed); + m_LastBlendMode = CCommandBuffer::BLEND_ALPHA; + m_LastClipEnable = false; + m_pPrimitiveProgram = new CGLSLPrimitiveProgram; + m_pPrimitiveProgramTextured = new CGLSLPrimitiveProgram; + m_pTileProgram = new CGLSLTileProgram; + m_pTileProgramTextured = new CGLSLTileProgram; + m_pPrimitive3DProgram = new CGLSLPrimitiveProgram; + m_pPrimitive3DProgramTextured = new CGLSLPrimitiveProgram; + m_pBorderTileProgram = new CGLSLTileProgram; + m_pBorderTileProgramTextured = new CGLSLTileProgram; + m_pBorderTileLineProgram = new CGLSLTileProgram; + m_pBorderTileLineProgramTextured = new CGLSLTileProgram; + m_pQuadProgram = new CGLSLQuadProgram; + m_pQuadProgramTextured = new CGLSLQuadProgram; + m_pTextProgram = new CGLSLTextProgram; + m_pPrimitiveExProgram = new CGLSLPrimitiveExProgram; + m_pPrimitiveExProgramTextured = new CGLSLPrimitiveExProgram; + m_pPrimitiveExProgramRotationless = new CGLSLPrimitiveExProgram; + m_pPrimitiveExProgramTexturedRotationless = new CGLSLPrimitiveExProgram; + m_pSpriteProgramMultiple = new CGLSLSpriteMultipleProgram; + m_LastProgramID = 0; + + CGLSLCompiler ShaderCompiler(g_Config.m_GfxOpenGLMajor, g_Config.m_GfxOpenGLMinor, g_Config.m_GfxOpenGLPatch, m_IsOpenGLES, m_OpenGLTextureLodBIAS / 1000.0f); + + GLint CapVal; + glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &CapVal); + + m_MaxQuadsAtOnce = minimum(((CapVal - 20) / (3 * 4)), m_MaxQuadsPossible); + + { + CGLSL PrimitiveVertexShader; + CGLSL PrimitiveFragmentShader; + PrimitiveVertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/prim.vert", GL_VERTEX_SHADER); + PrimitiveFragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/prim.frag", GL_FRAGMENT_SHADER); + + m_pPrimitiveProgram->CreateProgram(); + m_pPrimitiveProgram->AddShader(&PrimitiveVertexShader); + m_pPrimitiveProgram->AddShader(&PrimitiveFragmentShader); + m_pPrimitiveProgram->LinkProgram(); + + UseProgram(m_pPrimitiveProgram); + + m_pPrimitiveProgram->m_LocPos = m_pPrimitiveProgram->GetUniformLoc("gPos"); + m_pPrimitiveProgram->m_LocTextureSampler = m_pPrimitiveProgram->GetUniformLoc("gTextureSampler"); + } + { + CGLSL PrimitiveVertexShader; + CGLSL PrimitiveFragmentShader; + ShaderCompiler.AddDefine("TW_TEXTURED", ""); + PrimitiveVertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/prim.vert", GL_VERTEX_SHADER); + PrimitiveFragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/prim.frag", GL_FRAGMENT_SHADER); + ShaderCompiler.ClearDefines(); + + m_pPrimitiveProgramTextured->CreateProgram(); + m_pPrimitiveProgramTextured->AddShader(&PrimitiveVertexShader); + m_pPrimitiveProgramTextured->AddShader(&PrimitiveFragmentShader); + m_pPrimitiveProgramTextured->LinkProgram(); + + UseProgram(m_pPrimitiveProgramTextured); + + m_pPrimitiveProgramTextured->m_LocPos = m_pPrimitiveProgramTextured->GetUniformLoc("gPos"); + m_pPrimitiveProgramTextured->m_LocTextureSampler = m_pPrimitiveProgramTextured->GetUniformLoc("gTextureSampler"); + } + + { + CGLSL PrimitiveVertexShader; + CGLSL PrimitiveFragmentShader; + ShaderCompiler.AddDefine("TW_MODERN_GL", ""); + PrimitiveVertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/pipeline.vert", GL_VERTEX_SHADER); + PrimitiveFragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/pipeline.frag", GL_FRAGMENT_SHADER); + ShaderCompiler.ClearDefines(); + + m_pPrimitive3DProgram->CreateProgram(); + m_pPrimitive3DProgram->AddShader(&PrimitiveVertexShader); + m_pPrimitive3DProgram->AddShader(&PrimitiveFragmentShader); + m_pPrimitive3DProgram->LinkProgram(); + + UseProgram(m_pPrimitive3DProgram); + + m_pPrimitive3DProgram->m_LocPos = m_pPrimitive3DProgram->GetUniformLoc("gPos"); + } + { + CGLSL PrimitiveVertexShader; + CGLSL PrimitiveFragmentShader; + ShaderCompiler.AddDefine("TW_MODERN_GL", ""); + ShaderCompiler.AddDefine("TW_TEXTURED", ""); + if(!pCommand->m_pCapabilities->m_2DArrayTextures) + ShaderCompiler.AddDefine("TW_3D_TEXTURED", ""); + PrimitiveVertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/pipeline.vert", GL_VERTEX_SHADER); + PrimitiveFragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/pipeline.frag", GL_FRAGMENT_SHADER); + ShaderCompiler.ClearDefines(); + + m_pPrimitive3DProgramTextured->CreateProgram(); + m_pPrimitive3DProgramTextured->AddShader(&PrimitiveVertexShader); + m_pPrimitive3DProgramTextured->AddShader(&PrimitiveFragmentShader); + m_pPrimitive3DProgramTextured->LinkProgram(); + + UseProgram(m_pPrimitive3DProgramTextured); + + m_pPrimitive3DProgramTextured->m_LocPos = m_pPrimitive3DProgramTextured->GetUniformLoc("gPos"); + m_pPrimitive3DProgramTextured->m_LocTextureSampler = m_pPrimitive3DProgramTextured->GetUniformLoc("gTextureSampler"); + } + + { + CGLSL VertexShader; + CGLSL FragmentShader; + VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.vert", GL_VERTEX_SHADER); + FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.frag", GL_FRAGMENT_SHADER); + + m_pTileProgram->CreateProgram(); + m_pTileProgram->AddShader(&VertexShader); + m_pTileProgram->AddShader(&FragmentShader); + m_pTileProgram->LinkProgram(); + + UseProgram(m_pTileProgram); + + m_pTileProgram->m_LocPos = m_pTileProgram->GetUniformLoc("gPos"); + m_pTileProgram->m_LocColor = m_pTileProgram->GetUniformLoc("gVertColor"); + } + { + CGLSL VertexShader; + CGLSL FragmentShader; + ShaderCompiler.AddDefine("TW_TILE_TEXTURED", ""); + VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.vert", GL_VERTEX_SHADER); + FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.frag", GL_FRAGMENT_SHADER); + ShaderCompiler.ClearDefines(); + + m_pTileProgramTextured->CreateProgram(); + m_pTileProgramTextured->AddShader(&VertexShader); + m_pTileProgramTextured->AddShader(&FragmentShader); + m_pTileProgramTextured->LinkProgram(); + + UseProgram(m_pTileProgramTextured); + + m_pTileProgramTextured->m_LocPos = m_pTileProgramTextured->GetUniformLoc("gPos"); + m_pTileProgramTextured->m_LocTextureSampler = m_pTileProgramTextured->GetUniformLoc("gTextureSampler"); + m_pTileProgramTextured->m_LocColor = m_pTileProgramTextured->GetUniformLoc("gVertColor"); + } + { + CGLSL VertexShader; + CGLSL FragmentShader; + ShaderCompiler.AddDefine("TW_TILE_BORDER", ""); + VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.vert", GL_VERTEX_SHADER); + FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.frag", GL_FRAGMENT_SHADER); + ShaderCompiler.ClearDefines(); + + m_pBorderTileProgram->CreateProgram(); + m_pBorderTileProgram->AddShader(&VertexShader); + m_pBorderTileProgram->AddShader(&FragmentShader); + m_pBorderTileProgram->LinkProgram(); + + UseProgram(m_pBorderTileProgram); + + m_pBorderTileProgram->m_LocPos = m_pBorderTileProgram->GetUniformLoc("gPos"); + m_pBorderTileProgram->m_LocColor = m_pBorderTileProgram->GetUniformLoc("gVertColor"); + m_pBorderTileProgram->m_LocOffset = m_pBorderTileProgram->GetUniformLoc("gOffset"); + m_pBorderTileProgram->m_LocDir = m_pBorderTileProgram->GetUniformLoc("gDir"); + m_pBorderTileProgram->m_LocJumpIndex = m_pBorderTileProgram->GetUniformLoc("gJumpIndex"); + } + { + CGLSL VertexShader; + CGLSL FragmentShader; + ShaderCompiler.AddDefine("TW_TILE_BORDER", ""); + ShaderCompiler.AddDefine("TW_TILE_TEXTURED", ""); + VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.vert", GL_VERTEX_SHADER); + FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.frag", GL_FRAGMENT_SHADER); + ShaderCompiler.ClearDefines(); + + m_pBorderTileProgramTextured->CreateProgram(); + m_pBorderTileProgramTextured->AddShader(&VertexShader); + m_pBorderTileProgramTextured->AddShader(&FragmentShader); + m_pBorderTileProgramTextured->LinkProgram(); + + UseProgram(m_pBorderTileProgramTextured); + + m_pBorderTileProgramTextured->m_LocPos = m_pBorderTileProgramTextured->GetUniformLoc("gPos"); + m_pBorderTileProgramTextured->m_LocTextureSampler = m_pBorderTileProgramTextured->GetUniformLoc("gTextureSampler"); + m_pBorderTileProgramTextured->m_LocColor = m_pBorderTileProgramTextured->GetUniformLoc("gVertColor"); + m_pBorderTileProgramTextured->m_LocOffset = m_pBorderTileProgramTextured->GetUniformLoc("gOffset"); + m_pBorderTileProgramTextured->m_LocDir = m_pBorderTileProgramTextured->GetUniformLoc("gDir"); + m_pBorderTileProgramTextured->m_LocJumpIndex = m_pBorderTileProgramTextured->GetUniformLoc("gJumpIndex"); + } + { + CGLSL VertexShader; + CGLSL FragmentShader; + ShaderCompiler.AddDefine("TW_TILE_BORDER_LINE", ""); + VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.vert", GL_VERTEX_SHADER); + FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.frag", GL_FRAGMENT_SHADER); + ShaderCompiler.ClearDefines(); + + m_pBorderTileLineProgram->CreateProgram(); + m_pBorderTileLineProgram->AddShader(&VertexShader); + m_pBorderTileLineProgram->AddShader(&FragmentShader); + m_pBorderTileLineProgram->LinkProgram(); + + UseProgram(m_pBorderTileLineProgram); + + m_pBorderTileLineProgram->m_LocPos = m_pBorderTileLineProgram->GetUniformLoc("gPos"); + m_pBorderTileLineProgram->m_LocColor = m_pBorderTileLineProgram->GetUniformLoc("gVertColor"); + m_pBorderTileLineProgram->m_LocOffset = m_pBorderTileLineProgram->GetUniformLoc("gOffset"); + m_pBorderTileLineProgram->m_LocDir = m_pBorderTileLineProgram->GetUniformLoc("gDir"); + } + { + CGLSL VertexShader; + CGLSL FragmentShader; + ShaderCompiler.AddDefine("TW_TILE_BORDER_LINE", ""); + ShaderCompiler.AddDefine("TW_TILE_TEXTURED", ""); + VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.vert", GL_VERTEX_SHADER); + FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.frag", GL_FRAGMENT_SHADER); + ShaderCompiler.ClearDefines(); + + m_pBorderTileLineProgramTextured->CreateProgram(); + m_pBorderTileLineProgramTextured->AddShader(&VertexShader); + m_pBorderTileLineProgramTextured->AddShader(&FragmentShader); + m_pBorderTileLineProgramTextured->LinkProgram(); + + UseProgram(m_pBorderTileLineProgramTextured); + + m_pBorderTileLineProgramTextured->m_LocPos = m_pBorderTileLineProgramTextured->GetUniformLoc("gPos"); + m_pBorderTileLineProgramTextured->m_LocTextureSampler = m_pBorderTileLineProgramTextured->GetUniformLoc("gTextureSampler"); + m_pBorderTileLineProgramTextured->m_LocColor = m_pBorderTileLineProgramTextured->GetUniformLoc("gVertColor"); + m_pBorderTileLineProgramTextured->m_LocOffset = m_pBorderTileLineProgramTextured->GetUniformLoc("gOffset"); + m_pBorderTileLineProgramTextured->m_LocDir = m_pBorderTileLineProgramTextured->GetUniformLoc("gDir"); + } + { + CGLSL VertexShader; + CGLSL FragmentShader; + ShaderCompiler.AddDefine("TW_MAX_QUADS", std::to_string(m_MaxQuadsAtOnce).c_str()); + VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/quad.vert", GL_VERTEX_SHADER); + FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/quad.frag", GL_FRAGMENT_SHADER); + ShaderCompiler.ClearDefines(); + + m_pQuadProgram->CreateProgram(); + m_pQuadProgram->AddShader(&VertexShader); + m_pQuadProgram->AddShader(&FragmentShader); + m_pQuadProgram->LinkProgram(); + + UseProgram(m_pQuadProgram); + + m_pQuadProgram->m_LocPos = m_pQuadProgram->GetUniformLoc("gPos"); + m_pQuadProgram->m_LocColors = m_pQuadProgram->GetUniformLoc("gVertColors"); + m_pQuadProgram->m_LocRotations = m_pQuadProgram->GetUniformLoc("gRotations"); + m_pQuadProgram->m_LocOffsets = m_pQuadProgram->GetUniformLoc("gOffsets"); + m_pQuadProgram->m_LocQuadOffset = m_pQuadProgram->GetUniformLoc("gQuadOffset"); + } + { + CGLSL VertexShader; + CGLSL FragmentShader; + ShaderCompiler.AddDefine("TW_QUAD_TEXTURED", ""); + ShaderCompiler.AddDefine("TW_MAX_QUADS", std::to_string(m_MaxQuadsAtOnce).c_str()); + VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/quad.vert", GL_VERTEX_SHADER); + FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/quad.frag", GL_FRAGMENT_SHADER); + ShaderCompiler.ClearDefines(); + + m_pQuadProgramTextured->CreateProgram(); + m_pQuadProgramTextured->AddShader(&VertexShader); + m_pQuadProgramTextured->AddShader(&FragmentShader); + m_pQuadProgramTextured->LinkProgram(); + + UseProgram(m_pQuadProgramTextured); + + m_pQuadProgramTextured->m_LocPos = m_pQuadProgramTextured->GetUniformLoc("gPos"); + m_pQuadProgramTextured->m_LocTextureSampler = m_pQuadProgramTextured->GetUniformLoc("gTextureSampler"); + m_pQuadProgramTextured->m_LocColors = m_pQuadProgramTextured->GetUniformLoc("gVertColors"); + m_pQuadProgramTextured->m_LocRotations = m_pQuadProgramTextured->GetUniformLoc("gRotations"); + m_pQuadProgramTextured->m_LocOffsets = m_pQuadProgramTextured->GetUniformLoc("gOffsets"); + m_pQuadProgramTextured->m_LocQuadOffset = m_pQuadProgramTextured->GetUniformLoc("gQuadOffset"); + } + { + CGLSL VertexShader; + CGLSL FragmentShader; + VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/text.vert", GL_VERTEX_SHADER); + FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/text.frag", GL_FRAGMENT_SHADER); + + m_pTextProgram->CreateProgram(); + m_pTextProgram->AddShader(&VertexShader); + m_pTextProgram->AddShader(&FragmentShader); + m_pTextProgram->LinkProgram(); + + UseProgram(m_pTextProgram); + + m_pTextProgram->m_LocPos = m_pTextProgram->GetUniformLoc("gPos"); + m_pTextProgram->m_LocTextureSampler = -1; + m_pTextProgram->m_LocTextSampler = m_pTextProgram->GetUniformLoc("gTextSampler"); + m_pTextProgram->m_LocTextOutlineSampler = m_pTextProgram->GetUniformLoc("gTextOutlineSampler"); + m_pTextProgram->m_LocColor = m_pTextProgram->GetUniformLoc("gVertColor"); + m_pTextProgram->m_LocOutlineColor = m_pTextProgram->GetUniformLoc("gVertOutlineColor"); + m_pTextProgram->m_LocTextureSize = m_pTextProgram->GetUniformLoc("gTextureSize"); + } + InitPrimExProgram(m_pPrimitiveExProgram, &ShaderCompiler, pCommand->m_pStorage, false, false); + InitPrimExProgram(m_pPrimitiveExProgramTextured, &ShaderCompiler, pCommand->m_pStorage, true, false); + InitPrimExProgram(m_pPrimitiveExProgramRotationless, &ShaderCompiler, pCommand->m_pStorage, false, true); + InitPrimExProgram(m_pPrimitiveExProgramTexturedRotationless, &ShaderCompiler, pCommand->m_pStorage, true, true); + { + CGLSL PrimitiveVertexShader; + CGLSL PrimitiveFragmentShader; + PrimitiveVertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/spritemulti.vert", GL_VERTEX_SHADER); + PrimitiveFragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/spritemulti.frag", GL_FRAGMENT_SHADER); + + m_pSpriteProgramMultiple->CreateProgram(); + m_pSpriteProgramMultiple->AddShader(&PrimitiveVertexShader); + m_pSpriteProgramMultiple->AddShader(&PrimitiveFragmentShader); + m_pSpriteProgramMultiple->LinkProgram(); + + UseProgram(m_pSpriteProgramMultiple); + + m_pSpriteProgramMultiple->m_LocPos = m_pSpriteProgramMultiple->GetUniformLoc("gPos"); + m_pSpriteProgramMultiple->m_LocTextureSampler = m_pSpriteProgramMultiple->GetUniformLoc("gTextureSampler"); + m_pSpriteProgramMultiple->m_LocRSP = m_pSpriteProgramMultiple->GetUniformLoc("gRSP[0]"); + m_pSpriteProgramMultiple->m_LocCenter = m_pSpriteProgramMultiple->GetUniformLoc("gCenter"); + m_pSpriteProgramMultiple->m_LocVertciesColor = m_pSpriteProgramMultiple->GetUniformLoc("gVerticesColor"); + + float Center[2] = {0.f, 0.f}; + m_pSpriteProgramMultiple->SetUniformVec2(m_pSpriteProgramMultiple->m_LocCenter, 1, Center); + } + + m_LastStreamBuffer = 0; + + glGenBuffers(MAX_STREAM_BUFFER_COUNT, m_PrimitiveDrawBufferID); + glGenVertexArrays(MAX_STREAM_BUFFER_COUNT, m_PrimitiveDrawVertexID); + glGenBuffers(1, &m_PrimitiveDrawBufferIDTex3D); + glGenVertexArrays(1, &m_PrimitiveDrawVertexIDTex3D); + + m_UsePreinitializedVertexBuffer = g_Config.m_GfxUsePreinitBuffer; + + for(int i = 0; i < MAX_STREAM_BUFFER_COUNT; ++i) + { + glBindBuffer(GL_ARRAY_BUFFER, m_PrimitiveDrawBufferID[i]); + glBindVertexArray(m_PrimitiveDrawVertexID[i]); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); + + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(CCommandBuffer::SVertex), 0); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(CCommandBuffer::SVertex), (void *)(sizeof(float) * 2)); + glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(CCommandBuffer::SVertex), (void *)(sizeof(float) * 4)); + + if(m_UsePreinitializedVertexBuffer) + glBufferData(GL_ARRAY_BUFFER, sizeof(CCommandBuffer::SVertex) * CCommandBuffer::MAX_VERTICES, NULL, GL_STREAM_DRAW); + + m_LastIndexBufferBound[i] = 0; + } + + glBindBuffer(GL_ARRAY_BUFFER, m_PrimitiveDrawBufferIDTex3D); + glBindVertexArray(m_PrimitiveDrawVertexIDTex3D); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); + + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(CCommandBuffer::SVertexTex3DStream), 0); + glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(CCommandBuffer::SVertexTex3DStream), (void *)(sizeof(float) * 2)); + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(CCommandBuffer::SVertexTex3DStream), (void *)(sizeof(float) * 2 + sizeof(unsigned char) * 4)); + + if(m_UsePreinitializedVertexBuffer) + glBufferData(GL_ARRAY_BUFFER, sizeof(CCommandBuffer::SVertexTex3DStream) * CCommandBuffer::MAX_VERTICES, NULL, GL_STREAM_DRAW); + + //query the image max size only once + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_MaxTexSize); + + //query maximum of allowed textures + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &m_MaxTextureUnits); + m_TextureSlotBoundToUnit.resize(m_MaxTextureUnits); + for(int i = 0; i < m_MaxTextureUnits; ++i) + { + m_TextureSlotBoundToUnit[i].m_TextureSlot = -1; + m_TextureSlotBoundToUnit[i].m_Is2DArray = false; + } + + glBindVertexArray(0); + glGenBuffers(1, &m_QuadDrawIndexBufferID); + glBindBuffer(GL_COPY_WRITE_BUFFER, m_QuadDrawIndexBufferID); + + unsigned int Indices[CCommandBuffer::MAX_VERTICES / 4 * 6]; + int Primq = 0; + for(int i = 0; i < CCommandBuffer::MAX_VERTICES / 4 * 6; i += 6) + { + Indices[i] = Primq; + Indices[i + 1] = Primq + 1; + Indices[i + 2] = Primq + 2; + Indices[i + 3] = Primq; + Indices[i + 4] = Primq + 2; + Indices[i + 5] = Primq + 3; + Primq += 4; + } + glBufferData(GL_COPY_WRITE_BUFFER, sizeof(unsigned int) * CCommandBuffer::MAX_VERTICES / 4 * 6, Indices, GL_STATIC_DRAW); + + m_CurrentIndicesInBuffer = CCommandBuffer::MAX_VERTICES / 4 * 6; + + m_Textures.resize(CCommandBuffer::MAX_TEXTURES); + + m_ClearColor.r = m_ClearColor.g = m_ClearColor.b = -1.f; + + // fix the alignment to allow even 1byte changes, e.g. for alpha components + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_Shutdown(const SCommand_Shutdown *pCommand) +{ + glUseProgram(0); + + m_pPrimitiveProgram->DeleteProgram(); + m_pPrimitiveProgramTextured->DeleteProgram(); + m_pBorderTileProgram->DeleteProgram(); + m_pBorderTileProgramTextured->DeleteProgram(); + m_pBorderTileLineProgram->DeleteProgram(); + m_pBorderTileLineProgramTextured->DeleteProgram(); + m_pQuadProgram->DeleteProgram(); + m_pQuadProgramTextured->DeleteProgram(); + m_pTileProgram->DeleteProgram(); + m_pTileProgramTextured->DeleteProgram(); + m_pPrimitive3DProgram->DeleteProgram(); + m_pPrimitive3DProgramTextured->DeleteProgram(); + m_pTextProgram->DeleteProgram(); + m_pPrimitiveExProgram->DeleteProgram(); + m_pPrimitiveExProgramTextured->DeleteProgram(); + m_pPrimitiveExProgramRotationless->DeleteProgram(); + m_pPrimitiveExProgramTexturedRotationless->DeleteProgram(); + m_pSpriteProgramMultiple->DeleteProgram(); + + //clean up everything + delete m_pPrimitiveProgram; + delete m_pPrimitiveProgramTextured; + delete m_pBorderTileProgram; + delete m_pBorderTileProgramTextured; + delete m_pBorderTileLineProgram; + delete m_pBorderTileLineProgramTextured; + delete m_pQuadProgram; + delete m_pQuadProgramTextured; + delete m_pTileProgram; + delete m_pTileProgramTextured; + delete m_pPrimitive3DProgram; + delete m_pPrimitive3DProgramTextured; + delete m_pTextProgram; + delete m_pPrimitiveExProgram; + delete m_pPrimitiveExProgramTextured; + delete m_pPrimitiveExProgramRotationless; + delete m_pPrimitiveExProgramTexturedRotationless; + delete m_pSpriteProgramMultiple; + + glBindVertexArray(0); + glDeleteBuffers(MAX_STREAM_BUFFER_COUNT, m_PrimitiveDrawBufferID); + glDeleteBuffers(1, &m_QuadDrawIndexBufferID); + glDeleteVertexArrays(MAX_STREAM_BUFFER_COUNT, m_PrimitiveDrawVertexID); + glDeleteBuffers(1, &m_PrimitiveDrawBufferIDTex3D); + glDeleteVertexArrays(1, &m_PrimitiveDrawVertexIDTex3D); + + for(int i = 0; i < (int)m_Textures.size(); ++i) + { + DestroyTexture(i); + } + + for(size_t i = 0; i < m_BufferContainers.size(); ++i) + { + DestroyBufferContainer(i); + } + + m_BufferContainers.clear(); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand) +{ + if(m_UseMultipleTextureUnits) + { + int Slot = pCommand->m_Slot % m_MaxTextureUnits; + //just tell, that we using this texture now + IsAndUpdateTextureSlotBound(Slot, pCommand->m_Slot); + glActiveTexture(GL_TEXTURE0 + Slot); + glBindSampler(Slot, m_Textures[pCommand->m_Slot].m_Sampler); + } + + glBindTexture(GL_TEXTURE_2D, m_Textures[pCommand->m_Slot].m_Tex); + + void *pTexData = pCommand->m_pData; + int Width = pCommand->m_Width; + int Height = pCommand->m_Height; + int X = pCommand->m_X; + int Y = pCommand->m_Y; + if(m_Textures[pCommand->m_Slot].m_RescaleCount > 0) + { + for(int i = 0; i < m_Textures[pCommand->m_Slot].m_RescaleCount; ++i) + { + Width >>= 1; + Height >>= 1; + + X /= 2; + Y /= 2; + } + + void *pTmpData = Resize(pCommand->m_Width, pCommand->m_Height, Width, Height, pCommand->m_Format, static_cast(pCommand->m_pData)); + free(pTexData); + pTexData = pTmpData; + } + + glTexSubImage2D(GL_TEXTURE_2D, 0, X, Y, Width, Height, + TexFormatToNewOpenGLFormat(pCommand->m_Format), GL_UNSIGNED_BYTE, pTexData); + free(pTexData); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand) +{ + int Slot = 0; + if(m_UseMultipleTextureUnits) + { + Slot = pCommand->m_Slot % m_MaxTextureUnits; + IsAndUpdateTextureSlotBound(Slot, pCommand->m_Slot); + glActiveTexture(GL_TEXTURE0 + Slot); + } + glBindTexture(GL_TEXTURE_2D, 0); + glBindSampler(Slot, 0); + m_TextureSlotBoundToUnit[Slot].m_TextureSlot = -1; + m_TextureSlotBoundToUnit[Slot].m_Is2DArray = false; + DestroyTexture(pCommand->m_Slot); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand) +{ + int Width = pCommand->m_Width; + int Height = pCommand->m_Height; + void *pTexData = pCommand->m_pData; + + if(pCommand->m_Slot >= (int)m_Textures.size()) + m_Textures.resize(m_Textures.size() * 2); + + // resample if needed + int RescaleCount = 0; + if(pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGBA || pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGB || pCommand->m_Format == CCommandBuffer::TEXFORMAT_ALPHA) + { + if(Width > m_MaxTexSize || Height > m_MaxTexSize) + { + do + { + Width >>= 1; + Height >>= 1; + ++RescaleCount; + } while(Width > m_MaxTexSize || Height > m_MaxTexSize); + + void *pTmpData = Resize(pCommand->m_Width, pCommand->m_Height, Width, Height, pCommand->m_Format, static_cast(pCommand->m_pData)); + free(pTexData); + pTexData = pTmpData; + } + else if(pCommand->m_Format != CCommandBuffer::TEXFORMAT_ALPHA && (Width > 16 && Height > 16 && (pCommand->m_Flags & CCommandBuffer::TEXFLAG_QUALITY) == 0)) + { + Width >>= 1; + Height >>= 1; + ++RescaleCount; + + void *pTmpData = Resize(pCommand->m_Width, pCommand->m_Height, Width, Height, pCommand->m_Format, static_cast(pCommand->m_pData)); + free(pTexData); + pTexData = pTmpData; + } + } + m_Textures[pCommand->m_Slot].m_Width = Width; + m_Textures[pCommand->m_Slot].m_Height = Height; + m_Textures[pCommand->m_Slot].m_RescaleCount = RescaleCount; + + int Oglformat = TexFormatToNewOpenGLFormat(pCommand->m_Format); + int StoreOglformat = TexFormatToNewOpenGLFormat(pCommand->m_StoreFormat); + if(StoreOglformat == GL_RED) + StoreOglformat = GL_R8; + + int Slot = 0; + if(m_UseMultipleTextureUnits) + { + Slot = pCommand->m_Slot % m_MaxTextureUnits; + //just tell, that we using this texture now + IsAndUpdateTextureSlotBound(Slot, pCommand->m_Slot); + glActiveTexture(GL_TEXTURE0 + Slot); + m_TextureSlotBoundToUnit[Slot].m_TextureSlot = -1; + m_TextureSlotBoundToUnit[Slot].m_Is2DArray = false; + } + + if((pCommand->m_Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0) + { + glGenTextures(1, &m_Textures[pCommand->m_Slot].m_Tex); + glBindTexture(GL_TEXTURE_2D, m_Textures[pCommand->m_Slot].m_Tex); + + glGenSamplers(1, &m_Textures[pCommand->m_Slot].m_Sampler); + glBindSampler(Slot, m_Textures[pCommand->m_Slot].m_Sampler); + } + + if(pCommand->m_Flags & CCommandBuffer::TEXFLAG_NOMIPMAPS) + { + if((pCommand->m_Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, StoreOglformat, Width, Height, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData); + } + } + else + { + if((pCommand->m_Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0) + { + glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + +#ifndef CONF_BACKEND_OPENGL_ES + if(m_OpenGLTextureLodBIAS != 0 && !m_IsOpenGLES) + glSamplerParameterf(m_Textures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_LOD_BIAS, ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f)); +#endif + + //prevent mipmap display bugs, when zooming out far + if(Width >= 1024 && Height >= 1024) + { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 5.f); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 5); + } + glTexImage2D(GL_TEXTURE_2D, 0, StoreOglformat, Width, Height, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData); + glGenerateMipmap(GL_TEXTURE_2D); + } + + if((pCommand->m_Flags & (CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE | CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE_SINGLE_LAYER)) != 0) + { + glGenTextures(1, &m_Textures[pCommand->m_Slot].m_Tex2DArray); + glBindTexture(GL_TEXTURE_2D_ARRAY, m_Textures[pCommand->m_Slot].m_Tex2DArray); + + glGenSamplers(1, &m_Textures[pCommand->m_Slot].m_Sampler2DArray); + glBindSampler(Slot, m_Textures[pCommand->m_Slot].m_Sampler2DArray); + glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT); + +#ifndef CONF_BACKEND_OPENGL_ES + if(m_OpenGLTextureLodBIAS != 0 && !m_IsOpenGLES) + glSamplerParameterf(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_LOD_BIAS, ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f)); +#endif + + int ImageColorChannels = TexFormatToImageColorChannelCount(pCommand->m_Format); + + uint8_t *p3DImageData = NULL; + + bool IsSingleLayer = (pCommand->m_Flags & CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE_SINGLE_LAYER) != 0; + + if(!IsSingleLayer) + p3DImageData = (uint8_t *)malloc((size_t)ImageColorChannels * Width * Height); + int Image3DWidth, Image3DHeight; + + int ConvertWidth = Width; + int ConvertHeight = Height; + + if(!IsSingleLayer) + { + if(ConvertWidth == 0 || (ConvertWidth % 16) != 0 || ConvertHeight == 0 || (ConvertHeight % 16) != 0) + { + dbg_msg("gfx", "3D/2D array texture was resized"); + int NewWidth = maximum(HighestBit(ConvertWidth), 16); + int NewHeight = maximum(HighestBit(ConvertHeight), 16); + uint8_t *pNewTexData = (uint8_t *)Resize(ConvertWidth, ConvertHeight, NewWidth, NewHeight, pCommand->m_Format, (const uint8_t *)pTexData); + + ConvertWidth = NewWidth; + ConvertHeight = NewHeight; + + free(pTexData); + pTexData = pNewTexData; + } + } + + if(IsSingleLayer || (Texture2DTo3D(pTexData, ConvertWidth, ConvertHeight, ImageColorChannels, 16, 16, p3DImageData, Image3DWidth, Image3DHeight))) + { + if(IsSingleLayer) + { + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, StoreOglformat, ConvertWidth, ConvertHeight, 1, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData); + } + else + { + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, StoreOglformat, Image3DWidth, Image3DHeight, 256, 0, Oglformat, GL_UNSIGNED_BYTE, p3DImageData); + } + glGenerateMipmap(GL_TEXTURE_2D_ARRAY); + } + + if(!IsSingleLayer) + free(p3DImageData); + } + } + + // This is the initial value for the wrap modes + m_Textures[pCommand->m_Slot].m_LastWrapMode = CCommandBuffer::WRAP_REPEAT; + + // calculate memory usage + m_Textures[pCommand->m_Slot].m_MemSize = Width * Height * pCommand->m_PixelSize; + while(Width > 2 && Height > 2) + { + Width >>= 1; + Height >>= 1; + m_Textures[pCommand->m_Slot].m_MemSize += Width * Height * pCommand->m_PixelSize; + } + m_pTextureMemoryUsage->store(m_pTextureMemoryUsage->load(std::memory_order_relaxed) + m_Textures[pCommand->m_Slot].m_MemSize, std::memory_order_relaxed); + + free(pTexData); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand) +{ + if(pCommand->m_Color.r != m_ClearColor.r || pCommand->m_Color.g != m_ClearColor.g || pCommand->m_Color.b != m_ClearColor.b) + { + glClearColor(pCommand->m_Color.r, pCommand->m_Color.g, pCommand->m_Color.b, 0.0f); + m_ClearColor = pCommand->m_Color; + } + glClear(GL_COLOR_BUFFER_BIT); +} + +void CCommandProcessorFragment_OpenGL3_3::UploadStreamBufferData(unsigned int PrimitiveType, const void *pVertices, size_t VertSize, unsigned int PrimitiveCount, bool AsTex3D) +{ + int Count = 0; + switch(PrimitiveType) + { + case CCommandBuffer::PRIMTYPE_LINES: + Count = PrimitiveCount * 2; + break; + case CCommandBuffer::PRIMTYPE_TRIANGLES: + Count = PrimitiveCount * 3; + break; + case CCommandBuffer::PRIMTYPE_QUADS: + Count = PrimitiveCount * 4; + break; + default: + return; + }; + + if(AsTex3D) + glBindBuffer(GL_ARRAY_BUFFER, m_PrimitiveDrawBufferIDTex3D); + else + glBindBuffer(GL_ARRAY_BUFFER, m_PrimitiveDrawBufferID[m_LastStreamBuffer]); + + if(!m_UsePreinitializedVertexBuffer) + glBufferData(GL_ARRAY_BUFFER, VertSize * Count, pVertices, GL_STREAM_DRAW); + else + { + // This is better for some iGPUs. Probably due to not initializing a new buffer in the system memory again and again...(driver dependent) + void *pData = glMapBufferRange(GL_ARRAY_BUFFER, 0, VertSize * Count, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + + mem_copy(pData, pVertices, VertSize * Count); + + glUnmapBuffer(GL_ARRAY_BUFFER); + } +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand) +{ + CGLSLTWProgram *pProgram = m_pPrimitiveProgram; + if(IsTexturedState(pCommand->m_State)) + pProgram = m_pPrimitiveProgramTextured; + UseProgram(pProgram); + SetState(pCommand->m_State, pProgram); + + UploadStreamBufferData(pCommand->m_PrimType, pCommand->m_pVertices, sizeof(CCommandBuffer::SVertex), pCommand->m_PrimCount); + + glBindVertexArray(m_PrimitiveDrawVertexID[m_LastStreamBuffer]); + + switch(pCommand->m_PrimType) + { + // We don't support GL_QUADS due to core profile + case CCommandBuffer::PRIMTYPE_LINES: + glDrawArrays(GL_LINES, 0, pCommand->m_PrimCount * 2); + break; + case CCommandBuffer::PRIMTYPE_TRIANGLES: + glDrawArrays(GL_TRIANGLES, 0, pCommand->m_PrimCount * 3); + break; + case CCommandBuffer::PRIMTYPE_QUADS: + if(m_LastIndexBufferBound[m_LastStreamBuffer] != m_QuadDrawIndexBufferID) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); + m_LastIndexBufferBound[m_LastStreamBuffer] = m_QuadDrawIndexBufferID; + } + glDrawElements(GL_TRIANGLES, pCommand->m_PrimCount * 6, GL_UNSIGNED_INT, 0); + break; + default: + dbg_msg("render", "unknown primtype %d\n", pCommand->m_PrimType); + }; + + m_LastStreamBuffer = (m_LastStreamBuffer + 1 >= MAX_STREAM_BUFFER_COUNT ? 0 : m_LastStreamBuffer + 1); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderTex3D(const CCommandBuffer::SCommand_RenderTex3D *pCommand) +{ + CGLSLPrimitiveProgram *pProg = m_pPrimitive3DProgram; + if(IsTexturedState(pCommand->m_State)) + pProg = m_pPrimitive3DProgramTextured; + UseProgram(pProg); + SetState(pCommand->m_State, pProg, true); + + UploadStreamBufferData(pCommand->m_PrimType, pCommand->m_pVertices, sizeof(CCommandBuffer::SVertexTex3DStream), pCommand->m_PrimCount, true); + + glBindVertexArray(m_PrimitiveDrawVertexIDTex3D); + + switch(pCommand->m_PrimType) + { + // We don't support GL_QUADS due to core profile + case CCommandBuffer::PRIMTYPE_LINES: + glDrawArrays(GL_LINES, 0, pCommand->m_PrimCount * 2); + break; + case CCommandBuffer::PRIMTYPE_QUADS: + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); + glDrawElements(GL_TRIANGLES, pCommand->m_PrimCount * 6, GL_UNSIGNED_INT, 0); + break; + default: + dbg_msg("render", "unknown primtype %d\n", pCommand->m_PrimType); + }; +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_Screenshot(const CCommandBuffer::SCommand_Screenshot *pCommand) +{ + // fetch image data + GLint aViewport[4] = {0, 0, 0, 0}; + glGetIntegerv(GL_VIEWPORT, aViewport); + + int w = aViewport[2]; + int h = aViewport[3]; + + // we allocate one more row to use when we are flipping the texture + unsigned char *pPixelData = (unsigned char *)malloc((size_t)w * (h + 1) * 3); + unsigned char *pTempRow = pPixelData + w * h * 3; + + // fetch the pixels + GLint Alignment; + glGetIntegerv(GL_PACK_ALIGNMENT, &Alignment); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, pPixelData); + glPixelStorei(GL_PACK_ALIGNMENT, Alignment); + + // flip the pixel because opengl works from bottom left corner + for(int y = 0; y < h / 2; y++) + { + mem_copy(pTempRow, pPixelData + y * w * 3, w * 3); + mem_copy(pPixelData + y * w * 3, pPixelData + (h - y - 1) * w * 3, w * 3); + mem_copy(pPixelData + (h - y - 1) * w * 3, pTempRow, w * 3); + } + + // fill in the information + pCommand->m_pImage->m_Width = w; + pCommand->m_pImage->m_Height = h; + pCommand->m_pImage->m_Format = CImageInfo::FORMAT_RGB; + pCommand->m_pImage->m_pData = pPixelData; +} + +void CCommandProcessorFragment_OpenGL3_3::DestroyBufferContainer(int Index, bool DeleteBOs) +{ + SBufferContainer &BufferContainer = m_BufferContainers[Index]; + if(BufferContainer.m_VertArrayID != 0) + glDeleteVertexArrays(1, &BufferContainer.m_VertArrayID); + + // all buffer objects can deleted automatically, so the program doesn't need to deal with them (e.g. causing crashes because of driver bugs) + if(DeleteBOs) + { + for(size_t i = 0; i < BufferContainer.m_ContainerInfo.m_Attributes.size(); ++i) + { + int VertBufferID = BufferContainer.m_ContainerInfo.m_Attributes[i].m_VertBufferBindingIndex; + if(VertBufferID != -1) + { + for(auto &Attribute : BufferContainer.m_ContainerInfo.m_Attributes) + { + // set all equal ids to zero to not double delete + if(VertBufferID == Attribute.m_VertBufferBindingIndex) + { + Attribute.m_VertBufferBindingIndex = -1; + } + } + + glDeleteBuffers(1, &m_BufferObjectIndices[VertBufferID]); + } + } + } + + BufferContainer.m_LastIndexBufferBound = 0; + BufferContainer.m_ContainerInfo.m_Attributes.clear(); +} + +void CCommandProcessorFragment_OpenGL3_3::AppendIndices(unsigned int NewIndicesCount) +{ + if(NewIndicesCount <= m_CurrentIndicesInBuffer) + return; + unsigned int AddCount = NewIndicesCount - m_CurrentIndicesInBuffer; + unsigned int *Indices = new unsigned int[AddCount]; + int Primq = (m_CurrentIndicesInBuffer / 6) * 4; + for(unsigned int i = 0; i < AddCount; i += 6) + { + Indices[i] = Primq; + Indices[i + 1] = Primq + 1; + Indices[i + 2] = Primq + 2; + Indices[i + 3] = Primq; + Indices[i + 4] = Primq + 2; + Indices[i + 5] = Primq + 3; + Primq += 4; + } + + glBindBuffer(GL_COPY_READ_BUFFER, m_QuadDrawIndexBufferID); + GLuint NewIndexBufferID; + glGenBuffers(1, &NewIndexBufferID); + glBindBuffer(GL_COPY_WRITE_BUFFER, NewIndexBufferID); + GLsizeiptr size = sizeof(unsigned int); + glBufferData(GL_COPY_WRITE_BUFFER, (GLsizeiptr)NewIndicesCount * size, NULL, GL_STATIC_DRAW); + glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, (GLsizeiptr)m_CurrentIndicesInBuffer * size); + glBufferSubData(GL_COPY_WRITE_BUFFER, (GLsizeiptr)m_CurrentIndicesInBuffer * size, (GLsizeiptr)AddCount * size, Indices); + glBindBuffer(GL_COPY_WRITE_BUFFER, 0); + glBindBuffer(GL_COPY_READ_BUFFER, 0); + + glDeleteBuffers(1, &m_QuadDrawIndexBufferID); + m_QuadDrawIndexBufferID = NewIndexBufferID; + + for(unsigned int &i : m_LastIndexBufferBound) + i = 0; + for(auto &BufferContainer : m_BufferContainers) + { + BufferContainer.m_LastIndexBufferBound = 0; + } + + m_CurrentIndicesInBuffer = NewIndicesCount; + delete[] Indices; +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_CreateBufferObject(const CCommandBuffer::SCommand_CreateBufferObject *pCommand) +{ + void *pUploadData = pCommand->m_pUploadData; + int Index = pCommand->m_BufferIndex; + //create necessary space + if((size_t)Index >= m_BufferObjectIndices.size()) + { + for(int i = m_BufferObjectIndices.size(); i < Index + 1; ++i) + { + m_BufferObjectIndices.push_back(0); + } + } + + GLuint VertBufferID = 0; + + glGenBuffers(1, &VertBufferID); + glBindBuffer(GL_COPY_WRITE_BUFFER, VertBufferID); + glBufferData(GL_COPY_WRITE_BUFFER, (GLsizeiptr)(pCommand->m_DataSize), pUploadData, GL_STATIC_DRAW); + + m_BufferObjectIndices[Index] = VertBufferID; + + if(pCommand->m_DeletePointer) + free(pUploadData); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_RecreateBufferObject(const CCommandBuffer::SCommand_RecreateBufferObject *pCommand) +{ + void *pUploadData = pCommand->m_pUploadData; + int Index = pCommand->m_BufferIndex; + + glBindBuffer(GL_COPY_WRITE_BUFFER, m_BufferObjectIndices[Index]); + glBufferData(GL_COPY_WRITE_BUFFER, (GLsizeiptr)(pCommand->m_DataSize), pUploadData, GL_STATIC_DRAW); + + if(pCommand->m_DeletePointer) + free(pUploadData); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_UpdateBufferObject(const CCommandBuffer::SCommand_UpdateBufferObject *pCommand) +{ + void *pUploadData = pCommand->m_pUploadData; + int Index = pCommand->m_BufferIndex; + + glBindBuffer(GL_COPY_WRITE_BUFFER, m_BufferObjectIndices[Index]); + glBufferSubData(GL_COPY_WRITE_BUFFER, (GLintptr)(pCommand->m_pOffset), (GLsizeiptr)(pCommand->m_DataSize), pUploadData); + + if(pCommand->m_DeletePointer) + free(pUploadData); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_CopyBufferObject(const CCommandBuffer::SCommand_CopyBufferObject *pCommand) +{ + int WriteIndex = pCommand->m_WriteBufferIndex; + int ReadIndex = pCommand->m_ReadBufferIndex; + + glBindBuffer(GL_COPY_WRITE_BUFFER, m_BufferObjectIndices[WriteIndex]); + glBindBuffer(GL_COPY_READ_BUFFER, m_BufferObjectIndices[ReadIndex]); + glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, (GLsizeiptr)(pCommand->m_pReadOffset), (GLsizeiptr)(pCommand->m_pWriteOffset), (GLsizeiptr)pCommand->m_CopySize); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_DeleteBufferObject(const CCommandBuffer::SCommand_DeleteBufferObject *pCommand) +{ + int Index = pCommand->m_BufferIndex; + + glDeleteBuffers(1, &m_BufferObjectIndices[Index]); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_CreateBufferContainer(const CCommandBuffer::SCommand_CreateBufferContainer *pCommand) +{ + int Index = pCommand->m_BufferContainerIndex; + //create necessary space + if((size_t)Index >= m_BufferContainers.size()) + { + for(int i = m_BufferContainers.size(); i < Index + 1; ++i) + { + SBufferContainer Container; + Container.m_ContainerInfo.m_Stride = 0; + m_BufferContainers.push_back(Container); + } + } + + SBufferContainer &BufferContainer = m_BufferContainers[Index]; + glGenVertexArrays(1, &BufferContainer.m_VertArrayID); + glBindVertexArray(BufferContainer.m_VertArrayID); + + BufferContainer.m_LastIndexBufferBound = 0; + + for(int i = 0; i < pCommand->m_AttrCount; ++i) + { + glEnableVertexAttribArray((GLuint)i); + + glBindBuffer(GL_ARRAY_BUFFER, m_BufferObjectIndices[pCommand->m_Attributes[i].m_VertBufferBindingIndex]); + + SBufferContainerInfo::SAttribute &Attr = pCommand->m_Attributes[i]; + + if(Attr.m_FuncType == 0) + glVertexAttribPointer((GLuint)i, Attr.m_DataTypeCount, Attr.m_Type, (GLboolean)Attr.m_Normalized, pCommand->m_Stride, Attr.m_pOffset); + else if(Attr.m_FuncType == 1) + glVertexAttribIPointer((GLuint)i, Attr.m_DataTypeCount, Attr.m_Type, pCommand->m_Stride, Attr.m_pOffset); + + BufferContainer.m_ContainerInfo.m_Attributes.push_back(Attr); + } + + BufferContainer.m_ContainerInfo.m_Stride = pCommand->m_Stride; +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_UpdateBufferContainer(const CCommandBuffer::SCommand_UpdateBufferContainer *pCommand) +{ + SBufferContainer &BufferContainer = m_BufferContainers[pCommand->m_BufferContainerIndex]; + + glBindVertexArray(BufferContainer.m_VertArrayID); + + //disable all old attributes + for(size_t i = 0; i < BufferContainer.m_ContainerInfo.m_Attributes.size(); ++i) + { + glDisableVertexAttribArray((GLuint)i); + } + BufferContainer.m_ContainerInfo.m_Attributes.clear(); + + for(int i = 0; i < pCommand->m_AttrCount; ++i) + { + glEnableVertexAttribArray((GLuint)i); + + glBindBuffer(GL_ARRAY_BUFFER, m_BufferObjectIndices[pCommand->m_Attributes[i].m_VertBufferBindingIndex]); + SBufferContainerInfo::SAttribute &Attr = pCommand->m_Attributes[i]; + if(Attr.m_FuncType == 0) + glVertexAttribPointer((GLuint)i, Attr.m_DataTypeCount, Attr.m_Type, Attr.m_Normalized, pCommand->m_Stride, Attr.m_pOffset); + else if(Attr.m_FuncType == 1) + glVertexAttribIPointer((GLuint)i, Attr.m_DataTypeCount, Attr.m_Type, pCommand->m_Stride, Attr.m_pOffset); + + BufferContainer.m_ContainerInfo.m_Attributes.push_back(Attr); + } + + BufferContainer.m_ContainerInfo.m_Stride = pCommand->m_Stride; +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_DeleteBufferContainer(const CCommandBuffer::SCommand_DeleteBufferContainer *pCommand) +{ + DestroyBufferContainer(pCommand->m_BufferContainerIndex, pCommand->m_DestroyAllBO); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_IndicesRequiredNumNotify(const CCommandBuffer::SCommand_IndicesRequiredNumNotify *pCommand) +{ + if(pCommand->m_RequiredIndicesNum > m_CurrentIndicesInBuffer) + AppendIndices(pCommand->m_RequiredIndicesNum); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderBorderTile(const CCommandBuffer::SCommand_RenderBorderTile *pCommand) +{ + int Index = pCommand->m_BufferContainerIndex; + //if space not there return + if((size_t)Index >= m_BufferContainers.size()) + return; + + SBufferContainer &BufferContainer = m_BufferContainers[Index]; + if(BufferContainer.m_VertArrayID == 0) + return; + + CGLSLTileProgram *pProgram = NULL; + if(IsTexturedState(pCommand->m_State)) + { + pProgram = m_pBorderTileProgramTextured; + } + else + pProgram = m_pBorderTileProgram; + UseProgram(pProgram); + + SetState(pCommand->m_State, pProgram, true); + pProgram->SetUniformVec4(pProgram->m_LocColor, 1, (float *)&pCommand->m_Color); + + pProgram->SetUniformVec2(pProgram->m_LocOffset, 1, (float *)&pCommand->m_Offset); + pProgram->SetUniformVec2(pProgram->m_LocDir, 1, (float *)&pCommand->m_Dir); + pProgram->SetUniform(pProgram->m_LocJumpIndex, (int)pCommand->m_JumpIndex); + + glBindVertexArray(BufferContainer.m_VertArrayID); + if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferID) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); + BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferID; + } + glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, pCommand->m_pIndicesOffset, pCommand->m_DrawNum); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderBorderTileLine(const CCommandBuffer::SCommand_RenderBorderTileLine *pCommand) +{ + int Index = pCommand->m_BufferContainerIndex; + //if space not there return + if((size_t)Index >= m_BufferContainers.size()) + return; + + SBufferContainer &BufferContainer = m_BufferContainers[Index]; + if(BufferContainer.m_VertArrayID == 0) + return; + + CGLSLTileProgram *pProgram = NULL; + if(IsTexturedState(pCommand->m_State)) + { + pProgram = m_pBorderTileLineProgramTextured; + } + else + pProgram = m_pBorderTileLineProgram; + UseProgram(pProgram); + + SetState(pCommand->m_State, pProgram, true); + pProgram->SetUniformVec4(pProgram->m_LocColor, 1, (float *)&pCommand->m_Color); + pProgram->SetUniformVec2(pProgram->m_LocOffset, 1, (float *)&pCommand->m_Offset); + pProgram->SetUniformVec2(pProgram->m_LocDir, 1, (float *)&pCommand->m_Dir); + + glBindVertexArray(BufferContainer.m_VertArrayID); + if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferID) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); + BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferID; + } + glDrawElementsInstanced(GL_TRIANGLES, pCommand->m_IndexDrawNum, GL_UNSIGNED_INT, pCommand->m_pIndicesOffset, pCommand->m_DrawNum); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderTileLayer(const CCommandBuffer::SCommand_RenderTileLayer *pCommand) +{ + int Index = pCommand->m_BufferContainerIndex; + //if space not there return + if((size_t)Index >= m_BufferContainers.size()) + return; + + SBufferContainer &BufferContainer = m_BufferContainers[Index]; + if(BufferContainer.m_VertArrayID == 0) + return; + + if(pCommand->m_IndicesDrawNum == 0) + { + return; //nothing to draw + } + + CGLSLTileProgram *pProgram = NULL; + if(IsTexturedState(pCommand->m_State)) + { + pProgram = m_pTileProgramTextured; + } + else + pProgram = m_pTileProgram; + + UseProgram(pProgram); + + SetState(pCommand->m_State, pProgram, true); + pProgram->SetUniformVec4(pProgram->m_LocColor, 1, (float *)&pCommand->m_Color); + + glBindVertexArray(BufferContainer.m_VertArrayID); + if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferID) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); + BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferID; + } + for(int i = 0; i < pCommand->m_IndicesDrawNum; ++i) + { + glDrawElements(GL_TRIANGLES, pCommand->m_pDrawCount[i], GL_UNSIGNED_INT, pCommand->m_pIndicesOffsets[i]); + } +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadLayer(const CCommandBuffer::SCommand_RenderQuadLayer *pCommand) +{ + int Index = pCommand->m_BufferContainerIndex; + //if space not there return + if((size_t)Index >= m_BufferContainers.size()) + return; + + SBufferContainer &BufferContainer = m_BufferContainers[Index]; + if(BufferContainer.m_VertArrayID == 0) + return; + + if(pCommand->m_QuadNum == 0) + { + return; //nothing to draw + } + + CGLSLQuadProgram *pProgram = NULL; + if(IsTexturedState(pCommand->m_State)) + { + pProgram = m_pQuadProgramTextured; + } + else + pProgram = m_pQuadProgram; + + UseProgram(pProgram); + SetState(pCommand->m_State, pProgram); + + glBindVertexArray(BufferContainer.m_VertArrayID); + if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferID) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); + BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferID; + } + + int QuadsLeft = pCommand->m_QuadNum; + size_t QuadOffset = 0; + // the extra offset is not related to the information from the command, but an actual offset in the buffer + size_t QuadOffsetExtra = pCommand->m_QuadOffset; + + vec4 aColors[m_MaxQuadsPossible]; + vec2 aOffsets[m_MaxQuadsPossible]; + float aRotations[m_MaxQuadsPossible]; + + while(QuadsLeft > 0) + { + int ActualQuadCount = minimum(QuadsLeft, m_MaxQuadsAtOnce); + + for(size_t i = 0; i < (size_t)ActualQuadCount; ++i) + { + mem_copy(&aColors[i], pCommand->m_pQuadInfo[i + QuadOffset].m_aColor, sizeof(vec4)); + mem_copy(&aOffsets[i], pCommand->m_pQuadInfo[i + QuadOffset].m_aOffsets, sizeof(vec2)); + mem_copy(&aRotations[i], &pCommand->m_pQuadInfo[i + QuadOffset].m_Rotation, sizeof(float)); + } + + pProgram->SetUniformVec4(pProgram->m_LocColors, ActualQuadCount, (float *)aColors); + pProgram->SetUniformVec2(pProgram->m_LocOffsets, ActualQuadCount, (float *)aOffsets); + pProgram->SetUniform(pProgram->m_LocRotations, ActualQuadCount, (float *)aRotations); + pProgram->SetUniform(pProgram->m_LocQuadOffset, (int)(QuadOffset + QuadOffsetExtra)); + glDrawElements(GL_TRIANGLES, ActualQuadCount * 6, GL_UNSIGNED_INT, (void *)((QuadOffset + QuadOffsetExtra) * 6 * sizeof(unsigned int))); + + QuadsLeft -= ActualQuadCount; + QuadOffset += (size_t)ActualQuadCount; + } +} + +void CCommandProcessorFragment_OpenGL3_3::RenderText(const CCommandBuffer::SState &State, int DrawNum, int TextTextureIndex, int TextOutlineTextureIndex, int TextureSize, const float *pTextColor, const float *pTextOutlineColor) +{ + if(DrawNum == 0) + { + return; //nothing to draw + } + + UseProgram(m_pTextProgram); + + int SlotText = 0; + int SlotTextOutline = 0; + + if(m_UseMultipleTextureUnits) + { + SlotText = TextTextureIndex % m_MaxTextureUnits; + SlotTextOutline = TextOutlineTextureIndex % m_MaxTextureUnits; + if(SlotText == SlotTextOutline) + SlotTextOutline = (TextOutlineTextureIndex + 1) % m_MaxTextureUnits; + + if(!IsAndUpdateTextureSlotBound(SlotText, TextTextureIndex)) + { + glActiveTexture(GL_TEXTURE0 + SlotText); + glBindTexture(GL_TEXTURE_2D, m_Textures[TextTextureIndex].m_Tex); + glBindSampler(SlotText, m_Textures[TextTextureIndex].m_Sampler); + } + if(!IsAndUpdateTextureSlotBound(SlotTextOutline, TextOutlineTextureIndex)) + { + glActiveTexture(GL_TEXTURE0 + SlotTextOutline); + glBindTexture(GL_TEXTURE_2D, m_Textures[TextOutlineTextureIndex].m_Tex); + glBindSampler(SlotTextOutline, m_Textures[TextOutlineTextureIndex].m_Sampler); + } + } + else + { + SlotText = 0; + SlotTextOutline = 1; + glBindTexture(GL_TEXTURE_2D, m_Textures[TextTextureIndex].m_Tex); + glBindSampler(SlotText, m_Textures[TextTextureIndex].m_Sampler); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, m_Textures[TextOutlineTextureIndex].m_Tex); + glBindSampler(SlotTextOutline, m_Textures[TextOutlineTextureIndex].m_Sampler); + glActiveTexture(GL_TEXTURE0); + } + + if(m_pTextProgram->m_LastTextSampler != SlotText) + { + m_pTextProgram->SetUniform(m_pTextProgram->m_LocTextSampler, SlotText); + m_pTextProgram->m_LastTextSampler = SlotText; + } + + if(m_pTextProgram->m_LastTextOutlineSampler != SlotTextOutline) + { + m_pTextProgram->SetUniform(m_pTextProgram->m_LocTextOutlineSampler, SlotTextOutline); + m_pTextProgram->m_LastTextOutlineSampler = SlotTextOutline; + } + + SetState(State, m_pTextProgram); + + if(m_pTextProgram->m_LastTextureSize != TextureSize) + { + m_pTextProgram->SetUniform(m_pTextProgram->m_LocTextureSize, (float)TextureSize); + m_pTextProgram->m_LastTextureSize = TextureSize; + } + + if(m_pTextProgram->m_LastOutlineColor[0] != pTextOutlineColor[0] || m_pTextProgram->m_LastOutlineColor[1] != pTextOutlineColor[1] || m_pTextProgram->m_LastOutlineColor[2] != pTextOutlineColor[2] || m_pTextProgram->m_LastOutlineColor[3] != pTextOutlineColor[3]) + { + m_pTextProgram->SetUniformVec4(m_pTextProgram->m_LocOutlineColor, 1, (float *)pTextOutlineColor); + m_pTextProgram->m_LastOutlineColor[0] = pTextOutlineColor[0]; + m_pTextProgram->m_LastOutlineColor[1] = pTextOutlineColor[1]; + m_pTextProgram->m_LastOutlineColor[2] = pTextOutlineColor[2]; + m_pTextProgram->m_LastOutlineColor[3] = pTextOutlineColor[3]; + } + + if(m_pTextProgram->m_LastColor[0] != pTextColor[0] || m_pTextProgram->m_LastColor[1] != pTextColor[1] || m_pTextProgram->m_LastColor[2] != pTextColor[2] || m_pTextProgram->m_LastColor[3] != pTextColor[3]) + { + m_pTextProgram->SetUniformVec4(m_pTextProgram->m_LocColor, 1, (float *)pTextColor); + m_pTextProgram->m_LastColor[0] = pTextColor[0]; + m_pTextProgram->m_LastColor[1] = pTextColor[1]; + m_pTextProgram->m_LastColor[2] = pTextColor[2]; + m_pTextProgram->m_LastColor[3] = pTextColor[3]; + } + + glDrawElements(GL_TRIANGLES, DrawNum, GL_UNSIGNED_INT, (void *)(0)); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderText(const CCommandBuffer::SCommand_RenderText *pCommand) +{ + int Index = pCommand->m_BufferContainerIndex; + //if space not there return + if((size_t)Index >= m_BufferContainers.size()) + return; + + SBufferContainer &BufferContainer = m_BufferContainers[Index]; + if(BufferContainer.m_VertArrayID == 0) + return; + + glBindVertexArray(BufferContainer.m_VertArrayID); + if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferID) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); + BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferID; + } + + RenderText(pCommand->m_State, pCommand->m_DrawNum, pCommand->m_TextTextureIndex, pCommand->m_TextOutlineTextureIndex, pCommand->m_TextureSize, pCommand->m_aTextColor, pCommand->m_aTextOutlineColor); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderTextStream(const CCommandBuffer::SCommand_RenderTextStream *pCommand) +{ + if(pCommand->m_PrimCount == 0) + { + return; //nothing to draw + } + + UploadStreamBufferData(CCommandBuffer::PRIMTYPE_QUADS, pCommand->m_pVertices, sizeof(CCommandBuffer::SVertex), pCommand->m_PrimCount); + + glBindVertexArray(m_PrimitiveDrawVertexID[m_LastStreamBuffer]); + if(m_LastIndexBufferBound[m_LastStreamBuffer] != m_QuadDrawIndexBufferID) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); + m_LastIndexBufferBound[m_LastStreamBuffer] = m_QuadDrawIndexBufferID; + } + + float aTextColor[4] = {1.f, 1.f, 1.f, 1.f}; + + RenderText(pCommand->m_State, pCommand->m_PrimCount * 6, pCommand->m_TextTextureIndex, pCommand->m_TextOutlineTextureIndex, pCommand->m_TextureSize, aTextColor, pCommand->m_aTextOutlineColor); + + m_LastStreamBuffer = (m_LastStreamBuffer + 1 >= MAX_STREAM_BUFFER_COUNT ? 0 : m_LastStreamBuffer + 1); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadContainer(const CCommandBuffer::SCommand_RenderQuadContainer *pCommand) +{ + if(pCommand->m_DrawNum == 0) + { + return; //nothing to draw + } + + int Index = pCommand->m_BufferContainerIndex; + //if space not there return + if((size_t)Index >= m_BufferContainers.size()) + return; + + SBufferContainer &BufferContainer = m_BufferContainers[Index]; + if(BufferContainer.m_VertArrayID == 0) + return; + + glBindVertexArray(BufferContainer.m_VertArrayID); + if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferID) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); + BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferID; + } + + CGLSLTWProgram *pProgram = m_pPrimitiveProgram; + if(IsTexturedState(pCommand->m_State)) + pProgram = m_pPrimitiveProgramTextured; + UseProgram(pProgram); + SetState(pCommand->m_State, pProgram); + + glDrawElements(GL_TRIANGLES, pCommand->m_DrawNum, GL_UNSIGNED_INT, pCommand->m_pOffset); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadContainerEx(const CCommandBuffer::SCommand_RenderQuadContainerEx *pCommand) +{ + if(pCommand->m_DrawNum == 0) + { + return; //nothing to draw + } + + int Index = pCommand->m_BufferContainerIndex; + //if space not there return + if((size_t)Index >= m_BufferContainers.size()) + return; + + SBufferContainer &BufferContainer = m_BufferContainers[Index]; + if(BufferContainer.m_VertArrayID == 0) + return; + + glBindVertexArray(BufferContainer.m_VertArrayID); + if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferID) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); + BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferID; + } + + CGLSLPrimitiveExProgram *pProgram = m_pPrimitiveExProgramRotationless; + if(IsTexturedState(pCommand->m_State)) + { + if(pCommand->m_Rotation != 0.0f) + pProgram = m_pPrimitiveExProgramTextured; + else + pProgram = m_pPrimitiveExProgramTexturedRotationless; + } + else + { + if(pCommand->m_Rotation != 0.0f) + pProgram = m_pPrimitiveExProgram; + } + + UseProgram(pProgram); + SetState(pCommand->m_State, pProgram); + + if(pCommand->m_Rotation != 0.0f && (pProgram->m_LastCenter[0] != pCommand->m_Center.x || pProgram->m_LastCenter[1] != pCommand->m_Center.y)) + { + pProgram->SetUniformVec2(pProgram->m_LocCenter, 1, (float *)&pCommand->m_Center); + pProgram->m_LastCenter[0] = pCommand->m_Center.x; + pProgram->m_LastCenter[1] = pCommand->m_Center.y; + } + + if(pProgram->m_LastRotation != pCommand->m_Rotation) + { + pProgram->SetUniform(pProgram->m_LocRotation, pCommand->m_Rotation); + pProgram->m_LastRotation = pCommand->m_Rotation; + } + + if(pProgram->m_LastVertciesColor[0] != pCommand->m_VertexColor.r || pProgram->m_LastVertciesColor[1] != pCommand->m_VertexColor.g || pProgram->m_LastVertciesColor[2] != pCommand->m_VertexColor.b || pProgram->m_LastVertciesColor[3] != pCommand->m_VertexColor.a) + { + pProgram->SetUniformVec4(pProgram->m_LocVertciesColor, 1, (float *)&pCommand->m_VertexColor); + pProgram->m_LastVertciesColor[0] = pCommand->m_VertexColor.r; + pProgram->m_LastVertciesColor[1] = pCommand->m_VertexColor.g; + pProgram->m_LastVertciesColor[2] = pCommand->m_VertexColor.b; + pProgram->m_LastVertciesColor[3] = pCommand->m_VertexColor.a; + } + + glDrawElements(GL_TRIANGLES, pCommand->m_DrawNum, GL_UNSIGNED_INT, pCommand->m_pOffset); +} + +void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadContainerAsSpriteMultiple(const CCommandBuffer::SCommand_RenderQuadContainerAsSpriteMultiple *pCommand) +{ + if(pCommand->m_DrawNum == 0 || pCommand->m_DrawCount == 0) + { + return; //nothing to draw + } + + int Index = pCommand->m_BufferContainerIndex; + //if space not there return + if((size_t)Index >= m_BufferContainers.size()) + return; + + SBufferContainer &BufferContainer = m_BufferContainers[Index]; + if(BufferContainer.m_VertArrayID == 0) + return; + + glBindVertexArray(BufferContainer.m_VertArrayID); + if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferID) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); + BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferID; + } + + UseProgram(m_pSpriteProgramMultiple); + SetState(pCommand->m_State, m_pSpriteProgramMultiple); + + if((m_pSpriteProgramMultiple->m_LastCenter[0] != pCommand->m_Center.x || m_pSpriteProgramMultiple->m_LastCenter[1] != pCommand->m_Center.y)) + { + m_pSpriteProgramMultiple->SetUniformVec2(m_pSpriteProgramMultiple->m_LocCenter, 1, (float *)&pCommand->m_Center); + m_pSpriteProgramMultiple->m_LastCenter[0] = pCommand->m_Center.x; + m_pSpriteProgramMultiple->m_LastCenter[1] = pCommand->m_Center.y; + } + + if(m_pSpriteProgramMultiple->m_LastVertciesColor[0] != pCommand->m_VertexColor.r || m_pSpriteProgramMultiple->m_LastVertciesColor[1] != pCommand->m_VertexColor.g || m_pSpriteProgramMultiple->m_LastVertciesColor[2] != pCommand->m_VertexColor.b || m_pSpriteProgramMultiple->m_LastVertciesColor[3] != pCommand->m_VertexColor.a) + { + m_pSpriteProgramMultiple->SetUniformVec4(m_pSpriteProgramMultiple->m_LocVertciesColor, 1, (float *)&pCommand->m_VertexColor); + m_pSpriteProgramMultiple->m_LastVertciesColor[0] = pCommand->m_VertexColor.r; + m_pSpriteProgramMultiple->m_LastVertciesColor[1] = pCommand->m_VertexColor.g; + m_pSpriteProgramMultiple->m_LastVertciesColor[2] = pCommand->m_VertexColor.b; + m_pSpriteProgramMultiple->m_LastVertciesColor[3] = pCommand->m_VertexColor.a; + } + + int DrawCount = pCommand->m_DrawCount; + size_t RenderOffset = 0; + + // 4 for the center (always use vec4) and 16 for the matrix(just to be sure), 4 for the sampler and vertex color + const int RSPCount = 256 - 4 - 16 - 8; + + while(DrawCount > 0) + { + int UniformCount = (DrawCount > RSPCount ? RSPCount : DrawCount); + + m_pSpriteProgramMultiple->SetUniformVec4(m_pSpriteProgramMultiple->m_LocRSP, UniformCount, (float *)(pCommand->m_pRenderInfo + RenderOffset)); + + glDrawElementsInstanced(GL_TRIANGLES, pCommand->m_DrawNum, GL_UNSIGNED_INT, pCommand->m_pOffset, UniformCount); + + RenderOffset += RSPCount; + DrawCount -= RSPCount; + } +} diff --git a/src/engine/client/backend_sdl.cpp b/src/engine/client/backend_sdl.cpp index 0e33d2a87..283540c0f 100644 --- a/src/engine/client/backend_sdl.cpp +++ b/src/engine/client/backend_sdl.cpp @@ -6,11 +6,17 @@ #define WINVER 0x0501 #endif +#ifndef CONF_BACKEND_OPENGL_ES #include +#else +#define GL_GLEXT_PROTOTYPES 1 +#include "SDL_opengles2.h" +#endif + #include #include "SDL.h" -#include "SDL_opengl.h" + #include "SDL_syswm.h" #include #include @@ -133,33 +139,6 @@ void CGraphicsBackend_Threaded::WaitForIdle() m_BufferDone.Wait(); } -static bool Texture2DTo3D(void *pImageBuffer, int ImageWidth, int ImageHeight, int ImageColorChannelCount, int SplitCountWidth, int SplitCountHeight, void *pTarget3DImageData, int &Target3DImageWidth, int &Target3DImageHeight) -{ - Target3DImageWidth = ImageWidth / SplitCountWidth; - Target3DImageHeight = ImageHeight / SplitCountHeight; - - size_t FullImageWidth = (size_t)ImageWidth * ImageColorChannelCount; - - for(int Y = 0; Y < SplitCountHeight; ++Y) - { - for(int X = 0; X < SplitCountWidth; ++X) - { - for(int Y3D = 0; Y3D < Target3DImageHeight; ++Y3D) - { - int DepthIndex = X + Y * SplitCountWidth; - - size_t TargetImageFullWidth = (size_t)Target3DImageWidth * ImageColorChannelCount; - size_t TargetImageFullSize = (size_t)TargetImageFullWidth * Target3DImageHeight; - ptrdiff_t ImageOffset = (ptrdiff_t)(((size_t)Y * FullImageWidth * (size_t)Target3DImageHeight) + ((size_t)Y3D * FullImageWidth) + ((size_t)X * TargetImageFullWidth)); - ptrdiff_t TargetImageOffset = (ptrdiff_t)(TargetImageFullSize * (size_t)DepthIndex + ((size_t)Y3D * TargetImageFullWidth)); - mem_copy(((uint8_t *)pTarget3DImageData) + TargetImageOffset, ((uint8_t *)pImageBuffer) + (ptrdiff_t)(ImageOffset), TargetImageFullWidth); - } - } - } - - return true; -} - // ------------ CCommandProcessorFragment_General void CCommandProcessorFragment_General::Cmd_Signal(const CCommandBuffer::SCommand_Signal *pCommand) @@ -179,3804 +158,12 @@ bool CCommandProcessorFragment_General::RunCommand(const CCommandBuffer::SComman return true; } -// ------------ CCommandProcessorFragment_OpenGL - -int CCommandProcessorFragment_OpenGL::TexFormatToOpenGLFormat(int TexFormat) -{ - if(TexFormat == CCommandBuffer::TEXFORMAT_RGB) - return GL_RGB; - if(TexFormat == CCommandBuffer::TEXFORMAT_ALPHA) - return GL_ALPHA; - if(TexFormat == CCommandBuffer::TEXFORMAT_RGBA) - return GL_RGBA; - return GL_RGBA; -} - -int CCommandProcessorFragment_OpenGL::TexFormatToImageColorChannelCount(int TexFormat) -{ - if(TexFormat == CCommandBuffer::TEXFORMAT_RGB) - return 3; - if(TexFormat == CCommandBuffer::TEXFORMAT_ALPHA) - return 1; - if(TexFormat == CCommandBuffer::TEXFORMAT_RGBA) - return 4; - return 4; -} - -void *CCommandProcessorFragment_OpenGL::Resize(int Width, int Height, int NewWidth, int NewHeight, int Format, const unsigned char *pData) -{ - int Bpp = TexFormatToImageColorChannelCount(Format); - - return ResizeImage((const uint8_t *)pData, Width, Height, NewWidth, NewHeight, Bpp); -} - -bool CCommandProcessorFragment_OpenGL::IsTexturedState(const CCommandBuffer::SState &State) -{ - return State.m_Texture >= 0 && State.m_Texture < (int)m_Textures.size(); -} - -void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &State, bool Use2DArrayTextures) -{ - // blend - switch(State.m_BlendMode) - { - case CCommandBuffer::BLEND_NONE: - glDisable(GL_BLEND); - break; - case CCommandBuffer::BLEND_ALPHA: - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - break; - case CCommandBuffer::BLEND_ADDITIVE: - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - break; - default: - dbg_msg("render", "unknown blendmode %d\n", State.m_BlendMode); - }; - m_LastBlendMode = State.m_BlendMode; - - // clip - if(State.m_ClipEnable) - { - glScissor(State.m_ClipX, State.m_ClipY, State.m_ClipW, State.m_ClipH); - glEnable(GL_SCISSOR_TEST); - m_LastClipEnable = true; - } - else if(m_LastClipEnable) - { - // Don't disable it always - glDisable(GL_SCISSOR_TEST); - m_LastClipEnable = false; - } - - glDisable(GL_TEXTURE_2D); - if(!m_HasShaders) - { - if(m_Has3DTextures) - glDisable(GL_TEXTURE_3D); - if(m_Has2DArrayTextures) - { - glDisable(m_2DArrayTarget); - } - } - - if(m_HasShaders && IsNewApi()) - { - glBindSampler(0, 0); - } - - // texture - if(IsTexturedState(State)) - { - if(!Use2DArrayTextures) - { - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, m_Textures[State.m_Texture].m_Tex); - - if(m_Textures[State.m_Texture].m_LastWrapMode != State.m_WrapMode) - { - switch(State.m_WrapMode) - { - case CCommandBuffer::WRAP_REPEAT: - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - break; - case CCommandBuffer::WRAP_CLAMP: - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - break; - default: - dbg_msg("render", "unknown wrapmode %d\n", State.m_WrapMode); - }; - m_Textures[State.m_Texture].m_LastWrapMode = State.m_WrapMode; - } - } - else - { - if(m_Has2DArrayTextures) - { - if(!m_HasShaders) - glEnable(m_2DArrayTarget); - glBindTexture(m_2DArrayTarget, m_Textures[State.m_Texture].m_Tex2DArray); - } - else if(m_Has3DTextures) - { - if(!m_HasShaders) - glEnable(GL_TEXTURE_3D); - glBindTexture(GL_TEXTURE_3D, m_Textures[State.m_Texture].m_Tex2DArray); - } - else - { - dbg_msg("opengl", "Error: this call should not happen."); - } - } - } - - // screen mapping - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(State.m_ScreenTL.x, State.m_ScreenBR.x, State.m_ScreenBR.y, State.m_ScreenTL.y, -10.0f, 10.f); -} - -void CCommandProcessorFragment_OpenGL::Cmd_Init(const SCommand_Init *pCommand) -{ - m_pTextureMemoryUsage = pCommand->m_pTextureMemoryUsage; - m_pTextureMemoryUsage->store(0, std::memory_order_relaxed); - m_MaxTexSize = -1; - - m_OpenGLTextureLodBIAS = 0; - - m_Has2DArrayTextures = pCommand->m_pCapabilities->m_2DArrayTextures; - if(pCommand->m_pCapabilities->m_2DArrayTexturesAsExtension) - { - m_Has2DArrayTexturesAsExtension = true; - m_2DArrayTarget = GL_TEXTURE_2D_ARRAY_EXT; - } - else - { - m_Has2DArrayTexturesAsExtension = false; - m_2DArrayTarget = GL_TEXTURE_2D_ARRAY; - } - - m_Has3DTextures = pCommand->m_pCapabilities->m_3DTextures; - m_HasMipMaps = pCommand->m_pCapabilities->m_MipMapping; - m_HasNPOTTextures = pCommand->m_pCapabilities->m_NPOTTextures; - - m_LastBlendMode = CCommandBuffer::BLEND_ALPHA; - m_LastClipEnable = false; -} - -void CCommandProcessorFragment_OpenGL::Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand) -{ - glBindTexture(GL_TEXTURE_2D, m_Textures[pCommand->m_Slot].m_Tex); - - void *pTexData = pCommand->m_pData; - int Width = pCommand->m_Width; - int Height = pCommand->m_Height; - int X = pCommand->m_X; - int Y = pCommand->m_Y; - - if(!m_HasNPOTTextures) - { - float ResizeW = m_Textures[pCommand->m_Slot].m_ResizeWidth; - float ResizeH = m_Textures[pCommand->m_Slot].m_ResizeHeight; - if(ResizeW > 0 && ResizeH > 0) - { - int ResizedW = (int)(Width * ResizeW); - int ResizedH = (int)(Height * ResizeH); - - void *pTmpData = Resize(Width, Height, ResizedW, ResizedH, pCommand->m_Format, static_cast(pTexData)); - free(pTexData); - pTexData = pTmpData; - - Width = ResizedW; - Height = ResizedH; - } - } - - if(m_Textures[pCommand->m_Slot].m_RescaleCount > 0) - { - int OldWidth = Width; - int OldHeight = Height; - for(int i = 0; i < m_Textures[pCommand->m_Slot].m_RescaleCount; ++i) - { - Width >>= 1; - Height >>= 1; - - X /= 2; - Y /= 2; - } - - void *pTmpData = Resize(OldWidth, OldHeight, Width, Height, pCommand->m_Format, static_cast(pTexData)); - free(pTexData); - pTexData = pTmpData; - } - - glTexSubImage2D(GL_TEXTURE_2D, 0, X, Y, Width, Height, - TexFormatToOpenGLFormat(pCommand->m_Format), GL_UNSIGNED_BYTE, pTexData); - free(pTexData); -} - -void CCommandProcessorFragment_OpenGL::DestroyTexture(int Slot) -{ - m_pTextureMemoryUsage->store(m_pTextureMemoryUsage->load(std::memory_order_relaxed) - m_Textures[Slot].m_MemSize, std::memory_order_relaxed); - - if(m_Textures[Slot].m_Tex != 0) - { - glDeleteTextures(1, &m_Textures[Slot].m_Tex); - } - - if(m_Textures[Slot].m_Tex2DArray != 0) - { - glDeleteTextures(1, &m_Textures[Slot].m_Tex2DArray); - } - - if(IsNewApi()) - { - if(m_Textures[Slot].m_Sampler != 0) - { - glDeleteSamplers(1, &m_Textures[Slot].m_Sampler); - } - if(m_Textures[Slot].m_Sampler2DArray != 0) - { - glDeleteSamplers(1, &m_Textures[Slot].m_Sampler2DArray); - } - } - - m_Textures[Slot].m_Tex = 0; - m_Textures[Slot].m_Sampler = 0; - m_Textures[Slot].m_Tex2DArray = 0; - m_Textures[Slot].m_Sampler2DArray = 0; - m_Textures[Slot].m_LastWrapMode = CCommandBuffer::WRAP_REPEAT; -} - -void CCommandProcessorFragment_OpenGL::Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand) -{ - DestroyTexture(pCommand->m_Slot); -} - -void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand) -{ - int Width = pCommand->m_Width; - int Height = pCommand->m_Height; - void *pTexData = pCommand->m_pData; - - if(m_MaxTexSize == -1) - { - // fix the alignment to allow even 1byte changes, e.g. for alpha components - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_MaxTexSize); - } - - if(pCommand->m_Slot >= (int)m_Textures.size()) - m_Textures.resize(m_Textures.size() * 2); - - m_Textures[pCommand->m_Slot].m_ResizeWidth = -1.f; - m_Textures[pCommand->m_Slot].m_ResizeHeight = -1.f; - - if(!m_HasNPOTTextures) - { - int PowerOfTwoWidth = HighestBit(Width); - int PowerOfTwoHeight = HighestBit(Height); - if(Width != PowerOfTwoWidth || Height != PowerOfTwoHeight) - { - void *pTmpData = Resize(Width, Height, PowerOfTwoWidth, PowerOfTwoHeight, pCommand->m_Format, static_cast(pTexData)); - free(pTexData); - pTexData = pTmpData; - - m_Textures[pCommand->m_Slot].m_ResizeWidth = (float)PowerOfTwoWidth / (float)Width; - m_Textures[pCommand->m_Slot].m_ResizeHeight = (float)PowerOfTwoHeight / (float)Height; - - Width = PowerOfTwoWidth; - Height = PowerOfTwoHeight; - } - } - - int RescaleCount = 0; - if(pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGBA || pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGB || pCommand->m_Format == CCommandBuffer::TEXFORMAT_ALPHA) - { - int OldWidth = Width; - int OldHeight = Height; - bool NeedsResize = false; - - if(Width > m_MaxTexSize || Height > m_MaxTexSize) - { - do - { - Width >>= 1; - Height >>= 1; - ++RescaleCount; - } while(Width > m_MaxTexSize || Height > m_MaxTexSize); - NeedsResize = true; - } - else if(pCommand->m_Format != CCommandBuffer::TEXFORMAT_ALPHA && (Width > 16 && Height > 16 && (pCommand->m_Flags & CCommandBuffer::TEXFLAG_QUALITY) == 0)) - { - Width >>= 1; - Height >>= 1; - ++RescaleCount; - NeedsResize = true; - } - - if(NeedsResize) - { - void *pTmpData = Resize(OldWidth, OldHeight, Width, Height, pCommand->m_Format, static_cast(pTexData)); - free(pTexData); - pTexData = pTmpData; - } - } - m_Textures[pCommand->m_Slot].m_Width = Width; - m_Textures[pCommand->m_Slot].m_Height = Height; - m_Textures[pCommand->m_Slot].m_RescaleCount = RescaleCount; - - int Oglformat = TexFormatToOpenGLFormat(pCommand->m_Format); - int StoreOglformat = TexFormatToOpenGLFormat(pCommand->m_StoreFormat); - - if(pCommand->m_Flags & CCommandBuffer::TEXFLAG_COMPRESSED) - { - switch(StoreOglformat) - { - case GL_RGB: StoreOglformat = GL_COMPRESSED_RGB_ARB; break; - case GL_ALPHA: StoreOglformat = GL_COMPRESSED_ALPHA_ARB; break; - case GL_RGBA: StoreOglformat = GL_COMPRESSED_RGBA_ARB; break; - default: StoreOglformat = GL_COMPRESSED_RGBA_ARB; - } - } - - if((pCommand->m_Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0) - { - glGenTextures(1, &m_Textures[pCommand->m_Slot].m_Tex); - glBindTexture(GL_TEXTURE_2D, m_Textures[pCommand->m_Slot].m_Tex); - } - - if(pCommand->m_Flags & CCommandBuffer::TEXFLAG_NOMIPMAPS || !m_HasMipMaps) - { - if((pCommand->m_Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0) - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, StoreOglformat, Width, Height, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData); - } - } - else - { - if((pCommand->m_Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0) - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); - if(m_OpenGLTextureLodBIAS != 0) - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f)); - glTexImage2D(GL_TEXTURE_2D, 0, StoreOglformat, Width, Height, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData); - } - - int Flag2DArrayTexture = (CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE | CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE_SINGLE_LAYER); - int Flag3DTexture = (CCommandBuffer::TEXFLAG_TO_3D_TEXTURE | CCommandBuffer::TEXFLAG_TO_3D_TEXTURE_SINGLE_LAYER); - if((pCommand->m_Flags & (Flag2DArrayTexture | Flag3DTexture)) != 0) - { - bool Is3DTexture = (pCommand->m_Flags & Flag3DTexture) != 0; - - glGenTextures(1, &m_Textures[pCommand->m_Slot].m_Tex2DArray); - - GLenum Target = GL_TEXTURE_3D; - - if(Is3DTexture) - { - Target = GL_TEXTURE_3D; - } - else - { - Target = m_2DArrayTarget; - } - - glBindTexture(Target, m_Textures[pCommand->m_Slot].m_Tex2DArray); - - if(IsNewApi()) - { - glGenSamplers(1, &m_Textures[pCommand->m_Slot].m_Sampler2DArray); - glBindSampler(0, m_Textures[pCommand->m_Slot].m_Sampler2DArray); - } - - glTexParameteri(Target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - if(Is3DTexture) - { - glTexParameteri(Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - if(IsNewApi()) - glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - else - { - glTexParameteri(Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(Target, GL_GENERATE_MIPMAP, GL_TRUE); - if(IsNewApi()) - glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - } - - glTexParameteri(Target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(Target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(Target, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT); - if(m_OpenGLTextureLodBIAS != 0) - glTexParameterf(Target, GL_TEXTURE_LOD_BIAS, ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f)); - - if(IsNewApi()) - { - glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT); - if(m_OpenGLTextureLodBIAS != 0) - glSamplerParameterf(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_LOD_BIAS, ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f)); - - glBindSampler(0, 0); - } - - int ImageColorChannels = TexFormatToImageColorChannelCount(pCommand->m_Format); - - uint8_t *p3DImageData = NULL; - - bool IsSingleLayer = (pCommand->m_Flags & (CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE_SINGLE_LAYER | CCommandBuffer::TEXFLAG_TO_3D_TEXTURE_SINGLE_LAYER)) != 0; - - if(!IsSingleLayer) - p3DImageData = (uint8_t *)malloc((size_t)ImageColorChannels * Width * Height); - int Image3DWidth, Image3DHeight; - - int ConvertWidth = Width; - int ConvertHeight = Height; - - if(!IsSingleLayer) - { - if(ConvertWidth == 0 || (ConvertWidth % 16) != 0 || ConvertHeight == 0 || (ConvertHeight % 16) != 0) - { - dbg_msg("gfx", "3D/2D array texture was resized"); - int NewWidth = maximum(HighestBit(ConvertWidth), 16); - int NewHeight = maximum(HighestBit(ConvertHeight), 16); - uint8_t *pNewTexData = (uint8_t *)Resize(ConvertWidth, ConvertHeight, NewWidth, NewHeight, pCommand->m_Format, (const uint8_t *)pTexData); - - ConvertWidth = NewWidth; - ConvertHeight = NewHeight; - - free(pTexData); - pTexData = pNewTexData; - } - } - - if(IsSingleLayer || (Texture2DTo3D(pTexData, ConvertWidth, ConvertHeight, ImageColorChannels, 16, 16, p3DImageData, Image3DWidth, Image3DHeight))) - { - if(IsSingleLayer) - { - glTexImage3D(Target, 0, StoreOglformat, ConvertWidth, ConvertHeight, 1, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData); - } - else - { - glTexImage3D(Target, 0, StoreOglformat, Image3DWidth, Image3DHeight, 256, 0, Oglformat, GL_UNSIGNED_BYTE, p3DImageData); - } - - /*if(StoreOglformat == GL_R8) - { - //Bind the texture 2D. - GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_RED}; - glTexParameteriv(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - }*/ - } - - if(!IsSingleLayer) - free(p3DImageData); - } - } - - // This is the initial value for the wrap modes - m_Textures[pCommand->m_Slot].m_LastWrapMode = CCommandBuffer::WRAP_REPEAT; - - // calculate memory usage - m_Textures[pCommand->m_Slot].m_MemSize = Width * Height * pCommand->m_PixelSize; - while(Width > 2 && Height > 2) - { - Width >>= 1; - Height >>= 1; - m_Textures[pCommand->m_Slot].m_MemSize += Width * Height * pCommand->m_PixelSize; - } - m_pTextureMemoryUsage->store(m_pTextureMemoryUsage->load(std::memory_order_relaxed) + m_Textures[pCommand->m_Slot].m_MemSize, std::memory_order_relaxed); - - free(pTexData); -} - -void CCommandProcessorFragment_OpenGL::Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand) -{ - glClearColor(pCommand->m_Color.r, pCommand->m_Color.g, pCommand->m_Color.b, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -} - -void CCommandProcessorFragment_OpenGL::Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand) -{ - SetState(pCommand->m_State); - - glVertexPointer(2, GL_FLOAT, sizeof(CCommandBuffer::SVertex), (char *)pCommand->m_pVertices); - glTexCoordPointer(2, GL_FLOAT, sizeof(CCommandBuffer::SVertex), (char *)pCommand->m_pVertices + sizeof(float) * 2); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(CCommandBuffer::SVertex), (char *)pCommand->m_pVertices + sizeof(float) * 4); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - switch(pCommand->m_PrimType) - { - case CCommandBuffer::PRIMTYPE_QUADS: - glDrawArrays(GL_QUADS, 0, pCommand->m_PrimCount * 4); - break; - case CCommandBuffer::PRIMTYPE_LINES: - glDrawArrays(GL_LINES, 0, pCommand->m_PrimCount * 2); - break; - case CCommandBuffer::PRIMTYPE_TRIANGLES: - glDrawArrays(GL_TRIANGLES, 0, pCommand->m_PrimCount * 3); - break; - default: - dbg_msg("render", "unknown primtype %d\n", pCommand->m_PrimType); - }; -} - -void CCommandProcessorFragment_OpenGL::Cmd_Screenshot(const CCommandBuffer::SCommand_Screenshot *pCommand) -{ - // fetch image data - GLint aViewport[4] = {0, 0, 0, 0}; - glGetIntegerv(GL_VIEWPORT, aViewport); - - int w = aViewport[2]; - int h = aViewport[3]; - - // we allocate one more row to use when we are flipping the texture - unsigned char *pPixelData = (unsigned char *)malloc((size_t)w * (h + 1) * 3); - unsigned char *pTempRow = pPixelData + w * h * 3; - - // fetch the pixels - GLint Alignment; - glGetIntegerv(GL_PACK_ALIGNMENT, &Alignment); - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, pPixelData); - glPixelStorei(GL_PACK_ALIGNMENT, Alignment); - - // flip the pixel because opengl works from bottom left corner - for(int y = 0; y < h / 2; y++) - { - mem_copy(pTempRow, pPixelData + y * w * 3, w * 3); - mem_copy(pPixelData + y * w * 3, pPixelData + (h - y - 1) * w * 3, w * 3); - mem_copy(pPixelData + (h - y - 1) * w * 3, pTempRow, w * 3); - } - - // fill in the information - pCommand->m_pImage->m_Width = w; - pCommand->m_pImage->m_Height = h; - pCommand->m_pImage->m_Format = CImageInfo::FORMAT_RGB; - pCommand->m_pImage->m_pData = pPixelData; -} - -CCommandProcessorFragment_OpenGL::CCommandProcessorFragment_OpenGL() -{ - m_Textures.resize(CCommandBuffer::MAX_TEXTURES); - m_HasShaders = false; -} - -bool CCommandProcessorFragment_OpenGL::RunCommand(const CCommandBuffer::SCommand *pBaseCommand) -{ - switch(pBaseCommand->m_Cmd) - { - case CCommandProcessorFragment_OpenGL::CMD_INIT: - Cmd_Init(static_cast(pBaseCommand)); - break; - case CCommandProcessorFragment_OpenGL::CMD_SHUTDOWN: - Cmd_Shutdown(static_cast(pBaseCommand)); - break; - case CCommandBuffer::CMD_TEXTURE_CREATE: - Cmd_Texture_Create(static_cast(pBaseCommand)); - break; - case CCommandBuffer::CMD_TEXTURE_DESTROY: - Cmd_Texture_Destroy(static_cast(pBaseCommand)); - break; - case CCommandBuffer::CMD_TEXTURE_UPDATE: - Cmd_Texture_Update(static_cast(pBaseCommand)); - break; - case CCommandBuffer::CMD_CLEAR: - Cmd_Clear(static_cast(pBaseCommand)); - break; - case CCommandBuffer::CMD_RENDER: - Cmd_Render(static_cast(pBaseCommand)); - break; - case CCommandBuffer::CMD_RENDER_TEX3D: - Cmd_RenderTex3D(static_cast(pBaseCommand)); - break; - case CCommandBuffer::CMD_SCREENSHOT: - Cmd_Screenshot(static_cast(pBaseCommand)); - break; - - case CCommandBuffer::CMD_CREATE_BUFFER_OBJECT: Cmd_CreateBufferObject(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_UPDATE_BUFFER_OBJECT: Cmd_UpdateBufferObject(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_RECREATE_BUFFER_OBJECT: Cmd_RecreateBufferObject(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_COPY_BUFFER_OBJECT: Cmd_CopyBufferObject(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_DELETE_BUFFER_OBJECT: Cmd_DeleteBufferObject(static_cast(pBaseCommand)); break; - - case CCommandBuffer::CMD_CREATE_BUFFER_CONTAINER: Cmd_CreateBufferContainer(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_UPDATE_BUFFER_CONTAINER: Cmd_UpdateBufferContainer(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_DELETE_BUFFER_CONTAINER: Cmd_DeleteBufferContainer(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_INDICES_REQUIRED_NUM_NOTIFY: Cmd_IndicesRequiredNumNotify(static_cast(pBaseCommand)); break; - - case CCommandBuffer::CMD_RENDER_TILE_LAYER: Cmd_RenderTileLayer(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_RENDER_BORDER_TILE: Cmd_RenderBorderTile(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_RENDER_BORDER_TILE_LINE: Cmd_RenderBorderTileLine(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_RENDER_QUAD_LAYER: Cmd_RenderQuadLayer(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_RENDER_TEXT: Cmd_RenderText(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_RENDER_TEXT_STREAM: Cmd_RenderTextStream(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_RENDER_QUAD_CONTAINER: Cmd_RenderQuadContainer(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_RENDER_QUAD_CONTAINER_EX: Cmd_RenderQuadContainerEx(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_RENDER_QUAD_CONTAINER_SPRITE_MULTIPLE: Cmd_RenderQuadContainerAsSpriteMultiple(static_cast(pBaseCommand)); break; - default: return false; - } - - return true; -} - -// ------------ CCommandProcessorFragment_OpenGL2 - -void CCommandProcessorFragment_OpenGL2::UseProgram(CGLSLTWProgram *pProgram) -{ - pProgram->UseProgram(); -} - -bool CCommandProcessorFragment_OpenGL2::IsAndUpdateTextureSlotBound(int IDX, int Slot, bool Is2DArray) -{ - if(m_TextureSlotBoundToUnit[IDX].m_TextureSlot == Slot && m_TextureSlotBoundToUnit[IDX].m_Is2DArray == Is2DArray) - return true; - else - { - //the texture slot uses this index now - m_TextureSlotBoundToUnit[IDX].m_TextureSlot = Slot; - m_TextureSlotBoundToUnit[IDX].m_Is2DArray = Is2DArray; - return false; - } -} - -void CCommandProcessorFragment_OpenGL2::SetState(const CCommandBuffer::SState &State, CGLSLTWProgram *pProgram, bool Use2DArrayTextures) -{ - if(m_LastBlendMode == CCommandBuffer::BLEND_NONE) - { - m_LastBlendMode = CCommandBuffer::BLEND_ALPHA; - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - if(State.m_BlendMode != m_LastBlendMode && State.m_BlendMode != CCommandBuffer::BLEND_NONE) - { - // blend - switch(State.m_BlendMode) - { - case CCommandBuffer::BLEND_NONE: - // We don't really need this anymore - //glDisable(GL_BLEND); - break; - case CCommandBuffer::BLEND_ALPHA: - //glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - break; - case CCommandBuffer::BLEND_ADDITIVE: - //glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - break; - default: - dbg_msg("render", "unknown blendmode %d\n", State.m_BlendMode); - }; - - m_LastBlendMode = State.m_BlendMode; - } - - // clip - if(State.m_ClipEnable) - { - glScissor(State.m_ClipX, State.m_ClipY, State.m_ClipW, State.m_ClipH); - glEnable(GL_SCISSOR_TEST); - m_LastClipEnable = true; - } - else if(m_LastClipEnable) - { - // Don't disable it always - glDisable(GL_SCISSOR_TEST); - m_LastClipEnable = false; - } - - if(!IsNewApi()) - { - glDisable(GL_TEXTURE_2D); - if(!m_HasShaders) - { - if(m_Has3DTextures) - glDisable(GL_TEXTURE_3D); - if(m_Has2DArrayTextures) - { - glDisable(m_2DArrayTarget); - } - } - } - - // texture - if(IsTexturedState(State)) - { - int Slot = 0; - if(m_UseMultipleTextureUnits) - { - Slot = State.m_Texture % m_MaxTextureUnits; - if(!IsAndUpdateTextureSlotBound(Slot, State.m_Texture, Use2DArrayTextures)) - { - glActiveTexture(GL_TEXTURE0 + Slot); - if(!Use2DArrayTextures) - { - glBindTexture(GL_TEXTURE_2D, m_Textures[State.m_Texture].m_Tex); - if(IsNewApi()) - glBindSampler(Slot, m_Textures[State.m_Texture].m_Sampler); - } - else - { - glBindTexture(GL_TEXTURE_2D_ARRAY, m_Textures[State.m_Texture].m_Tex2DArray); - if(IsNewApi()) - glBindSampler(Slot, m_Textures[State.m_Texture].m_Sampler2DArray); - } - } - } - else - { - Slot = 0; - if(!Use2DArrayTextures) - { - if(!IsNewApi() && !m_HasShaders) - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, m_Textures[State.m_Texture].m_Tex); - if(IsNewApi()) - glBindSampler(Slot, m_Textures[State.m_Texture].m_Sampler); - } - else - { - if(!m_Has2DArrayTextures) - { - if(!IsNewApi() && !m_HasShaders) - glEnable(GL_TEXTURE_3D); - glBindTexture(GL_TEXTURE_3D, m_Textures[State.m_Texture].m_Tex2DArray); - if(IsNewApi()) - glBindSampler(Slot, m_Textures[State.m_Texture].m_Sampler2DArray); - } - else - { - if(!IsNewApi() && !m_HasShaders) - glEnable(m_2DArrayTarget); - glBindTexture(m_2DArrayTarget, m_Textures[State.m_Texture].m_Tex2DArray); - if(IsNewApi()) - glBindSampler(Slot, m_Textures[State.m_Texture].m_Sampler2DArray); - } - } - } - - if(pProgram->m_LastTextureSampler != Slot) - { - pProgram->SetUniform(pProgram->m_LocTextureSampler, Slot); - pProgram->m_LastTextureSampler = Slot; - } - - if(m_Textures[State.m_Texture].m_LastWrapMode != State.m_WrapMode && !Use2DArrayTextures) - { - switch(State.m_WrapMode) - { - case CCommandBuffer::WRAP_REPEAT: - if(IsNewApi()) - { - glSamplerParameteri(m_Textures[State.m_Texture].m_Sampler, GL_TEXTURE_WRAP_S, GL_REPEAT); - glSamplerParameteri(m_Textures[State.m_Texture].m_Sampler, GL_TEXTURE_WRAP_T, GL_REPEAT); - } - break; - case CCommandBuffer::WRAP_CLAMP: - if(IsNewApi()) - { - glSamplerParameteri(m_Textures[State.m_Texture].m_Sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glSamplerParameteri(m_Textures[State.m_Texture].m_Sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - break; - default: - dbg_msg("render", "unknown wrapmode %d\n", State.m_WrapMode); - }; - m_Textures[State.m_Texture].m_LastWrapMode = State.m_WrapMode; - } - } - - if(pProgram->m_LastScreen[0] != State.m_ScreenTL.x || pProgram->m_LastScreen[1] != State.m_ScreenTL.y || pProgram->m_LastScreen[2] != State.m_ScreenBR.x || pProgram->m_LastScreen[3] != State.m_ScreenBR.y) - { - pProgram->m_LastScreen[0] = State.m_ScreenTL.x; - pProgram->m_LastScreen[1] = State.m_ScreenTL.y; - pProgram->m_LastScreen[2] = State.m_ScreenBR.x; - pProgram->m_LastScreen[3] = State.m_ScreenBR.y; - // screen mapping - // orthographic projection matrix - // the z coordinate is the same for every vertex, so just ignore the z coordinate and set it in the shaders - float m[2 * 4] = { - 2.f / (State.m_ScreenBR.x - State.m_ScreenTL.x), 0, 0, -((State.m_ScreenBR.x + State.m_ScreenTL.x) / (State.m_ScreenBR.x - State.m_ScreenTL.x)), - 0, (2.f / (State.m_ScreenTL.y - State.m_ScreenBR.y)), 0, -((State.m_ScreenTL.y + State.m_ScreenBR.y) / (State.m_ScreenTL.y - State.m_ScreenBR.y)), - //0, 0, -(2.f/(9.f)), -((11.f)/(9.f)), - //0, 0, 0, 1.0f - }; - - // transpose bcs of column-major order of opengl - glUniformMatrix4x2fv(pProgram->m_LocPos, 1, true, (float *)&m); - } -} - -bool CCommandProcessorFragment_OpenGL2::DoAnalyzeStep(size_t StepN, size_t CheckCount, size_t VerticesCount, uint8_t aFakeTexture[], size_t SingleImageSize) -{ - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - int Slot = 0; - if(m_HasShaders) - { - CGLSLTWProgram *pProgram = m_pPrimitive3DProgramTextured; - if(StepN == 1) - pProgram = m_pTileProgramTextured; - UseProgram(pProgram); - - pProgram->SetUniform(pProgram->m_LocTextureSampler, Slot); - - if(StepN == 1) - { - float aColor[4] = {1.f, 1.f, 1.f, 1.f}; - pProgram->SetUniformVec4(((CGLSLTileProgram *)pProgram)->m_LocColor, 1, aColor); - } - - float m[2 * 4] = { - 1, 0, 0, 0, - 0, 1, 0, 0}; - - // transpose bcs of column-major order of opengl - glUniformMatrix4x2fv(pProgram->m_LocPos, 1, true, (float *)&m); - } - else - { - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(-1, 1, -1, 1, -10.0f, 10.f); - } - - GLuint BufferID = 0; - if(StepN == 1 && m_HasShaders) - { - glGenBuffers(1, &BufferID); - glBindBuffer(GL_ARRAY_BUFFER, BufferID); - glBufferData(GL_ARRAY_BUFFER, VerticesCount * sizeof((m_aStreamVertices[0])), m_aStreamVertices, GL_STATIC_DRAW); - - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, false, sizeof((m_aStreamVertices[0])), 0); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, false, sizeof((m_aStreamVertices[0])), (GLvoid *)(sizeof(vec4) + sizeof(vec2))); - } - else - { - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - glVertexPointer(2, GL_FLOAT, sizeof(m_aStreamVertices[0]), m_aStreamVertices); - glColorPointer(4, GL_FLOAT, sizeof(m_aStreamVertices[0]), (uint8_t *)m_aStreamVertices + (ptrdiff_t)(sizeof(vec2))); - glTexCoordPointer(3, GL_FLOAT, sizeof(m_aStreamVertices[0]), (uint8_t *)m_aStreamVertices + (ptrdiff_t)(sizeof(vec2) + sizeof(vec4))); - } - - glDrawArrays(GL_QUADS, 0, VerticesCount); - - if(StepN == 1 && m_HasShaders) - { - glDisableVertexAttribArray(0); - glDisableVertexAttribArray(1); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glDeleteBuffers(1, &BufferID); - } - else - { - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - } - - if(m_HasShaders) - { - glUseProgram(0); - } - - glFinish(); - - GLint aViewport[4] = {0, 0, 0, 0}; - glGetIntegerv(GL_VIEWPORT, aViewport); - - int w = aViewport[2]; - int h = aViewport[3]; - - size_t PixelDataSize = (size_t)w * h * 3; - if(PixelDataSize == 0) - return false; - uint8_t *pPixelData = (uint8_t *)malloc(PixelDataSize); - - // fetch the pixels - GLint Alignment; - glGetIntegerv(GL_PACK_ALIGNMENT, &Alignment); - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, pPixelData); - glPixelStorei(GL_PACK_ALIGNMENT, Alignment); - - // now analyse the image data - bool CheckFailed = false; - int WidthTile = w / 16; - int HeightTile = h / 16; - int StartX = WidthTile / 2; - int StartY = HeightTile / 2; - for(size_t d = 0; d < CheckCount; ++d) - { - int CurX = (int)d % 16; - int CurY = (int)d / 16; - - int CheckX = StartX + CurX * WidthTile; - int CheckY = StartY + CurY * HeightTile; - - ptrdiff_t OffsetPixelData = (CheckY * (w * 3)) + (CheckX * 3); - ptrdiff_t OffsetFakeTexture = SingleImageSize * d; - OffsetPixelData = clamp(OffsetPixelData, 0, (ptrdiff_t)PixelDataSize); - OffsetFakeTexture = clamp(OffsetFakeTexture, 0, (ptrdiff_t)(SingleImageSize * CheckCount)); - uint8_t *pPixel = pPixelData + OffsetPixelData; - uint8_t *pPixelTex = aFakeTexture + OffsetFakeTexture; - for(size_t i = 0; i < 3; ++i) - { - if((pPixel[i] < pPixelTex[i] - 25) || (pPixel[i] > pPixelTex[i] + 25)) - { - CheckFailed = true; - break; - } - } - } - - free(pPixelData); - return !CheckFailed; -} - -bool CCommandProcessorFragment_OpenGL2::IsTileMapAnalysisSucceeded() -{ - glClearColor(0, 0, 0, 1); - - // create fake texture 1024x1024 - const size_t ImageWidth = 1024; - const size_t ImageHeight = 1024; - uint8_t *pFakeTexture = (uint8_t *)malloc(sizeof(uint8_t) * ImageWidth * ImageHeight * 4); - // fill by colors stepping by 50 => (255 / 50 ~ 5) => 5 times 3(color channels) = 5 ^ 3 = 125 possibilities to check - size_t CheckCount = 5 * 5 * 5; - // always fill 4 pixels of the texture, so the sampling is accurate - int aCurColor[4] = {25, 25, 25, 255}; - const size_t SingleImageWidth = 64; - const size_t SingleImageHeight = 64; - size_t SingleImageSize = SingleImageWidth * SingleImageHeight * 4; - for(size_t d = 0; d < CheckCount; ++d) - { - uint8_t *pCurFakeTexture = pFakeTexture + (ptrdiff_t)(SingleImageSize * d); - - uint8_t aCurColorUint8[SingleImageWidth * SingleImageHeight * 4]; - for(size_t y = 0; y < SingleImageHeight; ++y) - { - for(size_t x = 0; x < SingleImageWidth; ++x) - { - for(size_t i = 0; i < 4; ++i) - { - aCurColorUint8[(y * SingleImageWidth * 4) + (x * 4) + i] = (uint8_t)aCurColor[i]; - } - } - } - mem_copy(pCurFakeTexture, aCurColorUint8, sizeof(aCurColorUint8)); - - aCurColor[2] += 50; - if(aCurColor[2] > 225) - { - aCurColor[2] -= 250; - aCurColor[1] += 50; - } - if(aCurColor[1] > 225) - { - aCurColor[1] -= 250; - aCurColor[0] += 50; - } - if(aCurColor[0] > 225) - { - break; - } - } - - // upload the texture - GLuint FakeTexture; - glGenTextures(1, &FakeTexture); - - GLenum Target = GL_TEXTURE_3D; - if(m_Has2DArrayTextures) - { - Target = m_2DArrayTarget; - } - - glBindTexture(Target, FakeTexture); - glTexParameteri(Target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - if(!m_Has2DArrayTextures) - { - glTexParameteri(Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - else - { - glTexParameteri(Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(Target, GL_GENERATE_MIPMAP, GL_TRUE); - } - - glTexParameteri(Target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(Target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(Target, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT); - - glTexImage3D(Target, 0, GL_RGBA, ImageWidth / 16, ImageHeight / 16, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, pFakeTexture); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_SCISSOR_TEST); - - if(!m_HasShaders) - { - glDisable(GL_TEXTURE_2D); - if(m_Has3DTextures) - glDisable(GL_TEXTURE_3D); - if(m_Has2DArrayTextures) - { - glDisable(m_2DArrayTarget); - } - - if(!m_Has2DArrayTextures) - { - glEnable(GL_TEXTURE_3D); - glBindTexture(GL_TEXTURE_3D, FakeTexture); - } - else - { - glEnable(m_2DArrayTarget); - glBindTexture(m_2DArrayTarget, FakeTexture); - } - } - - static_assert(sizeof(m_aStreamVertices) / sizeof(m_aStreamVertices[0]) >= 256 * 4, "Keep the number of stream vertices >= 256 * 4."); - - size_t VertexCount = 0; - for(size_t i = 0; i < CheckCount; ++i) - { - float XPos = (float)(i % 16); - float YPos = (float)(i / 16); - - GL_SVertexTex3D *pVertex = &m_aStreamVertices[VertexCount++]; - GL_SVertexTex3D *pVertexBefore = pVertex; - pVertex->m_Pos.x = XPos / 16.f; - pVertex->m_Pos.y = YPos / 16.f; - pVertex->m_Color.r = 1; - pVertex->m_Color.g = 1; - pVertex->m_Color.b = 1; - pVertex->m_Color.a = 1; - pVertex->m_Tex.u = 0; - pVertex->m_Tex.v = 0; - - pVertex = &m_aStreamVertices[VertexCount++]; - pVertex->m_Pos.x = XPos / 16.f + 1.f / 16.f; - pVertex->m_Pos.y = YPos / 16.f; - pVertex->m_Color.r = 1; - pVertex->m_Color.g = 1; - pVertex->m_Color.b = 1; - pVertex->m_Color.a = 1; - pVertex->m_Tex.u = 1; - pVertex->m_Tex.v = 0; - - pVertex = &m_aStreamVertices[VertexCount++]; - pVertex->m_Pos.x = XPos / 16.f + 1.f / 16.f; - pVertex->m_Pos.y = YPos / 16.f + 1.f / 16.f; - pVertex->m_Color.r = 1; - pVertex->m_Color.g = 1; - pVertex->m_Color.b = 1; - pVertex->m_Color.a = 1; - pVertex->m_Tex.u = 1; - pVertex->m_Tex.v = 1; - - pVertex = &m_aStreamVertices[VertexCount++]; - pVertex->m_Pos.x = XPos / 16.f; - pVertex->m_Pos.y = YPos / 16.f + 1.f / 16.f; - pVertex->m_Color.r = 1; - pVertex->m_Color.g = 1; - pVertex->m_Color.b = 1; - pVertex->m_Color.a = 1; - pVertex->m_Tex.u = 0; - pVertex->m_Tex.v = 1; - - for(size_t n = 0; n < 4; ++n) - { - pVertexBefore[n].m_Pos.x *= 2; - pVertexBefore[n].m_Pos.x -= 1; - pVertexBefore[n].m_Pos.y *= 2; - pVertexBefore[n].m_Pos.y -= 1; - if(m_Has2DArrayTextures) - { - pVertexBefore[n].m_Tex.w = i; - } - else - { - pVertexBefore[n].m_Tex.w = (i + 0.5f) / 256.f; - } - } - } - - //everything build up, now do the analyze steps - bool NoError = DoAnalyzeStep(0, CheckCount, VertexCount, pFakeTexture, SingleImageSize); - if(NoError && m_HasShaders) - NoError &= DoAnalyzeStep(1, CheckCount, VertexCount, pFakeTexture, SingleImageSize); - - glDeleteTextures(1, &FakeTexture); - free(pFakeTexture); - - return NoError; -} - -void CCommandProcessorFragment_OpenGL2::Cmd_Init(const SCommand_Init *pCommand) -{ - CCommandProcessorFragment_OpenGL::Cmd_Init(pCommand); - - m_OpenGLTextureLodBIAS = g_Config.m_GfxOpenGLTextureLODBIAS; - - m_HasShaders = pCommand->m_pCapabilities->m_ShaderSupport; - - bool HasAllFunc = true; - if(m_HasShaders) - { - HasAllFunc &= (glUniformMatrix4x2fv != NULL) && (glGenBuffers != NULL); - HasAllFunc &= (glBindBuffer != NULL) && (glBufferData != NULL); - HasAllFunc &= (glEnableVertexAttribArray != NULL) && (glVertexAttribPointer != NULL); - HasAllFunc &= (glDisableVertexAttribArray != NULL) && (glDeleteBuffers != NULL); - HasAllFunc &= (glUseProgram != NULL) && (glTexImage3D != NULL); - HasAllFunc &= (glBindAttribLocation != NULL) && (glTexImage3D != NULL); - HasAllFunc &= (glBufferSubData != NULL) && (glGetUniformLocation != NULL); - HasAllFunc &= (glUniform1i != NULL) && (glUniform1f != NULL); - HasAllFunc &= (glUniform1ui != NULL) && (glUniform1i != NULL); - HasAllFunc &= (glUniform1fv != NULL) && (glUniform2fv != NULL); - HasAllFunc &= (glUniform4fv != NULL) && (glGetAttachedShaders != NULL); - HasAllFunc &= (glGetProgramInfoLog != NULL) && (glGetProgramiv != NULL); - HasAllFunc &= (glLinkProgram != NULL) && (glDetachShader != NULL); - HasAllFunc &= (glAttachShader != NULL) && (glDeleteProgram != NULL); - HasAllFunc &= (glCreateProgram != NULL) && (glShaderSource != NULL); - HasAllFunc &= (glCompileShader != NULL) && (glGetShaderiv != NULL); - HasAllFunc &= (glGetShaderInfoLog != NULL) && (glDeleteShader != NULL); - HasAllFunc &= (glCreateShader != NULL); - } - - bool AnalysisCorrect = true; - if(HasAllFunc) - { - if(m_HasShaders) - { - m_pTileProgram = new CGLSLTileProgram; - m_pTileProgramTextured = new CGLSLTileProgram; - m_pPrimitive3DProgram = new CGLSLPrimitiveProgram; - m_pPrimitive3DProgramTextured = new CGLSLPrimitiveProgram; - - CGLSLCompiler ShaderCompiler(g_Config.m_GfxOpenGLMajor, g_Config.m_GfxOpenGLMinor, g_Config.m_GfxOpenGLPatch); - ShaderCompiler.SetHasTextureArray(pCommand->m_pCapabilities->m_2DArrayTextures); - - if(pCommand->m_pCapabilities->m_2DArrayTextures) - ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY); - else - ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D); - { - CGLSL PrimitiveVertexShader; - CGLSL PrimitiveFragmentShader; - PrimitiveVertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/pipeline.vert", GL_VERTEX_SHADER); - PrimitiveFragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/pipeline.frag", GL_FRAGMENT_SHADER); - - m_pPrimitive3DProgram->CreateProgram(); - m_pPrimitive3DProgram->AddShader(&PrimitiveVertexShader); - m_pPrimitive3DProgram->AddShader(&PrimitiveFragmentShader); - m_pPrimitive3DProgram->LinkProgram(); - - UseProgram(m_pPrimitive3DProgram); - - m_pPrimitive3DProgram->m_LocPos = m_pPrimitive3DProgram->GetUniformLoc("gPos"); - } - - if(pCommand->m_pCapabilities->m_2DArrayTextures) - ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY); - else - ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D); - { - CGLSL PrimitiveVertexShader; - CGLSL PrimitiveFragmentShader; - ShaderCompiler.AddDefine("TW_TEXTURED", ""); - if(!pCommand->m_pCapabilities->m_2DArrayTextures) - ShaderCompiler.AddDefine("TW_3D_TEXTURED", ""); - PrimitiveVertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/pipeline.vert", GL_VERTEX_SHADER); - PrimitiveFragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/pipeline.frag", GL_FRAGMENT_SHADER); - ShaderCompiler.ClearDefines(); - - m_pPrimitive3DProgramTextured->CreateProgram(); - m_pPrimitive3DProgramTextured->AddShader(&PrimitiveVertexShader); - m_pPrimitive3DProgramTextured->AddShader(&PrimitiveFragmentShader); - m_pPrimitive3DProgramTextured->LinkProgram(); - - UseProgram(m_pPrimitive3DProgramTextured); - - m_pPrimitive3DProgramTextured->m_LocPos = m_pPrimitive3DProgramTextured->GetUniformLoc("gPos"); - m_pPrimitive3DProgramTextured->m_LocTextureSampler = m_pPrimitive3DProgramTextured->GetUniformLoc("gTextureSampler"); - } - if(pCommand->m_pCapabilities->m_2DArrayTextures) - ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY); - else - ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D); - { - CGLSL VertexShader; - CGLSL FragmentShader; - VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.vert", GL_VERTEX_SHADER); - FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.frag", GL_FRAGMENT_SHADER); - - m_pTileProgram->CreateProgram(); - m_pTileProgram->AddShader(&VertexShader); - m_pTileProgram->AddShader(&FragmentShader); - - glBindAttribLocation(m_pTileProgram->GetProgramID(), 0, "inVertex"); - - m_pTileProgram->LinkProgram(); - - UseProgram(m_pTileProgram); - - m_pTileProgram->m_LocPos = m_pTileProgram->GetUniformLoc("gPos"); - m_pTileProgram->m_LocColor = m_pTileProgram->GetUniformLoc("gVertColor"); - } - if(pCommand->m_pCapabilities->m_2DArrayTextures) - ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY); - else - ShaderCompiler.SetTextureReplaceType(CGLSLCompiler::GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D); - { - CGLSL VertexShader; - CGLSL FragmentShader; - ShaderCompiler.AddDefine("TW_TILE_TEXTURED", ""); - if(!pCommand->m_pCapabilities->m_2DArrayTextures) - ShaderCompiler.AddDefine("TW_TILE_3D_TEXTURED", ""); - VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.vert", GL_VERTEX_SHADER); - FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.frag", GL_FRAGMENT_SHADER); - ShaderCompiler.ClearDefines(); - - m_pTileProgramTextured->CreateProgram(); - m_pTileProgramTextured->AddShader(&VertexShader); - m_pTileProgramTextured->AddShader(&FragmentShader); - - glBindAttribLocation(m_pTileProgram->GetProgramID(), 0, "inVertex"); - glBindAttribLocation(m_pTileProgram->GetProgramID(), 1, "inVertexTexCoord"); - - m_pTileProgramTextured->LinkProgram(); - - UseProgram(m_pTileProgramTextured); - - m_pTileProgramTextured->m_LocPos = m_pTileProgramTextured->GetUniformLoc("gPos"); - m_pTileProgramTextured->m_LocTextureSampler = m_pTileProgramTextured->GetUniformLoc("gTextureSampler"); - m_pTileProgramTextured->m_LocColor = m_pTileProgramTextured->GetUniformLoc("gVertColor"); - } - - glUseProgram(0); - } - - if(g_Config.m_Gfx3DTextureAnalysisDone == 0) - { - AnalysisCorrect = IsTileMapAnalysisSucceeded(); - if(AnalysisCorrect) - { - g_Config.m_Gfx3DTextureAnalysisDone = 1; - } - } - } - - if(!AnalysisCorrect || !HasAllFunc) - { - // downgrade to opengl 1.5 - *pCommand->m_pInitError = -2; - pCommand->m_pCapabilities->m_ContextMajor = 1; - pCommand->m_pCapabilities->m_ContextMinor = 5; - pCommand->m_pCapabilities->m_ContextPatch = 0; - } -} - -void CCommandProcessorFragment_OpenGL2::Cmd_RenderTex3D(const CCommandBuffer::SCommand_RenderTex3D *pCommand) -{ - if(m_HasShaders) - { - CGLSLPrimitiveProgram *pProgram = NULL; - if(IsTexturedState(pCommand->m_State)) - { - pProgram = m_pPrimitive3DProgramTextured; - } - else - pProgram = m_pPrimitive3DProgram; - - UseProgram(pProgram); - - SetState(pCommand->m_State, pProgram, true); - } - else - { - CCommandProcessorFragment_OpenGL::SetState(pCommand->m_State, true); - } - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - glVertexPointer(2, GL_FLOAT, sizeof(pCommand->m_pVertices[0]), pCommand->m_pVertices); - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(pCommand->m_pVertices[0]), (uint8_t *)pCommand->m_pVertices + (ptrdiff_t)(sizeof(vec2))); - glTexCoordPointer(3, GL_FLOAT, sizeof(pCommand->m_pVertices[0]), (uint8_t *)pCommand->m_pVertices + (ptrdiff_t)(sizeof(vec2) + sizeof(unsigned char) * 4)); - - switch(pCommand->m_PrimType) - { - case CCommandBuffer::PRIMTYPE_QUADS: - glDrawArrays(GL_QUADS, 0, pCommand->m_PrimCount * 4); - break; - case CCommandBuffer::PRIMTYPE_TRIANGLES: - glDrawArrays(GL_TRIANGLES, 0, pCommand->m_PrimCount * 3); - break; - default: - dbg_msg("render", "unknown primtype %d\n", pCommand->m_PrimType); - }; - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - if(m_HasShaders) - { - glUseProgram(0); - } -} - -void CCommandProcessorFragment_OpenGL2::Cmd_CreateBufferObject(const CCommandBuffer::SCommand_CreateBufferObject *pCommand) -{ - void *pUploadData = pCommand->m_pUploadData; - int Index = pCommand->m_BufferIndex; - //create necessary space - if((size_t)Index >= m_BufferObjectIndices.size()) - { - for(int i = m_BufferObjectIndices.size(); i < Index + 1; ++i) - { - m_BufferObjectIndices.push_back(SBufferObject(0)); - } - } - - GLuint VertBufferID = 0; - - if(m_HasShaders) - { - glGenBuffers(1, &VertBufferID); - glBindBuffer(GL_COPY_WRITE_BUFFER, VertBufferID); - glBufferData(GL_COPY_WRITE_BUFFER, (GLsizeiptr)(pCommand->m_DataSize), pUploadData, GL_STATIC_DRAW); - glBindBuffer(GL_COPY_WRITE_BUFFER, 0); - } - - SBufferObject &BufferObject = m_BufferObjectIndices[Index]; - BufferObject.m_BufferObjectID = VertBufferID; - BufferObject.m_DataSize = pCommand->m_DataSize; - BufferObject.m_pData = malloc(pCommand->m_DataSize); - if(pUploadData) - mem_copy(BufferObject.m_pData, pUploadData, pCommand->m_DataSize); - - if(pCommand->m_DeletePointer) - free(pUploadData); -} - -void CCommandProcessorFragment_OpenGL2::Cmd_RecreateBufferObject(const CCommandBuffer::SCommand_RecreateBufferObject *pCommand) -{ - void *pUploadData = pCommand->m_pUploadData; - int Index = pCommand->m_BufferIndex; - SBufferObject &BufferObject = m_BufferObjectIndices[Index]; - - if(m_HasShaders) - { - glBindBuffer(GL_COPY_WRITE_BUFFER, BufferObject.m_BufferObjectID); - glBufferData(GL_COPY_WRITE_BUFFER, (GLsizeiptr)(pCommand->m_DataSize), pUploadData, GL_STATIC_DRAW); - glBindBuffer(GL_COPY_WRITE_BUFFER, 0); - } - - BufferObject.m_DataSize = pCommand->m_DataSize; - if(BufferObject.m_pData) - free(BufferObject.m_pData); - BufferObject.m_pData = malloc(pCommand->m_DataSize); - if(pUploadData) - mem_copy(BufferObject.m_pData, pUploadData, pCommand->m_DataSize); - - if(pCommand->m_DeletePointer) - free(pUploadData); -} - -void CCommandProcessorFragment_OpenGL2::Cmd_UpdateBufferObject(const CCommandBuffer::SCommand_UpdateBufferObject *pCommand) -{ - void *pUploadData = pCommand->m_pUploadData; - int Index = pCommand->m_BufferIndex; - SBufferObject &BufferObject = m_BufferObjectIndices[Index]; - - if(m_HasShaders) - { - glBindBuffer(GL_COPY_WRITE_BUFFER, BufferObject.m_BufferObjectID); - glBufferSubData(GL_COPY_WRITE_BUFFER, (GLintptr)(pCommand->m_pOffset), (GLsizeiptr)(pCommand->m_DataSize), pUploadData); - glBindBuffer(GL_COPY_WRITE_BUFFER, 0); - } - - if(pUploadData) - mem_copy(((uint8_t *)BufferObject.m_pData) + (ptrdiff_t)pCommand->m_pOffset, pUploadData, pCommand->m_DataSize); - - if(pCommand->m_DeletePointer) - free(pUploadData); -} - -void CCommandProcessorFragment_OpenGL2::Cmd_CopyBufferObject(const CCommandBuffer::SCommand_CopyBufferObject *pCommand) -{ - int WriteIndex = pCommand->m_WriteBufferIndex; - int ReadIndex = pCommand->m_ReadBufferIndex; - - SBufferObject &ReadBufferObject = m_BufferObjectIndices[ReadIndex]; - SBufferObject &WriteBufferObject = m_BufferObjectIndices[WriteIndex]; - - mem_copy(((uint8_t *)WriteBufferObject.m_pData) + (ptrdiff_t)pCommand->m_pWriteOffset, ((uint8_t *)ReadBufferObject.m_pData) + (ptrdiff_t)pCommand->m_pReadOffset, pCommand->m_CopySize); - - if(m_HasShaders) - { - glBindBuffer(GL_COPY_WRITE_BUFFER, WriteBufferObject.m_BufferObjectID); - glBufferSubData(GL_COPY_WRITE_BUFFER, (GLintptr)(pCommand->m_pWriteOffset), (GLsizeiptr)(pCommand->m_CopySize), ((uint8_t *)WriteBufferObject.m_pData) + (ptrdiff_t)pCommand->m_pWriteOffset); - glBindBuffer(GL_COPY_WRITE_BUFFER, 0); - } -} - -void CCommandProcessorFragment_OpenGL2::Cmd_DeleteBufferObject(const CCommandBuffer::SCommand_DeleteBufferObject *pCommand) -{ - int Index = pCommand->m_BufferIndex; - SBufferObject &BufferObject = m_BufferObjectIndices[Index]; - - if(m_HasShaders) - { - glDeleteBuffers(1, &BufferObject.m_BufferObjectID); - } - - if(BufferObject.m_pData) - { - free(BufferObject.m_pData); - BufferObject.m_pData = NULL; - } -} - -void CCommandProcessorFragment_OpenGL2::Cmd_CreateBufferContainer(const CCommandBuffer::SCommand_CreateBufferContainer *pCommand) -{ - int Index = pCommand->m_BufferContainerIndex; - //create necessary space - if((size_t)Index >= m_BufferContainers.size()) - { - for(int i = m_BufferContainers.size(); i < Index + 1; ++i) - { - SBufferContainer Container; - Container.m_ContainerInfo.m_Stride = 0; - m_BufferContainers.push_back(Container); - } - } - - SBufferContainer &BufferContainer = m_BufferContainers[Index]; - - for(int i = 0; i < pCommand->m_AttrCount; ++i) - { - SBufferContainerInfo::SAttribute &Attr = pCommand->m_Attributes[i]; - BufferContainer.m_ContainerInfo.m_Attributes.push_back(Attr); - } - - BufferContainer.m_ContainerInfo.m_Stride = pCommand->m_Stride; -} - -void CCommandProcessorFragment_OpenGL2::Cmd_UpdateBufferContainer(const CCommandBuffer::SCommand_UpdateBufferContainer *pCommand) -{ - SBufferContainer &BufferContainer = m_BufferContainers[pCommand->m_BufferContainerIndex]; - - BufferContainer.m_ContainerInfo.m_Attributes.clear(); - - for(int i = 0; i < pCommand->m_AttrCount; ++i) - { - SBufferContainerInfo::SAttribute &Attr = pCommand->m_Attributes[i]; - BufferContainer.m_ContainerInfo.m_Attributes.push_back(Attr); - } - - BufferContainer.m_ContainerInfo.m_Stride = pCommand->m_Stride; -} - -void CCommandProcessorFragment_OpenGL2::Cmd_DeleteBufferContainer(const CCommandBuffer::SCommand_DeleteBufferContainer *pCommand) -{ - SBufferContainer &BufferContainer = m_BufferContainers[pCommand->m_BufferContainerIndex]; - - if(pCommand->m_DestroyAllBO) - { - for(size_t i = 0; i < BufferContainer.m_ContainerInfo.m_Attributes.size(); ++i) - { - int VertBufferID = BufferContainer.m_ContainerInfo.m_Attributes[i].m_VertBufferBindingIndex; - if(VertBufferID != -1) - { - for(auto &Attribute : BufferContainer.m_ContainerInfo.m_Attributes) - { - // set all equal ids to zero to not double delete - if(VertBufferID == Attribute.m_VertBufferBindingIndex) - { - Attribute.m_VertBufferBindingIndex = -1; - } - } - - if(m_HasShaders) - { - glDeleteBuffers(1, &m_BufferObjectIndices[VertBufferID].m_BufferObjectID); - } - - if(m_BufferObjectIndices[VertBufferID].m_pData) - { - free(m_BufferObjectIndices[VertBufferID].m_pData); - m_BufferObjectIndices[VertBufferID].m_pData = NULL; - } - } - } - } - - BufferContainer.m_ContainerInfo.m_Attributes.clear(); -} - -void CCommandProcessorFragment_OpenGL2::Cmd_IndicesRequiredNumNotify(const CCommandBuffer::SCommand_IndicesRequiredNumNotify *pCommand) -{ -} - -void CCommandProcessorFragment_OpenGL2::RenderBorderTileEmulation(SBufferContainer &BufferContainer, const CCommandBuffer::SState &State, const float *pColor, const char *pBuffOffset, unsigned int DrawNum, const float *pOffset, const float *pDir, int JumpIndex) -{ - if(m_HasShaders) - { - CGLSLPrimitiveProgram *pProgram = NULL; - if(IsTexturedState(State)) - { - pProgram = m_pPrimitive3DProgramTextured; - } - else - pProgram = m_pPrimitive3DProgram; - - UseProgram(pProgram); - - SetState(State, pProgram, true); - } - else - { - CCommandProcessorFragment_OpenGL::SetState(State, true); - } - - bool IsTextured = BufferContainer.m_ContainerInfo.m_Attributes.size() == 2; - - SBufferObject &BufferObject = m_BufferObjectIndices[(size_t)BufferContainer.m_ContainerInfo.m_Attributes[0].m_VertBufferBindingIndex]; - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - if(IsTextured) - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - glVertexPointer(2, GL_FLOAT, sizeof(m_aStreamVertices[0]), m_aStreamVertices); - glColorPointer(4, GL_FLOAT, sizeof(m_aStreamVertices[0]), (uint8_t *)m_aStreamVertices + (ptrdiff_t)(sizeof(vec2))); - if(IsTextured) - glTexCoordPointer(3, GL_FLOAT, sizeof(m_aStreamVertices[0]), (uint8_t *)m_aStreamVertices + (ptrdiff_t)(sizeof(vec2) + sizeof(vec4))); - - size_t VertexCount = 0; - for(size_t i = 0; i < DrawNum; ++i) - { - GLint RealOffset = (GLint)((((size_t)(uintptr_t)(pBuffOffset)) / (6 * sizeof(unsigned int))) * 4); - size_t SingleVertSize = (sizeof(vec2) + (IsTextured ? sizeof(vec3) : 0)); - size_t CurBufferOffset = (RealOffset)*SingleVertSize; - - for(size_t n = 0; n < 4; ++n) - { - int XCount = i - (int(i / JumpIndex) * JumpIndex); - int YCount = (int(i / JumpIndex)); - - ptrdiff_t VertOffset = (ptrdiff_t)(CurBufferOffset + (n * SingleVertSize)); - vec2 *pPos = (vec2 *)((uint8_t *)BufferObject.m_pData + VertOffset); - - GL_SVertexTex3D &Vertex = m_aStreamVertices[VertexCount++]; - mem_copy(&Vertex.m_Pos, pPos, sizeof(vec2)); - mem_copy(&Vertex.m_Color, pColor, sizeof(vec4)); - if(IsTextured) - { - vec3 *pTex = (vec3 *)((uint8_t *)BufferObject.m_pData + VertOffset + (ptrdiff_t)sizeof(vec2)); - mem_copy(&Vertex.m_Tex, pTex, sizeof(vec3)); - } - - Vertex.m_Pos.x += pOffset[0] + pDir[0] * XCount; - Vertex.m_Pos.y += pOffset[1] + pDir[1] * YCount; - - if(VertexCount >= sizeof(m_aStreamVertices) / sizeof(m_aStreamVertices[0])) - { - glDrawArrays(GL_QUADS, 0, VertexCount); - VertexCount = 0; - } - } - } - if(VertexCount > 0) - glDrawArrays(GL_QUADS, 0, VertexCount); - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - if(IsTextured) - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - if(m_HasShaders) - { - glUseProgram(0); - } -} - -void CCommandProcessorFragment_OpenGL2::RenderBorderTileLineEmulation(SBufferContainer &BufferContainer, const CCommandBuffer::SState &State, const float *pColor, const char *pBuffOffset, unsigned int IndexDrawNum, unsigned int DrawNum, const float *pOffset, const float *pDir) -{ - if(m_HasShaders) - { - CGLSLPrimitiveProgram *pProgram = NULL; - if(IsTexturedState(State)) - { - pProgram = m_pPrimitive3DProgramTextured; - } - else - pProgram = m_pPrimitive3DProgram; - - UseProgram(pProgram); - - SetState(State, pProgram, true); - } - else - { - CCommandProcessorFragment_OpenGL::SetState(State, true); - } - - bool IsTextured = BufferContainer.m_ContainerInfo.m_Attributes.size() == 2; - - SBufferObject &BufferObject = m_BufferObjectIndices[(size_t)BufferContainer.m_ContainerInfo.m_Attributes[0].m_VertBufferBindingIndex]; - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - if(IsTextured) - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - - glVertexPointer(2, GL_FLOAT, sizeof(m_aStreamVertices[0]), m_aStreamVertices); - glColorPointer(4, GL_FLOAT, sizeof(m_aStreamVertices[0]), (uint8_t *)m_aStreamVertices + (ptrdiff_t)(sizeof(vec2))); - if(IsTextured) - glTexCoordPointer(3, GL_FLOAT, sizeof(m_aStreamVertices[0]), (uint8_t *)m_aStreamVertices + (ptrdiff_t)(sizeof(vec2) + sizeof(vec4))); - - size_t VertexCount = 0; - for(size_t i = 0; i < DrawNum; ++i) - { - GLint RealOffset = (GLint)((((size_t)(uintptr_t)(pBuffOffset)) / (6 * sizeof(unsigned int))) * 4); - size_t SingleVertSize = (sizeof(vec2) + (IsTextured ? sizeof(vec3) : 0)); - size_t CurBufferOffset = (RealOffset)*SingleVertSize; - size_t VerticesPerLine = (size_t)IndexDrawNum / 6; - - for(size_t n = 0; n < 4 * (size_t)VerticesPerLine; ++n) - { - ptrdiff_t VertOffset = (ptrdiff_t)(CurBufferOffset + (n * SingleVertSize)); - vec2 *pPos = (vec2 *)((uint8_t *)BufferObject.m_pData + VertOffset); - - GL_SVertexTex3D &Vertex = m_aStreamVertices[VertexCount++]; - mem_copy(&Vertex.m_Pos, pPos, sizeof(vec2)); - mem_copy(&Vertex.m_Color, pColor, sizeof(vec4)); - if(IsTextured) - { - vec3 *pTex = (vec3 *)((uint8_t *)BufferObject.m_pData + VertOffset + (ptrdiff_t)sizeof(vec2)); - mem_copy(&Vertex.m_Tex, pTex, sizeof(vec3)); - } - - Vertex.m_Pos.x += pOffset[0] + pDir[0] * i; - Vertex.m_Pos.y += pOffset[1] + pDir[1] * i; - - if(VertexCount >= sizeof(m_aStreamVertices) / sizeof(m_aStreamVertices[0])) - { - glDrawArrays(GL_QUADS, 0, VertexCount); - VertexCount = 0; - } - } - } - if(VertexCount > 0) - glDrawArrays(GL_QUADS, 0, VertexCount); - - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - if(IsTextured) - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - if(m_HasShaders) - { - glUseProgram(0); - } -} - -void CCommandProcessorFragment_OpenGL2::Cmd_RenderBorderTile(const CCommandBuffer::SCommand_RenderBorderTile *pCommand) -{ - int Index = pCommand->m_BufferContainerIndex; - //if space not there return - if((size_t)Index >= m_BufferContainers.size()) - return; - - SBufferContainer &BufferContainer = m_BufferContainers[Index]; - - RenderBorderTileEmulation(BufferContainer, pCommand->m_State, (float *)&pCommand->m_Color, pCommand->m_pIndicesOffset, pCommand->m_DrawNum, pCommand->m_Offset, pCommand->m_Dir, pCommand->m_JumpIndex); -} - -void CCommandProcessorFragment_OpenGL2::Cmd_RenderBorderTileLine(const CCommandBuffer::SCommand_RenderBorderTileLine *pCommand) -{ - int Index = pCommand->m_BufferContainerIndex; - //if space not there return - if((size_t)Index >= m_BufferContainers.size()) - return; - - SBufferContainer &BufferContainer = m_BufferContainers[Index]; - - RenderBorderTileLineEmulation(BufferContainer, pCommand->m_State, (float *)&pCommand->m_Color, pCommand->m_pIndicesOffset, pCommand->m_IndexDrawNum, pCommand->m_DrawNum, pCommand->m_Offset, pCommand->m_Dir); -} - -void CCommandProcessorFragment_OpenGL2::Cmd_RenderTileLayer(const CCommandBuffer::SCommand_RenderTileLayer *pCommand) -{ - int Index = pCommand->m_BufferContainerIndex; - //if space not there return - if((size_t)Index >= m_BufferContainers.size()) - return; - - SBufferContainer &BufferContainer = m_BufferContainers[Index]; - - if(pCommand->m_IndicesDrawNum == 0) - { - return; //nothing to draw - } - - if(m_HasShaders) - { - CGLSLTileProgram *pProgram = NULL; - if(IsTexturedState(pCommand->m_State)) - { - pProgram = m_pTileProgramTextured; - } - else - pProgram = m_pTileProgram; - - UseProgram(pProgram); - - SetState(pCommand->m_State, pProgram, true); - pProgram->SetUniformVec4(pProgram->m_LocColor, 1, (float *)&pCommand->m_Color); - } - else - { - CCommandProcessorFragment_OpenGL::SetState(pCommand->m_State, true); - } - - bool IsTextured = BufferContainer.m_ContainerInfo.m_Attributes.size() == 2; - - SBufferObject &BufferObject = m_BufferObjectIndices[(size_t)BufferContainer.m_ContainerInfo.m_Attributes[0].m_VertBufferBindingIndex]; - if(m_HasShaders) - glBindBuffer(GL_ARRAY_BUFFER, BufferObject.m_BufferObjectID); - - if(!m_HasShaders) - { - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - if(IsTextured) - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - } - - if(m_HasShaders) - { - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, false, BufferContainer.m_ContainerInfo.m_Stride, BufferContainer.m_ContainerInfo.m_Attributes[0].m_pOffset); - if(IsTextured) - { - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, false, BufferContainer.m_ContainerInfo.m_Stride, BufferContainer.m_ContainerInfo.m_Attributes[1].m_pOffset); - } - - for(int i = 0; i < pCommand->m_IndicesDrawNum; ++i) - { - size_t RealDrawCount = (pCommand->m_pDrawCount[i] / 6) * 4; - GLint RealOffset = (GLint)((((size_t)(uintptr_t)(pCommand->m_pIndicesOffsets[i])) / (6 * sizeof(unsigned int))) * 4); - glDrawArrays(GL_QUADS, RealOffset, RealDrawCount); - } - } - else - { - glVertexPointer(2, GL_FLOAT, sizeof(m_aStreamVertices[0]), m_aStreamVertices); - glColorPointer(4, GL_FLOAT, sizeof(m_aStreamVertices[0]), (uint8_t *)m_aStreamVertices + (ptrdiff_t)(sizeof(vec2))); - if(IsTextured) - glTexCoordPointer(3, GL_FLOAT, sizeof(m_aStreamVertices[0]), (uint8_t *)m_aStreamVertices + (ptrdiff_t)(sizeof(vec2) + sizeof(vec4))); - - size_t VertexCount = 0; - for(int i = 0; i < pCommand->m_IndicesDrawNum; ++i) - { - size_t RealDrawCount = (pCommand->m_pDrawCount[i] / 6) * 4; - GLint RealOffset = (GLint)((((size_t)(uintptr_t)(pCommand->m_pIndicesOffsets[i])) / (6 * sizeof(unsigned int))) * 4); - size_t SingleVertSize = (sizeof(vec2) + (IsTextured ? sizeof(vec3) : 0)); - size_t CurBufferOffset = RealOffset * SingleVertSize; - - for(size_t n = 0; n < RealDrawCount; ++n) - { - ptrdiff_t VertOffset = (ptrdiff_t)(CurBufferOffset + (n * SingleVertSize)); - vec2 *pPos = (vec2 *)((uint8_t *)BufferObject.m_pData + VertOffset); - GL_SVertexTex3D &Vertex = m_aStreamVertices[VertexCount++]; - mem_copy(&Vertex.m_Pos, pPos, sizeof(vec2)); - mem_copy(&Vertex.m_Color, &pCommand->m_Color, sizeof(vec4)); - if(IsTextured) - { - vec3 *pTex = (vec3 *)((uint8_t *)BufferObject.m_pData + VertOffset + (ptrdiff_t)sizeof(vec2)); - mem_copy(&Vertex.m_Tex, pTex, sizeof(vec3)); - } - - if(VertexCount >= sizeof(m_aStreamVertices) / sizeof(m_aStreamVertices[0])) - { - glDrawArrays(GL_QUADS, 0, VertexCount); - VertexCount = 0; - } - } - } - if(VertexCount > 0) - glDrawArrays(GL_QUADS, 0, VertexCount); - } - - if(!m_HasShaders) - { - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - if(IsTextured) - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - } - else - { - glDisableVertexAttribArray(0); - if(IsTextured) - glDisableVertexAttribArray(1); - glBindBuffer(GL_ARRAY_BUFFER, 0); - glUseProgram(0); - } -} - -// ------------ CCommandProcessorFragment_OpenGL3_3 -int CCommandProcessorFragment_OpenGL3_3::TexFormatToNewOpenGLFormat(int TexFormat) -{ - if(TexFormat == CCommandBuffer::TEXFORMAT_RGB) - return GL_RGB; - if(TexFormat == CCommandBuffer::TEXFORMAT_ALPHA) - return GL_RED; - if(TexFormat == CCommandBuffer::TEXFORMAT_RGBA) - return GL_RGBA; - return GL_RGBA; -} - -void CCommandProcessorFragment_OpenGL3_3::UseProgram(CGLSLTWProgram *pProgram) -{ - if(m_LastProgramID != pProgram->GetProgramID()) - { - pProgram->UseProgram(); - m_LastProgramID = pProgram->GetProgramID(); - } -} - -void CCommandProcessorFragment_OpenGL3_3::InitPrimExProgram(CGLSLPrimitiveExProgram *pProgram, CGLSLCompiler *pCompiler, IStorage *pStorage, bool Textured, bool Rotationless) -{ - CGLSL PrimitiveVertexShader; - CGLSL PrimitiveFragmentShader; - if(Textured) - pCompiler->AddDefine("TW_TEXTURED", ""); - if(Rotationless) - pCompiler->AddDefine("TW_ROTATIONLESS", ""); - PrimitiveVertexShader.LoadShader(pCompiler, pStorage, "shader/primex.vert", GL_VERTEX_SHADER); - PrimitiveFragmentShader.LoadShader(pCompiler, pStorage, "shader/primex.frag", GL_FRAGMENT_SHADER); - if(Textured || Rotationless) - pCompiler->ClearDefines(); - - pProgram->CreateProgram(); - pProgram->AddShader(&PrimitiveVertexShader); - pProgram->AddShader(&PrimitiveFragmentShader); - pProgram->LinkProgram(); - - UseProgram(pProgram); - - pProgram->m_LocPos = pProgram->GetUniformLoc("gPos"); - pProgram->m_LocTextureSampler = pProgram->GetUniformLoc("gTextureSampler"); - pProgram->m_LocRotation = pProgram->GetUniformLoc("gRotation"); - pProgram->m_LocCenter = pProgram->GetUniformLoc("gCenter"); - pProgram->m_LocVertciesColor = pProgram->GetUniformLoc("gVerticesColor"); - - pProgram->SetUniform(pProgram->m_LocRotation, 0.0f); - float Center[2] = {0.f, 0.f}; - pProgram->SetUniformVec2(pProgram->m_LocCenter, 1, Center); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_Init(const SCommand_Init *pCommand) -{ - m_OpenGLTextureLodBIAS = g_Config.m_GfxOpenGLTextureLODBIAS; - - m_UseMultipleTextureUnits = g_Config.m_GfxEnableTextureUnitOptimization; - if(!m_UseMultipleTextureUnits) - { - glActiveTexture(GL_TEXTURE0); - } - - m_Has2DArrayTextures = true; - m_Has2DArrayTexturesAsExtension = false; - m_2DArrayTarget = GL_TEXTURE_2D_ARRAY; - m_Has3DTextures = false; - m_HasMipMaps = true; - m_HasNPOTTextures = true; - m_HasShaders = true; - - m_pTextureMemoryUsage = pCommand->m_pTextureMemoryUsage; - m_pTextureMemoryUsage->store(0, std::memory_order_relaxed); - m_LastBlendMode = CCommandBuffer::BLEND_ALPHA; - m_LastClipEnable = false; - m_pPrimitiveProgram = new CGLSLPrimitiveProgram; - m_pPrimitiveProgramTextured = new CGLSLPrimitiveProgram; - m_pTileProgram = new CGLSLTileProgram; - m_pTileProgramTextured = new CGLSLTileProgram; - m_pPrimitive3DProgram = new CGLSLPrimitiveProgram; - m_pPrimitive3DProgramTextured = new CGLSLPrimitiveProgram; - m_pBorderTileProgram = new CGLSLTileProgram; - m_pBorderTileProgramTextured = new CGLSLTileProgram; - m_pBorderTileLineProgram = new CGLSLTileProgram; - m_pBorderTileLineProgramTextured = new CGLSLTileProgram; - m_pQuadProgram = new CGLSLQuadProgram; - m_pQuadProgramTextured = new CGLSLQuadProgram; - m_pTextProgram = new CGLSLTextProgram; - m_pPrimitiveExProgram = new CGLSLPrimitiveExProgram; - m_pPrimitiveExProgramTextured = new CGLSLPrimitiveExProgram; - m_pPrimitiveExProgramRotationless = new CGLSLPrimitiveExProgram; - m_pPrimitiveExProgramTexturedRotationless = new CGLSLPrimitiveExProgram; - m_pSpriteProgramMultiple = new CGLSLSpriteMultipleProgram; - m_LastProgramID = 0; - - CGLSLCompiler ShaderCompiler(g_Config.m_GfxOpenGLMajor, g_Config.m_GfxOpenGLMinor, g_Config.m_GfxOpenGLPatch); - - GLint CapVal; - glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &CapVal); - ; - m_MaxQuadsAtOnce = minimum(((CapVal - 20) / (3 * 4)), m_MaxQuadsPossible); - - { - CGLSL PrimitiveVertexShader; - CGLSL PrimitiveFragmentShader; - PrimitiveVertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/prim.vert", GL_VERTEX_SHADER); - PrimitiveFragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/prim.frag", GL_FRAGMENT_SHADER); - - m_pPrimitiveProgram->CreateProgram(); - m_pPrimitiveProgram->AddShader(&PrimitiveVertexShader); - m_pPrimitiveProgram->AddShader(&PrimitiveFragmentShader); - m_pPrimitiveProgram->LinkProgram(); - - UseProgram(m_pPrimitiveProgram); - - m_pPrimitiveProgram->m_LocPos = m_pPrimitiveProgram->GetUniformLoc("gPos"); - m_pPrimitiveProgram->m_LocTextureSampler = m_pPrimitiveProgram->GetUniformLoc("gTextureSampler"); - } - { - CGLSL PrimitiveVertexShader; - CGLSL PrimitiveFragmentShader; - ShaderCompiler.AddDefine("TW_TEXTURED", ""); - PrimitiveVertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/prim.vert", GL_VERTEX_SHADER); - PrimitiveFragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/prim.frag", GL_FRAGMENT_SHADER); - ShaderCompiler.ClearDefines(); - - m_pPrimitiveProgramTextured->CreateProgram(); - m_pPrimitiveProgramTextured->AddShader(&PrimitiveVertexShader); - m_pPrimitiveProgramTextured->AddShader(&PrimitiveFragmentShader); - m_pPrimitiveProgramTextured->LinkProgram(); - - UseProgram(m_pPrimitiveProgramTextured); - - m_pPrimitiveProgramTextured->m_LocPos = m_pPrimitiveProgramTextured->GetUniformLoc("gPos"); - m_pPrimitiveProgramTextured->m_LocTextureSampler = m_pPrimitiveProgramTextured->GetUniformLoc("gTextureSampler"); - } - - { - CGLSL PrimitiveVertexShader; - CGLSL PrimitiveFragmentShader; - ShaderCompiler.AddDefine("TW_MODERN_GL", ""); - PrimitiveVertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/pipeline.vert", GL_VERTEX_SHADER); - PrimitiveFragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/pipeline.frag", GL_FRAGMENT_SHADER); - ShaderCompiler.ClearDefines(); - - m_pPrimitive3DProgram->CreateProgram(); - m_pPrimitive3DProgram->AddShader(&PrimitiveVertexShader); - m_pPrimitive3DProgram->AddShader(&PrimitiveFragmentShader); - m_pPrimitive3DProgram->LinkProgram(); - - UseProgram(m_pPrimitive3DProgram); - - m_pPrimitive3DProgram->m_LocPos = m_pPrimitive3DProgram->GetUniformLoc("gPos"); - } - { - CGLSL PrimitiveVertexShader; - CGLSL PrimitiveFragmentShader; - ShaderCompiler.AddDefine("TW_MODERN_GL", ""); - ShaderCompiler.AddDefine("TW_TEXTURED", ""); - if(!pCommand->m_pCapabilities->m_2DArrayTextures) - ShaderCompiler.AddDefine("TW_3D_TEXTURED", ""); - PrimitiveVertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/pipeline.vert", GL_VERTEX_SHADER); - PrimitiveFragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/pipeline.frag", GL_FRAGMENT_SHADER); - ShaderCompiler.ClearDefines(); - - m_pPrimitive3DProgramTextured->CreateProgram(); - m_pPrimitive3DProgramTextured->AddShader(&PrimitiveVertexShader); - m_pPrimitive3DProgramTextured->AddShader(&PrimitiveFragmentShader); - m_pPrimitive3DProgramTextured->LinkProgram(); - - UseProgram(m_pPrimitive3DProgramTextured); - - m_pPrimitive3DProgramTextured->m_LocPos = m_pPrimitive3DProgramTextured->GetUniformLoc("gPos"); - m_pPrimitive3DProgramTextured->m_LocTextureSampler = m_pPrimitive3DProgramTextured->GetUniformLoc("gTextureSampler"); - } - - { - CGLSL VertexShader; - CGLSL FragmentShader; - VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.vert", GL_VERTEX_SHADER); - FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.frag", GL_FRAGMENT_SHADER); - - m_pTileProgram->CreateProgram(); - m_pTileProgram->AddShader(&VertexShader); - m_pTileProgram->AddShader(&FragmentShader); - m_pTileProgram->LinkProgram(); - - UseProgram(m_pTileProgram); - - m_pTileProgram->m_LocPos = m_pTileProgram->GetUniformLoc("gPos"); - m_pTileProgram->m_LocColor = m_pTileProgram->GetUniformLoc("gVertColor"); - } - { - CGLSL VertexShader; - CGLSL FragmentShader; - ShaderCompiler.AddDefine("TW_TILE_TEXTURED", ""); - VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.vert", GL_VERTEX_SHADER); - FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.frag", GL_FRAGMENT_SHADER); - ShaderCompiler.ClearDefines(); - - m_pTileProgramTextured->CreateProgram(); - m_pTileProgramTextured->AddShader(&VertexShader); - m_pTileProgramTextured->AddShader(&FragmentShader); - m_pTileProgramTextured->LinkProgram(); - - UseProgram(m_pTileProgramTextured); - - m_pTileProgramTextured->m_LocPos = m_pTileProgramTextured->GetUniformLoc("gPos"); - m_pTileProgramTextured->m_LocTextureSampler = m_pTileProgramTextured->GetUniformLoc("gTextureSampler"); - m_pTileProgramTextured->m_LocColor = m_pTileProgramTextured->GetUniformLoc("gVertColor"); - } - { - CGLSL VertexShader; - CGLSL FragmentShader; - ShaderCompiler.AddDefine("TW_TILE_BORDER", ""); - VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.vert", GL_VERTEX_SHADER); - FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.frag", GL_FRAGMENT_SHADER); - ShaderCompiler.ClearDefines(); - - m_pBorderTileProgram->CreateProgram(); - m_pBorderTileProgram->AddShader(&VertexShader); - m_pBorderTileProgram->AddShader(&FragmentShader); - m_pBorderTileProgram->LinkProgram(); - - UseProgram(m_pBorderTileProgram); - - m_pBorderTileProgram->m_LocPos = m_pBorderTileProgram->GetUniformLoc("gPos"); - m_pBorderTileProgram->m_LocColor = m_pBorderTileProgram->GetUniformLoc("gVertColor"); - m_pBorderTileProgram->m_LocOffset = m_pBorderTileProgram->GetUniformLoc("gOffset"); - m_pBorderTileProgram->m_LocDir = m_pBorderTileProgram->GetUniformLoc("gDir"); - m_pBorderTileProgram->m_LocJumpIndex = m_pBorderTileProgram->GetUniformLoc("gJumpIndex"); - } - { - CGLSL VertexShader; - CGLSL FragmentShader; - ShaderCompiler.AddDefine("TW_TILE_BORDER", ""); - ShaderCompiler.AddDefine("TW_TILE_TEXTURED", ""); - VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.vert", GL_VERTEX_SHADER); - FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.frag", GL_FRAGMENT_SHADER); - ShaderCompiler.ClearDefines(); - - m_pBorderTileProgramTextured->CreateProgram(); - m_pBorderTileProgramTextured->AddShader(&VertexShader); - m_pBorderTileProgramTextured->AddShader(&FragmentShader); - m_pBorderTileProgramTextured->LinkProgram(); - - UseProgram(m_pBorderTileProgramTextured); - - m_pBorderTileProgramTextured->m_LocPos = m_pBorderTileProgramTextured->GetUniformLoc("gPos"); - m_pBorderTileProgramTextured->m_LocTextureSampler = m_pBorderTileProgramTextured->GetUniformLoc("gTextureSampler"); - m_pBorderTileProgramTextured->m_LocColor = m_pBorderTileProgramTextured->GetUniformLoc("gVertColor"); - m_pBorderTileProgramTextured->m_LocOffset = m_pBorderTileProgramTextured->GetUniformLoc("gOffset"); - m_pBorderTileProgramTextured->m_LocDir = m_pBorderTileProgramTextured->GetUniformLoc("gDir"); - m_pBorderTileProgramTextured->m_LocJumpIndex = m_pBorderTileProgramTextured->GetUniformLoc("gJumpIndex"); - } - { - CGLSL VertexShader; - CGLSL FragmentShader; - ShaderCompiler.AddDefine("TW_TILE_BORDER_LINE", ""); - VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.vert", GL_VERTEX_SHADER); - FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.frag", GL_FRAGMENT_SHADER); - ShaderCompiler.ClearDefines(); - - m_pBorderTileLineProgram->CreateProgram(); - m_pBorderTileLineProgram->AddShader(&VertexShader); - m_pBorderTileLineProgram->AddShader(&FragmentShader); - m_pBorderTileLineProgram->LinkProgram(); - - UseProgram(m_pBorderTileLineProgram); - - m_pBorderTileLineProgram->m_LocPos = m_pBorderTileLineProgram->GetUniformLoc("gPos"); - m_pBorderTileLineProgram->m_LocColor = m_pBorderTileLineProgram->GetUniformLoc("gVertColor"); - m_pBorderTileLineProgram->m_LocOffset = m_pBorderTileLineProgram->GetUniformLoc("gOffset"); - m_pBorderTileLineProgram->m_LocDir = m_pBorderTileLineProgram->GetUniformLoc("gDir"); - } - { - CGLSL VertexShader; - CGLSL FragmentShader; - ShaderCompiler.AddDefine("TW_TILE_BORDER_LINE", ""); - ShaderCompiler.AddDefine("TW_TILE_TEXTURED", ""); - VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.vert", GL_VERTEX_SHADER); - FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/tile.frag", GL_FRAGMENT_SHADER); - ShaderCompiler.ClearDefines(); - - m_pBorderTileLineProgramTextured->CreateProgram(); - m_pBorderTileLineProgramTextured->AddShader(&VertexShader); - m_pBorderTileLineProgramTextured->AddShader(&FragmentShader); - m_pBorderTileLineProgramTextured->LinkProgram(); - - UseProgram(m_pBorderTileLineProgramTextured); - - m_pBorderTileLineProgramTextured->m_LocPos = m_pBorderTileLineProgramTextured->GetUniformLoc("gPos"); - m_pBorderTileLineProgramTextured->m_LocTextureSampler = m_pBorderTileLineProgramTextured->GetUniformLoc("gTextureSampler"); - m_pBorderTileLineProgramTextured->m_LocColor = m_pBorderTileLineProgramTextured->GetUniformLoc("gVertColor"); - m_pBorderTileLineProgramTextured->m_LocOffset = m_pBorderTileLineProgramTextured->GetUniformLoc("gOffset"); - m_pBorderTileLineProgramTextured->m_LocDir = m_pBorderTileLineProgramTextured->GetUniformLoc("gDir"); - } - { - CGLSL VertexShader; - CGLSL FragmentShader; - ShaderCompiler.AddDefine("TW_MAX_QUADS", std::to_string(m_MaxQuadsAtOnce).c_str()); - VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/quad.vert", GL_VERTEX_SHADER); - FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/quad.frag", GL_FRAGMENT_SHADER); - ShaderCompiler.ClearDefines(); - - m_pQuadProgram->CreateProgram(); - m_pQuadProgram->AddShader(&VertexShader); - m_pQuadProgram->AddShader(&FragmentShader); - m_pQuadProgram->LinkProgram(); - - UseProgram(m_pQuadProgram); - - m_pQuadProgram->m_LocPos = m_pQuadProgram->GetUniformLoc("gPos"); - m_pQuadProgram->m_LocColors = m_pQuadProgram->GetUniformLoc("gVertColors"); - m_pQuadProgram->m_LocRotations = m_pQuadProgram->GetUniformLoc("gRotations"); - m_pQuadProgram->m_LocOffsets = m_pQuadProgram->GetUniformLoc("gOffsets"); - m_pQuadProgram->m_LocQuadOffset = m_pQuadProgram->GetUniformLoc("gQuadOffset"); - } - { - CGLSL VertexShader; - CGLSL FragmentShader; - ShaderCompiler.AddDefine("TW_QUAD_TEXTURED", ""); - ShaderCompiler.AddDefine("TW_MAX_QUADS", std::to_string(m_MaxQuadsAtOnce).c_str()); - VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/quad.vert", GL_VERTEX_SHADER); - FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/quad.frag", GL_FRAGMENT_SHADER); - ShaderCompiler.ClearDefines(); - - m_pQuadProgramTextured->CreateProgram(); - m_pQuadProgramTextured->AddShader(&VertexShader); - m_pQuadProgramTextured->AddShader(&FragmentShader); - m_pQuadProgramTextured->LinkProgram(); - - UseProgram(m_pQuadProgramTextured); - - m_pQuadProgramTextured->m_LocPos = m_pQuadProgramTextured->GetUniformLoc("gPos"); - m_pQuadProgramTextured->m_LocTextureSampler = m_pQuadProgramTextured->GetUniformLoc("gTextureSampler"); - m_pQuadProgramTextured->m_LocColors = m_pQuadProgramTextured->GetUniformLoc("gVertColors"); - m_pQuadProgramTextured->m_LocRotations = m_pQuadProgramTextured->GetUniformLoc("gRotations"); - m_pQuadProgramTextured->m_LocOffsets = m_pQuadProgramTextured->GetUniformLoc("gOffsets"); - m_pQuadProgramTextured->m_LocQuadOffset = m_pQuadProgramTextured->GetUniformLoc("gQuadOffset"); - } - { - CGLSL VertexShader; - CGLSL FragmentShader; - VertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/text.vert", GL_VERTEX_SHADER); - FragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/text.frag", GL_FRAGMENT_SHADER); - - m_pTextProgram->CreateProgram(); - m_pTextProgram->AddShader(&VertexShader); - m_pTextProgram->AddShader(&FragmentShader); - m_pTextProgram->LinkProgram(); - - UseProgram(m_pTextProgram); - - m_pTextProgram->m_LocPos = m_pTextProgram->GetUniformLoc("gPos"); - m_pTextProgram->m_LocTextureSampler = -1; - m_pTextProgram->m_LocTextSampler = m_pTextProgram->GetUniformLoc("gTextSampler"); - m_pTextProgram->m_LocTextOutlineSampler = m_pTextProgram->GetUniformLoc("gTextOutlineSampler"); - m_pTextProgram->m_LocColor = m_pTextProgram->GetUniformLoc("gVertColor"); - m_pTextProgram->m_LocOutlineColor = m_pTextProgram->GetUniformLoc("gVertOutlineColor"); - m_pTextProgram->m_LocTextureSize = m_pTextProgram->GetUniformLoc("gTextureSize"); - } - InitPrimExProgram(m_pPrimitiveExProgram, &ShaderCompiler, pCommand->m_pStorage, false, false); - InitPrimExProgram(m_pPrimitiveExProgramTextured, &ShaderCompiler, pCommand->m_pStorage, true, false); - InitPrimExProgram(m_pPrimitiveExProgramRotationless, &ShaderCompiler, pCommand->m_pStorage, false, true); - InitPrimExProgram(m_pPrimitiveExProgramTexturedRotationless, &ShaderCompiler, pCommand->m_pStorage, true, true); - { - CGLSL PrimitiveVertexShader; - CGLSL PrimitiveFragmentShader; - PrimitiveVertexShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/spritemulti.vert", GL_VERTEX_SHADER); - PrimitiveFragmentShader.LoadShader(&ShaderCompiler, pCommand->m_pStorage, "shader/spritemulti.frag", GL_FRAGMENT_SHADER); - - m_pSpriteProgramMultiple->CreateProgram(); - m_pSpriteProgramMultiple->AddShader(&PrimitiveVertexShader); - m_pSpriteProgramMultiple->AddShader(&PrimitiveFragmentShader); - m_pSpriteProgramMultiple->LinkProgram(); - - UseProgram(m_pSpriteProgramMultiple); - - m_pSpriteProgramMultiple->m_LocPos = m_pSpriteProgramMultiple->GetUniformLoc("gPos"); - m_pSpriteProgramMultiple->m_LocTextureSampler = m_pSpriteProgramMultiple->GetUniformLoc("gTextureSampler"); - m_pSpriteProgramMultiple->m_LocRSP = m_pSpriteProgramMultiple->GetUniformLoc("gRSP[0]"); - m_pSpriteProgramMultiple->m_LocCenter = m_pSpriteProgramMultiple->GetUniformLoc("gCenter"); - m_pSpriteProgramMultiple->m_LocVertciesColor = m_pSpriteProgramMultiple->GetUniformLoc("gVerticesColor"); - - float Center[2] = {0.f, 0.f}; - m_pSpriteProgramMultiple->SetUniformVec2(m_pSpriteProgramMultiple->m_LocCenter, 1, Center); - } - - m_LastStreamBuffer = 0; - - glGenBuffers(MAX_STREAM_BUFFER_COUNT, m_PrimitiveDrawBufferID); - glGenVertexArrays(MAX_STREAM_BUFFER_COUNT, m_PrimitiveDrawVertexID); - glGenBuffers(1, &m_PrimitiveDrawBufferIDTex3D); - glGenVertexArrays(1, &m_PrimitiveDrawVertexIDTex3D); - - m_UsePreinitializedVertexBuffer = g_Config.m_GfxUsePreinitBuffer; - - for(int i = 0; i < MAX_STREAM_BUFFER_COUNT; ++i) - { - glBindBuffer(GL_ARRAY_BUFFER, m_PrimitiveDrawBufferID[i]); - glBindVertexArray(m_PrimitiveDrawVertexID[i]); - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(CCommandBuffer::SVertex), 0); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(CCommandBuffer::SVertex), (void *)(sizeof(float) * 2)); - glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(CCommandBuffer::SVertex), (void *)(sizeof(float) * 4)); - - if(m_UsePreinitializedVertexBuffer) - glBufferData(GL_ARRAY_BUFFER, sizeof(CCommandBuffer::SVertex) * CCommandBuffer::MAX_VERTICES, NULL, GL_STREAM_DRAW); - - m_LastIndexBufferBound[i] = 0; - } - - glBindBuffer(GL_ARRAY_BUFFER, m_PrimitiveDrawBufferIDTex3D); - glBindVertexArray(m_PrimitiveDrawVertexIDTex3D); - glEnableVertexAttribArray(0); - glEnableVertexAttribArray(1); - glEnableVertexAttribArray(2); - - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(CCommandBuffer::SVertexTex3DStream), 0); - glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(CCommandBuffer::SVertexTex3DStream), (void *)(sizeof(float) * 2)); - glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(CCommandBuffer::SVertexTex3DStream), (void *)(sizeof(float) * 2 + sizeof(unsigned char) * 4)); - - if(m_UsePreinitializedVertexBuffer) - glBufferData(GL_ARRAY_BUFFER, sizeof(CCommandBuffer::SVertexTex3DStream) * CCommandBuffer::MAX_VERTICES, NULL, GL_STREAM_DRAW); - - //query the image max size only once - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_MaxTexSize); - - //query maximum of allowed textures - glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &m_MaxTextureUnits); - m_TextureSlotBoundToUnit.resize(m_MaxTextureUnits); - for(int i = 0; i < m_MaxTextureUnits; ++i) - { - m_TextureSlotBoundToUnit[i].m_TextureSlot = -1; - m_TextureSlotBoundToUnit[i].m_Is2DArray = false; - } - - glBindVertexArray(0); - glGenBuffers(1, &m_QuadDrawIndexBufferID); - glBindBuffer(GL_COPY_WRITE_BUFFER, m_QuadDrawIndexBufferID); - - unsigned int Indices[CCommandBuffer::MAX_VERTICES / 4 * 6]; - int Primq = 0; - for(int i = 0; i < CCommandBuffer::MAX_VERTICES / 4 * 6; i += 6) - { - Indices[i] = Primq; - Indices[i + 1] = Primq + 1; - Indices[i + 2] = Primq + 2; - Indices[i + 3] = Primq; - Indices[i + 4] = Primq + 2; - Indices[i + 5] = Primq + 3; - Primq += 4; - } - glBufferData(GL_COPY_WRITE_BUFFER, sizeof(unsigned int) * CCommandBuffer::MAX_VERTICES / 4 * 6, Indices, GL_STATIC_DRAW); - - m_CurrentIndicesInBuffer = CCommandBuffer::MAX_VERTICES / 4 * 6; - - m_Textures.resize(CCommandBuffer::MAX_TEXTURES); - - m_ClearColor.r = m_ClearColor.g = m_ClearColor.b = -1.f; - - // fix the alignment to allow even 1byte changes, e.g. for alpha components - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_Shutdown(const SCommand_Shutdown *pCommand) -{ - glUseProgram(0); - - m_pPrimitiveProgram->DeleteProgram(); - m_pPrimitiveProgramTextured->DeleteProgram(); - m_pBorderTileProgram->DeleteProgram(); - m_pBorderTileProgramTextured->DeleteProgram(); - m_pBorderTileLineProgram->DeleteProgram(); - m_pBorderTileLineProgramTextured->DeleteProgram(); - m_pQuadProgram->DeleteProgram(); - m_pQuadProgramTextured->DeleteProgram(); - m_pTileProgram->DeleteProgram(); - m_pTileProgramTextured->DeleteProgram(); - m_pPrimitive3DProgram->DeleteProgram(); - m_pPrimitive3DProgramTextured->DeleteProgram(); - m_pTextProgram->DeleteProgram(); - m_pPrimitiveExProgram->DeleteProgram(); - m_pPrimitiveExProgramTextured->DeleteProgram(); - m_pPrimitiveExProgramRotationless->DeleteProgram(); - m_pPrimitiveExProgramTexturedRotationless->DeleteProgram(); - m_pSpriteProgramMultiple->DeleteProgram(); - - //clean up everything - delete m_pPrimitiveProgram; - delete m_pPrimitiveProgramTextured; - delete m_pBorderTileProgram; - delete m_pBorderTileProgramTextured; - delete m_pBorderTileLineProgram; - delete m_pBorderTileLineProgramTextured; - delete m_pQuadProgram; - delete m_pQuadProgramTextured; - delete m_pTileProgram; - delete m_pTileProgramTextured; - delete m_pPrimitive3DProgram; - delete m_pPrimitive3DProgramTextured; - delete m_pTextProgram; - delete m_pPrimitiveExProgram; - delete m_pPrimitiveExProgramTextured; - delete m_pPrimitiveExProgramRotationless; - delete m_pPrimitiveExProgramTexturedRotationless; - delete m_pSpriteProgramMultiple; - - glBindVertexArray(0); - glDeleteBuffers(MAX_STREAM_BUFFER_COUNT, m_PrimitiveDrawBufferID); - glDeleteBuffers(1, &m_QuadDrawIndexBufferID); - glDeleteVertexArrays(MAX_STREAM_BUFFER_COUNT, m_PrimitiveDrawVertexID); - glDeleteBuffers(1, &m_PrimitiveDrawBufferIDTex3D); - glDeleteVertexArrays(1, &m_PrimitiveDrawVertexIDTex3D); - - for(int i = 0; i < (int)m_Textures.size(); ++i) - { - DestroyTexture(i); - } - - for(size_t i = 0; i < m_BufferContainers.size(); ++i) - { - DestroyBufferContainer(i); - } - - m_BufferContainers.clear(); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand) -{ - if(m_UseMultipleTextureUnits) - { - int Slot = pCommand->m_Slot % m_MaxTextureUnits; - //just tell, that we using this texture now - IsAndUpdateTextureSlotBound(Slot, pCommand->m_Slot); - glActiveTexture(GL_TEXTURE0 + Slot); - glBindSampler(Slot, m_Textures[pCommand->m_Slot].m_Sampler); - } - - glBindTexture(GL_TEXTURE_2D, m_Textures[pCommand->m_Slot].m_Tex); - - void *pTexData = pCommand->m_pData; - int Width = pCommand->m_Width; - int Height = pCommand->m_Height; - int X = pCommand->m_X; - int Y = pCommand->m_Y; - if(m_Textures[pCommand->m_Slot].m_RescaleCount > 0) - { - for(int i = 0; i < m_Textures[pCommand->m_Slot].m_RescaleCount; ++i) - { - Width >>= 1; - Height >>= 1; - - X /= 2; - Y /= 2; - } - - void *pTmpData = Resize(pCommand->m_Width, pCommand->m_Height, Width, Height, pCommand->m_Format, static_cast(pCommand->m_pData)); - free(pTexData); - pTexData = pTmpData; - } - - glTexSubImage2D(GL_TEXTURE_2D, 0, X, Y, Width, Height, - TexFormatToNewOpenGLFormat(pCommand->m_Format), GL_UNSIGNED_BYTE, pTexData); - free(pTexData); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand) -{ - int Slot = 0; - if(m_UseMultipleTextureUnits) - { - Slot = pCommand->m_Slot % m_MaxTextureUnits; - IsAndUpdateTextureSlotBound(Slot, pCommand->m_Slot); - glActiveTexture(GL_TEXTURE0 + Slot); - } - glBindTexture(GL_TEXTURE_2D, 0); - glBindSampler(Slot, 0); - m_TextureSlotBoundToUnit[Slot].m_TextureSlot = -1; - m_TextureSlotBoundToUnit[Slot].m_Is2DArray = false; - DestroyTexture(pCommand->m_Slot); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand) -{ - int Width = pCommand->m_Width; - int Height = pCommand->m_Height; - void *pTexData = pCommand->m_pData; - - if(pCommand->m_Slot >= (int)m_Textures.size()) - m_Textures.resize(m_Textures.size() * 2); - - // resample if needed - int RescaleCount = 0; - if(pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGBA || pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGB || pCommand->m_Format == CCommandBuffer::TEXFORMAT_ALPHA) - { - if(Width > m_MaxTexSize || Height > m_MaxTexSize) - { - do - { - Width >>= 1; - Height >>= 1; - ++RescaleCount; - } while(Width > m_MaxTexSize || Height > m_MaxTexSize); - - void *pTmpData = Resize(pCommand->m_Width, pCommand->m_Height, Width, Height, pCommand->m_Format, static_cast(pCommand->m_pData)); - free(pTexData); - pTexData = pTmpData; - } - else if(pCommand->m_Format != CCommandBuffer::TEXFORMAT_ALPHA && (Width > 16 && Height > 16 && (pCommand->m_Flags & CCommandBuffer::TEXFLAG_QUALITY) == 0)) - { - Width >>= 1; - Height >>= 1; - ++RescaleCount; - - void *pTmpData = Resize(pCommand->m_Width, pCommand->m_Height, Width, Height, pCommand->m_Format, static_cast(pCommand->m_pData)); - free(pTexData); - pTexData = pTmpData; - } - } - m_Textures[pCommand->m_Slot].m_Width = Width; - m_Textures[pCommand->m_Slot].m_Height = Height; - m_Textures[pCommand->m_Slot].m_RescaleCount = RescaleCount; - - int Oglformat = TexFormatToNewOpenGLFormat(pCommand->m_Format); - int StoreOglformat = TexFormatToNewOpenGLFormat(pCommand->m_StoreFormat); - - if(pCommand->m_Flags & CCommandBuffer::TEXFLAG_COMPRESSED) - { - switch(StoreOglformat) - { - case GL_RGB: StoreOglformat = GL_COMPRESSED_RGB; break; - // COMPRESSED_ALPHA is deprecated, so use different single channel format. - case GL_RED: StoreOglformat = GL_COMPRESSED_RED; break; - case GL_RGBA: StoreOglformat = GL_COMPRESSED_RGBA; break; - default: StoreOglformat = GL_COMPRESSED_RGBA; - } - } - int Slot = 0; - if(m_UseMultipleTextureUnits) - { - Slot = pCommand->m_Slot % m_MaxTextureUnits; - //just tell, that we using this texture now - IsAndUpdateTextureSlotBound(Slot, pCommand->m_Slot); - glActiveTexture(GL_TEXTURE0 + Slot); - m_TextureSlotBoundToUnit[Slot].m_TextureSlot = -1; - m_TextureSlotBoundToUnit[Slot].m_Is2DArray = false; - } - - if((pCommand->m_Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0) - { - glGenTextures(1, &m_Textures[pCommand->m_Slot].m_Tex); - glBindTexture(GL_TEXTURE_2D, m_Textures[pCommand->m_Slot].m_Tex); - - glGenSamplers(1, &m_Textures[pCommand->m_Slot].m_Sampler); - glBindSampler(Slot, m_Textures[pCommand->m_Slot].m_Sampler); - } - - if(Oglformat == GL_RED) - { - //Bind the texture 2D. - GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_RED}; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - StoreOglformat = GL_R8; - } - - if(pCommand->m_Flags & CCommandBuffer::TEXFLAG_NOMIPMAPS) - { - if((pCommand->m_Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0) - { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, StoreOglformat, Width, Height, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData); - } - } - else - { - if((pCommand->m_Flags & CCommandBuffer::TEXFLAG_NO_2D_TEXTURE) == 0) - { - glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - if(m_OpenGLTextureLodBIAS != 0) - glSamplerParameterf(m_Textures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_LOD_BIAS, ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f)); - //prevent mipmap display bugs, when zooming out far - if(Width >= 1024 && Height >= 1024) - { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 5.f); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 5); - } - glTexImage2D(GL_TEXTURE_2D, 0, StoreOglformat, Width, Height, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData); - glGenerateMipmap(GL_TEXTURE_2D); - } - - if((pCommand->m_Flags & (CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE | CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE_SINGLE_LAYER)) != 0) - { - glGenTextures(1, &m_Textures[pCommand->m_Slot].m_Tex2DArray); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_Textures[pCommand->m_Slot].m_Tex2DArray); - - glGenSamplers(1, &m_Textures[pCommand->m_Slot].m_Sampler2DArray); - glBindSampler(Slot, m_Textures[pCommand->m_Slot].m_Sampler2DArray); - glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glSamplerParameteri(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT); - if(m_OpenGLTextureLodBIAS != 0) - glSamplerParameterf(m_Textures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_LOD_BIAS, ((GLfloat)m_OpenGLTextureLodBIAS / 1000.0f)); - - int ImageColorChannels = TexFormatToImageColorChannelCount(pCommand->m_Format); - - uint8_t *p3DImageData = NULL; - - bool IsSingleLayer = (pCommand->m_Flags & CCommandBuffer::TEXFLAG_TO_2D_ARRAY_TEXTURE_SINGLE_LAYER) != 0; - - if(!IsSingleLayer) - p3DImageData = (uint8_t *)malloc((size_t)ImageColorChannels * Width * Height); - int Image3DWidth, Image3DHeight; - - int ConvertWidth = Width; - int ConvertHeight = Height; - - if(!IsSingleLayer) - { - if(ConvertWidth == 0 || (ConvertWidth % 16) != 0 || ConvertHeight == 0 || (ConvertHeight % 16) != 0) - { - dbg_msg("gfx", "3D/2D array texture was resized"); - int NewWidth = maximum(HighestBit(ConvertWidth), 16); - int NewHeight = maximum(HighestBit(ConvertHeight), 16); - uint8_t *pNewTexData = (uint8_t *)Resize(ConvertWidth, ConvertHeight, NewWidth, NewHeight, pCommand->m_Format, (const uint8_t *)pTexData); - - ConvertWidth = NewWidth; - ConvertHeight = NewHeight; - - free(pTexData); - pTexData = pNewTexData; - } - } - - if(IsSingleLayer || (Texture2DTo3D(pTexData, ConvertWidth, ConvertHeight, ImageColorChannels, 16, 16, p3DImageData, Image3DWidth, Image3DHeight))) - { - if(IsSingleLayer) - { - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, StoreOglformat, ConvertWidth, ConvertHeight, 1, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData); - } - else - { - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, StoreOglformat, Image3DWidth, Image3DHeight, 256, 0, Oglformat, GL_UNSIGNED_BYTE, p3DImageData); - } - glGenerateMipmap(GL_TEXTURE_2D_ARRAY); - - if(StoreOglformat == GL_R8) - { - //Bind the texture 2D. - GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_RED}; - glTexParameteriv(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - } - } - - if(!IsSingleLayer) - free(p3DImageData); - } - } - - // This is the initial value for the wrap modes - m_Textures[pCommand->m_Slot].m_LastWrapMode = CCommandBuffer::WRAP_REPEAT; - - // calculate memory usage - m_Textures[pCommand->m_Slot].m_MemSize = Width * Height * pCommand->m_PixelSize; - while(Width > 2 && Height > 2) - { - Width >>= 1; - Height >>= 1; - m_Textures[pCommand->m_Slot].m_MemSize += Width * Height * pCommand->m_PixelSize; - } - m_pTextureMemoryUsage->store(m_pTextureMemoryUsage->load(std::memory_order_relaxed) + m_Textures[pCommand->m_Slot].m_MemSize, std::memory_order_relaxed); - - free(pTexData); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand) -{ - if(pCommand->m_Color.r != m_ClearColor.r || pCommand->m_Color.g != m_ClearColor.g || pCommand->m_Color.b != m_ClearColor.b) - { - glClearColor(pCommand->m_Color.r, pCommand->m_Color.g, pCommand->m_Color.b, 0.0f); - m_ClearColor = pCommand->m_Color; - } - glClear(GL_COLOR_BUFFER_BIT); -} - -void CCommandProcessorFragment_OpenGL3_3::UploadStreamBufferData(unsigned int PrimitiveType, const void *pVertices, size_t VertSize, unsigned int PrimitiveCount, bool AsTex3D) -{ - int Count = 0; - switch(PrimitiveType) - { - case CCommandBuffer::PRIMTYPE_LINES: - Count = PrimitiveCount * 2; - break; - case CCommandBuffer::PRIMTYPE_TRIANGLES: - Count = PrimitiveCount * 3; - break; - case CCommandBuffer::PRIMTYPE_QUADS: - Count = PrimitiveCount * 4; - break; - default: - return; - }; - - if(AsTex3D) - glBindBuffer(GL_ARRAY_BUFFER, m_PrimitiveDrawBufferIDTex3D); - else - glBindBuffer(GL_ARRAY_BUFFER, m_PrimitiveDrawBufferID[m_LastStreamBuffer]); - - if(!m_UsePreinitializedVertexBuffer) - glBufferData(GL_ARRAY_BUFFER, VertSize * Count, pVertices, GL_STREAM_DRAW); - else - { - // This is better for some iGPUs. Probably due to not initializing a new buffer in the system memory again and again...(driver dependent) - void *pData = glMapBufferRange(GL_ARRAY_BUFFER, 0, VertSize * Count, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); - - mem_copy(pData, pVertices, VertSize * Count); - - glUnmapBuffer(GL_ARRAY_BUFFER); - } -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand) -{ - CGLSLTWProgram *pProgram = m_pPrimitiveProgram; - if(IsTexturedState(pCommand->m_State)) - pProgram = m_pPrimitiveProgramTextured; - UseProgram(pProgram); - SetState(pCommand->m_State, pProgram); - - UploadStreamBufferData(pCommand->m_PrimType, pCommand->m_pVertices, sizeof(CCommandBuffer::SVertex), pCommand->m_PrimCount); - - glBindVertexArray(m_PrimitiveDrawVertexID[m_LastStreamBuffer]); - - switch(pCommand->m_PrimType) - { - // We don't support GL_QUADS due to core profile - case CCommandBuffer::PRIMTYPE_LINES: - glDrawArrays(GL_LINES, 0, pCommand->m_PrimCount * 2); - break; - case CCommandBuffer::PRIMTYPE_TRIANGLES: - glDrawArrays(GL_TRIANGLES, 0, pCommand->m_PrimCount * 3); - break; - case CCommandBuffer::PRIMTYPE_QUADS: - if(m_LastIndexBufferBound[m_LastStreamBuffer] != m_QuadDrawIndexBufferID) - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); - m_LastIndexBufferBound[m_LastStreamBuffer] = m_QuadDrawIndexBufferID; - } - glDrawElements(GL_TRIANGLES, pCommand->m_PrimCount * 6, GL_UNSIGNED_INT, 0); - break; - default: - dbg_msg("render", "unknown primtype %d\n", pCommand->m_PrimType); - }; - - m_LastStreamBuffer = (m_LastStreamBuffer + 1 >= MAX_STREAM_BUFFER_COUNT ? 0 : m_LastStreamBuffer + 1); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderTex3D(const CCommandBuffer::SCommand_RenderTex3D *pCommand) -{ - CGLSLPrimitiveProgram *pProg = m_pPrimitive3DProgram; - if(IsTexturedState(pCommand->m_State)) - pProg = m_pPrimitive3DProgramTextured; - UseProgram(pProg); - SetState(pCommand->m_State, pProg, true); - - UploadStreamBufferData(pCommand->m_PrimType, pCommand->m_pVertices, sizeof(CCommandBuffer::SVertexTex3DStream), pCommand->m_PrimCount, true); - - glBindVertexArray(m_PrimitiveDrawVertexIDTex3D); - - switch(pCommand->m_PrimType) - { - // We don't support GL_QUADS due to core profile - case CCommandBuffer::PRIMTYPE_LINES: - glDrawArrays(GL_LINES, 0, pCommand->m_PrimCount * 2); - break; - case CCommandBuffer::PRIMTYPE_QUADS: - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); - glDrawElements(GL_TRIANGLES, pCommand->m_PrimCount * 6, GL_UNSIGNED_INT, 0); - break; - default: - dbg_msg("render", "unknown primtype %d\n", pCommand->m_PrimType); - }; -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_Screenshot(const CCommandBuffer::SCommand_Screenshot *pCommand) -{ - // fetch image data - GLint aViewport[4] = {0, 0, 0, 0}; - glGetIntegerv(GL_VIEWPORT, aViewport); - - int w = aViewport[2]; - int h = aViewport[3]; - - // we allocate one more row to use when we are flipping the texture - unsigned char *pPixelData = (unsigned char *)malloc((size_t)w * (h + 1) * 3); - unsigned char *pTempRow = pPixelData + w * h * 3; - - // fetch the pixels - GLint Alignment; - glGetIntegerv(GL_PACK_ALIGNMENT, &Alignment); - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, pPixelData); - glPixelStorei(GL_PACK_ALIGNMENT, Alignment); - - // flip the pixel because opengl works from bottom left corner - for(int y = 0; y < h / 2; y++) - { - mem_copy(pTempRow, pPixelData + y * w * 3, w * 3); - mem_copy(pPixelData + y * w * 3, pPixelData + (h - y - 1) * w * 3, w * 3); - mem_copy(pPixelData + (h - y - 1) * w * 3, pTempRow, w * 3); - } - - // fill in the information - pCommand->m_pImage->m_Width = w; - pCommand->m_pImage->m_Height = h; - pCommand->m_pImage->m_Format = CImageInfo::FORMAT_RGB; - pCommand->m_pImage->m_pData = pPixelData; -} - -void CCommandProcessorFragment_OpenGL3_3::DestroyBufferContainer(int Index, bool DeleteBOs) -{ - SBufferContainer &BufferContainer = m_BufferContainers[Index]; - if(BufferContainer.m_VertArrayID != 0) - glDeleteVertexArrays(1, &BufferContainer.m_VertArrayID); - - // all buffer objects can deleted automatically, so the program doesn't need to deal with them (e.g. causing crashes because of driver bugs) - if(DeleteBOs) - { - for(size_t i = 0; i < BufferContainer.m_ContainerInfo.m_Attributes.size(); ++i) - { - int VertBufferID = BufferContainer.m_ContainerInfo.m_Attributes[i].m_VertBufferBindingIndex; - if(VertBufferID != -1) - { - for(auto &Attribute : BufferContainer.m_ContainerInfo.m_Attributes) - { - // set all equal ids to zero to not double delete - if(VertBufferID == Attribute.m_VertBufferBindingIndex) - { - Attribute.m_VertBufferBindingIndex = -1; - } - } - - glDeleteBuffers(1, &m_BufferObjectIndices[VertBufferID]); - } - } - } - - BufferContainer.m_LastIndexBufferBound = 0; - BufferContainer.m_ContainerInfo.m_Attributes.clear(); -} - -void CCommandProcessorFragment_OpenGL3_3::AppendIndices(unsigned int NewIndicesCount) -{ - if(NewIndicesCount <= m_CurrentIndicesInBuffer) - return; - unsigned int AddCount = NewIndicesCount - m_CurrentIndicesInBuffer; - unsigned int *Indices = new unsigned int[AddCount]; - int Primq = (m_CurrentIndicesInBuffer / 6) * 4; - for(unsigned int i = 0; i < AddCount; i += 6) - { - Indices[i] = Primq; - Indices[i + 1] = Primq + 1; - Indices[i + 2] = Primq + 2; - Indices[i + 3] = Primq; - Indices[i + 4] = Primq + 2; - Indices[i + 5] = Primq + 3; - Primq += 4; - } - - glBindBuffer(GL_COPY_READ_BUFFER, m_QuadDrawIndexBufferID); - GLuint NewIndexBufferID; - glGenBuffers(1, &NewIndexBufferID); - glBindBuffer(GL_COPY_WRITE_BUFFER, NewIndexBufferID); - GLsizeiptr size = sizeof(unsigned int); - glBufferData(GL_COPY_WRITE_BUFFER, (GLsizeiptr)NewIndicesCount * size, NULL, GL_STATIC_DRAW); - glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, (GLsizeiptr)m_CurrentIndicesInBuffer * size); - glBufferSubData(GL_COPY_WRITE_BUFFER, (GLsizeiptr)m_CurrentIndicesInBuffer * size, (GLsizeiptr)AddCount * size, Indices); - glBindBuffer(GL_COPY_WRITE_BUFFER, 0); - glBindBuffer(GL_COPY_READ_BUFFER, 0); - - glDeleteBuffers(1, &m_QuadDrawIndexBufferID); - m_QuadDrawIndexBufferID = NewIndexBufferID; - - for(unsigned int &i : m_LastIndexBufferBound) - i = 0; - for(auto &BufferContainer : m_BufferContainers) - { - BufferContainer.m_LastIndexBufferBound = 0; - } - - m_CurrentIndicesInBuffer = NewIndicesCount; - delete[] Indices; -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_CreateBufferObject(const CCommandBuffer::SCommand_CreateBufferObject *pCommand) -{ - void *pUploadData = pCommand->m_pUploadData; - int Index = pCommand->m_BufferIndex; - //create necessary space - if((size_t)Index >= m_BufferObjectIndices.size()) - { - for(int i = m_BufferObjectIndices.size(); i < Index + 1; ++i) - { - m_BufferObjectIndices.push_back(0); - } - } - - GLuint VertBufferID = 0; - - glGenBuffers(1, &VertBufferID); - glBindBuffer(GL_COPY_WRITE_BUFFER, VertBufferID); - glBufferData(GL_COPY_WRITE_BUFFER, (GLsizeiptr)(pCommand->m_DataSize), pUploadData, GL_STATIC_DRAW); - - m_BufferObjectIndices[Index] = VertBufferID; - - if(pCommand->m_DeletePointer) - free(pUploadData); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_RecreateBufferObject(const CCommandBuffer::SCommand_RecreateBufferObject *pCommand) -{ - void *pUploadData = pCommand->m_pUploadData; - int Index = pCommand->m_BufferIndex; - - glBindBuffer(GL_COPY_WRITE_BUFFER, m_BufferObjectIndices[Index]); - glBufferData(GL_COPY_WRITE_BUFFER, (GLsizeiptr)(pCommand->m_DataSize), pUploadData, GL_STATIC_DRAW); - - if(pCommand->m_DeletePointer) - free(pUploadData); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_UpdateBufferObject(const CCommandBuffer::SCommand_UpdateBufferObject *pCommand) -{ - void *pUploadData = pCommand->m_pUploadData; - int Index = pCommand->m_BufferIndex; - - glBindBuffer(GL_COPY_WRITE_BUFFER, m_BufferObjectIndices[Index]); - glBufferSubData(GL_COPY_WRITE_BUFFER, (GLintptr)(pCommand->m_pOffset), (GLsizeiptr)(pCommand->m_DataSize), pUploadData); - - if(pCommand->m_DeletePointer) - free(pUploadData); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_CopyBufferObject(const CCommandBuffer::SCommand_CopyBufferObject *pCommand) -{ - int WriteIndex = pCommand->m_WriteBufferIndex; - int ReadIndex = pCommand->m_ReadBufferIndex; - - glBindBuffer(GL_COPY_WRITE_BUFFER, m_BufferObjectIndices[WriteIndex]); - glBindBuffer(GL_COPY_READ_BUFFER, m_BufferObjectIndices[ReadIndex]); - glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, (GLsizeiptr)(pCommand->m_pReadOffset), (GLsizeiptr)(pCommand->m_pWriteOffset), (GLsizeiptr)pCommand->m_CopySize); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_DeleteBufferObject(const CCommandBuffer::SCommand_DeleteBufferObject *pCommand) -{ - int Index = pCommand->m_BufferIndex; - - glDeleteBuffers(1, &m_BufferObjectIndices[Index]); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_CreateBufferContainer(const CCommandBuffer::SCommand_CreateBufferContainer *pCommand) -{ - int Index = pCommand->m_BufferContainerIndex; - //create necessary space - if((size_t)Index >= m_BufferContainers.size()) - { - for(int i = m_BufferContainers.size(); i < Index + 1; ++i) - { - SBufferContainer Container; - Container.m_ContainerInfo.m_Stride = 0; - m_BufferContainers.push_back(Container); - } - } - - SBufferContainer &BufferContainer = m_BufferContainers[Index]; - glGenVertexArrays(1, &BufferContainer.m_VertArrayID); - glBindVertexArray(BufferContainer.m_VertArrayID); - - BufferContainer.m_LastIndexBufferBound = 0; - - for(int i = 0; i < pCommand->m_AttrCount; ++i) - { - glEnableVertexAttribArray((GLuint)i); - - glBindBuffer(GL_ARRAY_BUFFER, m_BufferObjectIndices[pCommand->m_Attributes[i].m_VertBufferBindingIndex]); - - SBufferContainerInfo::SAttribute &Attr = pCommand->m_Attributes[i]; - - if(Attr.m_FuncType == 0) - glVertexAttribPointer((GLuint)i, Attr.m_DataTypeCount, Attr.m_Type, (GLboolean)Attr.m_Normalized, pCommand->m_Stride, Attr.m_pOffset); - else if(Attr.m_FuncType == 1) - glVertexAttribIPointer((GLuint)i, Attr.m_DataTypeCount, Attr.m_Type, pCommand->m_Stride, Attr.m_pOffset); - - BufferContainer.m_ContainerInfo.m_Attributes.push_back(Attr); - } - - BufferContainer.m_ContainerInfo.m_Stride = pCommand->m_Stride; -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_UpdateBufferContainer(const CCommandBuffer::SCommand_UpdateBufferContainer *pCommand) -{ - SBufferContainer &BufferContainer = m_BufferContainers[pCommand->m_BufferContainerIndex]; - - glBindVertexArray(BufferContainer.m_VertArrayID); - - //disable all old attributes - for(size_t i = 0; i < BufferContainer.m_ContainerInfo.m_Attributes.size(); ++i) - { - glDisableVertexAttribArray((GLuint)i); - } - BufferContainer.m_ContainerInfo.m_Attributes.clear(); - - for(int i = 0; i < pCommand->m_AttrCount; ++i) - { - glEnableVertexAttribArray((GLuint)i); - - glBindBuffer(GL_ARRAY_BUFFER, m_BufferObjectIndices[pCommand->m_Attributes[i].m_VertBufferBindingIndex]); - SBufferContainerInfo::SAttribute &Attr = pCommand->m_Attributes[i]; - if(Attr.m_FuncType == 0) - glVertexAttribPointer((GLuint)i, Attr.m_DataTypeCount, Attr.m_Type, Attr.m_Normalized, pCommand->m_Stride, Attr.m_pOffset); - else if(Attr.m_FuncType == 1) - glVertexAttribIPointer((GLuint)i, Attr.m_DataTypeCount, Attr.m_Type, pCommand->m_Stride, Attr.m_pOffset); - - BufferContainer.m_ContainerInfo.m_Attributes.push_back(Attr); - } - - BufferContainer.m_ContainerInfo.m_Stride = pCommand->m_Stride; -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_DeleteBufferContainer(const CCommandBuffer::SCommand_DeleteBufferContainer *pCommand) -{ - DestroyBufferContainer(pCommand->m_BufferContainerIndex, pCommand->m_DestroyAllBO); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_IndicesRequiredNumNotify(const CCommandBuffer::SCommand_IndicesRequiredNumNotify *pCommand) -{ - if(pCommand->m_RequiredIndicesNum > m_CurrentIndicesInBuffer) - AppendIndices(pCommand->m_RequiredIndicesNum); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderBorderTile(const CCommandBuffer::SCommand_RenderBorderTile *pCommand) -{ - int Index = pCommand->m_BufferContainerIndex; - //if space not there return - if((size_t)Index >= m_BufferContainers.size()) - return; - - SBufferContainer &BufferContainer = m_BufferContainers[Index]; - if(BufferContainer.m_VertArrayID == 0) - return; - - CGLSLTileProgram *pProgram = NULL; - if(IsTexturedState(pCommand->m_State)) - { - pProgram = m_pBorderTileProgramTextured; - } - else - pProgram = m_pBorderTileProgram; - UseProgram(pProgram); - - SetState(pCommand->m_State, pProgram, true); - pProgram->SetUniformVec4(pProgram->m_LocColor, 1, (float *)&pCommand->m_Color); - - pProgram->SetUniformVec2(pProgram->m_LocOffset, 1, (float *)&pCommand->m_Offset); - pProgram->SetUniformVec2(pProgram->m_LocDir, 1, (float *)&pCommand->m_Dir); - pProgram->SetUniform(pProgram->m_LocJumpIndex, (int)pCommand->m_JumpIndex); - - glBindVertexArray(BufferContainer.m_VertArrayID); - if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferID) - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); - BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferID; - } - glDrawElementsInstanced(GL_TRIANGLES, 6, GL_UNSIGNED_INT, pCommand->m_pIndicesOffset, pCommand->m_DrawNum); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderBorderTileLine(const CCommandBuffer::SCommand_RenderBorderTileLine *pCommand) -{ - int Index = pCommand->m_BufferContainerIndex; - //if space not there return - if((size_t)Index >= m_BufferContainers.size()) - return; - - SBufferContainer &BufferContainer = m_BufferContainers[Index]; - if(BufferContainer.m_VertArrayID == 0) - return; - - CGLSLTileProgram *pProgram = NULL; - if(IsTexturedState(pCommand->m_State)) - { - pProgram = m_pBorderTileLineProgramTextured; - } - else - pProgram = m_pBorderTileLineProgram; - UseProgram(pProgram); - - SetState(pCommand->m_State, pProgram, true); - pProgram->SetUniformVec4(pProgram->m_LocColor, 1, (float *)&pCommand->m_Color); - pProgram->SetUniformVec2(pProgram->m_LocOffset, 1, (float *)&pCommand->m_Offset); - pProgram->SetUniformVec2(pProgram->m_LocDir, 1, (float *)&pCommand->m_Dir); - - glBindVertexArray(BufferContainer.m_VertArrayID); - if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferID) - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); - BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferID; - } - glDrawElementsInstanced(GL_TRIANGLES, pCommand->m_IndexDrawNum, GL_UNSIGNED_INT, pCommand->m_pIndicesOffset, pCommand->m_DrawNum); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderTileLayer(const CCommandBuffer::SCommand_RenderTileLayer *pCommand) -{ - int Index = pCommand->m_BufferContainerIndex; - //if space not there return - if((size_t)Index >= m_BufferContainers.size()) - return; - - SBufferContainer &BufferContainer = m_BufferContainers[Index]; - if(BufferContainer.m_VertArrayID == 0) - return; - - if(pCommand->m_IndicesDrawNum == 0) - { - return; //nothing to draw - } - - CGLSLTileProgram *pProgram = NULL; - if(IsTexturedState(pCommand->m_State)) - { - pProgram = m_pTileProgramTextured; - } - else - pProgram = m_pTileProgram; - - UseProgram(pProgram); - - SetState(pCommand->m_State, pProgram, true); - pProgram->SetUniformVec4(pProgram->m_LocColor, 1, (float *)&pCommand->m_Color); - - glBindVertexArray(BufferContainer.m_VertArrayID); - if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferID) - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); - BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferID; - } - for(int i = 0; i < pCommand->m_IndicesDrawNum; ++i) - { - glDrawElements(GL_TRIANGLES, pCommand->m_pDrawCount[i], GL_UNSIGNED_INT, pCommand->m_pIndicesOffsets[i]); - } -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadLayer(const CCommandBuffer::SCommand_RenderQuadLayer *pCommand) -{ - int Index = pCommand->m_BufferContainerIndex; - //if space not there return - if((size_t)Index >= m_BufferContainers.size()) - return; - - SBufferContainer &BufferContainer = m_BufferContainers[Index]; - if(BufferContainer.m_VertArrayID == 0) - return; - - if(pCommand->m_QuadNum == 0) - { - return; //nothing to draw - } - - CGLSLQuadProgram *pProgram = NULL; - if(IsTexturedState(pCommand->m_State)) - { - pProgram = m_pQuadProgramTextured; - } - else - pProgram = m_pQuadProgram; - - UseProgram(pProgram); - SetState(pCommand->m_State, pProgram); - - glBindVertexArray(BufferContainer.m_VertArrayID); - if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferID) - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); - BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferID; - } - - int QuadsLeft = pCommand->m_QuadNum; - size_t QuadOffset = 0; - // the extra offset is not related to the information from the command, but an actual offset in the buffer - size_t QuadOffsetExtra = pCommand->m_QuadOffset; - - vec4 aColors[m_MaxQuadsPossible]; - vec2 aOffsets[m_MaxQuadsPossible]; - float aRotations[m_MaxQuadsPossible]; - - while(QuadsLeft > 0) - { - int ActualQuadCount = minimum(QuadsLeft, m_MaxQuadsAtOnce); - - for(size_t i = 0; i < (size_t)ActualQuadCount; ++i) - { - mem_copy(&aColors[i], pCommand->m_pQuadInfo[i + QuadOffset].m_aColor, sizeof(vec4)); - mem_copy(&aOffsets[i], pCommand->m_pQuadInfo[i + QuadOffset].m_aOffsets, sizeof(vec2)); - mem_copy(&aRotations[i], &pCommand->m_pQuadInfo[i + QuadOffset].m_Rotation, sizeof(float)); - } - - pProgram->SetUniformVec4(pProgram->m_LocColors, ActualQuadCount, (float *)aColors); - pProgram->SetUniformVec2(pProgram->m_LocOffsets, ActualQuadCount, (float *)aOffsets); - pProgram->SetUniform(pProgram->m_LocRotations, ActualQuadCount, (float *)aRotations); - pProgram->SetUniform(pProgram->m_LocQuadOffset, (int)(QuadOffset + QuadOffsetExtra)); - glDrawElements(GL_TRIANGLES, ActualQuadCount * 6, GL_UNSIGNED_INT, (void *)((QuadOffset + QuadOffsetExtra) * 6 * sizeof(unsigned int))); - - QuadsLeft -= ActualQuadCount; - QuadOffset += (size_t)ActualQuadCount; - } -} - -void CCommandProcessorFragment_OpenGL3_3::RenderText(const CCommandBuffer::SState &State, int DrawNum, int TextTextureIndex, int TextOutlineTextureIndex, int TextureSize, const float *pTextColor, const float *pTextOutlineColor) -{ - if(DrawNum == 0) - { - return; //nothing to draw - } - - UseProgram(m_pTextProgram); - - int SlotText = 0; - int SlotTextOutline = 0; - - if(m_UseMultipleTextureUnits) - { - SlotText = TextTextureIndex % m_MaxTextureUnits; - SlotTextOutline = TextOutlineTextureIndex % m_MaxTextureUnits; - if(SlotText == SlotTextOutline) - SlotTextOutline = (TextOutlineTextureIndex + 1) % m_MaxTextureUnits; - - if(!IsAndUpdateTextureSlotBound(SlotText, TextTextureIndex)) - { - glActiveTexture(GL_TEXTURE0 + SlotText); - glBindTexture(GL_TEXTURE_2D, m_Textures[TextTextureIndex].m_Tex); - glBindSampler(SlotText, m_Textures[TextTextureIndex].m_Sampler); - } - if(!IsAndUpdateTextureSlotBound(SlotTextOutline, TextOutlineTextureIndex)) - { - glActiveTexture(GL_TEXTURE0 + SlotTextOutline); - glBindTexture(GL_TEXTURE_2D, m_Textures[TextOutlineTextureIndex].m_Tex); - glBindSampler(SlotTextOutline, m_Textures[TextOutlineTextureIndex].m_Sampler); - } - } - else - { - SlotText = 0; - SlotTextOutline = 1; - glBindTexture(GL_TEXTURE_2D, m_Textures[TextTextureIndex].m_Tex); - glBindSampler(SlotText, m_Textures[TextTextureIndex].m_Sampler); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, m_Textures[TextOutlineTextureIndex].m_Tex); - glBindSampler(SlotTextOutline, m_Textures[TextOutlineTextureIndex].m_Sampler); - glActiveTexture(GL_TEXTURE0); - } - - if(m_pTextProgram->m_LastTextSampler != SlotText) - { - m_pTextProgram->SetUniform(m_pTextProgram->m_LocTextSampler, SlotText); - m_pTextProgram->m_LastTextSampler = SlotText; - } - - if(m_pTextProgram->m_LastTextOutlineSampler != SlotTextOutline) - { - m_pTextProgram->SetUniform(m_pTextProgram->m_LocTextOutlineSampler, SlotTextOutline); - m_pTextProgram->m_LastTextOutlineSampler = SlotTextOutline; - } - - SetState(State, m_pTextProgram); - - if(m_pTextProgram->m_LastTextureSize != TextureSize) - { - m_pTextProgram->SetUniform(m_pTextProgram->m_LocTextureSize, (float)TextureSize); - m_pTextProgram->m_LastTextureSize = TextureSize; - } - - if(m_pTextProgram->m_LastOutlineColor[0] != pTextOutlineColor[0] || m_pTextProgram->m_LastOutlineColor[1] != pTextOutlineColor[1] || m_pTextProgram->m_LastOutlineColor[2] != pTextOutlineColor[2] || m_pTextProgram->m_LastOutlineColor[3] != pTextOutlineColor[3]) - { - m_pTextProgram->SetUniformVec4(m_pTextProgram->m_LocOutlineColor, 1, (float *)pTextOutlineColor); - m_pTextProgram->m_LastOutlineColor[0] = pTextOutlineColor[0]; - m_pTextProgram->m_LastOutlineColor[1] = pTextOutlineColor[1]; - m_pTextProgram->m_LastOutlineColor[2] = pTextOutlineColor[2]; - m_pTextProgram->m_LastOutlineColor[3] = pTextOutlineColor[3]; - } - - if(m_pTextProgram->m_LastColor[0] != pTextColor[0] || m_pTextProgram->m_LastColor[1] != pTextColor[1] || m_pTextProgram->m_LastColor[2] != pTextColor[2] || m_pTextProgram->m_LastColor[3] != pTextColor[3]) - { - m_pTextProgram->SetUniformVec4(m_pTextProgram->m_LocColor, 1, (float *)pTextColor); - m_pTextProgram->m_LastColor[0] = pTextColor[0]; - m_pTextProgram->m_LastColor[1] = pTextColor[1]; - m_pTextProgram->m_LastColor[2] = pTextColor[2]; - m_pTextProgram->m_LastColor[3] = pTextColor[3]; - } - - glDrawElements(GL_TRIANGLES, DrawNum, GL_UNSIGNED_INT, (void *)(0)); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderText(const CCommandBuffer::SCommand_RenderText *pCommand) -{ - int Index = pCommand->m_BufferContainerIndex; - //if space not there return - if((size_t)Index >= m_BufferContainers.size()) - return; - - SBufferContainer &BufferContainer = m_BufferContainers[Index]; - if(BufferContainer.m_VertArrayID == 0) - return; - - glBindVertexArray(BufferContainer.m_VertArrayID); - if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferID) - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); - BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferID; - } - - RenderText(pCommand->m_State, pCommand->m_DrawNum, pCommand->m_TextTextureIndex, pCommand->m_TextOutlineTextureIndex, pCommand->m_TextureSize, pCommand->m_aTextColor, pCommand->m_aTextOutlineColor); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderTextStream(const CCommandBuffer::SCommand_RenderTextStream *pCommand) -{ - if(pCommand->m_PrimCount == 0) - { - return; //nothing to draw - } - - UploadStreamBufferData(CCommandBuffer::PRIMTYPE_QUADS, pCommand->m_pVertices, sizeof(CCommandBuffer::SVertex), pCommand->m_PrimCount); - - glBindVertexArray(m_PrimitiveDrawVertexID[m_LastStreamBuffer]); - if(m_LastIndexBufferBound[m_LastStreamBuffer] != m_QuadDrawIndexBufferID) - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); - m_LastIndexBufferBound[m_LastStreamBuffer] = m_QuadDrawIndexBufferID; - } - - float aTextColor[4] = {1.f, 1.f, 1.f, 1.f}; - - RenderText(pCommand->m_State, pCommand->m_PrimCount * 6, pCommand->m_TextTextureIndex, pCommand->m_TextOutlineTextureIndex, pCommand->m_TextureSize, aTextColor, pCommand->m_aTextOutlineColor); - - m_LastStreamBuffer = (m_LastStreamBuffer + 1 >= MAX_STREAM_BUFFER_COUNT ? 0 : m_LastStreamBuffer + 1); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadContainer(const CCommandBuffer::SCommand_RenderQuadContainer *pCommand) -{ - if(pCommand->m_DrawNum == 0) - { - return; //nothing to draw - } - - int Index = pCommand->m_BufferContainerIndex; - //if space not there return - if((size_t)Index >= m_BufferContainers.size()) - return; - - SBufferContainer &BufferContainer = m_BufferContainers[Index]; - if(BufferContainer.m_VertArrayID == 0) - return; - - glBindVertexArray(BufferContainer.m_VertArrayID); - if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferID) - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); - BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferID; - } - - CGLSLTWProgram *pProgram = m_pPrimitiveProgram; - if(IsTexturedState(pCommand->m_State)) - pProgram = m_pPrimitiveProgramTextured; - UseProgram(pProgram); - SetState(pCommand->m_State, pProgram); - - glDrawElements(GL_TRIANGLES, pCommand->m_DrawNum, GL_UNSIGNED_INT, pCommand->m_pOffset); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadContainerEx(const CCommandBuffer::SCommand_RenderQuadContainerEx *pCommand) -{ - if(pCommand->m_DrawNum == 0) - { - return; //nothing to draw - } - - int Index = pCommand->m_BufferContainerIndex; - //if space not there return - if((size_t)Index >= m_BufferContainers.size()) - return; - - SBufferContainer &BufferContainer = m_BufferContainers[Index]; - if(BufferContainer.m_VertArrayID == 0) - return; - - glBindVertexArray(BufferContainer.m_VertArrayID); - if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferID) - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); - BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferID; - } - - CGLSLPrimitiveExProgram *pProgram = m_pPrimitiveExProgramRotationless; - if(IsTexturedState(pCommand->m_State)) - { - if(pCommand->m_Rotation != 0.0f) - pProgram = m_pPrimitiveExProgramTextured; - else - pProgram = m_pPrimitiveExProgramTexturedRotationless; - } - else - { - if(pCommand->m_Rotation != 0.0f) - pProgram = m_pPrimitiveExProgram; - } - - UseProgram(pProgram); - SetState(pCommand->m_State, pProgram); - - if(pCommand->m_Rotation != 0.0f && (pProgram->m_LastCenter[0] != pCommand->m_Center.x || pProgram->m_LastCenter[1] != pCommand->m_Center.y)) - { - pProgram->SetUniformVec2(pProgram->m_LocCenter, 1, (float *)&pCommand->m_Center); - pProgram->m_LastCenter[0] = pCommand->m_Center.x; - pProgram->m_LastCenter[1] = pCommand->m_Center.y; - } - - if(pProgram->m_LastRotation != pCommand->m_Rotation) - { - pProgram->SetUniform(pProgram->m_LocRotation, pCommand->m_Rotation); - pProgram->m_LastRotation = pCommand->m_Rotation; - } - - if(pProgram->m_LastVertciesColor[0] != pCommand->m_VertexColor.r || pProgram->m_LastVertciesColor[1] != pCommand->m_VertexColor.g || pProgram->m_LastVertciesColor[2] != pCommand->m_VertexColor.b || pProgram->m_LastVertciesColor[3] != pCommand->m_VertexColor.a) - { - pProgram->SetUniformVec4(pProgram->m_LocVertciesColor, 1, (float *)&pCommand->m_VertexColor); - pProgram->m_LastVertciesColor[0] = pCommand->m_VertexColor.r; - pProgram->m_LastVertciesColor[1] = pCommand->m_VertexColor.g; - pProgram->m_LastVertciesColor[2] = pCommand->m_VertexColor.b; - pProgram->m_LastVertciesColor[3] = pCommand->m_VertexColor.a; - } - - glDrawElements(GL_TRIANGLES, pCommand->m_DrawNum, GL_UNSIGNED_INT, pCommand->m_pOffset); -} - -void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadContainerAsSpriteMultiple(const CCommandBuffer::SCommand_RenderQuadContainerAsSpriteMultiple *pCommand) -{ - if(pCommand->m_DrawNum == 0 || pCommand->m_DrawCount == 0) - { - return; //nothing to draw - } - - int Index = pCommand->m_BufferContainerIndex; - //if space not there return - if((size_t)Index >= m_BufferContainers.size()) - return; - - SBufferContainer &BufferContainer = m_BufferContainers[Index]; - if(BufferContainer.m_VertArrayID == 0) - return; - - glBindVertexArray(BufferContainer.m_VertArrayID); - if(BufferContainer.m_LastIndexBufferBound != m_QuadDrawIndexBufferID) - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_QuadDrawIndexBufferID); - BufferContainer.m_LastIndexBufferBound = m_QuadDrawIndexBufferID; - } - - UseProgram(m_pSpriteProgramMultiple); - SetState(pCommand->m_State, m_pSpriteProgramMultiple); - - if((m_pSpriteProgramMultiple->m_LastCenter[0] != pCommand->m_Center.x || m_pSpriteProgramMultiple->m_LastCenter[1] != pCommand->m_Center.y)) - { - m_pSpriteProgramMultiple->SetUniformVec2(m_pSpriteProgramMultiple->m_LocCenter, 1, (float *)&pCommand->m_Center); - m_pSpriteProgramMultiple->m_LastCenter[0] = pCommand->m_Center.x; - m_pSpriteProgramMultiple->m_LastCenter[1] = pCommand->m_Center.y; - } - - if(m_pSpriteProgramMultiple->m_LastVertciesColor[0] != pCommand->m_VertexColor.r || m_pSpriteProgramMultiple->m_LastVertciesColor[1] != pCommand->m_VertexColor.g || m_pSpriteProgramMultiple->m_LastVertciesColor[2] != pCommand->m_VertexColor.b || m_pSpriteProgramMultiple->m_LastVertciesColor[3] != pCommand->m_VertexColor.a) - { - m_pSpriteProgramMultiple->SetUniformVec4(m_pSpriteProgramMultiple->m_LocVertciesColor, 1, (float *)&pCommand->m_VertexColor); - m_pSpriteProgramMultiple->m_LastVertciesColor[0] = pCommand->m_VertexColor.r; - m_pSpriteProgramMultiple->m_LastVertciesColor[1] = pCommand->m_VertexColor.g; - m_pSpriteProgramMultiple->m_LastVertciesColor[2] = pCommand->m_VertexColor.b; - m_pSpriteProgramMultiple->m_LastVertciesColor[3] = pCommand->m_VertexColor.a; - } - - int DrawCount = pCommand->m_DrawCount; - size_t RenderOffset = 0; - - // 4 for the center (always use vec4) and 16 for the matrix(just to be sure), 4 for the sampler and vertex color - const int RSPCount = 256 - 4 - 16 - 8; - - while(DrawCount > 0) - { - int UniformCount = (DrawCount > RSPCount ? RSPCount : DrawCount); - - m_pSpriteProgramMultiple->SetUniformVec4(m_pSpriteProgramMultiple->m_LocRSP, UniformCount, (float *)(pCommand->m_pRenderInfo + RenderOffset)); - - glDrawElementsInstanced(GL_TRIANGLES, pCommand->m_DrawNum, GL_UNSIGNED_INT, pCommand->m_pOffset, UniformCount); - - RenderOffset += RSPCount; - DrawCount -= RSPCount; - } -} - // ------------ CCommandProcessorFragment_SDL - -static void ParseVersionString(const char *pStr, int &VersionMajor, int &VersionMinor, int &VersionPatch) -{ - if(pStr) - { - char aCurNumberStr[32]; - size_t CurNumberStrLen = 0; - size_t TotalNumbersPassed = 0; - int aNumbers[3] = {0}; - bool LastWasNumber = false; - while(*pStr && TotalNumbersPassed < 3) - { - if(*pStr >= '0' && *pStr <= '9') - { - aCurNumberStr[CurNumberStrLen++] = (char)*pStr; - LastWasNumber = true; - } - else if(LastWasNumber && (*pStr == '.' || *pStr == ' ' || *pStr == '\0')) - { - int CurNumber = 0; - if(CurNumberStrLen > 0) - { - aCurNumberStr[CurNumberStrLen] = 0; - CurNumber = str_toint(aCurNumberStr); - aNumbers[TotalNumbersPassed++] = CurNumber; - CurNumberStrLen = 0; - } - - LastWasNumber = false; - - if(*pStr != '.') - break; - } - else - { - break; - } - - ++pStr; - } - - VersionMajor = aNumbers[0]; - VersionMinor = aNumbers[1]; - VersionPatch = aNumbers[2]; - } -} - -static const char *GetGLErrorName(GLenum Type) -{ - if(Type == GL_DEBUG_TYPE_ERROR) - return "ERROR"; - else if(Type == GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR) - return "DEPRECATED BEHAVIOR"; - else if(Type == GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR) - return "UNDEFINED BEHAVIOR"; - else if(Type == GL_DEBUG_TYPE_PORTABILITY) - return "PORTABILITY"; - else if(Type == GL_DEBUG_TYPE_PERFORMANCE) - return "PERFORMANCE"; - else if(Type == GL_DEBUG_TYPE_OTHER) - return "OTHER"; - else if(Type == GL_DEBUG_TYPE_MARKER) - return "MARKER"; - else if(Type == GL_DEBUG_TYPE_PUSH_GROUP) - return "PUSH_GROUP"; - else if(Type == GL_DEBUG_TYPE_POP_GROUP) - return "POP_GROUP"; - return "UNKNOWN"; -}; - -static const char *GetGLSeverity(GLenum Type) -{ - if(Type == GL_DEBUG_SEVERITY_HIGH) - return "high"; // All OpenGL Errors, shader compilation/linking errors, or highly-dangerous undefined behavior - else if(Type == GL_DEBUG_SEVERITY_MEDIUM) - return "medium"; // Major performance warnings, shader compilation/linking warnings, or the use of deprecated functionality - else if(Type == GL_DEBUG_SEVERITY_LOW) - return "low"; // Redundant state change performance warning, or unimportant undefined behavior - else if(Type == GL_DEBUG_SEVERITY_NOTIFICATION) - return "notification"; // Anything that isn't an error or performance issue. - - return "unknown"; -} - -static void GLAPIENTRY -GfxOpenGLMessageCallback(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const GLchar *message, - const void *userParam) -{ - dbg_msg("gfx", "[%s] (importance: %s) %s", GetGLErrorName(type), GetGLSeverity(severity), message); -} - void CCommandProcessorFragment_SDL::Cmd_Init(const SCommand_Init *pCommand) { m_GLContext = pCommand->m_GLContext; m_pWindow = pCommand->m_pWindow; SDL_GL_MakeCurrent(m_pWindow, m_GLContext); - - // set some default settings - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - - glAlphaFunc(GL_GREATER, 0); - glEnable(GL_ALPHA_TEST); - glDepthMask(0); - - if(g_Config.m_DbgGfx) - { - if(GLEW_KHR_debug || GLEW_ARB_debug_output) - { - // During init, enable debug output - if(GLEW_KHR_debug) - { - glEnable(GL_DEBUG_OUTPUT); - glDebugMessageCallback(GfxOpenGLMessageCallback, 0); - } - else if(GLEW_ARB_debug_output) - { - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); - glDebugMessageCallbackARB(GfxOpenGLMessageCallback, 0); - } - dbg_msg("gfx", "Enabled OpenGL debug mode"); - } - else - dbg_msg("gfx", "Requested OpenGL debug mode, but the driver does not support the required extension"); - } - - const char *pVendorString = (const char *)glGetString(GL_VENDOR); - dbg_msg("opengl", "Vendor string: %s", pVendorString); - - // check what this context can do - const char *pVersionString = (const char *)glGetString(GL_VERSION); - dbg_msg("opengl", "Version string: %s", pVersionString); - - const char *pRendererString = (const char *)glGetString(GL_RENDERER); - - str_copy(pCommand->m_pVendorString, pVendorString, gs_GPUInfoStringSize); - str_copy(pCommand->m_pVersionString, pVersionString, gs_GPUInfoStringSize); - str_copy(pCommand->m_pRendererString, pRendererString, gs_GPUInfoStringSize); - - // parse version string - ParseVersionString(pVersionString, pCommand->m_pCapabilities->m_ContextMajor, pCommand->m_pCapabilities->m_ContextMinor, pCommand->m_pCapabilities->m_ContextPatch); - - *pCommand->m_pInitError = 0; - - int BlocklistMajor = -1, BlocklistMinor = -1, BlocklistPatch = -1; - const char *pErrString = ParseBlocklistDriverVersions(pVendorString, pVersionString, BlocklistMajor, BlocklistMinor, BlocklistPatch); - //if the driver is buggy, and the requested GL version is the default, fallback - if(pErrString != NULL && pCommand->m_RequestedMajor == 3 && pCommand->m_RequestedMinor == 0 && pCommand->m_RequestedPatch == 0) - { - // if not already in the error state, set the GL version - if(g_Config.m_GfxDriverIsBlocked == 0) - { - // fallback to known good GL version - pCommand->m_pCapabilities->m_ContextMajor = BlocklistMajor; - pCommand->m_pCapabilities->m_ContextMinor = BlocklistMinor; - pCommand->m_pCapabilities->m_ContextPatch = BlocklistPatch; - - // set backend error string - *pCommand->m_pErrStringPtr = pErrString; - *pCommand->m_pInitError = -2; - - g_Config.m_GfxDriverIsBlocked = 1; - } - } - // if the driver was in a blocked error state, but is not anymore, reset all config variables - else if(pErrString == NULL && g_Config.m_GfxDriverIsBlocked == 1) - { - pCommand->m_pCapabilities->m_ContextMajor = 3; - pCommand->m_pCapabilities->m_ContextMinor = 0; - pCommand->m_pCapabilities->m_ContextPatch = 0; - - // tell the caller to reinitialize the context - *pCommand->m_pInitError = -2; - - g_Config.m_GfxDriverIsBlocked = 0; - } - - int MajorV = pCommand->m_pCapabilities->m_ContextMajor; - int MinorV = pCommand->m_pCapabilities->m_ContextMinor; - - if(*pCommand->m_pInitError == 0) - { - if(MajorV < pCommand->m_RequestedMajor) - { - *pCommand->m_pInitError = -2; - } - else if(MajorV == pCommand->m_RequestedMajor) - { - if(MinorV < pCommand->m_RequestedMinor) - { - *pCommand->m_pInitError = -2; - } - else if(MinorV == pCommand->m_RequestedMinor) - { - int PatchV = pCommand->m_pCapabilities->m_ContextPatch; - if(PatchV < pCommand->m_RequestedPatch) - { - *pCommand->m_pInitError = -2; - } - } - } - } - - if(*pCommand->m_pInitError == 0) - { - MajorV = pCommand->m_RequestedMajor; - MinorV = pCommand->m_RequestedMinor; - - pCommand->m_pCapabilities->m_2DArrayTexturesAsExtension = false; - pCommand->m_pCapabilities->m_NPOTTextures = true; - - if(MajorV >= 4 || (MajorV == 3 && MinorV == 3)) - { - pCommand->m_pCapabilities->m_TileBuffering = true; - pCommand->m_pCapabilities->m_QuadBuffering = true; - pCommand->m_pCapabilities->m_TextBuffering = true; - pCommand->m_pCapabilities->m_QuadContainerBuffering = true; - pCommand->m_pCapabilities->m_ShaderSupport = true; - - pCommand->m_pCapabilities->m_MipMapping = true; - pCommand->m_pCapabilities->m_3DTextures = true; - pCommand->m_pCapabilities->m_2DArrayTextures = true; - } - else if(MajorV == 3) - { - pCommand->m_pCapabilities->m_MipMapping = true; - // check for context native 2D array texture size - pCommand->m_pCapabilities->m_3DTextures = false; - pCommand->m_pCapabilities->m_2DArrayTextures = false; - pCommand->m_pCapabilities->m_ShaderSupport = true; - - int TextureLayers = 0; - glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &TextureLayers); - if(TextureLayers >= 256) - { - pCommand->m_pCapabilities->m_2DArrayTextures = true; - } - - int Texture3DSize = 0; - glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &Texture3DSize); - if(Texture3DSize >= 256) - { - pCommand->m_pCapabilities->m_3DTextures = true; - } - - if(!pCommand->m_pCapabilities->m_3DTextures && !pCommand->m_pCapabilities->m_2DArrayTextures) - { - *pCommand->m_pInitError = -2; - pCommand->m_pCapabilities->m_ContextMajor = 1; - pCommand->m_pCapabilities->m_ContextMinor = 5; - pCommand->m_pCapabilities->m_ContextPatch = 0; - } - - pCommand->m_pCapabilities->m_TileBuffering = pCommand->m_pCapabilities->m_2DArrayTextures || pCommand->m_pCapabilities->m_3DTextures; - pCommand->m_pCapabilities->m_QuadBuffering = false; - pCommand->m_pCapabilities->m_TextBuffering = false; - pCommand->m_pCapabilities->m_QuadContainerBuffering = false; - } - else if(MajorV == 2) - { - pCommand->m_pCapabilities->m_MipMapping = true; - // check for context extension: 2D array texture and its max size - pCommand->m_pCapabilities->m_3DTextures = false; - pCommand->m_pCapabilities->m_2DArrayTextures = false; - - pCommand->m_pCapabilities->m_ShaderSupport = false; - if(MinorV >= 1) - pCommand->m_pCapabilities->m_ShaderSupport = true; - - int Texture3DSize = 0; - glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &Texture3DSize); - if(Texture3DSize >= 256) - { - pCommand->m_pCapabilities->m_3DTextures = true; - } - - // check for array texture extension - if(pCommand->m_pCapabilities->m_ShaderSupport && GLEW_EXT_texture_array) - { - int TextureLayers = 0; - glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS_EXT, &TextureLayers); - if(TextureLayers >= 256) - { - pCommand->m_pCapabilities->m_2DArrayTextures = true; - pCommand->m_pCapabilities->m_2DArrayTexturesAsExtension = true; - } - } - - pCommand->m_pCapabilities->m_TileBuffering = pCommand->m_pCapabilities->m_2DArrayTextures || pCommand->m_pCapabilities->m_3DTextures; - pCommand->m_pCapabilities->m_QuadBuffering = false; - pCommand->m_pCapabilities->m_TextBuffering = false; - pCommand->m_pCapabilities->m_QuadContainerBuffering = false; - - if(GLEW_ARB_texture_non_power_of_two || pCommand->m_GlewMajor > 2) - pCommand->m_pCapabilities->m_NPOTTextures = true; - else - { - pCommand->m_pCapabilities->m_NPOTTextures = false; - } - - if(!pCommand->m_pCapabilities->m_NPOTTextures || (!pCommand->m_pCapabilities->m_3DTextures && !pCommand->m_pCapabilities->m_2DArrayTextures)) - { - *pCommand->m_pInitError = -2; - pCommand->m_pCapabilities->m_ContextMajor = 1; - pCommand->m_pCapabilities->m_ContextMinor = 5; - pCommand->m_pCapabilities->m_ContextPatch = 0; - } - } - else if(MajorV < 2) - { - pCommand->m_pCapabilities->m_TileBuffering = false; - pCommand->m_pCapabilities->m_QuadBuffering = false; - pCommand->m_pCapabilities->m_TextBuffering = false; - pCommand->m_pCapabilities->m_QuadContainerBuffering = false; - pCommand->m_pCapabilities->m_ShaderSupport = false; - - pCommand->m_pCapabilities->m_MipMapping = false; - pCommand->m_pCapabilities->m_3DTextures = false; - pCommand->m_pCapabilities->m_2DArrayTextures = false; - pCommand->m_pCapabilities->m_NPOTTextures = false; - } - } } void CCommandProcessorFragment_SDL::Cmd_Update_Viewport(const SCommand_Update_Viewport *pCommand) @@ -4083,23 +270,39 @@ void CCommandProcessor_SDL_OpenGL::RunBuffer(CCommandBuffer *pBuffer) } } -CCommandProcessor_SDL_OpenGL::CCommandProcessor_SDL_OpenGL(int OpenGLMajor, int OpenGLMinor, int OpenGLPatch) +CCommandProcessor_SDL_OpenGL::CCommandProcessor_SDL_OpenGL(EBackendType BackendType, int OpenGLMajor, int OpenGLMinor, int OpenGLPatch) { - if(OpenGLMajor < 2) + m_BackendType = BackendType; + + if(BackendType == BACKEND_TYPE_OPENGL_ES) { - m_pOpenGL = new CCommandProcessorFragment_OpenGL(); + if(OpenGLMajor < 3) + { + m_pOpenGL = new CCommandProcessorFragment_OpenGL(); + } + else + { + m_pOpenGL = new CCommandProcessorFragment_OpenGL3_3(); + } } - if(OpenGLMajor == 2) + else if(BackendType == BACKEND_TYPE_OPENGL) { - m_pOpenGL = new CCommandProcessorFragment_OpenGL2(); - } - if(OpenGLMajor == 3 && OpenGLMinor == 0) - { - m_pOpenGL = new CCommandProcessorFragment_OpenGL3(); - } - else if((OpenGLMajor == 3 && OpenGLMinor == 3) || OpenGLMajor >= 4) - { - m_pOpenGL = new CCommandProcessorFragment_OpenGL3_3(); + if(OpenGLMajor < 2) + { + m_pOpenGL = new CCommandProcessorFragment_OpenGL(); + } + if(OpenGLMajor == 2) + { + m_pOpenGL = new CCommandProcessorFragment_OpenGL2(); + } + if(OpenGLMajor == 3 && OpenGLMinor == 0) + { + m_pOpenGL = new CCommandProcessorFragment_OpenGL3(); + } + else if((OpenGLMajor == 3 && OpenGLMinor == 3) || OpenGLMajor >= 4) + { + m_pOpenGL = new CCommandProcessorFragment_OpenGL3_3(); + } } } @@ -4110,222 +313,307 @@ CCommandProcessor_SDL_OpenGL::~CCommandProcessor_SDL_OpenGL() // ------------ CGraphicsBackend_SDL_OpenGL -static void GetGlewVersion(int &GlewMajor, int &GlewMinor, int &GlewPatch) +static bool BackendInitGlew(EBackendType BackendType, int &GlewMajor, int &GlewMinor, int &GlewPatch) { + if(BackendType == BACKEND_TYPE_OPENGL) + { +#ifndef CONF_BACKEND_OPENGL_ES + //support graphic cards that are pretty old(and linux) + glewExperimental = GL_TRUE; + if(GLEW_OK != glewInit()) + return false; + #ifdef GLEW_VERSION_4_6 - if(GLEW_VERSION_4_6) - { - GlewMajor = 4; - GlewMinor = 6; - GlewPatch = 0; - return; - } + if(GLEW_VERSION_4_6) + { + GlewMajor = 4; + GlewMinor = 6; + GlewPatch = 0; + return true; + } +#endif + if(GLEW_VERSION_4_5) + { + GlewMajor = 4; + GlewMinor = 5; + GlewPatch = 0; + return true; + } + if(GLEW_VERSION_4_4) + { + GlewMajor = 4; + GlewMinor = 4; + GlewPatch = 0; + return true; + } + if(GLEW_VERSION_4_3) + { + GlewMajor = 4; + GlewMinor = 3; + GlewPatch = 0; + return true; + } + if(GLEW_VERSION_4_2) + { + GlewMajor = 4; + GlewMinor = 2; + GlewPatch = 0; + return true; + } + if(GLEW_VERSION_4_1) + { + GlewMajor = 4; + GlewMinor = 1; + GlewPatch = 0; + return true; + } + if(GLEW_VERSION_4_0) + { + GlewMajor = 4; + GlewMinor = 0; + GlewPatch = 0; + return true; + } + if(GLEW_VERSION_3_3) + { + GlewMajor = 3; + GlewMinor = 3; + GlewPatch = 0; + return true; + } + if(GLEW_VERSION_3_0) + { + GlewMajor = 3; + GlewMinor = 0; + GlewPatch = 0; + return true; + } + if(GLEW_VERSION_2_1) + { + GlewMajor = 2; + GlewMinor = 1; + GlewPatch = 0; + return true; + } + if(GLEW_VERSION_2_0) + { + GlewMajor = 2; + GlewMinor = 0; + GlewPatch = 0; + return true; + } + if(GLEW_VERSION_1_5) + { + GlewMajor = 1; + GlewMinor = 5; + GlewPatch = 0; + return true; + } + if(GLEW_VERSION_1_4) + { + GlewMajor = 1; + GlewMinor = 4; + GlewPatch = 0; + return true; + } + if(GLEW_VERSION_1_3) + { + GlewMajor = 1; + GlewMinor = 3; + GlewPatch = 0; + return true; + } + if(GLEW_VERSION_1_2_1) + { + GlewMajor = 1; + GlewMinor = 2; + GlewPatch = 1; + return true; + } + if(GLEW_VERSION_1_2) + { + GlewMajor = 1; + GlewMinor = 2; + GlewPatch = 0; + return true; + } + if(GLEW_VERSION_1_1) + { + GlewMajor = 1; + GlewMinor = 1; + GlewPatch = 0; + return true; + } #endif - if(GLEW_VERSION_4_5) - { - GlewMajor = 4; - GlewMinor = 5; - GlewPatch = 0; - return; } - if(GLEW_VERSION_4_4) - { - GlewMajor = 4; - GlewMinor = 4; - GlewPatch = 0; - return; - } - if(GLEW_VERSION_4_3) - { - GlewMajor = 4; - GlewMinor = 3; - GlewPatch = 0; - return; - } - if(GLEW_VERSION_4_2) - { - GlewMajor = 4; - GlewMinor = 2; - GlewPatch = 0; - return; - } - if(GLEW_VERSION_4_1) - { - GlewMajor = 4; - GlewMinor = 1; - GlewPatch = 0; - return; - } - if(GLEW_VERSION_4_0) - { - GlewMajor = 4; - GlewMinor = 0; - GlewPatch = 0; - return; - } - if(GLEW_VERSION_3_3) - { - GlewMajor = 3; - GlewMinor = 3; - GlewPatch = 0; - return; - } - if(GLEW_VERSION_3_0) + else if(BackendType == BACKEND_TYPE_OPENGL_ES) { + // just assume the version we need GlewMajor = 3; GlewMinor = 0; GlewPatch = 0; - return; - } - if(GLEW_VERSION_2_1) - { - GlewMajor = 2; - GlewMinor = 1; - GlewPatch = 0; - return; - } - if(GLEW_VERSION_2_0) - { - GlewMajor = 2; - GlewMinor = 0; - GlewPatch = 0; - return; - } - if(GLEW_VERSION_1_5) - { - GlewMajor = 1; - GlewMinor = 5; - GlewPatch = 0; - return; - } - if(GLEW_VERSION_1_4) - { - GlewMajor = 1; - GlewMinor = 4; - GlewPatch = 0; - return; - } - if(GLEW_VERSION_1_3) - { - GlewMajor = 1; - GlewMinor = 3; - GlewPatch = 0; - return; - } - if(GLEW_VERSION_1_2_1) - { - GlewMajor = 1; - GlewMinor = 2; - GlewPatch = 1; - return; - } - if(GLEW_VERSION_1_2) - { - GlewMajor = 1; - GlewMinor = 2; - GlewPatch = 0; - return; - } - if(GLEW_VERSION_1_1) - { - GlewMajor = 1; - GlewMinor = 1; - GlewPatch = 0; - return; + + return true; } + + return true; } -static int IsVersionSupportedGlew(int VersionMajor, int VersionMinor, int VersionPatch, int GlewMajor, int GlewMinor, int GlewPatch) +static int IsVersionSupportedGlew(EBackendType BackendType, int VersionMajor, int VersionMinor, int VersionPatch, int GlewMajor, int GlewMinor, int GlewPatch) { int InitError = 0; - if(VersionMajor >= 4 && GlewMajor < 4) + + if(BackendType == BACKEND_TYPE_OPENGL) { - InitError = -1; - } - else if(VersionMajor >= 3 && GlewMajor < 3) - { - InitError = -1; - } - else if(VersionMajor == 3 && GlewMajor == 3) - { - if(VersionMinor >= 3 && GlewMinor < 3) + if(VersionMajor >= 4 && GlewMajor < 4) { InitError = -1; } - if(VersionMinor >= 2 && GlewMinor < 2) + else if(VersionMajor >= 3 && GlewMajor < 3) { InitError = -1; } - if(VersionMinor >= 1 && GlewMinor < 1) + else if(VersionMajor == 3 && GlewMajor == 3) { - InitError = -1; - } - if(VersionMinor >= 0 && GlewMinor < 0) - { - InitError = -1; - } - } - else if(VersionMajor >= 2 && GlewMajor < 2) - { - InitError = -1; - } - else if(VersionMajor == 2 && GlewMajor == 2) - { - if(VersionMinor >= 1 && GlewMinor < 1) - { - InitError = -1; - } - if(VersionMinor >= 0 && GlewMinor < 0) - { - InitError = -1; - } - } - else if(VersionMajor >= 1 && GlewMajor < 1) - { - InitError = -1; - } - else if(VersionMajor == 1 && GlewMajor == 1) - { - if(VersionMinor >= 5 && GlewMinor < 5) - { - InitError = -1; - } - if(VersionMinor >= 4 && GlewMinor < 4) - { - InitError = -1; - } - if(VersionMinor >= 3 && GlewMinor < 3) - { - InitError = -1; - } - if(VersionMinor >= 2 && GlewMinor < 2) - { - InitError = -1; - } - else if(VersionMinor == 2 && GlewMinor == 2) - { - if(VersionPatch >= 1 && GlewPatch < 1) + if(VersionMinor >= 3 && GlewMinor < 3) { InitError = -1; } - if(VersionPatch >= 0 && GlewPatch < 0) + if(VersionMinor >= 2 && GlewMinor < 2) + { + InitError = -1; + } + if(VersionMinor >= 1 && GlewMinor < 1) + { + InitError = -1; + } + if(VersionMinor >= 0 && GlewMinor < 0) { InitError = -1; } } - if(VersionMinor >= 1 && GlewMinor < 1) + else if(VersionMajor >= 2 && GlewMajor < 2) { InitError = -1; } - if(VersionMinor >= 0 && GlewMinor < 0) + else if(VersionMajor == 2 && GlewMajor == 2) + { + if(VersionMinor >= 1 && GlewMinor < 1) + { + InitError = -1; + } + if(VersionMinor >= 0 && GlewMinor < 0) + { + InitError = -1; + } + } + else if(VersionMajor >= 1 && GlewMajor < 1) { InitError = -1; } + else if(VersionMajor == 1 && GlewMajor == 1) + { + if(VersionMinor >= 5 && GlewMinor < 5) + { + InitError = -1; + } + if(VersionMinor >= 4 && GlewMinor < 4) + { + InitError = -1; + } + if(VersionMinor >= 3 && GlewMinor < 3) + { + InitError = -1; + } + if(VersionMinor >= 2 && GlewMinor < 2) + { + InitError = -1; + } + else if(VersionMinor == 2 && GlewMinor == 2) + { + if(VersionPatch >= 1 && GlewPatch < 1) + { + InitError = -1; + } + if(VersionPatch >= 0 && GlewPatch < 0) + { + InitError = -1; + } + } + if(VersionMinor >= 1 && GlewMinor < 1) + { + InitError = -1; + } + if(VersionMinor >= 0 && GlewMinor < 0) + { + InitError = -1; + } + } } return InitError; } +EBackendType CGraphicsBackend_SDL_OpenGL::DetectBackend() +{ +#ifndef CONF_BACKEND_OPENGL_ES + return BACKEND_TYPE_OPENGL; +#else + return BACKEND_TYPE_OPENGL_ES; +#endif +} + +void CGraphicsBackend_SDL_OpenGL::ClampDriverVersion(EBackendType BackendType) +{ + if(BackendType == BACKEND_TYPE_OPENGL) + { + //clamp the versions to existing versions(only for OpenGL major <= 3) + if(g_Config.m_GfxOpenGLMajor == 1) + { + g_Config.m_GfxOpenGLMinor = clamp(g_Config.m_GfxOpenGLMinor, 1, 5); + if(g_Config.m_GfxOpenGLMinor == 2) + g_Config.m_GfxOpenGLPatch = clamp(g_Config.m_GfxOpenGLPatch, 0, 1); + else + g_Config.m_GfxOpenGLPatch = 0; + } + else if(g_Config.m_GfxOpenGLMajor == 2) + { + g_Config.m_GfxOpenGLMinor = clamp(g_Config.m_GfxOpenGLMinor, 0, 1); + g_Config.m_GfxOpenGLPatch = 0; + } + else if(g_Config.m_GfxOpenGLMajor == 3) + { + g_Config.m_GfxOpenGLMinor = clamp(g_Config.m_GfxOpenGLMinor, 0, 3); + if(g_Config.m_GfxOpenGLMinor < 3) + g_Config.m_GfxOpenGLMinor = 0; + g_Config.m_GfxOpenGLPatch = 0; + } + } + else if(BackendType == BACKEND_TYPE_OPENGL_ES) + { + // Make sure GLES is set to 1.0 (which is equivalent to OpenGL 1.3), if its not set to >= 3.0(which is equivalent to OpenGL 3.3) + if(g_Config.m_GfxOpenGLMajor < 3) + { + g_Config.m_GfxOpenGLMajor = 1; + g_Config.m_GfxOpenGLMinor = 0; + g_Config.m_GfxOpenGLPatch = 0; + + // GLES also doesnt know GL_QUAD + g_Config.m_GfxQuadAsTriangle = 1; + } + } +} + +bool CGraphicsBackend_SDL_OpenGL::IsModernAPI(EBackendType BackendType) +{ + if(BackendType == BACKEND_TYPE_OPENGL) + return (g_Config.m_GfxOpenGLMajor == 3 && g_Config.m_GfxOpenGLMinor == 3) || g_Config.m_GfxOpenGLMajor >= 4; + else if(BackendType == BACKEND_TYPE_OPENGL_ES) + return g_Config.m_GfxOpenGLMajor >= 3; + + return false; +} + int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidth, int *pHeight, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight, int *pCurrentWidth, int *pCurrentHeight, IStorage *pStorage) { // print sdl version @@ -4348,115 +636,30 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt } } - SDL_ClearError(); - const char *pErr = NULL; + EBackendType BackendType = DetectBackend(); - // Query default values, since they are platform dependent - static bool s_InitDefaultParams = false; - static int s_SDLGLContextProfileMask, s_SDLGLContextMajorVersion, s_SDLGLContextMinorVersion; - static bool s_TriedOpenGL3Context = false; + ClampDriverVersion(BackendType); - if(!s_InitDefaultParams) + m_UseNewOpenGL = IsModernAPI(BackendType); + + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, g_Config.m_GfxOpenGLMajor); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, g_Config.m_GfxOpenGLMinor); + dbg_msg("gfx", "Created OpenGL %zu.%zu context.", (size_t)g_Config.m_GfxOpenGLMajor, (size_t)g_Config.m_GfxOpenGLMinor); + + if(BackendType == BACKEND_TYPE_OPENGL) { - SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &s_SDLGLContextProfileMask); - SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &s_SDLGLContextMajorVersion); - SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &s_SDLGLContextMinorVersion); - s_InitDefaultParams = true; - } - - //clamp the versions to existing versions(only for OpenGL major <= 3) - if(g_Config.m_GfxOpenGLMajor == 1) - { - g_Config.m_GfxOpenGLMinor = clamp(g_Config.m_GfxOpenGLMinor, 1, 5); - if(g_Config.m_GfxOpenGLMinor == 2) - g_Config.m_GfxOpenGLPatch = clamp(g_Config.m_GfxOpenGLPatch, 0, 1); - else - g_Config.m_GfxOpenGLPatch = 0; - } - else if(g_Config.m_GfxOpenGLMajor == 2) - { - g_Config.m_GfxOpenGLMinor = clamp(g_Config.m_GfxOpenGLMinor, 0, 1); - g_Config.m_GfxOpenGLPatch = 0; - } - else if(g_Config.m_GfxOpenGLMajor == 3) - { - g_Config.m_GfxOpenGLMinor = clamp(g_Config.m_GfxOpenGLMinor, 0, 3); - if(g_Config.m_GfxOpenGLMinor < 3) - g_Config.m_GfxOpenGLMinor = 0; - g_Config.m_GfxOpenGLPatch = 0; - } - - // if OpenGL3 context was tried to be created, but failed, we have to restore the old context attributes - bool IsNewOpenGL = (g_Config.m_GfxOpenGLMajor == 3 && g_Config.m_GfxOpenGLMinor == 3) || g_Config.m_GfxOpenGLMajor >= 4; - if(s_TriedOpenGL3Context && !IsNewOpenGL) - { - s_TriedOpenGL3Context = false; - - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, s_SDLGLContextProfileMask); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, s_SDLGLContextMajorVersion); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, s_SDLGLContextMinorVersion); - } - - m_UseNewOpenGL = false; - if(IsNewOpenGL) - { - s_TriedOpenGL3Context = true; - - if(SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE) == 0) - { - pErr = SDL_GetError(); - if(pErr[0] != '\0') - { - dbg_msg("gfx", "Using old OpenGL context, because an error occurred while trying to use OpenGL context %zu.%zu: %s.", (size_t)g_Config.m_GfxOpenGLMajor, (size_t)g_Config.m_GfxOpenGLMinor, pErr); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, s_SDLGLContextProfileMask); - } - else - { - if(SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, g_Config.m_GfxOpenGLMajor) == 0 && SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, g_Config.m_GfxOpenGLMinor) == 0) - { - pErr = SDL_GetError(); - if(pErr[0] != '\0') - { - dbg_msg("gfx", "Using old OpenGL context, because an error occurred while trying to use OpenGL context %zu.%zu: %s.", (size_t)g_Config.m_GfxOpenGLMajor, (size_t)g_Config.m_GfxOpenGLMinor, pErr); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, s_SDLGLContextMajorVersion); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, s_SDLGLContextMinorVersion); - } - else - { - m_UseNewOpenGL = true; - int vMaj, vMin; - SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &vMaj); - SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &vMin); - dbg_msg("gfx", "Using OpenGL version %d.%d.", vMaj, vMin); - } - } - else - { - dbg_msg("gfx", "Couldn't create OpenGL %zu.%zu context.", (size_t)g_Config.m_GfxOpenGLMajor, (size_t)g_Config.m_GfxOpenGLMinor); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, s_SDLGLContextMajorVersion); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, s_SDLGLContextMinorVersion); - } - } - } - else - { - //set default attributes - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, s_SDLGLContextProfileMask); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, s_SDLGLContextMajorVersion); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, s_SDLGLContextMinorVersion); - } - } - //if non standard opengl, set it - else if(s_SDLGLContextMajorVersion != g_Config.m_GfxOpenGLMajor || s_SDLGLContextMinorVersion != g_Config.m_GfxOpenGLMinor) - { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, g_Config.m_GfxOpenGLMajor); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, g_Config.m_GfxOpenGLMinor); - dbg_msg("gfx", "Created OpenGL %zu.%zu context.", (size_t)g_Config.m_GfxOpenGLMajor, (size_t)g_Config.m_GfxOpenGLMinor); - if(g_Config.m_GfxOpenGLMajor == 3 && g_Config.m_GfxOpenGLMinor == 0) { SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); } + else if(m_UseNewOpenGL) + { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + } + } + else if(BackendType == BACKEND_TYPE_OPENGL_ES) + { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); } // set screen @@ -4569,25 +772,26 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt if(m_GLContext == NULL) { + SDL_DestroyWindow(m_pWindow); dbg_msg("gfx", "unable to create OpenGL context: %s", SDL_GetError()); return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_OPENGL_CONTEXT_FAILED; } - //support graphic cards that are pretty old(and linux) - glewExperimental = GL_TRUE; - if(GLEW_OK != glewInit()) - return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_UNKNOWN; - int GlewMajor = 0; int GlewMinor = 0; int GlewPatch = 0; - GetGlewVersion(GlewMajor, GlewMinor, GlewPatch); + if(!BackendInitGlew(BackendType, GlewMajor, GlewMinor, GlewPatch)) + { + SDL_GL_DeleteContext(m_GLContext); + SDL_DestroyWindow(m_pWindow); + return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_UNKNOWN; + } int InitError = 0; const char *pErrorStr = NULL; - InitError = IsVersionSupportedGlew(g_Config.m_GfxOpenGLMajor, g_Config.m_GfxOpenGLMinor, g_Config.m_GfxOpenGLPatch, GlewMajor, GlewMinor, GlewPatch); + InitError = IsVersionSupportedGlew(BackendType, g_Config.m_GfxOpenGLMajor, g_Config.m_GfxOpenGLMinor, g_Config.m_GfxOpenGLPatch, GlewMajor, GlewMinor, GlewPatch); SDL_GL_GetDrawableSize(m_pWindow, pCurrentWidth, pCurrentHeight); SDL_GL_SetSwapInterval(Flags & IGraphicsBackend::INITFLAG_VSYNC ? 1 : 0); @@ -4607,7 +811,7 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt } // start the command processor - m_pProcessor = new CCommandProcessor_SDL_OpenGL(g_Config.m_GfxOpenGLMajor, g_Config.m_GfxOpenGLMinor, g_Config.m_GfxOpenGLPatch); + m_pProcessor = new CCommandProcessor_SDL_OpenGL(BackendType, g_Config.m_GfxOpenGLMajor, g_Config.m_GfxOpenGLMinor, g_Config.m_GfxOpenGLPatch); StartProcessor(m_pProcessor); mem_zero(m_aErrorString, sizeof(m_aErrorString) / sizeof(m_aErrorString[0])); @@ -4618,18 +822,6 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt CCommandProcessorFragment_SDL::SCommand_Init CmdSDL; CmdSDL.m_pWindow = m_pWindow; CmdSDL.m_GLContext = m_GLContext; - CmdSDL.m_pCapabilities = &m_Capabilites; - CmdSDL.m_RequestedMajor = g_Config.m_GfxOpenGLMajor; - CmdSDL.m_RequestedMinor = g_Config.m_GfxOpenGLMinor; - CmdSDL.m_RequestedPatch = g_Config.m_GfxOpenGLPatch; - CmdSDL.m_GlewMajor = GlewMajor; - CmdSDL.m_GlewMinor = GlewMinor; - CmdSDL.m_GlewPatch = GlewPatch; - CmdSDL.m_pInitError = &InitError; - CmdSDL.m_pErrStringPtr = &pErrorStr; - CmdSDL.m_pVendorString = m_aVendorString; - CmdSDL.m_pVersionString = m_aVersionString; - CmdSDL.m_pRendererString = m_aRendererString; CmdBuffer.AddCommandUnsafe(CmdSDL); RunBuffer(&CmdBuffer); WaitForIdle(); @@ -4642,7 +834,21 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt CmdOpenGL.m_pStorage = pStorage; CmdOpenGL.m_pCapabilities = &m_Capabilites; CmdOpenGL.m_pInitError = &InitError; + CmdOpenGL.m_pCapabilities = &m_Capabilites; + CmdOpenGL.m_RequestedMajor = g_Config.m_GfxOpenGLMajor; + CmdOpenGL.m_RequestedMinor = g_Config.m_GfxOpenGLMinor; + CmdOpenGL.m_RequestedPatch = g_Config.m_GfxOpenGLPatch; + CmdOpenGL.m_GlewMajor = GlewMajor; + CmdOpenGL.m_GlewMinor = GlewMinor; + CmdOpenGL.m_GlewPatch = GlewPatch; + CmdOpenGL.m_pInitError = &InitError; + CmdOpenGL.m_pErrStringPtr = &pErrorStr; + CmdOpenGL.m_pVendorString = m_aVendorString; + CmdOpenGL.m_pVersionString = m_aVersionString; + CmdOpenGL.m_pRendererString = m_aRendererString; + CmdOpenGL.m_RequestedBackend = BackendType; CmdBuffer.AddCommandUnsafe(CmdOpenGL); + RunBuffer(&CmdBuffer); WaitForIdle(); CmdBuffer.Reset(); @@ -4655,9 +861,9 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt WaitForIdle(); CmdBuffer.Reset(); - g_Config.m_GfxOpenGLMajor = 1; - g_Config.m_GfxOpenGLMinor = 5; - g_Config.m_GfxOpenGLPatch = 0; + g_Config.m_GfxOpenGLMajor = m_Capabilites.m_ContextMajor; + g_Config.m_GfxOpenGLMinor = m_Capabilites.m_ContextMinor; + g_Config.m_GfxOpenGLPatch = m_Capabilites.m_ContextPatch; } } diff --git a/src/engine/client/backend_sdl.h b/src/engine/client/backend_sdl.h index 4d383c0f9..2019713c7 100644 --- a/src/engine/client/backend_sdl.h +++ b/src/engine/client/backend_sdl.h @@ -2,7 +2,17 @@ #define ENGINE_CLIENT_BACKEND_SDL_H #include "SDL.h" -#include "SDL_opengl.h" + +#include + +#ifndef CONF_BACKEND_OPENGL_ES +#include +#else +#define GL_GLEXT_PROTOTYPES 1 +#include "SDL_opengles2.h" +#include +#include +#endif #include "blocklist_driver.h" #include "graphics_threaded.h" @@ -79,6 +89,12 @@ public: bool RunCommand(const CCommandBuffer::SCommand *pBaseCommand); }; +enum EBackendType +{ + BACKEND_TYPE_OPENGL = 0, + BACKEND_TYPE_OPENGL_ES, +}; + struct SBackendCapabilites { bool m_TileBuffering; @@ -150,6 +166,8 @@ protected: int m_OpenGLTextureLodBIAS; + bool m_IsOpenGLES; + public: enum { @@ -165,6 +183,22 @@ public: std::atomic *m_pTextureMemoryUsage; SBackendCapabilites *m_pCapabilities; int *m_pInitError; + + const char **m_pErrStringPtr; + + char *m_pVendorString; + char *m_pVersionString; + char *m_pRendererString; + + int m_RequestedMajor; + int m_RequestedMinor; + int m_RequestedPatch; + + EBackendType m_RequestedBackend; + + int m_GlewMajor; + int m_GlewMinor; + int m_GlewPatch; }; struct SCommand_Shutdown : public CCommandBuffer::SCommand @@ -175,6 +209,10 @@ public: protected: bool IsTexturedState(const CCommandBuffer::SState &State); + static bool Texture2DTo3D(void *pImageBuffer, int ImageWidth, int ImageHeight, int ImageColorChannelCount, int SplitCountWidth, int SplitCountHeight, void *pTarget3DImageData, int &Target3DImageWidth, int &Target3DImageHeight); + + void InitOpenGL(const SCommand_Init *pCommand); + void SetState(const CCommandBuffer::SState &State, bool Use2DArrayTexture = false); virtual bool IsNewApi() { return false; } void DestroyTexture(int Slot); @@ -427,23 +465,6 @@ public: SCommand(CMD_INIT) {} SDL_Window *m_pWindow; SDL_GLContext m_GLContext; - SBackendCapabilites *m_pCapabilities; - - const char **m_pErrStringPtr; - - int *m_pInitError; - - char *m_pVendorString; - char *m_pVersionString; - char *m_pRendererString; - - int m_RequestedMajor; - int m_RequestedMinor; - int m_RequestedPatch; - - int m_GlewMajor; - int m_GlewMinor; - int m_GlewPatch; }; struct SCommand_Update_Viewport : public CCommandBuffer::SCommand @@ -484,8 +505,10 @@ class CCommandProcessor_SDL_OpenGL : public CGraphicsBackend_Threaded::ICommandP CCommandProcessorFragment_SDL m_SDL; CCommandProcessorFragment_General m_General; + EBackendType m_BackendType; + public: - CCommandProcessor_SDL_OpenGL(int OpenGLMajor, int OpenGLMinor, int OpenGLPatch); + CCommandProcessor_SDL_OpenGL(EBackendType BackendType, int OpenGLMajor, int OpenGLMinor, int OpenGLPatch); virtual ~CCommandProcessor_SDL_OpenGL(); virtual void RunBuffer(CCommandBuffer *pBuffer); }; @@ -511,6 +534,9 @@ class CGraphicsBackend_SDL_OpenGL : public CGraphicsBackend_Threaded char m_aErrorString[256]; + static EBackendType DetectBackend(); + static void ClampDriverVersion(EBackendType BackendType); + public: virtual int Init(const char *pName, int *Screen, int *pWidth, int *pHeight, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight, int *pCurrentWidth, int *pCurrentHeight, class IStorage *pStorage); virtual int Shutdown(); @@ -560,6 +586,8 @@ public: { return m_aRendererString; } + + static bool IsModernAPI(EBackendType BackendType); }; #endif // ENGINE_CLIENT_BACKEND_SDL_H diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index 582d7fc6a..8ceac802d 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -456,8 +456,6 @@ IGraphics::CTextureHandle CGraphics_Threaded::LoadTextureRaw(int Width, int Heig Cmd.m_Flags = 0; if(Flags & IGraphics::TEXLOAD_NOMIPMAPS) Cmd.m_Flags |= CCommandBuffer::TEXFLAG_NOMIPMAPS; - if(g_Config.m_GfxTextureCompressionOld && ((Flags & IGraphics::TEXLOAD_NO_COMPRESSION) == 0)) - Cmd.m_Flags |= CCommandBuffer::TEXFLAG_COMPRESSED; if(g_Config.m_GfxTextureQualityOld || Flags & TEXLOAD_NORESAMPLE) Cmd.m_Flags |= CCommandBuffer::TEXFLAG_QUALITY; if((Flags & IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE) != 0) diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index 5abccc871..62d46a3f4 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -136,7 +136,6 @@ public: TEXFORMAT_ALPHA, TEXFLAG_NOMIPMAPS = 1, - TEXFLAG_COMPRESSED = 2, TEXFLAG_QUALITY = 4, TEXFLAG_TO_3D_TEXTURE = (1 << 3), TEXFLAG_TO_2D_ARRAY_TEXTURE = (1 << 4), diff --git a/src/engine/client/opengl_sl.cpp b/src/engine/client/opengl_sl.cpp index bc59e910a..2e35fac90 100644 --- a/src/engine/client/opengl_sl.cpp +++ b/src/engine/client/opengl_sl.cpp @@ -5,6 +5,8 @@ #include #include +#include + bool CGLSL::LoadShader(CGLSLCompiler *pCompiler, IStorage *pStorage, const char *pFile, int Type) { if(m_IsLoaded) @@ -14,10 +16,14 @@ bool CGLSL::LoadShader(CGLSLCompiler *pCompiler, IStorage *pStorage, const char std::vector Lines; if(f) { - bool IsNewOpenGL = pCompiler->m_OpenGLVersionMajor >= 4 || (pCompiler->m_OpenGLVersionMajor == 3 && pCompiler->m_OpenGLVersionMinor == 3); + EBackendType BackendType = pCompiler->m_IsOpenGLES ? BACKEND_TYPE_OPENGL_ES : BACKEND_TYPE_OPENGL; + bool IsNewOpenGL = (BackendType == BACKEND_TYPE_OPENGL ? (pCompiler->m_OpenGLVersionMajor >= 4 || (pCompiler->m_OpenGLVersionMajor == 3 && pCompiler->m_OpenGLVersionMinor == 3)) : pCompiler->m_OpenGLVersionMajor >= 3); + std::string GLShaderStringPostfix = std::string(" core\r\n"); + if(BackendType == BACKEND_TYPE_OPENGL_ES) + GLShaderStringPostfix = std::string(" es\r\n"); //add compiler specific values if(IsNewOpenGL) - Lines.push_back(std::string("#version ") + std::string(std::to_string(pCompiler->m_OpenGLVersionMajor)) + std::string(std::to_string(pCompiler->m_OpenGLVersionMinor)) + std::string(std::to_string(pCompiler->m_OpenGLVersionPatch)) + std::string(" core\r\n")); + Lines.push_back(std::string("#version ") + std::string(std::to_string(pCompiler->m_OpenGLVersionMajor)) + std::string(std::to_string(pCompiler->m_OpenGLVersionMinor)) + std::string(std::to_string(pCompiler->m_OpenGLVersionPatch)) + GLShaderStringPostfix); else { if(pCompiler->m_OpenGLVersionMajor == 3) @@ -38,6 +44,21 @@ bool CGLSL::LoadShader(CGLSLCompiler *pCompiler, IStorage *pStorage, const char } } + if(BackendType == BACKEND_TYPE_OPENGL_ES) + { + if(Type == GL_FRAGMENT_SHADER) + { + Lines.push_back("precision highp float; \r\n"); + Lines.push_back("precision highp sampler2D; \r\n"); + Lines.push_back("precision highp sampler3D; \r\n"); + Lines.push_back("precision highp samplerCube; \r\n"); + Lines.push_back("precision highp samplerCubeShadow; \r\n"); + Lines.push_back("precision highp sampler2DShadow; \r\n"); + Lines.push_back("precision highp sampler2DArray; \r\n"); + Lines.push_back("precision highp sampler2DArrayShadow; \r\n"); + } + } + for(CGLSLCompiler::SGLSLCompilerDefine &Define : pCompiler->m_Defines) { Lines.push_back(std::string("#define ") + Define.m_DefineName + std::string(" ") + Define.m_DefineValue + std::string("\r\n")); @@ -129,12 +150,16 @@ CGLSL::~CGLSL() DeleteShader(); } -CGLSLCompiler::CGLSLCompiler(int OpenGLVersionMajor, int OpenGLVersionMinor, int OpenGLVersionPatch) +CGLSLCompiler::CGLSLCompiler(int OpenGLVersionMajor, int OpenGLVersionMinor, int OpenGLVersionPatch, bool IsOpenGLES, float TextureLODBias) { m_OpenGLVersionMajor = OpenGLVersionMajor; m_OpenGLVersionMinor = OpenGLVersionMinor; m_OpenGLVersionPatch = OpenGLVersionPatch; + m_IsOpenGLES = IsOpenGLES; + + m_TextureLODBias = TextureLODBias; + m_HasTextureArray = false; m_TextureReplaceType = 0; } @@ -156,7 +181,8 @@ void CGLSLCompiler::ClearDefines() void CGLSLCompiler::ParseLine(std::string &Line, const char *pReadLine, int Type) { - bool IsNewOpenGL = m_OpenGLVersionMajor >= 4 || (m_OpenGLVersionMajor == 3 && m_OpenGLVersionMinor == 3); + EBackendType BackendType = m_IsOpenGLES ? BACKEND_TYPE_OPENGL_ES : BACKEND_TYPE_OPENGL; + bool IsNewOpenGL = (BackendType == BACKEND_TYPE_OPENGL ? (m_OpenGLVersionMajor >= 4 || (m_OpenGLVersionMajor == 3 && m_OpenGLVersionMinor == 3)) : m_OpenGLVersionMajor >= 3); if(!IsNewOpenGL) { const char *pBuff = pReadLine; @@ -274,6 +300,92 @@ void CGLSLCompiler::ParseLine(std::string &Line, const char *pReadLine, int Type } else { - Line = pReadLine; + if(BackendType == BACKEND_TYPE_OPENGL_ES) + { + const char *pBuff = pReadLine; + char aTmpStr[1024]; + size_t TmpStrSize = 0; + while(*pBuff) + { + while(*pBuff && str_isspace(*pBuff)) + { + Line.append(1, *pBuff); + ++pBuff; + } + + while(*pBuff && !str_isspace(*pBuff) && *pBuff != '(' && *pBuff != '.') + { + aTmpStr[TmpStrSize++] = *pBuff; + ++pBuff; + } + + if(TmpStrSize > 0) + { + aTmpStr[TmpStrSize] = 0; + TmpStrSize = 0; + + if(str_comp(aTmpStr, "noperspective") == 0) + { + Line.append("smooth"); + Line.append(pBuff); + return; + } + // since GLES doesnt support texture LOD bias as global state, use the shader function instead(since GLES 3.0 uses shaders only anyway) + else if(str_comp(aTmpStr, "texture") == 0) + { + Line.append("texture"); + // check opening and closing brackets to find the end + int CurBrackets = 1; + while(*pBuff && *pBuff != '(') + { + Line.append(1, *pBuff); + + ++pBuff; + } + + if(*pBuff) + { + Line.append(1, *pBuff); + ++pBuff; + } + + while(*pBuff) + { + if(*pBuff == '(') + ++CurBrackets; + if(*pBuff == ')') + --CurBrackets; + + if(CurBrackets == 0) + { + // found end + Line.append(std::string(", ") + std::to_string(m_TextureLODBias) + ")"); + ++pBuff; + break; + } + else + Line.append(1, *pBuff); + ++pBuff; + } + + Line.append(pBuff); + + return; + } + else + { + Line.append(aTmpStr); + } + } + + if(*pBuff) + { + Line.append(1, *pBuff); + ++pBuff; + } + } + } + else + Line = pReadLine; } } diff --git a/src/engine/client/opengl_sl.h b/src/engine/client/opengl_sl.h index f5f95bd8c..fceee29f1 100644 --- a/src/engine/client/opengl_sl.h +++ b/src/engine/client/opengl_sl.h @@ -1,7 +1,15 @@ #ifndef ENGINE_CLIENT_OPENGL_SL_H #define ENGINE_CLIENT_OPENGL_SL_H +#include + +#ifndef CONF_BACKEND_OPENGL_ES #include +#else +#define GL_GLEXT_PROTOTYPES 1 +#include "SDL_opengles2.h" +#endif + #include #include @@ -47,10 +55,14 @@ private: int m_OpenGLVersionMinor; int m_OpenGLVersionPatch; + bool m_IsOpenGLES; + + float m_TextureLODBias; + bool m_HasTextureArray; int m_TextureReplaceType; // @see EGLSLCompilerTextureReplaceType public: - CGLSLCompiler(int OpenGLVersionMajor, int OpenGLVersionMinor, int OpenGLVersionPatch); + CGLSLCompiler(int OpenGLVersionMajor, int OpenGLVersionMinor, int OpenGLVersionPatch, bool IsOpenGLES, float TextureLODBias); void SetHasTextureArray(bool TextureArray) { m_HasTextureArray = TextureArray; } void SetTextureReplaceType(int TextureReplaceType) { m_TextureReplaceType = TextureReplaceType; } diff --git a/src/engine/client/opengl_sl_program.cpp b/src/engine/client/opengl_sl_program.cpp index 2a0b696d5..e521a254c 100644 --- a/src/engine/client/opengl_sl_program.cpp +++ b/src/engine/client/opengl_sl_program.cpp @@ -99,11 +99,6 @@ void CGLSLProgram::SetUniform(int Loc, const int Value) glUniform1i(Loc, Value); } -void CGLSLProgram::SetUniform(int Loc, const unsigned int Value) -{ - glUniform1ui(Loc, Value); -} - void CGLSLProgram::SetUniform(int Loc, const float Value) { glUniform1f(Loc, Value); diff --git a/src/engine/client/opengl_sl_program.h b/src/engine/client/opengl_sl_program.h index 9d916959e..76cc64395 100644 --- a/src/engine/client/opengl_sl_program.h +++ b/src/engine/client/opengl_sl_program.h @@ -1,7 +1,14 @@ #ifndef ENGINE_CLIENT_OPENGL_SL_PROGRAM_H #define ENGINE_CLIENT_OPENGL_SL_PROGRAM_H +#include + +#ifndef CONF_BACKEND_OPENGL_ES #include +#else +#define GL_GLEXT_PROTOTYPES 1 +#include "SDL_opengles2.h" +#endif class CGLSL; @@ -25,7 +32,6 @@ public: void SetUniformVec2(int Loc, int Count, const float *pValue); void SetUniformVec4(int Loc, int Count, const float *pValue); void SetUniform(int Loc, const int Value); - void SetUniform(int Loc, const unsigned int Value); void SetUniform(int Loc, const bool Value); void SetUniform(int Loc, const float Value); void SetUniform(int Loc, int Count, const float *pValues); diff --git a/src/engine/client/video.h b/src/engine/client/video.h index 6d8c64c11..04ab2cf66 100644 --- a/src/engine/client/video.h +++ b/src/engine/client/video.h @@ -1,7 +1,9 @@ #ifndef ENGINE_CLIENT_VIDEO_H #define ENGINE_CLIENT_VIDEO_H -#if defined(__ANDROID__) +#include + +#if defined(CONF_BACKEND_OPENGL_ES) #define GL_GLEXT_PROTOTYPES #include #include @@ -26,8 +28,6 @@ extern "C" { #include }; -#include - #include #include #define ALEN 2048 diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index c193f9113..16b9d1701 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -112,7 +112,6 @@ MACRO_CONFIG_INT(GfxColorDepth, gfx_color_depth, 24, 16, 24, CFGFLAG_SAVE | CFGF MACRO_CONFIG_INT(GfxVsync, gfx_vsync, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Vertical sync (may cause delay)") MACRO_CONFIG_INT(GfxResizable, gfx_resizable, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Enables window resizing") MACRO_CONFIG_INT(GfxDisplayAllModes, gfx_display_all_modes, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "") -MACRO_CONFIG_INT(GfxTextureCompressionOld, gfx_texture_compression_old, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Use texture compression") MACRO_CONFIG_INT(GfxTextureQualityOld, gfx_texture_quality_old, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "") MACRO_CONFIG_INT(GfxHighDetail, gfx_high_detail, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "High detail") MACRO_CONFIG_INT(GfxFsaaSamples, gfx_fsaa_samples, 0, 0, 16, CFGFLAG_SAVE | CFGFLAG_CLIENT, "FSAA Samples") diff --git a/src/game/client/components/menus_settings.cpp b/src/game/client/components/menus_settings.cpp index f6080a07e..81f41163a 100644 --- a/src/game/client/components/menus_settings.cpp +++ b/src/game/client/components/menus_settings.cpp @@ -1080,7 +1080,11 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView) static int s_GfxColorDepth = g_Config.m_GfxColorDepth; static int s_GfxVsync = g_Config.m_GfxVsync; static int s_GfxFsaaSamples = g_Config.m_GfxFsaaSamples; +#ifndef CONF_BACKEND_OPENGL_ES static int s_GfxOpenGLVersion = (g_Config.m_GfxOpenGLMajor == 3 && g_Config.m_GfxOpenGLMinor == 3) || g_Config.m_GfxOpenGLMajor >= 4; +#else + static int s_GfxOpenGLVersion = g_Config.m_GfxOpenGLMajor >= 3; +#endif static int s_GfxEnableTextureUnitOptimization = g_Config.m_GfxEnableTextureUnitOptimization; static int s_GfxUsePreinitBuffer = g_Config.m_GfxUsePreinitBuffer; static int s_GfxHighdpi = g_Config.m_GfxHighdpi; @@ -1201,10 +1205,16 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView) g_Config.m_GfxHighDetail ^= 1; MainView.HSplitTop(20.0f, &Button, &MainView); +#ifndef CONF_BACKEND_OPENGL_ES bool IsNewOpenGL = (g_Config.m_GfxOpenGLMajor == 3 && g_Config.m_GfxOpenGLMinor == 3) || g_Config.m_GfxOpenGLMajor >= 4; - if(DoButton_CheckBox(&g_Config.m_GfxOpenGLMajor, Localize("Use OpenGL 3.3 (experimental)"), IsNewOpenGL, &Button)) +#else + bool IsNewOpenGL = g_Config.m_GfxOpenGLMajor >= 3; +#endif + + if(DoButton_CheckBox(&g_Config.m_GfxOpenGLMajor, Localize("Use modern OpenGL"), IsNewOpenGL, &Button)) { CheckSettings = true; +#ifndef CONF_BACKEND_OPENGL_ES if(IsNewOpenGL) { g_Config.m_GfxOpenGLMajor = 3; @@ -1219,6 +1229,22 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView) g_Config.m_GfxOpenGLPatch = 0; IsNewOpenGL = true; } +#else + if(IsNewOpenGL) + { + g_Config.m_GfxOpenGLMajor = 1; + g_Config.m_GfxOpenGLMinor = 0; + g_Config.m_GfxOpenGLPatch = 0; + IsNewOpenGL = false; + } + else + { + g_Config.m_GfxOpenGLMajor = 3; + g_Config.m_GfxOpenGLMinor = 0; + g_Config.m_GfxOpenGLPatch = 0; + IsNewOpenGL = true; + } +#endif } if(IsNewOpenGL)