diff --git a/CMakeLists.txt b/CMakeLists.txt index cbd081f0b..b1c7d4e7f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1107,6 +1107,8 @@ set(EXPECTED_DATA maps7/Gold\ Mine.map maps7/readme.txt particles.png + shader/pipeline.frag + shader/pipeline.vert shader/prim.frag shader/prim.vert shader/quad.frag diff --git a/data/shader/pipeline.frag b/data/shader/pipeline.frag new file mode 100644 index 000000000..cb9b5dfaf --- /dev/null +++ b/data/shader/pipeline.frag @@ -0,0 +1,18 @@ +#ifdef TW_TEXTURED +#ifdef TW_3D_TEXTURED +uniform sampler3D gTextureSampler; +#else +uniform sampler2DArray gTextureSampler; +#endif +#endif + +void main() +{ +#ifdef TW_TEXTURED + vec4 TexColor = texture(gTextureSampler, gl_TexCoord[0].xyz).rgba; + gl_FragColor = TexColor.rgba * gl_Color.rgba; +#else + gl_FragColor = gl_Color.rgba; +#endif +} + diff --git a/data/shader/pipeline.vert b/data/shader/pipeline.vert new file mode 100644 index 000000000..a1a8cf8a5 --- /dev/null +++ b/data/shader/pipeline.vert @@ -0,0 +1,11 @@ +uniform mat4x2 gPos; + +void main() +{ + gl_Position = vec4(gPos * vec4(gl_Vertex.xy, 0.0, 1.0), 0.0, 1.0); +#ifdef TW_TEXTURED + gl_TexCoord[0] = gl_MultiTexCoord0; +#endif + gl_FrontColor = gl_Color.rgba; + gl_BackColor = gl_Color.rgba; +} diff --git a/data/shader/tile.frag b/data/shader/tile.frag index 97a99cddc..9e2f483e2 100644 --- a/data/shader/tile.frag +++ b/data/shader/tile.frag @@ -16,7 +16,7 @@ out vec4 FragClr; void main() { #ifdef TW_TILE_TEXTURED - vec4 TexColor = texture(gTextureSampler, TexCoord); + vec4 TexColor = texture(gTextureSampler, TexCoord.xyz); FragClr = TexColor * gVertColor; #else FragClr = gVertColor; diff --git a/src/engine/client/backend_sdl.cpp b/src/engine/client/backend_sdl.cpp index 5d565ef59..52ccd4368 100644 --- a/src/engine/client/backend_sdl.cpp +++ b/src/engine/client/backend_sdl.cpp @@ -186,6 +186,14 @@ int CCommandProcessorFragment_OpenGL::TexFormatToOpenGLFormat(int TexFormat) 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; +} + unsigned char CCommandProcessorFragment_OpenGL::Sample(int w, int h, const unsigned char *pData, int u, int v, int Offset, int ScaleW, int ScaleH, int Bpp) { int Value = 0; @@ -202,11 +210,7 @@ void *CCommandProcessorFragment_OpenGL::Rescale(int Width, int Height, int NewWi int ScaleW = Width / NewWidth; int ScaleH = Height / NewHeight; - int Bpp = 3; - if(Format == CCommandBuffer::TEXFORMAT_RGBA) - Bpp = 4; - else if(Format == CCommandBuffer::TEXFORMAT_ALPHA) - Bpp = 1; + int Bpp = TexFormatToImageColorChannelCount(Format); pTmpData = (unsigned char *)malloc(NewWidth * NewHeight * Bpp); @@ -222,7 +226,7 @@ void *CCommandProcessorFragment_OpenGL::Rescale(int Width, int Height, int NewWi return pTmpData; } -void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &State) +void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &State, bool Use2DArrayTextures) { // blend switch(State.m_BlendMode) @@ -241,24 +245,62 @@ void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &St 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 + else if(m_LastClipEnable) + { + // Don't disable it always glDisable(GL_SCISSOR_TEST); + m_LastClipEnable = false; + } + + glDisable(GL_TEXTURE_2D); + if(m_Has3DTextures) + glDisable(GL_TEXTURE_3D); + if(m_Has2DArrayTextures) + { + glDisable(m_2DArrayTarget); + } + + if(m_HasShaders) + { + glBindSampler(0, 0); + } // texture if(State.m_Texture >= 0 && State.m_Texture < CCommandBuffer::MAX_TEXTURES) { - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, m_aTextures[State.m_Texture].m_Tex); + if(!Use2DArrayTextures) + { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, m_aTextures[State.m_Texture].m_Tex); + } + else + { + if(m_Has2DArrayTextures) + { + glEnable(m_2DArrayTarget); + glBindTexture(m_2DArrayTarget, m_aTextures[State.m_Texture].m_Tex2DArray); + } + else if(m_Has3DTextures) + { + glEnable(GL_TEXTURE_3D); + glBindTexture(GL_TEXTURE_3D, m_aTextures[State.m_Texture].m_Tex2DArray); + } + else + { + dbg_msg("OpenGL", "Error: this call should not happen."); + } + + } } - else - glDisable(GL_TEXTURE_2D); switch(State.m_WrapMode) { @@ -283,7 +325,26 @@ void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &St 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_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_LastBlendMode = CCommandBuffer::BLEND_ALPHA; + m_LastClipEnable = false; } void CCommandProcessorFragment_OpenGL::Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand) @@ -320,7 +381,7 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Destroy(const CCommandBuffer: { glDeleteTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex); m_aTextures[pCommand->m_Slot].m_Tex = 0; - *m_pTextureMemoryUsage -= m_aTextures[pCommand->m_Slot].m_MemSize; + m_pTextureMemoryUsage->store(m_pTextureMemoryUsage->load(std::memory_order_relaxed) - m_aTextures[pCommand->m_Slot].m_MemSize, std::memory_order_relaxed); } void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand) @@ -380,10 +441,11 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer:: default: StoreOglformat = GL_COMPRESSED_RGBA_ARB; } } + glGenTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex); glBindTexture(GL_TEXTURE_2D, m_aTextures[pCommand->m_Slot].m_Tex); - if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_NOMIPMAPS) + if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_NOMIPMAPS || !m_HasMipMaps) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -395,6 +457,86 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer:: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); 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_aTextures[pCommand->m_Slot].m_Tex2DArray); + + GLenum Target = GL_TEXTURE_3D; + + if(Is3DTexture) + { + Target = GL_TEXTURE_3D; + } + else + { + Target = m_2DArrayTarget; + } + + glBindTexture(Target, m_aTextures[pCommand->m_Slot].m_Tex2DArray); + + glGenSamplers(1, &m_aTextures[pCommand->m_Slot].m_Sampler2DArray); + glBindSampler(0, m_aTextures[pCommand->m_Slot].m_Sampler2DArray); + + glTexParameteri(Target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + if(Is3DTexture) + { + glTexParameteri(Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glSamplerParameteri(m_aTextures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + else + { + glTexParameteri(Target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + glTexParameteri(Target, GL_GENERATE_MIPMAP, GL_TRUE); + glSamplerParameteri(m_aTextures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + } + + 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); + + glSamplerParameteri(m_aTextures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glSamplerParameteri(m_aTextures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glSamplerParameteri(m_aTextures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT); + + 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(ImageColorChannels * Width * Height); + int Image3DWidth, Image3DHeight; + + if(IsSingleLayer || (Width != 0 && Width % 16 == 0 && Height != 0 && Height % 16 == 0 && Texture2DTo3D(pTexData, Width, Height, ImageColorChannels, 16, 16, p3DImageData, Image3DWidth, Image3DHeight))) + { + if(IsSingleLayer) + { + glTexImage3D(Target, 0, StoreOglformat, Width, Height, 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); + } } // calculate memory usage @@ -405,7 +547,7 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer:: Height>>=1; m_aTextures[pCommand->m_Slot].m_MemSize += Width*Height*pCommand->m_PixelSize; } - *m_pTextureMemoryUsage += m_aTextures[pCommand->m_Slot].m_MemSize; + m_pTextureMemoryUsage->store(m_pTextureMemoryUsage->load(std::memory_order_relaxed) + m_aTextures[pCommand->m_Slot].m_MemSize, std::memory_order_relaxed); free(pTexData); } @@ -481,81 +623,76 @@ void CCommandProcessorFragment_OpenGL::Cmd_Screenshot(const CCommandBuffer::SCom CCommandProcessorFragment_OpenGL::CCommandProcessorFragment_OpenGL() { mem_zero(m_aTextures, sizeof(m_aTextures)); - m_pTextureMemoryUsage = 0; + m_HasShaders = false; } bool CCommandProcessorFragment_OpenGL::RunCommand(const CCommandBuffer::SCommand *pBaseCommand) { switch(pBaseCommand->m_Cmd) { - case CMD_INIT: Cmd_Init(static_cast(pBaseCommand)); break; + 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_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_SPRITE: Cmd_RenderQuadContainerAsSprite(static_cast(pBaseCommand)); break; + case CCommandBuffer::CMD_RENDER_QUAD_CONTAINER_SPRITE_MULTIPLE: Cmd_RenderQuadContainerAsSpriteMultiple(static_cast(pBaseCommand)); break; default: return false; } return true; } -// ------------ CCommandProcessorFragment_OpenGL3_3 +// ------------ CCommandProcessorFragment_OpenGL2 -int CCommandProcessorFragment_OpenGL3_3::TexFormatToOpenGLFormat(int TexFormat) +void CCommandProcessorFragment_OpenGL2::UseProgram(CGLSLTWProgram *pProgram) { - 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; + pProgram->UseProgram(); } -int CCommandProcessorFragment_OpenGL3_3::TexFormatToImageColorChannelCount(int TexFormat) +bool CCommandProcessorFragment_OpenGL2::IsAndUpdateTextureSlotBound(int IDX, int Slot, bool Is2DArray) { - if(TexFormat == CCommandBuffer::TEXFORMAT_RGB) return 3; - if(TexFormat == CCommandBuffer::TEXFORMAT_ALPHA) return 1; - if(TexFormat == CCommandBuffer::TEXFORMAT_RGBA) return 4; - return 4; + 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; + } } -unsigned char CCommandProcessorFragment_OpenGL3_3::Sample(int w, int h, const unsigned char *pData, int u, int v, int Offset, int ScaleW, int ScaleH, int Bpp) -{ - int Value = 0; - for(int x = 0; x < ScaleW; x++) - for(int y = 0; y < ScaleH; y++) - Value += pData[((v+y)*w+(u+x))*Bpp+Offset]; - return Value/(ScaleW*ScaleH); -} - -void *CCommandProcessorFragment_OpenGL3_3::Rescale(int Width, int Height, int NewWidth, int NewHeight, int Format, const unsigned char *pData) -{ - unsigned char *pTmpData; - int ScaleW = Width/NewWidth; - int ScaleH = Height/NewHeight; - - int Bpp = 3; - if(Format == CCommandBuffer::TEXFORMAT_RGBA) - Bpp = 4; - else if(Format == CCommandBuffer::TEXFORMAT_ALPHA) - Bpp = 1; - - pTmpData = (unsigned char *)malloc(NewWidth*NewHeight*Bpp); - - int c = 0; - for(int y = 0; y < NewHeight; y++) - for(int x = 0; x < NewWidth; x++, c++) - { - for(int i = 0; i < Bpp; ++i) { - pTmpData[c*Bpp + i] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, i, ScaleW, ScaleH, Bpp); - } - } - - return pTmpData; -} - -void CCommandProcessorFragment_OpenGL3_3::SetState(const CCommandBuffer::SState &State, CGLSLTWProgram *pProgram, bool Use2DArrayTextures) +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 @@ -594,13 +731,24 @@ void CCommandProcessorFragment_OpenGL3_3::SetState(const CCommandBuffer::SState m_LastClipEnable = false; } + if(!IsNewApi()) + { + glDisable(GL_TEXTURE_2D); + if(m_Has3DTextures) + glDisable(GL_TEXTURE_3D); + if(m_Has2DArrayTextures) + { + glDisable(m_2DArrayTarget); + } + } + // texture if(State.m_Texture >= 0 && State.m_Texture < CCommandBuffer::MAX_TEXTURES) { - int Slot = State.m_Texture % m_MaxTextureUnits; - + int Slot = 0; if(m_UseMultipleTextureUnits) { + Slot = State.m_Texture % m_MaxTextureUnits; if(!IsAndUpdateTextureSlotBound(Slot, State.m_Texture, Use2DArrayTextures)) { glActiveTexture(GL_TEXTURE0 + Slot); @@ -615,18 +763,33 @@ void CCommandProcessorFragment_OpenGL3_3::SetState(const CCommandBuffer::SState glBindSampler(Slot, m_aTextures[State.m_Texture].m_Sampler2DArray); } } - } else + } + else { Slot = 0; if(!Use2DArrayTextures) { + if(!IsNewApi()) + glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, m_aTextures[State.m_Texture].m_Tex); glBindSampler(Slot, m_aTextures[State.m_Texture].m_Sampler); } else { - glBindTexture(GL_TEXTURE_2D_ARRAY, m_aTextures[State.m_Texture].m_Tex2DArray); - glBindSampler(Slot, m_aTextures[State.m_Texture].m_Sampler2DArray); + if(!m_Has2DArrayTextures) + { + if(!IsNewApi()) + glEnable(GL_TEXTURE_3D); + glBindTexture(GL_TEXTURE_3D, m_aTextures[State.m_Texture].m_Tex2DArray); + glBindSampler(Slot, m_aTextures[State.m_Texture].m_Sampler2DArray); + } + else + { + if(!IsNewApi()) + glEnable(m_2DArrayTarget); + glBindTexture(m_2DArrayTarget, m_aTextures[State.m_Texture].m_Tex2DArray); + glBindSampler(Slot, m_aTextures[State.m_Texture].m_Sampler2DArray); + } } } if(pProgram->m_LocIsTextured != -1) @@ -695,6 +858,630 @@ void CCommandProcessorFragment_OpenGL3_3::SetState(const CCommandBuffer::SState } } +void CCommandProcessorFragment_OpenGL2::Cmd_Init(const SCommand_Init *pCommand) +{ + CCommandProcessorFragment_OpenGL::Cmd_Init(pCommand); + m_HasShaders = pCommand->m_pCapabilities->m_ShaderSupport; + + 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); + } +} + +void CCommandProcessorFragment_OpenGL2::Cmd_CreateBufferObject(const CCommandBuffer::SCommand_CreateBufferObject *pCommand) +{ + 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), pCommand->m_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(pCommand->m_pUploadData) + mem_copy(BufferObject.m_pData, pCommand->m_pUploadData, pCommand->m_DataSize); +} + +void CCommandProcessorFragment_OpenGL2::Cmd_RecreateBufferObject(const CCommandBuffer::SCommand_RecreateBufferObject *pCommand) +{ + 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), pCommand->m_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(pCommand->m_pUploadData) + mem_copy(BufferObject.m_pData, pCommand->m_pUploadData, pCommand->m_DataSize); +} + +void CCommandProcessorFragment_OpenGL2::Cmd_UpdateBufferObject(const CCommandBuffer::SCommand_UpdateBufferObject *pCommand) +{ + 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), pCommand->m_pUploadData); + glBindBuffer(GL_COPY_WRITE_BUFFER, 0); + } + + if(pCommand->m_pUploadData) + mem_copy(((uint8_t*)BufferObject.m_pData) + (ptrdiff_t)pCommand->m_pOffset, pCommand->m_pUploadData, pCommand->m_DataSize); +} + +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(size_t j = 0; j < BufferContainer.m_ContainerInfo.m_Attributes.size(); ++j) + { + // set all equal ids to zero to not double delete + if(VertBufferID == BufferContainer.m_ContainerInfo.m_Attributes[j].m_VertBufferBindingIndex) { + BufferContainer.m_ContainerInfo.m_Attributes[j].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(State.m_Texture >= 0 && State.m_Texture < CCommandBuffer::MAX_TEXTURES) + { + 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(State.m_Texture >= 0 && State.m_Texture < CCommandBuffer::MAX_TEXTURES) + { + 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(pCommand->m_State.m_Texture >= 0 && pCommand->m_State.m_Texture < CCommandBuffer::MAX_TEXTURES) + { + 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()) { @@ -712,6 +1499,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Init(const SCommand_Init *pCommand } 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; @@ -1114,7 +1902,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Update(const CCommandBuffe } glTexSubImage2D(GL_TEXTURE_2D, 0, X, Y, Width, Height, - TexFormatToOpenGLFormat(pCommand->m_Format), GL_UNSIGNED_BYTE, pTexData); + TexFormatToNewOpenGLFormat(pCommand->m_Format), GL_UNSIGNED_BYTE, pTexData); free(pTexData); } @@ -1173,8 +1961,8 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Create(const CCommandBuffe m_aTextures[pCommand->m_Slot].m_Height = Height; m_aTextures[pCommand->m_Slot].m_RescaleCount = RescaleCount; - int Oglformat = TexFormatToOpenGLFormat(pCommand->m_Format); - int StoreOglformat = TexFormatToOpenGLFormat(pCommand->m_StoreFormat); + int Oglformat = TexFormatToNewOpenGLFormat(pCommand->m_Format); + int StoreOglformat = TexFormatToNewOpenGLFormat(pCommand->m_StoreFormat); if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_COMPRESSED) { @@ -1241,7 +2029,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Create(const CCommandBuffe glSamplerParameteri(m_aTextures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); glSamplerParameteri(m_aTextures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glSamplerParameteri(m_aTextures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glSamplerParameteri(m_aTextures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glSamplerParameteri(m_aTextures[pCommand->m_Slot].m_Sampler2DArray, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT); int ImageColorChannels = TexFormatToImageColorChannelCount(pCommand->m_Format); @@ -1289,7 +2077,7 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Create(const CCommandBuffe Height>>=1; m_aTextures[pCommand->m_Slot].m_MemSize += Width*Height*pCommand->m_PixelSize; } - *m_pTextureMemoryUsage += m_aTextures[pCommand->m_Slot].m_MemSize; + m_pTextureMemoryUsage->store(m_pTextureMemoryUsage->load(std::memory_order_relaxed) + m_aTextures[pCommand->m_Slot].m_MemSize, std::memory_order_relaxed); free(pTexData); } @@ -1399,69 +2187,11 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_Screenshot(const CCommandBuffer::S pCommand->m_pImage->m_pData = pPixelData; } -CCommandProcessorFragment_OpenGL3_3::CCommandProcessorFragment_OpenGL3_3() -{ - mem_zero(m_aTextures, sizeof(m_aTextures)); - m_pTextureMemoryUsage = 0; -} - -bool CCommandProcessorFragment_OpenGL3_3::RunCommand(const CCommandBuffer::SCommand *pBaseCommand) -{ - switch(pBaseCommand->m_Cmd) - { - case CMD_INIT: Cmd_Init(static_cast(pBaseCommand)); break; - case 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_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_SPRITE: Cmd_RenderQuadContainerAsSprite(static_cast(pBaseCommand)); break; - case CCommandBuffer::CMD_RENDER_QUAD_CONTAINER_SPRITE_MULTIPLE: Cmd_RenderQuadContainerAsSpriteMultiple(static_cast(pBaseCommand)); break; - default: return false; - } - - return true; -} - -bool CCommandProcessorFragment_OpenGL3_3::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_OpenGL3_3::DestroyTexture(int Slot) { glDeleteTextures(1, &m_aTextures[Slot].m_Tex); glDeleteSamplers(1, &m_aTextures[Slot].m_Sampler); - *m_pTextureMemoryUsage -= m_aTextures[Slot].m_MemSize; + m_pTextureMemoryUsage->store(m_pTextureMemoryUsage->load(std::memory_order_relaxed) - m_aTextures[Slot].m_MemSize, std::memory_order_relaxed); if(m_aTextures[Slot].m_Tex2DArray != 0) { @@ -1772,7 +2502,8 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderTileLayer(const CCommandBuff { pProgram = m_pTileProgramTextured; } - else pProgram = m_pTileProgram; + else + pProgram = m_pTileProgram; UseProgram(pProgram); @@ -1934,7 +2665,6 @@ void CCommandProcessorFragment_OpenGL3_3::RenderText(const CCommandBuffer::SStat m_pTextProgram->m_LastColor[3] = pTextColor[3]; } - glDrawElements(GL_TRIANGLES, DrawNum, GL_UNSIGNED_INT, (void*)(0)); } @@ -2125,6 +2855,52 @@ void CCommandProcessorFragment_OpenGL3_3::Cmd_RenderQuadContainerAsSpriteMultipl // ------------ CCommandProcessorFragment_SDL +static void ParseVersionString(const GLubyte* 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 >= (GLubyte)'0' && *pStr <= (GLubyte)'9') + { + aCurNumberStr[CurNumberStrLen++] = (char)*pStr; + LastWasNumber = true; + } + else if(LastWasNumber && (*pStr == (GLubyte)'.' || *pStr == (GLubyte)' ' || *pStr == (GLubyte)'\0')) + { + int CurNumber = 0; + if(CurNumberStrLen > 0) + { + aCurNumberStr[CurNumberStrLen] = 0; + CurNumber = str_toint(aCurNumberStr); + aNumbers[TotalNumbersPassed++] = CurNumber; + CurNumberStrLen = 0; + } + + LastWasNumber = false; + + if(*pStr != (GLubyte)'.') + break; + } + else + { + break; + } + + ++pStr; + } + + VersionMajor = aNumbers[0]; + VersionMinor = aNumbers[1]; + VersionPatch = aNumbers[2]; + } +} + void CCommandProcessorFragment_SDL::Cmd_Init(const SCommand_Init *pCommand) { m_GLContext = pCommand->m_GLContext; @@ -2140,6 +2916,133 @@ void CCommandProcessorFragment_SDL::Cmd_Init(const SCommand_Init *pCommand) glAlphaFunc(GL_GREATER, 0); glEnable(GL_ALPHA_TEST); glDepthMask(0); + + // check what this context can do + const GLubyte* pVersionString = glGetString(GL_VERSION); + dbg_msg("OpenGL", "Version string: %s", (const char*)pVersionString); + // parse version string + ParseVersionString(pVersionString, pCommand->m_pCapabilities->m_ContextMajor, pCommand->m_pCapabilities->m_ContextMinor, pCommand->m_pCapabilities->m_ContextPatch); + + int MajorV = pCommand->m_pCapabilities->m_ContextMajor; + int MinorV = pCommand->m_pCapabilities->m_ContextMinor; + int PatchV = pCommand->m_pCapabilities->m_ContextPatch; + + *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) + { + if(PatchV < pCommand->m_RequestedPatch) + { + *pCommand->m_pInitError = -2; + } + } + } + + if(*pCommand->m_pInitError == 0) + { + MajorV = pCommand->m_RequestedMajor; + MinorV = pCommand->m_RequestedMinor; + PatchV = pCommand->m_RequestedPatch; + + pCommand->m_pCapabilities->m_2DArrayTexturesAsExtension = false; + + 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; + } + + 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; + } + 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; + } + } } void CCommandProcessorFragment_SDL::Cmd_Update_Viewport(const SCommand_Update_Viewport *pCommand) @@ -2239,16 +3142,9 @@ void CCommandProcessor_SDL_OpenGL::RunBuffer(CCommandBuffer *pBuffer) if(pBaseCommand == 0x0) break; - if(m_UseOpenGL3_3) - { - if(m_OpenGL3_3.RunCommand(pBaseCommand)) + if(m_pOpenGL->RunCommand(pBaseCommand)) continue; - } - else - { - if(m_OpenGL.RunCommand(pBaseCommand)) - continue; - } + if(m_SDL.RunCommand(pBaseCommand)) continue; @@ -2259,8 +3155,196 @@ void CCommandProcessor_SDL_OpenGL::RunBuffer(CCommandBuffer *pBuffer) } } +CCommandProcessor_SDL_OpenGL::CCommandProcessor_SDL_OpenGL(int OpenGLMajor, int OpenGLMinor, int OpenGLPatch) +{ + 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(); + } +} + // ------------ CGraphicsBackend_SDL_OpenGL +static void GetGlewVersion(int& GlewMajor, int& GlewMinor, int& GlewPatch) +{ + 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) + { + 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; + } +} + +static int IsVersionSupportedGlew(int VersionMajor, int VersionMinor, int VersionPatch, int GlewMajor, int GlewMinor, int GlewPatch) +{ + int InitError = 0; + if(VersionMajor >= 4 && GlewMajor < 4) + { + InitError = -1; + } + else if(VersionMajor >= 3 && GlewMajor < 3) + { + InitError = -1; + } + else if(VersionMajor == 3 && GlewMajor == 3) + { + if(VersionMinor >= 3 && GlewMinor < 3) + { + InitError = -1; + } + if(VersionMinor >= 2 && GlewMinor < 2) + { + InitError = -1; + } + if(VersionMinor >= 1 && GlewMinor < 1) + { + 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) + { + 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; +} + 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 @@ -2279,7 +3363,7 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt if(SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { dbg_msg("gfx", "unable to init SDL video: %s", SDL_GetError()); - return -1; + return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_SDL_INIT_FAILED; } #ifdef CONF_FAMILY_WINDOWS @@ -2321,6 +3405,8 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt 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; } @@ -2385,10 +3471,16 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt } } //if non standard opengl, set it - else if(s_SDLGLContextMajorVersion != g_Config.m_GfxOpenGLMajor || s_SDLGLContextMinorVersion != g_Config.m_GfxOpenGLMinor) { + 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); + } } // set screen @@ -2401,14 +3493,14 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt if(SDL_GetDisplayBounds(*Screen, &ScreenPos) != 0) { dbg_msg("gfx", "unable to retrieve screen information: %s", SDL_GetError()); - return -1; + return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_INFO_REQUEST_FAILED; } } else { dbg_msg("gfx", "unable to retrieve number of screens: %s", SDL_GetError()); - return -1; + return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_REQUEST_FAILED; } // store desktop resolution for settings reset button @@ -2416,7 +3508,7 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt if(SDL_GetDesktopDisplayMode(*Screen, &DisplayMode)) { dbg_msg("gfx", "unable to get desktop resolution: %s", SDL_GetError()); - return -1; + return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_RESOLUTION_REQUEST_FAILED; } *pDesktopWidth = DisplayMode.w; *pDesktopHeight = DisplayMode.h; @@ -2495,7 +3587,7 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt if(m_pWindow == NULL) { dbg_msg("gfx", "unable to create window: %s", SDL_GetError()); - return -1; + return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_SDL_WINDOW_CREATE_FAILED; } m_GLContext = SDL_GL_CreateContext(m_pWindow); @@ -2503,57 +3595,96 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt if(m_GLContext == NULL) { dbg_msg("gfx", "unable to create OpenGL context: %s", SDL_GetError()); - return -1; + return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_OPENGL_CONTEXT_FAILED; } - if(m_UseNewOpenGL) - { - //support graphic cards that are pretty old(and linux) - glewExperimental = GL_TRUE; - if(GLEW_OK != glewInit()) - return -1; - } + //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); + + int InitError = 0; + + InitError = IsVersionSupportedGlew(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); SDL_GL_MakeCurrent(NULL, NULL); - // start the command processor - m_pProcessor = new CCommandProcessor_SDL_OpenGL; - ((CCommandProcessor_SDL_OpenGL*)m_pProcessor)->UseOpenGL3_3(m_UseNewOpenGL); - StartProcessor(m_pProcessor); + if(InitError != 0) + { + SDL_GL_DeleteContext(m_GLContext); + SDL_DestroyWindow(m_pWindow); + // try setting to glew supported version + g_Config.m_GfxOpenGLMajor = GlewMajor; + g_Config.m_GfxOpenGLMinor = GlewMinor; + g_Config.m_GfxOpenGLPatch = GlewPatch; + + return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_OPENGL_VERSION_FAILED; + } + + // start the command processor + m_pProcessor = new CCommandProcessor_SDL_OpenGL(g_Config.m_GfxOpenGLMajor, g_Config.m_GfxOpenGLMinor, g_Config.m_GfxOpenGLPatch); + StartProcessor(m_pProcessor); + // issue init commands for OpenGL and SDL CCommandBuffer CmdBuffer(1024, 512); - if(m_UseNewOpenGL) + //run sdl first to have the context in the thread + 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_pInitError = &InitError; + CmdBuffer.AddCommand(CmdSDL); + RunBuffer(&CmdBuffer); + WaitForIdle(); + CmdBuffer.Reset(); + + if(InitError != 0) { - //run sdl first to have the context in the thread - CCommandProcessorFragment_SDL::SCommand_Init CmdSDL; - CmdSDL.m_pWindow = m_pWindow; - CmdSDL.m_GLContext = m_GLContext; - CmdBuffer.AddCommand(CmdSDL); - RunBuffer(&CmdBuffer); - WaitForIdle(); - CCommandProcessorFragment_OpenGL3_3::SCommand_Init CmdOpenGL; - CmdOpenGL.m_pTextureMemoryUsage = &m_TextureMemoryUsage; - CmdOpenGL.m_pStorage = pStorage; - CmdBuffer.AddCommand(CmdOpenGL); - RunBuffer(&CmdBuffer); - WaitForIdle(); - } - else - { - CCommandProcessorFragment_OpenGL::SCommand_Init CmdOpenGL; - CmdOpenGL.m_pTextureMemoryUsage = &m_TextureMemoryUsage; - CmdBuffer.AddCommand(CmdOpenGL); - CCommandProcessorFragment_SDL::SCommand_Init CmdSDL; - CmdSDL.m_pWindow = m_pWindow; - CmdSDL.m_GLContext = m_GLContext; - CmdBuffer.AddCommand(CmdSDL); + CCommandProcessorFragment_SDL::SCommand_Shutdown Cmd; + CmdBuffer.AddCommand(Cmd); RunBuffer(&CmdBuffer); WaitForIdle(); + CmdBuffer.Reset(); + + // stop and delete the processor + StopProcessor(); + delete m_pProcessor; + m_pProcessor = 0; + + SDL_GL_DeleteContext(m_GLContext); + SDL_DestroyWindow(m_pWindow); + + // try setting to version string's supported version + if(InitError == -2) + { + g_Config.m_GfxOpenGLMajor = m_Capabilites.m_ContextMajor; + g_Config.m_GfxOpenGLMinor = m_Capabilites.m_ContextMinor; + g_Config.m_GfxOpenGLPatch = m_Capabilites.m_ContextPatch; + } + + return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_OPENGL_VERSION_FAILED; } + CCommandProcessorFragment_OpenGL::SCommand_Init CmdOpenGL; + CmdOpenGL.m_pTextureMemoryUsage = &m_TextureMemoryUsage; + CmdOpenGL.m_pStorage = pStorage; + CmdOpenGL.m_pCapabilities = &m_Capabilites; + CmdBuffer.AddCommand(CmdOpenGL); + RunBuffer(&CmdBuffer); + WaitForIdle(); + CmdBuffer.Reset(); SDL_ShowWindow(m_pWindow); if(SetWindowScreen(g_Config.m_GfxScreen)) @@ -2583,26 +3714,23 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt CmdBuffer.AddCommand(CmdSDL); RunBuffer(&CmdBuffer); WaitForIdle(); + CmdBuffer.Reset(); } } // return - return 0; + return EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_NONE; } int CGraphicsBackend_SDL_OpenGL::Shutdown() { // issue a shutdown command CCommandBuffer CmdBuffer(1024, 512); - if(m_UseNewOpenGL) - { - CCommandProcessorFragment_OpenGL3_3::SCommand_Shutdown Cmd; - CmdBuffer.AddCommand(Cmd); - } CCommandProcessorFragment_SDL::SCommand_Shutdown Cmd; CmdBuffer.AddCommand(Cmd); RunBuffer(&CmdBuffer); WaitForIdle(); + CmdBuffer.Reset(); // stop and delete the processor StopProcessor(); diff --git a/src/engine/client/backend_sdl.h b/src/engine/client/backend_sdl.h index 6377d8859..8ed6bc819 100644 --- a/src/engine/client/backend_sdl.h +++ b/src/engine/client/backend_sdl.h @@ -5,6 +5,8 @@ #include "graphics_threaded.h" +#include + # if defined(CONF_PLATFORM_MACOSX) #include @@ -73,58 +75,25 @@ public: bool RunCommand(const CCommandBuffer::SCommand *pBaseCommand); }; -// takes care of opengl related rendering -class CCommandProcessorFragment_OpenGL + +struct SBackendCapabilites { - struct CTexture - { - GLuint m_Tex; - int m_MemSize; + bool m_TileBuffering; + bool m_QuadBuffering; + bool m_TextBuffering; + bool m_QuadContainerBuffering; - int m_Width; - int m_Height; - int m_RescaleCount; - }; - CTexture m_aTextures[CCommandBuffer::MAX_TEXTURES]; - volatile int *m_pTextureMemoryUsage; + bool m_MipMapping; + bool m_3DTextures; + bool m_2DArrayTextures; + bool m_2DArrayTexturesAsExtension; + bool m_ShaderSupport; - GLint m_MaxTexSize; -public: - enum - { - CMD_INIT = CCommandBuffer::CMDGROUP_PLATFORM_OPENGL, - }; - - struct SCommand_Init : public CCommandBuffer::SCommand - { - SCommand_Init() : SCommand(CMD_INIT) {} - volatile int *m_pTextureMemoryUsage; - }; - -private: - static int TexFormatToOpenGLFormat(int TexFormat); - static unsigned char Sample(int w, int h, const unsigned char *pData, int u, int v, int Offset, int ScaleW, int ScaleH, int Bpp); - static void *Rescale(int Width, int Height, int NewWidth, int NewHeight, int Format, const unsigned char *pData); - - void SetState(const CCommandBuffer::SState &State); - - void Cmd_Init(const SCommand_Init *pCommand); - void Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand); - void Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand); - void Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand); - void Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand); - void Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand); - void Cmd_Screenshot(const CCommandBuffer::SCommand_Screenshot *pCommand); - -public: - CCommandProcessorFragment_OpenGL(); - - bool RunCommand(const CCommandBuffer::SCommand *pBaseCommand); + int m_ContextMajor; + int m_ContextMinor; + int m_ContextPatch; }; - -#define MAX_STREAM_BUFFER_COUNT 30 - class CGLSLProgram; class CGLSLTWProgram; class CGLSLPrimitiveProgram; @@ -133,36 +102,187 @@ class CGLSLTileProgram; class CGLSLTextProgram; class CGLSLSpriteProgram; class CGLSLSpriteMultipleProgram; -// takes care of opengl 3.3+ related rendering -class CCommandProcessorFragment_OpenGL3_3 + +// takes care of opengl related rendering +class CCommandProcessorFragment_OpenGL { - bool m_UseMultipleTextureUnits; - bool m_UsePreinitializedVertexBuffer; - +protected: struct CTexture { CTexture() : m_Tex2DArray(0), m_Sampler2DArray(0) {} GLuint m_Tex; - GLuint m_Tex2DArray; + GLuint m_Tex2DArray; //or 3D texture as fallback GLuint m_Sampler; - GLuint m_Sampler2DArray; + GLuint m_Sampler2DArray; //or 3D texture as fallback int m_LastWrapMode; + int m_MemSize; int m_Width; int m_Height; - int m_RescaleCount; }; CTexture m_aTextures[CCommandBuffer::MAX_TEXTURES]; - volatile int *m_pTextureMemoryUsage; + std::atomic *m_pTextureMemoryUsage; + + GLint m_MaxTexSize; + + bool m_Has2DArrayTextures; + bool m_Has2DArrayTexturesAsExtension; + GLenum m_2DArrayTarget; + bool m_Has3DTextures; + bool m_HasMipMaps; + + bool m_HasShaders; + int m_LastBlendMode; //avoid all possible opengl state changes + bool m_LastClipEnable; +public: + enum + { + CMD_INIT = CCommandBuffer::CMDGROUP_PLATFORM_OPENGL, + CMD_SHUTDOWN = CMD_INIT + 1, + }; + + struct SCommand_Init : public CCommandBuffer::SCommand + { + SCommand_Init() : SCommand(CMD_INIT) {} + class IStorage *m_pStorage; + std::atomic *m_pTextureMemoryUsage; + const SBackendCapabilites* m_pCapabilities; + }; + + struct SCommand_Shutdown : public CCommandBuffer::SCommand + { + SCommand_Shutdown() : SCommand(CMD_SHUTDOWN) {} + }; + +protected: + void SetState(const CCommandBuffer::SState &State, bool Use2DArrayTexture = false); + virtual bool IsNewApi() { return false; } + + static int TexFormatToOpenGLFormat(int TexFormat); + static int TexFormatToImageColorChannelCount(int TexFormat); + static unsigned char Sample(int w, int h, const unsigned char *pData, int u, int v, int Offset, int ScaleW, int ScaleH, int Bpp); + static void *Rescale(int Width, int Height, int NewWidth, int NewHeight, int Format, const unsigned char *pData); + + virtual void Cmd_Init(const SCommand_Init *pCommand); + virtual void Cmd_Shutdown(const SCommand_Shutdown *pCommand) {} + virtual void Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand); + virtual void Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand); + virtual void Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand); + virtual void Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand); + virtual void Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand); + virtual void Cmd_Screenshot(const CCommandBuffer::SCommand_Screenshot *pCommand); + + virtual void Cmd_CreateBufferObject(const CCommandBuffer::SCommand_CreateBufferObject *pCommand) {} + virtual void Cmd_RecreateBufferObject(const CCommandBuffer::SCommand_RecreateBufferObject *pCommand) {} + virtual void Cmd_UpdateBufferObject(const CCommandBuffer::SCommand_UpdateBufferObject *pCommand) {} + virtual void Cmd_CopyBufferObject(const CCommandBuffer::SCommand_CopyBufferObject *pCommand) {} + virtual void Cmd_DeleteBufferObject(const CCommandBuffer::SCommand_DeleteBufferObject *pCommand) {} + + virtual void Cmd_CreateBufferContainer(const CCommandBuffer::SCommand_CreateBufferContainer *pCommand) {} + virtual void Cmd_UpdateBufferContainer(const CCommandBuffer::SCommand_UpdateBufferContainer *pCommand) {} + virtual void Cmd_DeleteBufferContainer(const CCommandBuffer::SCommand_DeleteBufferContainer *pCommand) {} + virtual void Cmd_IndicesRequiredNumNotify(const CCommandBuffer::SCommand_IndicesRequiredNumNotify *pCommand) {} + + virtual void Cmd_RenderTileLayer(const CCommandBuffer::SCommand_RenderTileLayer *pCommand) {} + virtual void Cmd_RenderBorderTile(const CCommandBuffer::SCommand_RenderBorderTile *pCommand) {} + virtual void Cmd_RenderBorderTileLine(const CCommandBuffer::SCommand_RenderBorderTileLine *pCommand) {} + virtual void Cmd_RenderQuadLayer(const CCommandBuffer::SCommand_RenderQuadLayer *pCommand) {} + virtual void Cmd_RenderText(const CCommandBuffer::SCommand_RenderText *pCommand) {} + virtual void Cmd_RenderTextStream(const CCommandBuffer::SCommand_RenderTextStream *pCommand) {} + virtual void Cmd_RenderQuadContainer(const CCommandBuffer::SCommand_RenderQuadContainer *pCommand) {} + virtual void Cmd_RenderQuadContainerAsSprite(const CCommandBuffer::SCommand_RenderQuadContainerAsSprite *pCommand) {} + virtual void Cmd_RenderQuadContainerAsSpriteMultiple(const CCommandBuffer::SCommand_RenderQuadContainerAsSpriteMultiple *pCommand) {} +public: + CCommandProcessorFragment_OpenGL(); + + bool RunCommand(const CCommandBuffer::SCommand *pBaseCommand); +}; + +class CCommandProcessorFragment_OpenGL2 : public CCommandProcessorFragment_OpenGL { + struct SBufferContainer + { + SBufferContainer() {} + SBufferContainerInfo m_ContainerInfo; + }; + std::vector m_BufferContainers; + + GL_SVertexTex3D m_aStreamVertices[1024 * 4]; + + struct SBufferObject + { + SBufferObject(GLuint BufferObjectID) : m_BufferObjectID(BufferObjectID) + { + m_pData = NULL; + m_DataSize = 0; + } + GLuint m_BufferObjectID; + void* m_pData; + size_t m_DataSize; + }; + + std::vector m_BufferObjectIndices; + + void RenderBorderTileEmulation(SBufferContainer& BufferContainer, const CCommandBuffer::SState& State, const float* pColor, const char *pBuffOffset, unsigned int DrawNum, const float* pOffset, const float* pDir, int JumpIndex); + void 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); + + void UseProgram(CGLSLTWProgram *pProgram); +protected: + void SetState(const CCommandBuffer::SState &State, CGLSLTWProgram *pProgram, bool Use2DArrayTextures = false); + + void Cmd_Init(const SCommand_Init *pCommand) override; + + void Cmd_CreateBufferObject(const CCommandBuffer::SCommand_CreateBufferObject *pCommand) override; + void Cmd_RecreateBufferObject(const CCommandBuffer::SCommand_RecreateBufferObject *pCommand) override; + void Cmd_UpdateBufferObject(const CCommandBuffer::SCommand_UpdateBufferObject *pCommand) override; + void Cmd_CopyBufferObject(const CCommandBuffer::SCommand_CopyBufferObject *pCommand) override; + void Cmd_DeleteBufferObject(const CCommandBuffer::SCommand_DeleteBufferObject *pCommand) override; + + void Cmd_CreateBufferContainer(const CCommandBuffer::SCommand_CreateBufferContainer *pCommand) override; + void Cmd_UpdateBufferContainer(const CCommandBuffer::SCommand_UpdateBufferContainer *pCommand) override; + void Cmd_DeleteBufferContainer(const CCommandBuffer::SCommand_DeleteBufferContainer *pCommand) override; + void Cmd_IndicesRequiredNumNotify(const CCommandBuffer::SCommand_IndicesRequiredNumNotify *pCommand) override; + + void Cmd_RenderTileLayer(const CCommandBuffer::SCommand_RenderTileLayer *pCommand) override; + void Cmd_RenderBorderTile(const CCommandBuffer::SCommand_RenderBorderTile *pCommand) override; + void Cmd_RenderBorderTileLine(const CCommandBuffer::SCommand_RenderBorderTileLine *pCommand) override; + + CGLSLTileProgram *m_pTileProgram; + CGLSLTileProgram *m_pTileProgramTextured; + CGLSLPrimitiveProgram *m_pPrimitive3DProgram; + CGLSLPrimitiveProgram *m_pPrimitive3DProgramTextured; + + bool m_UseMultipleTextureUnits; + + GLint m_MaxTextureUnits; + + struct STextureBound{ + int m_TextureSlot; + bool m_Is2DArray; + }; + std::vector m_TextureSlotBoundToUnit; //the texture index generated by loadtextureraw is stored in an index calculated by max texture units + + bool IsAndUpdateTextureSlotBound(int IDX, int Slot, bool Is2DArray = false); +public: + CCommandProcessorFragment_OpenGL2() : CCommandProcessorFragment_OpenGL(), m_UseMultipleTextureUnits(false) {} +}; + +class CCommandProcessorFragment_OpenGL3 : public CCommandProcessorFragment_OpenGL2 { + +}; + +#define MAX_STREAM_BUFFER_COUNT 30 + +// takes care of opengl 3.3+ related rendering +class CCommandProcessorFragment_OpenGL3_3 : public CCommandProcessorFragment_OpenGL3 +{ + bool m_UsePreinitializedVertexBuffer; int m_MaxQuadsAtOnce; static const int m_MaxQuadsPossible = 256; CGLSLPrimitiveProgram *m_pPrimitiveProgram; - CGLSLTileProgram *m_pTileProgram; - CGLSLTileProgram *m_pTileProgramTextured; CGLSLTileProgram *m_pBorderTileProgram; CGLSLTileProgram *m_pBorderTileProgramTextured; CGLSLTileProgram *m_pBorderTileLineProgram; @@ -184,20 +304,7 @@ class CCommandProcessorFragment_OpenGL3_3 GLuint m_QuadDrawIndexBufferID; unsigned int m_CurrentIndicesInBuffer; - - GLint m_MaxTextureUnits; - GLint m_MaxTexSize; - - int m_LastBlendMode; //avoid all possible opengl state changes - bool m_LastClipEnable; - - struct STextureBound{ - int m_TextureSlot; - bool m_Is2DArray; - }; - std::vector m_TextureSlotBoundToUnit; //the texture index generated by loadtextureraw is stored in an index calculated by max texture units - - bool IsAndUpdateTextureSlotBound(int IDX, int Slot, bool Is2DArray = false); + void DestroyTexture(int Slot); void DestroyBufferContainer(int Index, bool DeleteBOs = true); @@ -215,69 +322,45 @@ class CCommandProcessorFragment_OpenGL3_3 std::vector m_BufferObjectIndices; CCommandBuffer::SColorf m_ClearColor; -public: - enum - { - CMD_INIT = CCommandBuffer::CMDGROUP_PLATFORM_OPENGL3_3, - CMD_SHUTDOWN, - }; +protected: + static int TexFormatToNewOpenGLFormat(int TexFormat); + bool IsNewApi() override { return true; } - struct SCommand_Init : public CCommandBuffer::SCommand - { - SCommand_Init() : SCommand(CMD_INIT) {} - class IStorage *m_pStorage; - volatile int *m_pTextureMemoryUsage; - }; - - struct SCommand_Shutdown : public CCommandBuffer::SCommand - { - SCommand_Shutdown() : SCommand(CMD_SHUTDOWN) {} - }; - -private: - static int TexFormatToOpenGLFormat(int TexFormat); - static int TexFormatToImageColorChannelCount(int TexFormat); - static unsigned char Sample(int w, int h, const unsigned char *pData, int u, int v, int Offset, int ScaleW, int ScaleH, int Bpp); - static void *Rescale(int Width, int Height, int NewWidth, int NewHeight, int Format, const unsigned char *pData); - - void SetState(const CCommandBuffer::SState &State, CGLSLTWProgram *pProgram, bool Use2DArrayTextures = false); void UseProgram(CGLSLTWProgram *pProgram); void UploadStreamBufferData(unsigned int PrimitiveType, const void* pVertices, unsigned int PrimitiveCount); void RenderText(const CCommandBuffer::SState& State, int DrawNum, int TextTextureIndex, int TextOutlineTextureIndex, int TextureSize, const float* pTextColor, const float* pTextOutlineColor); - void Cmd_Init(const SCommand_Init *pCommand); - void Cmd_Shutdown(const SCommand_Shutdown *pCommand); - void Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand); - void Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand); - void Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand); - void Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand); - void Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand); - void Cmd_Screenshot(const CCommandBuffer::SCommand_Screenshot *pCommand); + void Cmd_Init(const SCommand_Init *pCommand) override; + void Cmd_Shutdown(const SCommand_Shutdown *pCommand) override; + void Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand) override; + void Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand) override; + void Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand) override; + void Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand) override; + void Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand) override; + void Cmd_Screenshot(const CCommandBuffer::SCommand_Screenshot *pCommand) override; - void Cmd_CreateBufferObject(const CCommandBuffer::SCommand_CreateBufferObject *pCommand); - void Cmd_RecreateBufferObject(const CCommandBuffer::SCommand_RecreateBufferObject *pCommand); - void Cmd_UpdateBufferObject(const CCommandBuffer::SCommand_UpdateBufferObject *pCommand); - void Cmd_CopyBufferObject(const CCommandBuffer::SCommand_CopyBufferObject *pCommand); - void Cmd_DeleteBufferObject(const CCommandBuffer::SCommand_DeleteBufferObject *pCommand); + void Cmd_CreateBufferObject(const CCommandBuffer::SCommand_CreateBufferObject *pCommand) override; + void Cmd_RecreateBufferObject(const CCommandBuffer::SCommand_RecreateBufferObject *pCommand) override; + void Cmd_UpdateBufferObject(const CCommandBuffer::SCommand_UpdateBufferObject *pCommand) override; + void Cmd_CopyBufferObject(const CCommandBuffer::SCommand_CopyBufferObject *pCommand) override; + void Cmd_DeleteBufferObject(const CCommandBuffer::SCommand_DeleteBufferObject *pCommand) override; - void Cmd_CreateBufferContainer(const CCommandBuffer::SCommand_CreateBufferContainer *pCommand); - void Cmd_UpdateBufferContainer(const CCommandBuffer::SCommand_UpdateBufferContainer *pCommand); - void Cmd_DeleteBufferContainer(const CCommandBuffer::SCommand_DeleteBufferContainer *pCommand); - void Cmd_IndicesRequiredNumNotify(const CCommandBuffer::SCommand_IndicesRequiredNumNotify *pCommand); + void Cmd_CreateBufferContainer(const CCommandBuffer::SCommand_CreateBufferContainer *pCommand) override; + void Cmd_UpdateBufferContainer(const CCommandBuffer::SCommand_UpdateBufferContainer *pCommand) override; + void Cmd_DeleteBufferContainer(const CCommandBuffer::SCommand_DeleteBufferContainer *pCommand) override; + void Cmd_IndicesRequiredNumNotify(const CCommandBuffer::SCommand_IndicesRequiredNumNotify *pCommand) override; - void Cmd_RenderTileLayer(const CCommandBuffer::SCommand_RenderTileLayer *pCommand); - void Cmd_RenderBorderTile(const CCommandBuffer::SCommand_RenderBorderTile *pCommand); - void Cmd_RenderBorderTileLine(const CCommandBuffer::SCommand_RenderBorderTileLine *pCommand); - void Cmd_RenderQuadLayer(const CCommandBuffer::SCommand_RenderQuadLayer *pCommand); - void Cmd_RenderText(const CCommandBuffer::SCommand_RenderText *pCommand); - void Cmd_RenderTextStream(const CCommandBuffer::SCommand_RenderTextStream *pCommand); - void Cmd_RenderQuadContainer(const CCommandBuffer::SCommand_RenderQuadContainer *pCommand); - void Cmd_RenderQuadContainerAsSprite(const CCommandBuffer::SCommand_RenderQuadContainerAsSprite *pCommand); - void Cmd_RenderQuadContainerAsSpriteMultiple(const CCommandBuffer::SCommand_RenderQuadContainerAsSpriteMultiple *pCommand); + void Cmd_RenderTileLayer(const CCommandBuffer::SCommand_RenderTileLayer *pCommand) override; + void Cmd_RenderBorderTile(const CCommandBuffer::SCommand_RenderBorderTile *pCommand) override; + void Cmd_RenderBorderTileLine(const CCommandBuffer::SCommand_RenderBorderTileLine *pCommand) override; + void Cmd_RenderQuadLayer(const CCommandBuffer::SCommand_RenderQuadLayer *pCommand) override; + void Cmd_RenderText(const CCommandBuffer::SCommand_RenderText *pCommand) override; + void Cmd_RenderTextStream(const CCommandBuffer::SCommand_RenderTextStream *pCommand) override; + void Cmd_RenderQuadContainer(const CCommandBuffer::SCommand_RenderQuadContainer *pCommand) override; + void Cmd_RenderQuadContainerAsSprite(const CCommandBuffer::SCommand_RenderQuadContainerAsSprite *pCommand) override; + void Cmd_RenderQuadContainerAsSpriteMultiple(const CCommandBuffer::SCommand_RenderQuadContainerAsSpriteMultiple *pCommand) override; public: - CCommandProcessorFragment_OpenGL3_3(); - - bool RunCommand(const CCommandBuffer::SCommand *pBaseCommand); + CCommandProcessorFragment_OpenGL3_3() = default; }; // takes care of sdl related commands @@ -299,6 +382,13 @@ public: SCommand_Init() : SCommand(CMD_INIT) {} SDL_Window *m_pWindow; SDL_GLContext m_GLContext; + SBackendCapabilites* m_pCapabilities; + + int* m_pInitError; + + int m_RequestedMajor; + int m_RequestedMinor; + int m_RequestedPatch; }; struct SCommand_Update_Viewport : public CCommandBuffer::SCommand @@ -332,14 +422,11 @@ public: // command processor impelementation, uses the fragments to combine into one processor class CCommandProcessor_SDL_OpenGL : public CGraphicsBackend_Threaded::ICommandProcessor { - CCommandProcessorFragment_OpenGL m_OpenGL; - CCommandProcessorFragment_OpenGL3_3 m_OpenGL3_3; + CCommandProcessorFragment_OpenGL *m_pOpenGL; CCommandProcessorFragment_SDL m_SDL; CCommandProcessorFragment_General m_General; - - bool m_UseOpenGL3_3; public: - void UseOpenGL3_3(bool Use) { m_UseOpenGL3_3 = Use; } + CCommandProcessor_SDL_OpenGL(int OpenGLMajor, int OpenGLMinor, int OpenGLPatch); virtual void RunBuffer(CCommandBuffer *pBuffer); }; @@ -349,8 +436,10 @@ class CGraphicsBackend_SDL_OpenGL : public CGraphicsBackend_Threaded SDL_Window *m_pWindow; SDL_GLContext m_GLContext; ICommandProcessor *m_pProcessor; - volatile int m_TextureMemoryUsage; + std::atomic m_TextureMemoryUsage; int m_NumScreens; + + SBackendCapabilites m_Capabilites; bool m_UseNewOpenGL; public: @@ -373,6 +462,11 @@ public: virtual void NotifyWindow(); virtual bool IsNewOpenGL() { return m_UseNewOpenGL; } + virtual bool HasTileBuffering() { return m_Capabilites.m_TileBuffering; } + virtual bool HasQuadBuffering() { return m_Capabilites.m_QuadBuffering; } + virtual bool HasTextBuffering() { return m_Capabilites.m_TextBuffering; } + virtual bool HasQuadContainerBuffering() { return m_Capabilites.m_QuadContainerBuffering; } + virtual bool Has2DTextureArrays() { return m_Capabilites.m_2DArrayTextures; } }; #endif // ENGINE_CLIENT_BACKEND_SDL_H diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index ac3650f6e..9041ada30 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -1207,7 +1207,7 @@ int CGraphics_Threaded::CreateQuadContainer() void CGraphics_Threaded::QuadContainerUpload(int ContainerIndex) { - if(m_IsNewOpenGL) + if(IsQuadContainerBufferingEnabled()) { SQuadContainer& Container = m_QuadContainers[ContainerIndex]; if(Container.m_Quads.size() > 0) @@ -1343,7 +1343,7 @@ void CGraphics_Threaded::QuadContainerAddQuads(int ContainerIndex, CFreeformItem void CGraphics_Threaded::QuadContainerReset(int ContainerIndex) { SQuadContainer& Container = m_QuadContainers[ContainerIndex]; - if(m_IsNewOpenGL) + if(IsQuadContainerBufferingEnabled()) { if(Container.m_QuadBufferContainerIndex != -1) DeleteBufferContainer(Container.m_QuadBufferContainerIndex, true); @@ -1376,7 +1376,7 @@ void CGraphics_Threaded::RenderQuadContainer(int ContainerIndex, int QuadOffset, if((int)Container.m_Quads.size() < QuadOffset + QuadDrawNum || QuadDrawNum == 0) return; - if(m_IsNewOpenGL) + if(IsQuadContainerBufferingEnabled()) { if(Container.m_QuadBufferContainerIndex == -1) return; @@ -1434,7 +1434,7 @@ void CGraphics_Threaded::RenderQuadContainerAsSprite(int ContainerIndex, int Qua if((int)Container.m_Quads.size() < QuadOffset + 1) return; - if(m_IsNewOpenGL) + if(IsQuadContainerBufferingEnabled()) { if(Container.m_QuadBufferContainerIndex == -1) return; @@ -1560,7 +1560,7 @@ void CGraphics_Threaded::RenderQuadContainerAsSpriteMultiple(int ContainerIndex, if(DrawCount == 0) return; - if(m_IsNewOpenGL) + if(IsQuadContainerBufferingEnabled()) { if(Container.m_QuadBufferContainerIndex == -1) return; @@ -2037,14 +2037,18 @@ int CGraphics_Threaded::IssueInit() int r = m_pBackend->Init("DDNet Client", &g_Config.m_GfxScreen, &g_Config.m_GfxScreenWidth, &g_Config.m_GfxScreenHeight, g_Config.m_GfxFsaaSamples, Flags, &m_DesktopScreenWidth, &m_DesktopScreenHeight, &m_ScreenWidth, &m_ScreenHeight, m_pStorage); m_IsNewOpenGL = m_pBackend->IsNewOpenGL(); - m_OpenGLBufferingEnabled = m_IsNewOpenGL; - m_OpenGLHasTextureArrays = m_IsNewOpenGL; + m_OpenGLTileBufferingEnabled = m_IsNewOpenGL || m_pBackend->HasTileBuffering(); + m_OpenGLQuadBufferingEnabled = m_IsNewOpenGL || m_pBackend->HasQuadBuffering(); + m_OpenGLQuadContainerBufferingEnabled = m_IsNewOpenGL || m_pBackend->HasQuadContainerBuffering(); + m_OpenGLTextBufferingEnabled = m_IsNewOpenGL || (m_OpenGLQuadContainerBufferingEnabled && m_pBackend->HasTextBuffering()); + m_OpenGLHasTextureArrays = m_IsNewOpenGL || m_pBackend->Has2DTextureArrays(); return r; } int CGraphics_Threaded::InitWindow() { - if(IssueInit() == 0) + int ErrorCode = IssueInit(); + if(ErrorCode == 0) return 0; // try disabling fsaa @@ -2057,21 +2061,85 @@ int CGraphics_Threaded::InitWindow() else dbg_msg("gfx", "disabling FSAA and trying again"); - if(IssueInit() == 0) + ErrorCode = IssueInit(); + if(ErrorCode == 0) return 0; } - // try using old opengl context - bool IsNewOpenGL = (g_Config.m_GfxOpenGLMajor == 3 && g_Config.m_GfxOpenGLMinor == 3) || g_Config.m_GfxOpenGLMajor >= 4; - if(IsNewOpenGL) + size_t OpenGLInitTryCount = 0; + while(ErrorCode == EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_OPENGL_CONTEXT_FAILED || ErrorCode == EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_OPENGL_VERSION_FAILED) { - g_Config.m_GfxOpenGLMajor = 2; - g_Config.m_GfxOpenGLMinor = 1; - g_Config.m_GfxOpenGLPatch = 0; - if(IssueInit() == 0) + if(ErrorCode == EGraphicsBackendErrorCodes::GRAPHICS_BACKEND_ERROR_CODE_OPENGL_CONTEXT_FAILED) + { + // try next smaller major/minor or patch version + if(g_Config.m_GfxOpenGLMajor >= 4) + { + g_Config.m_GfxOpenGLMajor = 3; + g_Config.m_GfxOpenGLMinor = 3; + g_Config.m_GfxOpenGLPatch = 0; + } + else if(g_Config.m_GfxOpenGLMajor == 3 && g_Config.m_GfxOpenGLMinor >= 1) + { + g_Config.m_GfxOpenGLMajor = 3; + g_Config.m_GfxOpenGLMinor = 0; + g_Config.m_GfxOpenGLPatch = 0; + } + else if(g_Config.m_GfxOpenGLMajor == 3 && g_Config.m_GfxOpenGLMinor == 0) + { + g_Config.m_GfxOpenGLMajor = 2; + g_Config.m_GfxOpenGLMinor = 1; + g_Config.m_GfxOpenGLPatch = 0; + } + else if(g_Config.m_GfxOpenGLMajor == 2 && g_Config.m_GfxOpenGLMinor >= 1) + { + g_Config.m_GfxOpenGLMajor = 2; + g_Config.m_GfxOpenGLMinor = 0; + g_Config.m_GfxOpenGLPatch = 0; + } + else if(g_Config.m_GfxOpenGLMajor == 2 && g_Config.m_GfxOpenGLMinor == 0) + { + g_Config.m_GfxOpenGLMajor = 1; + g_Config.m_GfxOpenGLMinor = 5; + g_Config.m_GfxOpenGLPatch = 0; + } + else if(g_Config.m_GfxOpenGLMajor == 1 && g_Config.m_GfxOpenGLMinor == 5) + { + g_Config.m_GfxOpenGLMajor = 1; + g_Config.m_GfxOpenGLMinor = 4; + g_Config.m_GfxOpenGLPatch = 0; + } + else if(g_Config.m_GfxOpenGLMajor == 1 && g_Config.m_GfxOpenGLMinor == 4) + { + g_Config.m_GfxOpenGLMajor = 1; + g_Config.m_GfxOpenGLMinor = 3; + g_Config.m_GfxOpenGLPatch = 0; + } + else if(g_Config.m_GfxOpenGLMajor == 1 && g_Config.m_GfxOpenGLMinor == 3) + { + g_Config.m_GfxOpenGLMajor = 1; + g_Config.m_GfxOpenGLMinor = 2; + g_Config.m_GfxOpenGLPatch = 1; + } + else if(g_Config.m_GfxOpenGLMajor == 1 && g_Config.m_GfxOpenGLMinor == 2) + { + g_Config.m_GfxOpenGLMajor = 1; + g_Config.m_GfxOpenGLMinor = 1; + g_Config.m_GfxOpenGLPatch = 0; + } + } + + // new opengl version was set by backend, try again + ErrorCode = IssueInit(); + if(ErrorCode == 0) { return 0; } + + if(++OpenGLInitTryCount >= 9) + { + // try something else + break; + } } // try lowering the resolution diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index 45e83795a..f3390c25a 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -66,7 +66,6 @@ public: CMDGROUP_CORE = 0, // commands that everyone has to implement CMDGROUP_PLATFORM_OPENGL = 10000, // commands specific to a platform CMDGROUP_PLATFORM_SDL = 20000, - CMDGROUP_PLATFORM_OPENGL3_3 = 30000, // CMD_NOP = CMDGROUP_CORE, @@ -86,7 +85,7 @@ public: CMD_CLEAR, CMD_RENDER, - //opengl 3.3 commands + //opengl 2.0+ commands (some are just emulated and only exist in opengl 3.3+) CMD_CREATE_BUFFER_OBJECT, // create vbo CMD_RECREATE_BUFFER_OBJECT, // recreate vbo CMD_UPDATE_BUFFER_OBJECT, // update vbo @@ -555,6 +554,19 @@ public: } }; +enum EGraphicsBackendErrorCodes +{ + GRAPHICS_BACKEND_ERROR_CODE_UNKNOWN = -1, + GRAPHICS_BACKEND_ERROR_CODE_NONE = 0, + GRAPHICS_BACKEND_ERROR_CODE_OPENGL_CONTEXT_FAILED, + GRAPHICS_BACKEND_ERROR_CODE_OPENGL_VERSION_FAILED, + GRAPHICS_BACKEND_ERROR_CODE_SDL_INIT_FAILED, + GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_REQUEST_FAILED, + GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_INFO_REQUEST_FAILED, + GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_RESOLUTION_REQUEST_FAILED, + GRAPHICS_BACKEND_ERROR_CODE_SDL_WINDOW_CREATE_FAILED, +}; + // interface for the graphics backend // all these functions are called on the main thread class IGraphicsBackend @@ -594,6 +606,11 @@ public: virtual void WaitForIdle() = 0; virtual bool IsNewOpenGL() { return false; } + virtual bool HasTileBuffering() { return false; } + virtual bool HasQuadBuffering() { return false; } + virtual bool HasTextBuffering() { return false; } + virtual bool HasQuadContainerBuffering() { return false; } + virtual bool Has2DTextureArrays() { return false; } }; class CGraphics_Threaded : public IEngineGraphics @@ -611,7 +628,10 @@ class CGraphics_Threaded : public IEngineGraphics CCommandBuffer::SState m_State; IGraphicsBackend *m_pBackend; - bool m_OpenGLBufferingEnabled; + bool m_OpenGLTileBufferingEnabled; + bool m_OpenGLQuadBufferingEnabled; + bool m_OpenGLTextBufferingEnabled; + bool m_OpenGLQuadContainerBufferingEnabled; bool m_OpenGLHasTextureArrays; bool m_IsNewOpenGL; @@ -830,7 +850,10 @@ public: virtual bool IsIdle(); virtual void WaitForIdle(); - virtual bool IsBufferingEnabled() { return m_OpenGLBufferingEnabled; } + virtual bool IsTileBufferingEnabled() { return m_OpenGLTileBufferingEnabled; } + virtual bool IsQuadBufferingEnabled() { return m_OpenGLQuadBufferingEnabled; } + virtual bool IsTextBufferingEnabled() { return m_OpenGLTextBufferingEnabled; } + virtual bool IsQuadContainerBufferingEnabled() { return m_OpenGLQuadContainerBufferingEnabled; } virtual bool HasTextureArrays() { return m_OpenGLHasTextureArrays; } }; diff --git a/src/engine/client/opengl_sl.cpp b/src/engine/client/opengl_sl.cpp index 9e7b9e395..db10a9b0b 100644 --- a/src/engine/client/opengl_sl.cpp +++ b/src/engine/client/opengl_sl.cpp @@ -14,21 +14,49 @@ 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); //add compiler specific values - 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")); + 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")); + else + { + if(pCompiler->m_OpenGLVersionMajor == 3) + { + if(pCompiler->m_OpenGLVersionMinor == 0) + Lines.push_back(std::string("#version 130 \r\n")); + if(pCompiler->m_OpenGLVersionMinor == 1) + Lines.push_back(std::string("#version 140 \r\n")); + if(pCompiler->m_OpenGLVersionMinor == 2) + Lines.push_back(std::string("#version 150 \r\n")); + } + else if(pCompiler->m_OpenGLVersionMajor == 2) + { + if(pCompiler->m_OpenGLVersionMinor == 0) + Lines.push_back(std::string("#version 110 \r\n")); + if(pCompiler->m_OpenGLVersionMinor == 1) + Lines.push_back(std::string("#version 120 \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")); } + if(Type == GL_FRAGMENT_SHADER && !IsNewOpenGL && pCompiler->m_OpenGLVersionMajor <= 3 && pCompiler->m_HasTextureArray) + { + Lines.push_back(std::string("#extension GL_EXT_texture_array : enable\r\n")); + } + CLineReader LineReader; LineReader.Init(f); char* ReadLine = NULL; while ((ReadLine = LineReader.Get())) { - Lines.push_back(ReadLine); - Lines.back().append("\r\n"); + std::string Line; + pCompiler->ParseLine(Line, ReadLine, Type); + Line.append("\r\n"); + Lines.push_back(Line); } io_close(f); @@ -58,7 +86,7 @@ bool CGLSL::LoadShader(CGLSLCompiler* pCompiler, IStorage *pStorage, const char glGetShaderInfoLog(shader, maxLength, &maxLength, buff); - dbg_msg("GLSL", "%s", buff); + dbg_msg("GLSL", "%s: %s", pFile, buff); glDeleteShader(shader); return false; } @@ -105,6 +133,9 @@ CGLSLCompiler::CGLSLCompiler(int OpenGLVersionMajor, int OpenGLVersionMinor, int m_OpenGLVersionMajor = OpenGLVersionMajor; m_OpenGLVersionMinor = OpenGLVersionMinor; m_OpenGLVersionPatch = OpenGLVersionPatch; + + m_HasTextureArray = false; + m_TextureReplaceType = 0; } void CGLSLCompiler::AddDefine(const std::string& DefineName, const std::string& DefineValue) @@ -121,3 +152,127 @@ void CGLSLCompiler::ClearDefines() { m_Defines.clear(); } + +void CGLSLCompiler::ParseLine(std::string& Line, const char* pReadLine, int Type) +{ + bool IsNewOpenGL = m_OpenGLVersionMajor >= 4 || (m_OpenGLVersionMajor == 3 && m_OpenGLVersionMinor == 3); + if(!IsNewOpenGL) + { + 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, "layout") == 0) + { + //search for ' in' + while(*pBuff && (*pBuff != ' ' || (*(pBuff + 1) && *(pBuff + 1) != 'i') || *(pBuff + 2) != 'n')) + { + ++pBuff; + } + + if(*pBuff && *pBuff == ' ' && *(pBuff + 1) && *(pBuff + 1) == 'i' && *(pBuff + 2) == 'n') + { + pBuff += 3; + Line.append("attribute"); + Line.append(pBuff); + return; + } + else + { + dbg_msg("Shader compiler", "Fix shader for older OpenGL versions."); + } + } + else if(str_comp(aTmpStr, "noperspective") == 0 || str_comp(aTmpStr, "smooth") == 0 || str_comp(aTmpStr, "flat") == 0) + { + //search for 'in' or 'out' + while(*pBuff && ((*pBuff != 'i' || *(pBuff + 1) != 'n') && (*pBuff != 'o' || (*(pBuff + 1) && *(pBuff + 1) != 'u') || *(pBuff + 2) != 't'))) + { + ++pBuff; + } + + bool Found = false; + if(*pBuff) + { + if(*pBuff == 'i' && *(pBuff + 1) == 'n') + { + pBuff += 2; + Found = true; + } + else if(*pBuff == 'o' && *(pBuff + 1) && *(pBuff + 1) == 'u' && *(pBuff + 2) == 't') + { + pBuff += 3; + Found = true; + } + } + + if(!Found) + { + dbg_msg("Shader compiler", "Fix shader for older OpenGL versions."); + } + + Line.append("varying"); + Line.append(pBuff); + return; + } + else if(str_comp(aTmpStr, "out") == 0 || str_comp(aTmpStr, "in") == 0) + { + if(Type == GL_FRAGMENT_SHADER && str_comp(aTmpStr, "out") == 0) + return; + Line.append("varying"); + Line.append(pBuff); + return; + } + else if(str_comp(aTmpStr, "FragClr") == 0) + { + Line.append("gl_FragColor"); + Line.append(pBuff); + return; + } + else if(str_comp(aTmpStr, "texture") == 0) + { + if(m_TextureReplaceType == GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D) + Line.append("texture2D"); + else if(m_TextureReplaceType == GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D) + Line.append("texture3D"); + else if(m_TextureReplaceType == GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY) + Line.append("texture2DArray"); + std::string RestLine; + ParseLine(RestLine, pBuff, Type); + Line.append(RestLine); + 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 bab1bfe24..a0e0e96a1 100644 --- a/src/engine/client/opengl_sl.h +++ b/src/engine/client/opengl_sl.h @@ -44,12 +44,26 @@ private: int m_OpenGLVersionMajor; int m_OpenGLVersionMinor; int m_OpenGLVersionPatch; + + bool m_HasTextureArray; + int m_TextureReplaceType; // @see EGLSLCompilerTextureReplaceType public: CGLSLCompiler(int OpenGLVersionMajor, int OpenGLVersionMinor, int OpenGLVersionPatch); + void SetHasTextureArray(bool TextureArray) { m_HasTextureArray = TextureArray; } + void SetTextureReplaceType(int TextureReplaceType) { m_TextureReplaceType = TextureReplaceType; } void AddDefine(const std::string& DefineName, const std::string& DefineValue); void AddDefine(const char* pDefineName, const char* pDefineValue); void ClearDefines(); + + void ParseLine(std::string& Line, const char* pReadLine, int Type); + + enum EGLSLCompilerTextureReplaceType + { + GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D = 0, + GLSL_COMPILER_TEXTURE_REPLACE_TYPE_3D, + GLSL_COMPILER_TEXTURE_REPLACE_TYPE_2D_ARRAY, + }; }; #endif // ENGINE_CLIENT_OPENGL_SL_H diff --git a/src/engine/client/text.cpp b/src/engine/client/text.cpp index 4a06cdb8b..10902ac1d 100644 --- a/src/engine/client/text.cpp +++ b/src/engine/client/text.cpp @@ -860,7 +860,7 @@ public: // make sure there are no vertices Graphics()->FlushVertices(); - if(Graphics()->IsBufferingEnabled()) + if(Graphics()->IsTextBufferingEnabled()) { Graphics()->TextureClear(); Graphics()->TextQuadsBegin(); @@ -966,7 +966,7 @@ public: if(pCursor->m_Flags&TEXTFLAG_RENDER && m_Color.a != 0.f) { - if(Graphics()->IsBufferingEnabled()) + if(Graphics()->IsTextBufferingEnabled()) Graphics()->QuadsSetSubset(pChr->m_aUVs[0], pChr->m_aUVs[3], pChr->m_aUVs[2], pChr->m_aUVs[1]); else Graphics()->QuadsSetSubset(pChr->m_aUVs[0] * UVScale, pChr->m_aUVs[3] * UVScale, pChr->m_aUVs[2] * UVScale, pChr->m_aUVs[1] * UVScale); @@ -1011,7 +1011,7 @@ public: if(pCursor->m_Flags&TEXTFLAG_RENDER) { - if(Graphics()->IsBufferingEnabled()) + if(Graphics()->IsTextBufferingEnabled()) { float OutlineColor[4] = { m_OutlineColor.r, m_OutlineColor.g, m_OutlineColor.b, m_OutlineColor.a*m_Color.a }; Graphics()->TextQuadsEnd(pFont->m_CurTextureDimensions[0], pFont->m_aTextures[0], pFont->m_aTextures[1], OutlineColor); @@ -1094,7 +1094,7 @@ public: else { TextContainer.m_StringInfo.m_QuadNum = TextContainer.m_StringInfo.m_CharacterQuads.size(); - if(Graphics()->IsBufferingEnabled()) + if(Graphics()->IsTextBufferingEnabled()) { size_t DataSize = TextContainer.m_StringInfo.m_CharacterQuads.size() * sizeof(STextCharQuad); void *pUploadData = &TextContainer.m_StringInfo.m_CharacterQuads[0]; @@ -1349,7 +1349,7 @@ public: { TextContainer.m_StringInfo.m_QuadNum = TextContainer.m_StringInfo.m_CharacterQuads.size(); // setup the buffers - if(Graphics()->IsBufferingEnabled()) + if(Graphics()->IsTextBufferingEnabled()) { size_t DataSize = TextContainer.m_StringInfo.m_CharacterQuads.size() * sizeof(STextCharQuad); void *pUploadData = &TextContainer.m_StringInfo.m_CharacterQuads[0]; @@ -1604,7 +1604,7 @@ public: virtual void DeleteTextContainer(int TextContainerIndex) { STextContainer& TextContainer = GetTextContainer(TextContainerIndex); - if(Graphics()->IsBufferingEnabled()) + if(Graphics()->IsTextBufferingEnabled()) { if(TextContainer.m_StringInfo.m_QuadBufferContainerIndex != -1) Graphics()->DeleteBufferContainer(TextContainer.m_StringInfo.m_QuadBufferContainerIndex, true); @@ -1632,7 +1632,7 @@ public: s_CursorRenderTime = time_get_microseconds(); } - if(Graphics()->IsBufferingEnabled()) + if(Graphics()->IsTextBufferingEnabled()) { Graphics()->TextureClear(); // render buffered text @@ -1712,7 +1712,7 @@ public: Graphics()->MapScreen(ScreenX0, ScreenY0, ScreenX1, ScreenY1); } - virtual void UploadEntityLayerText(void* pTexBuff, int TexWidth, int TexHeight, const char *pText, int Length, float x, float y, int FontSize) + virtual void UploadEntityLayerText(void* pTexBuff, int ImageColorChannelCount, int TexWidth, int TexHeight, const char *pText, int Length, float x, float y, int FontSize) { if (FontSize < 1) return; @@ -1762,13 +1762,25 @@ public: uint8_t* pImageBuff = (uint8_t*)pTexBuff; for(int OffY = 0; OffY < SlotH; ++OffY) { - size_t ImageOffset = (y + OffY) * TexWidth + (x + WidthLastChars); - size_t GlyphOffset = (OffY) * SlotW; - mem_copy(pImageBuff + ImageOffset, ms_aGlyphData + GlyphOffset, sizeof(uint8_t) * SlotW); + for(int OffX = 0; OffX < SlotW; ++OffX) + { + size_t ImageOffset = (y + OffY) * (TexWidth * ImageColorChannelCount) + ((x + OffX) + WidthLastChars) * ImageColorChannelCount; + size_t GlyphOffset = (OffY) * SlotW + OffX; + for(size_t i = 0; i < (size_t)ImageColorChannelCount; ++i) + { + if(i != (size_t)ImageColorChannelCount - 1) + { + *(pImageBuff + ImageOffset + i) = 255; + } + else + { + *(pImageBuff + ImageOffset + i) = *(ms_aGlyphData + GlyphOffset); + } + } + } } WidthLastChars += (SlotW + 1); - } pCurrent = pTmp; } diff --git a/src/engine/graphics.h b/src/engine/graphics.h index a9cb8ded5..9a220761e 100644 --- a/src/engine/graphics.h +++ b/src/engine/graphics.h @@ -40,6 +40,22 @@ struct SQuadRenderInfo float m_Rotation; }; +struct SGraphicTile +{ + vec2 m_TopLeft; + vec2 m_TopRight; + vec2 m_BottomRight; + vec2 m_BottomLeft; +}; + +struct SGraphicTileTexureCoords +{ + vec3 m_TexCoordTopLeft; + vec3 m_TexCoordTopRight; + vec3 m_TexCoordBottomRight; + vec3 m_TexCoordBottomLeft; +}; + class CImageInfo { public: @@ -80,6 +96,7 @@ public: struct GL_SPoint { float x, y; }; struct GL_STexCoord { float u, v; }; +struct GL_STexCoord3D { float u, v, w; }; struct GL_SColorf { float r, g, b, a; }; //use normalized color values @@ -92,6 +109,13 @@ struct GL_SVertex GL_SColor m_Color; }; +struct GL_SVertexTex3D +{ + GL_SPoint m_Pos; + GL_SColorf m_Color; + GL_STexCoord3D m_Tex; +}; + typedef void(*WINDOW_RESIZE_FUNC)(void *pUser); class IGraphics : public IInterface @@ -190,7 +214,10 @@ public: virtual void UpdateBufferContainer(int ContainerIndex, struct SBufferContainerInfo *pContainerInfo) = 0; virtual void IndicesNumRequiredNotify(unsigned int RequiredIndicesCount) = 0; - virtual bool IsBufferingEnabled() = 0; + virtual bool IsTileBufferingEnabled() = 0; + virtual bool IsQuadBufferingEnabled() = 0; + virtual bool IsTextBufferingEnabled() = 0; + virtual bool IsQuadContainerBufferingEnabled() = 0; virtual bool HasTextureArrays() = 0; struct CLineItem diff --git a/src/engine/textrender.h b/src/engine/textrender.h index 409ecbc1e..1be56f726 100644 --- a/src/engine/textrender.h +++ b/src/engine/textrender.h @@ -6,6 +6,7 @@ #include #include +#include enum { @@ -99,7 +100,7 @@ public: virtual void RenderTextContainer(int TextContainerIndex, STextRenderColor *pTextColor, STextRenderColor *pTextOutlineColor) = 0; virtual void RenderTextContainer(int TextContainerIndex, STextRenderColor *pTextColor, STextRenderColor *pTextOutlineColor, float X, float Y) = 0; - virtual void UploadEntityLayerText(void* pTexBuff, int TexWidth, int TexHeight, const char *pText, int Length, float x, float y, int FontHeight) = 0; + virtual void UploadEntityLayerText(void* pTexBuff, int ImageColorChannelCount, int TexWidth, int TexHeight, const char *pText, int Length, float x, float y, int FontHeight) = 0; virtual int AdjustFontSize(const char *pText, int TextLength, int MaxSize = -1) = 0; virtual int CalculateTextWidth(const char *pText, int TextLength, int FontWidth, int FontHeight) = 0; diff --git a/src/game/client/components/camera.cpp b/src/game/client/components/camera.cpp index 8be58096e..55e075fbd 100644 --- a/src/game/client/components/camera.cpp +++ b/src/game/client/components/camera.cpp @@ -38,7 +38,7 @@ void CCamera::ScaleZoom(float Factor) void CCamera::ChangeZoom(float Target) { - if(Target >= (Graphics()->IsBufferingEnabled()? 60 : 30)) + if(Target >= (Graphics()->IsTileBufferingEnabled()? 60 : 30)) { return; } diff --git a/src/game/client/components/mapimages.cpp b/src/game/client/components/mapimages.cpp index 85831458e..e71d0006d 100644 --- a/src/game/client/components/mapimages.cpp +++ b/src/game/client/components/mapimages.cpp @@ -178,20 +178,20 @@ int CMapImages::GetTextureScale() IGraphics::CTextureHandle CMapImages::UploadEntityLayerText(int TextureSize, int YOffset) { - void *pMem = calloc(1024 * 1024, 1); + void *pMem = calloc(1024 * 1024 * 4, 1); - UpdateEntityLayerText(pMem, 1024, 1024, TextureSize, YOffset, 0); - UpdateEntityLayerText(pMem, 1024, 1024, TextureSize, YOffset, 1); - UpdateEntityLayerText(pMem, 1024, 1024, TextureSize, YOffset, 2, 255); + UpdateEntityLayerText(pMem, 4, 1024, 1024, TextureSize, YOffset, 0); + UpdateEntityLayerText(pMem, 4, 1024, 1024, TextureSize, YOffset, 1); + UpdateEntityLayerText(pMem, 4, 1024, 1024, TextureSize, YOffset, 2, 255); int TextureLoadFlag = Graphics()->HasTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE; - IGraphics::CTextureHandle Texture = Graphics()->LoadTextureRaw(1024, 1024, CImageInfo::FORMAT_ALPHA, pMem, CImageInfo::FORMAT_ALPHA, TextureLoadFlag); + IGraphics::CTextureHandle Texture = Graphics()->LoadTextureRaw(1024, 1024, CImageInfo::FORMAT_RGBA, pMem, CImageInfo::FORMAT_RGBA, TextureLoadFlag); free(pMem); return Texture; } -void CMapImages::UpdateEntityLayerText(void* pTexBuffer, int TexWidth, int TexHeight, int TextureSize, int YOffset, int NumbersPower, int MaxNumber) +void CMapImages::UpdateEntityLayerText(void* pTexBuffer, int ImageColorChannelCount, int TexWidth, int TexHeight, int TextureSize, int YOffset, int NumbersPower, int MaxNumber) { char aBuf[4]; int DigitsCount = NumbersPower+1; @@ -217,7 +217,7 @@ void CMapImages::UpdateEntityLayerText(void* pTexBuffer, int TexWidth, int TexHe float x = (CurrentNumber%16)*64; float y = (CurrentNumber/16)*64; - TextRender()->UploadEntityLayerText(pTexBuffer, TexWidth, TexHeight, aBuf, DigitsCount, x+XOffSet, y+YOffset, UniversalSuitableFontSize); + TextRender()->UploadEntityLayerText(pTexBuffer, ImageColorChannelCount, TexWidth, TexHeight, aBuf, DigitsCount, x+XOffSet, y+YOffset, UniversalSuitableFontSize); } } diff --git a/src/game/client/components/mapimages.h b/src/game/client/components/mapimages.h index 94591d027..d63626c5e 100644 --- a/src/game/client/components/mapimages.h +++ b/src/game/client/components/mapimages.h @@ -47,7 +47,7 @@ private: void InitOverlayTextures(); IGraphics::CTextureHandle UploadEntityLayerText(int TextureSize, int YOffset); - void UpdateEntityLayerText(void* pTexBuffer, int TexWidth, int TexHeight, int TextureSize, int YOffset, int NumbersPower, int MaxNumber = -1); + void UpdateEntityLayerText(void* pTexBuffer, int ImageColorChannelCount, int TexWidth, int TexHeight, int TextureSize, int YOffset, int NumbersPower, int MaxNumber = -1); }; #endif diff --git a/src/game/client/components/maplayers.cpp b/src/game/client/components/maplayers.cpp index 75a1406d1..b6b595bee 100644 --- a/src/game/client/components/maplayers.cpp +++ b/src/game/client/components/maplayers.cpp @@ -125,23 +125,7 @@ void CMapLayers::EnvelopeEval(float TimeOffset, int Env, float *pChannels, void } } -struct STmpTile -{ - vec2 m_TopLeft; - vec2 m_TopRight; - vec2 m_BottomRight; - vec2 m_BottomLeft; -}; - -struct STmpTileTexCoord -{ - vec3 m_TexCoordTopLeft; - vec3 m_TexCoordTopRight; - vec3 m_TexCoordBottomRight; - vec3 m_TexCoordBottomLeft; -}; - -void FillTmpTileSpeedup(STmpTile* pTmpTile, STmpTileTexCoord* pTmpTex, unsigned char Flags, unsigned char Index, int x, int y, int Scale, CMapItemGroup* pGroup, short AngleRotate) +void FillTmpTileSpeedup(SGraphicTile* pTmpTile, SGraphicTileTexureCoords* pTmpTex, bool As3DTextureCoord, unsigned char Flags, unsigned char Index, int x, int y, int Scale, CMapItemGroup* pGroup, short AngleRotate) { if(pTmpTex) { @@ -156,16 +140,27 @@ void FillTmpTileSpeedup(STmpTile* pTmpTile, STmpTileTexCoord* pTmpTex, unsigned pTmpTex->m_TexCoordTopLeft.x = x0; pTmpTex->m_TexCoordTopLeft.y = y0; - pTmpTex->m_TexCoordTopLeft.z = Index; pTmpTex->m_TexCoordBottomLeft.x = x3; pTmpTex->m_TexCoordBottomLeft.y = y3; - pTmpTex->m_TexCoordBottomLeft.z = Index; pTmpTex->m_TexCoordTopRight.x = x1; pTmpTex->m_TexCoordTopRight.y = y1; - pTmpTex->m_TexCoordTopRight.z = Index; pTmpTex->m_TexCoordBottomRight.x = x2; pTmpTex->m_TexCoordBottomRight.y = y2; - pTmpTex->m_TexCoordBottomRight.z = Index; + + if(As3DTextureCoord) + { + pTmpTex->m_TexCoordTopLeft.z = ((float)Index + 0.5f) / 256.f; + pTmpTex->m_TexCoordBottomLeft.z = ((float)Index + 0.5f) / 256.f; + pTmpTex->m_TexCoordTopRight.z = ((float)Index + 0.5f) / 256.f; + pTmpTex->m_TexCoordBottomRight.z = ((float)Index + 0.5f) / 256.f; + } + else + { + pTmpTex->m_TexCoordTopLeft.z = Index; + pTmpTex->m_TexCoordBottomLeft.z = Index; + pTmpTex->m_TexCoordTopRight.z = Index; + pTmpTex->m_TexCoordBottomRight.z = Index; + } } //same as in rotate from Graphics() @@ -200,7 +195,7 @@ void FillTmpTileSpeedup(STmpTile* pTmpTile, STmpTileTexCoord* pTmpTex, unsigned } } -void FillTmpTile(STmpTile* pTmpTile, STmpTileTexCoord* pTmpTex, unsigned char Flags, unsigned char Index, int x, int y, int Scale, CMapItemGroup* pGroup) +void FillTmpTile(SGraphicTile* pTmpTile, SGraphicTileTexureCoords* pTmpTex, bool As3DTextureCoord, unsigned char Flags, unsigned char Index, int x, int y, int Scale, CMapItemGroup* pGroup) { if(pTmpTex) { @@ -245,16 +240,27 @@ void FillTmpTile(STmpTile* pTmpTile, STmpTileTexCoord* pTmpTex, unsigned char Fl pTmpTex->m_TexCoordTopLeft.x = x0; pTmpTex->m_TexCoordTopLeft.y = y0; - pTmpTex->m_TexCoordTopLeft.z = Index; pTmpTex->m_TexCoordBottomLeft.x = x3; pTmpTex->m_TexCoordBottomLeft.y = y3; - pTmpTex->m_TexCoordBottomLeft.z = Index; pTmpTex->m_TexCoordTopRight.x = x1; pTmpTex->m_TexCoordTopRight.y = y1; - pTmpTex->m_TexCoordTopRight.z = Index; pTmpTex->m_TexCoordBottomRight.x = x2; pTmpTex->m_TexCoordBottomRight.y = y2; - pTmpTex->m_TexCoordBottomRight.z = Index; + + if(As3DTextureCoord) + { + pTmpTex->m_TexCoordTopLeft.z = ((float)Index + 0.5f) / 256.f; + pTmpTex->m_TexCoordBottomLeft.z = ((float)Index + 0.5f) / 256.f; + pTmpTex->m_TexCoordTopRight.z = ((float)Index + 0.5f) / 256.f; + pTmpTex->m_TexCoordBottomRight.z = ((float)Index + 0.5f) / 256.f; + } + else + { + pTmpTex->m_TexCoordTopLeft.z = Index; + pTmpTex->m_TexCoordBottomLeft.z = Index; + pTmpTex->m_TexCoordTopRight.z = Index; + pTmpTex->m_TexCoordBottomRight.z = Index; + } } pTmpTile->m_TopLeft.x = x*Scale; @@ -312,23 +318,23 @@ CMapLayers::STileLayerVisuals::~STileLayerVisuals() m_BorderRight = NULL; } -bool AddTile(std::vector& TmpTiles, std::vector& TmpTileTexCoords, unsigned char Index, unsigned char Flags, int x, int y, CMapItemGroup* pGroup, bool DoTextureCoords, bool FillSpeedup = false, int AngleRotate = -1) +bool AddTile(std::vector& TmpTiles, std::vector& TmpTileTexCoords, bool As3DTextureCoord, unsigned char Index, unsigned char Flags, int x, int y, CMapItemGroup* pGroup, bool DoTextureCoords, bool FillSpeedup = false, int AngleRotate = -1) { if(Index) { - TmpTiles.push_back(STmpTile()); - STmpTile& Tile = TmpTiles.back(); - STmpTileTexCoord* pTileTex = NULL; + TmpTiles.push_back(SGraphicTile()); + SGraphicTile& Tile = TmpTiles.back(); + SGraphicTileTexureCoords* pTileTex = NULL; if(DoTextureCoords) { - TmpTileTexCoords.push_back(STmpTileTexCoord()); - STmpTileTexCoord& TileTex = TmpTileTexCoords.back(); + TmpTileTexCoords.push_back(SGraphicTileTexureCoords()); + SGraphicTileTexureCoords& TileTex = TmpTileTexCoords.back(); pTileTex = &TileTex; } if(FillSpeedup) - FillTmpTileSpeedup(&Tile, pTileTex, Flags, 0, x, y, 32.f, pGroup, AngleRotate); + FillTmpTileSpeedup(&Tile, pTileTex, As3DTextureCoord, Flags, 0, x, y, 32.f, pGroup, AngleRotate); else - FillTmpTile(&Tile, pTileTex, Flags, Index, x, y, 32.f, pGroup); + FillTmpTile(&Tile, pTileTex, As3DTextureCoord, Flags, Index, x, y, 32.f, pGroup); return true; } @@ -370,7 +376,7 @@ void mem_copy_special(void *pDest, void *pSource, size_t Size, size_t Count, siz void CMapLayers::OnMapLoad() { - if(!Graphics()->IsBufferingEnabled()) + if(!Graphics()->IsTileBufferingEnabled() && !Graphics()->IsQuadBufferingEnabled()) return; //clear everything and destroy all buffers if(m_TileLayerVisuals.size() != 0) @@ -396,22 +402,24 @@ void CMapLayers::OnMapLoad() bool PassedGameLayer = false; //prepare all visuals for all tile layers - std::vector tmpTiles; - std::vector tmpTileTexCoords; - std::vector tmpBorderTopTiles; - std::vector tmpBorderTopTilesTexCoords; - std::vector tmpBorderLeftTiles; - std::vector tmpBorderLeftTilesTexCoords; - std::vector tmpBorderRightTiles; - std::vector tmpBorderRightTilesTexCoords; - std::vector tmpBorderBottomTiles; - std::vector tmpBorderBottomTilesTexCoords; - std::vector tmpBorderCorners; - std::vector tmpBorderCornersTexCoords; + std::vector tmpTiles; + std::vector tmpTileTexCoords; + std::vector tmpBorderTopTiles; + std::vector tmpBorderTopTilesTexCoords; + std::vector tmpBorderLeftTiles; + std::vector tmpBorderLeftTilesTexCoords; + std::vector tmpBorderRightTiles; + std::vector tmpBorderRightTilesTexCoords; + std::vector tmpBorderBottomTiles; + std::vector tmpBorderBottomTilesTexCoords; + std::vector tmpBorderCorners; + std::vector tmpBorderCornersTexCoords; std::vector tmpQuads; std::vector tmpQuadsTextured; + bool As3DTextureCoords = !Graphics()->HasTextureArrays(); + for(int g = 0; g < m_pLayers->NumGroups(); g++) { CMapItemGroup *pGroup = m_pLayers->GetGroup(g); @@ -467,7 +475,7 @@ void CMapLayers::OnMapLoad() continue; } - if(pLayer->m_Type == LAYERTYPE_TILES) + if(pLayer->m_Type == LAYERTYPE_TILES && Graphics()->IsTileBufferingEnabled()) { bool DoTextureCoords = false; CMapItemLayerTilemap *pTMap = (CMapItemLayerTilemap *)pLayer; @@ -548,6 +556,23 @@ void CMapLayers::OnMapLoad() tmpBorderBottomTilesTexCoords.clear(); tmpBorderCornersTexCoords.clear(); + if(!DoTextureCoords) { + tmpTiles.reserve((size_t)(pTMap->m_Width*pTMap->m_Height)); + tmpBorderTopTiles.reserve((size_t)pTMap->m_Width); + tmpBorderBottomTiles.reserve((size_t)pTMap->m_Width); + tmpBorderLeftTiles.reserve((size_t)pTMap->m_Height); + tmpBorderRightTiles.reserve((size_t)pTMap->m_Height); + tmpBorderCorners.reserve((size_t)4); + } + else { + tmpTileTexCoords.reserve((size_t)(pTMap->m_Width*pTMap->m_Height)); + tmpBorderTopTilesTexCoords.reserve((size_t)pTMap->m_Width); + tmpBorderBottomTilesTexCoords.reserve((size_t)pTMap->m_Width); + tmpBorderLeftTilesTexCoords.reserve((size_t)pTMap->m_Height); + tmpBorderRightTilesTexCoords.reserve((size_t)pTMap->m_Height); + tmpBorderCornersTexCoords.reserve((size_t)4); + } + int x = 0; int y = 0; for(y = 0; y < pTMap->m_Height; ++y) @@ -636,7 +661,7 @@ void CMapLayers::OnMapLoad() if(IsSpeedupLayer && CurOverlay == 0) AddAsSpeedup = true; - if(AddTile(tmpTiles, tmpTileTexCoords, Index, Flags, x, y, pGroup, DoTextureCoords, AddAsSpeedup, AngleRotate)) + if(AddTile(tmpTiles, tmpTileTexCoords, As3DTextureCoords, Index, Flags, x, y, pGroup, DoTextureCoords, AddAsSpeedup, AngleRotate)) Visuals.m_TilesOfLayer[y*pTMap->m_Width + x].Draw(true); //do the border tiles @@ -645,20 +670,20 @@ void CMapLayers::OnMapLoad() if(y == 0) { Visuals.m_BorderTopLeft.SetIndexBufferByteOffset((offset_ptr32)(tmpBorderCorners.size()*6*sizeof(unsigned int))); - if(AddTile(tmpBorderCorners, tmpBorderCornersTexCoords, Index, Flags, x, y, pGroup, DoTextureCoords, AddAsSpeedup, AngleRotate)) + if(AddTile(tmpBorderCorners, tmpBorderCornersTexCoords, As3DTextureCoords, Index, Flags, x, y, pGroup, DoTextureCoords, AddAsSpeedup, AngleRotate)) Visuals.m_BorderTopLeft.Draw(true); } else if(y == pTMap->m_Height - 1) { Visuals.m_BorderBottomLeft.SetIndexBufferByteOffset((offset_ptr32)(tmpBorderCorners.size()*6*sizeof(unsigned int))); - if(AddTile(tmpBorderCorners, tmpBorderCornersTexCoords, Index, Flags, x, y, pGroup, DoTextureCoords, AddAsSpeedup, AngleRotate)) + if(AddTile(tmpBorderCorners, tmpBorderCornersTexCoords, As3DTextureCoords, Index, Flags, x, y, pGroup, DoTextureCoords, AddAsSpeedup, AngleRotate)) Visuals.m_BorderBottomLeft.Draw(true); } else { Visuals.m_BorderLeft[y-1].SetIndexBufferByteOffset((offset_ptr32)(tmpBorderLeftTiles.size()*6*sizeof(unsigned int))); - if(AddTile(tmpBorderLeftTiles, tmpBorderLeftTilesTexCoords, Index, Flags, x, y, pGroup, DoTextureCoords, AddAsSpeedup, AngleRotate)) + if(AddTile(tmpBorderLeftTiles, tmpBorderLeftTilesTexCoords, As3DTextureCoords, Index, Flags, x, y, pGroup, DoTextureCoords, AddAsSpeedup, AngleRotate)) Visuals.m_BorderLeft[y-1].Draw(true); } } @@ -667,21 +692,21 @@ void CMapLayers::OnMapLoad() if(y == 0) { Visuals.m_BorderTopRight.SetIndexBufferByteOffset((offset_ptr32)(tmpBorderCorners.size()*6*sizeof(unsigned int))); - if(AddTile(tmpBorderCorners, tmpBorderCornersTexCoords, Index, Flags, x, y, pGroup, DoTextureCoords, AddAsSpeedup, AngleRotate)) + if(AddTile(tmpBorderCorners, tmpBorderCornersTexCoords, As3DTextureCoords, Index, Flags, x, y, pGroup, DoTextureCoords, AddAsSpeedup, AngleRotate)) Visuals.m_BorderTopRight.Draw(true); } else if(y == pTMap->m_Height - 1) { Visuals.m_BorderBottomRight.SetIndexBufferByteOffset((offset_ptr32)(tmpBorderCorners.size()*6*sizeof(unsigned int))); - if(AddTile(tmpBorderCorners, tmpBorderCornersTexCoords, Index, Flags, x, y, pGroup, DoTextureCoords, AddAsSpeedup, AngleRotate)) + if(AddTile(tmpBorderCorners, tmpBorderCornersTexCoords, As3DTextureCoords, Index, Flags, x, y, pGroup, DoTextureCoords, AddAsSpeedup, AngleRotate)) Visuals.m_BorderBottomRight.Draw(true); } else { Visuals.m_BorderRight[y-1].SetIndexBufferByteOffset((offset_ptr32)(tmpBorderRightTiles.size()*6*sizeof(unsigned int))); - if(AddTile(tmpBorderRightTiles, tmpBorderRightTilesTexCoords, Index, Flags, x, y, pGroup, DoTextureCoords, AddAsSpeedup, AngleRotate)) + if(AddTile(tmpBorderRightTiles, tmpBorderRightTilesTexCoords, As3DTextureCoords, Index, Flags, x, y, pGroup, DoTextureCoords, AddAsSpeedup, AngleRotate)) Visuals.m_BorderRight[y-1].Draw(true); } } @@ -690,7 +715,7 @@ void CMapLayers::OnMapLoad() if(x > 0 && x < pTMap->m_Width - 1) { Visuals.m_BorderTop[x-1].SetIndexBufferByteOffset((offset_ptr32)(tmpBorderTopTiles.size()*6*sizeof(unsigned int))); - if(AddTile(tmpBorderTopTiles, tmpBorderTopTilesTexCoords, Index, Flags, x, y, pGroup, DoTextureCoords, AddAsSpeedup, AngleRotate)) + if(AddTile(tmpBorderTopTiles, tmpBorderTopTilesTexCoords, As3DTextureCoords, Index, Flags, x, y, pGroup, DoTextureCoords, AddAsSpeedup, AngleRotate)) Visuals.m_BorderTop[x-1].Draw(true); } } @@ -699,7 +724,7 @@ void CMapLayers::OnMapLoad() if(x > 0 && x < pTMap->m_Width - 1) { Visuals.m_BorderBottom[x-1].SetIndexBufferByteOffset((offset_ptr32)(tmpBorderBottomTiles.size()*6*sizeof(unsigned int))); - if(AddTile(tmpBorderBottomTiles, tmpBorderBottomTilesTexCoords, Index, Flags, x, y, pGroup, DoTextureCoords, AddAsSpeedup, AngleRotate)) + if(AddTile(tmpBorderBottomTiles, tmpBorderBottomTilesTexCoords, As3DTextureCoords, Index, Flags, x, y, pGroup, DoTextureCoords, AddAsSpeedup, AngleRotate)) Visuals.m_BorderBottom[x-1].Draw(true); } } @@ -710,7 +735,7 @@ void CMapLayers::OnMapLoad() if(IsGameLayer) { Visuals.m_BorderKillTile.SetIndexBufferByteOffset((offset_ptr32)(tmpTiles.size() * 6 * sizeof(unsigned int))); - if(AddTile(tmpTiles, tmpTileTexCoords, TILE_DEATH, 0, 0, 0, pGroup, DoTextureCoords)) + if(AddTile(tmpTiles, tmpTileTexCoords, As3DTextureCoords, TILE_DEATH, 0, 0, 0, pGroup, DoTextureCoords)) Visuals.m_BorderKillTile.Draw(true); } @@ -773,51 +798,55 @@ void CMapLayers::OnMapLoad() float* pTmpTiles = (tmpTiles.size() == 0) ? NULL : (float*)&tmpTiles[0]; unsigned char* pTmpTileTexCoords = (tmpTileTexCoords.size() == 0) ? NULL : (unsigned char*)&tmpTileTexCoords[0]; - size_t UploadDataSize = tmpTileTexCoords.size() * sizeof(STmpTileTexCoord) + tmpTiles.size() * sizeof(STmpTile); - char* pUploadData = new char[UploadDataSize]; - - mem_copy_special(pUploadData, pTmpTiles, sizeof(vec2), tmpTiles.size() * 4, (DoTextureCoords ? sizeof(vec3) : 0)); - if(DoTextureCoords) + Visuals.m_BufferContainerIndex = -1; + size_t UploadDataSize = tmpTileTexCoords.size() * sizeof(SGraphicTileTexureCoords) + tmpTiles.size() * sizeof(SGraphicTile); + if(UploadDataSize > 0) { - mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), tmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0)); - } + char* pUploadData = new char[UploadDataSize]; - // first create the buffer object - int BufferObjectIndex = Graphics()->CreateBufferObject(UploadDataSize, pUploadData); - delete[] pUploadData; + mem_copy_special(pUploadData, pTmpTiles, sizeof(vec2), tmpTiles.size() * 4, (DoTextureCoords ? sizeof(vec3) : 0)); + if(DoTextureCoords) + { + mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), tmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0)); + } - // then create the buffer container - SBufferContainerInfo ContainerInfo; - ContainerInfo.m_Stride = (DoTextureCoords ? (sizeof(float) * 2 + sizeof(vec3)) : 0); - ContainerInfo.m_Attributes.push_back(SBufferContainerInfo::SAttribute()); - SBufferContainerInfo::SAttribute* pAttr = &ContainerInfo.m_Attributes.back(); - pAttr->m_DataTypeCount = 2; - pAttr->m_Type = GRAPHICS_TYPE_FLOAT; - pAttr->m_Normalized = false; - pAttr->m_pOffset = 0; - pAttr->m_FuncType = 0; - pAttr->m_VertBufferBindingIndex = BufferObjectIndex; - if(DoTextureCoords) - { + // first create the buffer object + int BufferObjectIndex = Graphics()->CreateBufferObject(UploadDataSize, pUploadData); + delete[] pUploadData; + + // then create the buffer container + SBufferContainerInfo ContainerInfo; + ContainerInfo.m_Stride = (DoTextureCoords ? (sizeof(float) * 2 + sizeof(vec3)) : 0); ContainerInfo.m_Attributes.push_back(SBufferContainerInfo::SAttribute()); - pAttr = &ContainerInfo.m_Attributes.back(); - pAttr->m_DataTypeCount = 3; + SBufferContainerInfo::SAttribute* pAttr = &ContainerInfo.m_Attributes.back(); + pAttr->m_DataTypeCount = 2; pAttr->m_Type = GRAPHICS_TYPE_FLOAT; pAttr->m_Normalized = false; - pAttr->m_pOffset = (void*)(sizeof(vec2)); + pAttr->m_pOffset = 0; pAttr->m_FuncType = 0; pAttr->m_VertBufferBindingIndex = BufferObjectIndex; - } + if(DoTextureCoords) + { + ContainerInfo.m_Attributes.push_back(SBufferContainerInfo::SAttribute()); + pAttr = &ContainerInfo.m_Attributes.back(); + pAttr->m_DataTypeCount = 3; + pAttr->m_Type = GRAPHICS_TYPE_FLOAT; + pAttr->m_Normalized = false; + pAttr->m_pOffset = (void*)(sizeof(vec2)); + pAttr->m_FuncType = 0; + pAttr->m_VertBufferBindingIndex = BufferObjectIndex; + } - Visuals.m_BufferContainerIndex = Graphics()->CreateBufferContainer(&ContainerInfo); - // and finally inform the backend how many indices are required - Graphics()->IndicesNumRequiredNotify(tmpTiles.size() * 6); + Visuals.m_BufferContainerIndex = Graphics()->CreateBufferContainer(&ContainerInfo); + // and finally inform the backend how many indices are required + Graphics()->IndicesNumRequiredNotify(tmpTiles.size() * 6); + } ++CurOverlay; } } } - else if(pLayer->m_Type == LAYERTYPE_QUADS) + else if(pLayer->m_Type == LAYERTYPE_QUADS && Graphics()->IsQuadBufferingEnabled()) { CMapItemLayerQuads *pQLayer = (CMapItemLayerQuads *)pLayer; @@ -1666,7 +1695,7 @@ void CMapLayers::OnRender() Color = ColorRGBA(pTMap->m_Color.r/255.0f, pTMap->m_Color.g/255.0f, pTMap->m_Color.b/255.0f, pTMap->m_Color.a/255.0f*g_Config.m_ClOverlayEntities/100.0f); else if(!IsGameLayer && g_Config.m_ClOverlayEntities && !(m_Type == TYPE_BACKGROUND_FORCE)) Color = ColorRGBA(pTMap->m_Color.r/255.0f, pTMap->m_Color.g/255.0f, pTMap->m_Color.b/255.0f, pTMap->m_Color.a/255.0f*(100-g_Config.m_ClOverlayEntities)/100.0f); - if(!Graphics()->IsBufferingEnabled()) + if(!Graphics()->IsTileBufferingEnabled()) { Graphics()->BlendNone(); RenderTools()->RenderTilemap(pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_OPAQUE, @@ -1689,7 +1718,8 @@ void CMapLayers::OnRender() RenderTools()->RenderTilemap(pTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_TRANSPARENT, EnvelopeEval, this, pTMap->m_ColorEnv, pTMap->m_ColorEnvOffset); - } else + } + else { Graphics()->BlendNormal(); // draw kill tiles outside the entity clipping rectangle @@ -1719,7 +1749,7 @@ void CMapLayers::OnRender() { if(g_Config.m_ClShowQuads) { - if(!Graphics()->IsBufferingEnabled()) + if(!Graphics()->IsQuadBufferingEnabled()) { //Graphics()->BlendNone(); //RenderTools()->ForceRenderQuads(pQuads, pQLayer->m_NumQuads, LAYERRENDERFLAG_OPAQUE, EnvelopeEval, this, 1.f); @@ -1733,7 +1763,7 @@ void CMapLayers::OnRender() } } else { - if(!Graphics()->IsBufferingEnabled()) + if(!Graphics()->IsQuadBufferingEnabled()) { //Graphics()->BlendNone(); //RenderTools()->RenderQuads(pQuads, pQLayer->m_NumQuads, LAYERRENDERFLAG_OPAQUE, EnvelopeEval, this); @@ -1758,7 +1788,7 @@ void CMapLayers::OnRender() if(Size >= pTMap->m_Width*pTMap->m_Height*sizeof(CTile)) { ColorRGBA Color = ColorRGBA(pTMap->m_Color.r/255.0f, pTMap->m_Color.g/255.0f, pTMap->m_Color.b/255.0f, pTMap->m_Color.a/255.0f*g_Config.m_ClOverlayEntities/100.0f); - if(!Graphics()->IsBufferingEnabled()) + if(!Graphics()->IsTileBufferingEnabled()) { Graphics()->BlendNone(); RenderTools()->RenderTilemap(pFrontTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_OPAQUE, @@ -1785,7 +1815,7 @@ void CMapLayers::OnRender() if(Size >= pTMap->m_Width*pTMap->m_Height*sizeof(CSwitchTile)) { ColorRGBA Color = ColorRGBA(pTMap->m_Color.r/255.0f, pTMap->m_Color.g/255.0f, pTMap->m_Color.b/255.0f, pTMap->m_Color.a/255.0f*g_Config.m_ClOverlayEntities/100.0f); - if(!Graphics()->IsBufferingEnabled()) + if(!Graphics()->IsTileBufferingEnabled()) { Graphics()->BlendNone(); RenderTools()->RenderSwitchmap(pSwitchTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_OPAQUE); @@ -1818,7 +1848,7 @@ void CMapLayers::OnRender() if(Size >= pTMap->m_Width*pTMap->m_Height*sizeof(CTeleTile)) { ColorRGBA Color = ColorRGBA(pTMap->m_Color.r/255.0f, pTMap->m_Color.g/255.0f, pTMap->m_Color.b/255.0f, pTMap->m_Color.a/255.0f*g_Config.m_ClOverlayEntities/100.0f); - if(!Graphics()->IsBufferingEnabled()) + if(!Graphics()->IsTileBufferingEnabled()) { Graphics()->BlendNone(); RenderTools()->RenderTelemap(pTeleTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_OPAQUE); @@ -1849,7 +1879,7 @@ void CMapLayers::OnRender() if(Size >= pTMap->m_Width*pTMap->m_Height*sizeof(CSpeedupTile)) { ColorRGBA Color = ColorRGBA(pTMap->m_Color.r/255.0f, pTMap->m_Color.g/255.0f, pTMap->m_Color.b/255.0f, pTMap->m_Color.a/255.0f*g_Config.m_ClOverlayEntities/100.0f); - if(!Graphics()->IsBufferingEnabled()) + if(!Graphics()->IsTileBufferingEnabled()) { Graphics()->BlendNone(); RenderTools()->RenderSpeedupmap(pSpeedupTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_OPAQUE); @@ -1887,7 +1917,7 @@ void CMapLayers::OnRender() if(Size >= pTMap->m_Width*pTMap->m_Height*sizeof(CTuneTile)) { ColorRGBA Color = ColorRGBA(pTMap->m_Color.r/255.0f, pTMap->m_Color.g/255.0f, pTMap->m_Color.b/255.0f, pTMap->m_Color.a/255.0f*g_Config.m_ClOverlayEntities/100.0f); - if(!Graphics()->IsBufferingEnabled()) + if(!Graphics()->IsTileBufferingEnabled()) { Graphics()->BlendNone(); RenderTools()->RenderTunemap(pTuneTiles, pTMap->m_Width, pTMap->m_Height, 32.0f, Color, TILERENDERFLAG_EXTEND|LAYERRENDERFLAG_OPAQUE); diff --git a/src/game/client/components/particles.cpp b/src/game/client/components/particles.cpp index 6f6d2840b..f92c04a26 100644 --- a/src/game/client/components/particles.cpp +++ b/src/game/client/components/particles.cpp @@ -178,7 +178,7 @@ void CParticles::RenderGroup(int Group) Graphics()->TextureSet(g_pData->m_aImages[IMAGE_PARTICLES].m_Id); // don't use the buffer methods here, else the old renderer gets many draw calls - if(Graphics()->IsBufferingEnabled()) + if(Graphics()->IsQuadContainerBufferingEnabled()) { int i = m_aFirstPart[Group];