diff --git a/src/engine/client/backend_sdl.cpp b/src/engine/client/backend_sdl.cpp index 00826c1bd..625db0583 100644 --- a/src/engine/client/backend_sdl.cpp +++ b/src/engine/client/backend_sdl.cpp @@ -176,7 +176,7 @@ void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &St else if(State.m_Dimension == 3 && (m_aTextures[State.m_Texture].m_State&CTexture::STATE_TEX3D)) { glEnable(GL_TEXTURE_3D); - glBindTexture(GL_TEXTURE_3D, m_aTextures[State.m_Texture].m_Tex3D); + glBindTexture(GL_TEXTURE_3D, m_aTextures[State.m_Texture].m_Tex3D[State.m_TextureArrayIndex]); } else dbg_msg("render", "invalid texture %d %d %d\n", State.m_Texture, State.m_Dimension, m_aTextures[State.m_Texture].m_State); @@ -249,6 +249,13 @@ void CCommandProcessorFragment_OpenGL::SetState(const CCommandBuffer::SState &St void CCommandProcessorFragment_OpenGL::Cmd_Init(const SCommand_Init *pCommand) { m_pTextureMemoryUsage = pCommand->m_pTextureMemoryUsage; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_MaxTexSize); + glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &m_Max3DTexSize); + dbg_msg("render", "opengl max texture sizes: %d, %d(3D)", m_MaxTexSize, m_Max3DTexSize); + if(m_Max3DTexSize < IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION) + dbg_msg("render", "*** warning *** max 3D texture size is too low - using the fallback system"); + m_TextureArraySize = IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION / min(m_Max3DTexSize, IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION); + *pCommand->m_pTextureArraySize = m_TextureArraySize; } void CCommandProcessorFragment_OpenGL::Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand) @@ -267,7 +274,10 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Destroy(const CCommandBuffer: if(m_aTextures[pCommand->m_Slot].m_State&CTexture::STATE_TEX2D) glDeleteTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex2D); if(m_aTextures[pCommand->m_Slot].m_State&CTexture::STATE_TEX3D) - glDeleteTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex3D); + { + for(int i = 0; i < m_TextureArraySize; ++i) + glDeleteTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex3D[i]); + } *m_pTextureMemoryUsage -= m_aTextures[pCommand->m_Slot].m_MemSize; m_aTextures[pCommand->m_Slot].m_State = CTexture::STATE_EMPTY; m_aTextures[pCommand->m_Slot].m_MemSize = 0; @@ -283,16 +293,13 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer:: // resample if needed if(pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGBA || pCommand->m_Format == CCommandBuffer::TEXFORMAT_RGB) { - int MaxTexSize; - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &MaxTexSize); - if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE3D) + int MaxTexSize = m_MaxTexSize; + if((pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE3D) && m_Max3DTexSize >= CTexture::MIN_GL_MAX_3D_TEXTURE_SIZE) { - int Max3DTexSize; - glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &Max3DTexSize); if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE2D) - MaxTexSize = min(MaxTexSize, Max3DTexSize*16); + MaxTexSize = min(MaxTexSize, m_Max3DTexSize * IGraphics::NUMTILES_DIMENSION); else - MaxTexSize = Max3DTexSize*16; + MaxTexSize = m_Max3DTexSize * IGraphics::NUMTILES_DIMENSION; } if(Width > MaxTexSize || Height > MaxTexSize) { @@ -307,7 +314,7 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer:: mem_free(pTexData); pTexData = pTmpData; } - else if(Width > 16 && Height > 16 && (pCommand->m_Flags&CCommandBuffer::TEXFLAG_QUALITY) == 0) + else if(Width > IGraphics::NUMTILES_DIMENSION && Height > IGraphics::NUMTILES_DIMENSION && (pCommand->m_Flags&CCommandBuffer::TEXFLAG_QUALITY) == 0) { Width>>=1; Height>>=1; @@ -382,42 +389,45 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer:: } // 3D texture - if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE3D) + if((pCommand->m_Flags&CCommandBuffer::TEXFLAG_TEXTURE3D) && m_Max3DTexSize >= CTexture::MIN_GL_MAX_3D_TEXTURE_SIZE) { - Width /= 16; - Height /= 16; - Depth = 256; + Width /= IGraphics::NUMTILES_DIMENSION; + Height /= IGraphics::NUMTILES_DIMENSION; + Depth = min(m_Max3DTexSize, IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION); // copy and reorder texture data - int MemSize = Width*Height*Depth*pCommand->m_PixelSize; + int MemSize = Width*Height*IGraphics::NUMTILES_DIMENSION*IGraphics::NUMTILES_DIMENSION*pCommand->m_PixelSize; char *pTmpData = (char *)mem_alloc(MemSize, sizeof(void*)); const int TileSize = (Height * Width) * pCommand->m_PixelSize; const int TileRowSize = Width * pCommand->m_PixelSize; - const int ImagePitch = Width*16 * pCommand->m_PixelSize; + const int ImagePitch = Width * IGraphics::NUMTILES_DIMENSION * pCommand->m_PixelSize; mem_zero(pTmpData, MemSize); - for(int i = 0; i < 256; i++) + for(int i = 0; i < IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION; i++) { - const int px = (i%16) * Width; - const int py = (i/16) * Height; - const char *pTileData = (const char *)pTexData + (py * Width*16 + px) * pCommand->m_PixelSize; + const int px = (i%IGraphics::NUMTILES_DIMENSION) * Width; + const int py = (i/IGraphics::NUMTILES_DIMENSION) * Height; + const char *pTileData = (const char *)pTexData + (py * Width * IGraphics::NUMTILES_DIMENSION + px) * pCommand->m_PixelSize; for(int y = 0; y < Height; y++) mem_copy(pTmpData + i*TileSize + y*TileRowSize, pTileData + y * ImagePitch, TileRowSize); } mem_free(pTexData); - pTexData = pTmpData; // - glGenTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex3D); + glGenTextures(m_TextureArraySize, m_aTextures[pCommand->m_Slot].m_Tex3D); m_aTextures[pCommand->m_Slot].m_State |= CTexture::STATE_TEX3D; - glBindTexture(GL_TEXTURE_3D, m_aTextures[pCommand->m_Slot].m_Tex3D); + for(int i = 0; i < m_TextureArraySize; ++i) + { + glBindTexture(GL_TEXTURE_3D, m_aTextures[pCommand->m_Slot].m_Tex3D[i]); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + pTexData = pTmpData+i*(Width*Height*Depth*pCommand->m_PixelSize); + glTexImage3D(GL_TEXTURE_3D, 0, StoreOglformat, Width, Height, Depth, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexImage3D(GL_TEXTURE_3D, 0, StoreOglformat, Width, Height, Depth, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData); - - m_aTextures[pCommand->m_Slot].m_MemSize += Width*Height*pCommand->m_PixelSize; + m_aTextures[pCommand->m_Slot].m_MemSize += Width*Height*pCommand->m_PixelSize; + } + pTexData = pTmpData; } *m_pTextureMemoryUsage += m_aTextures[pCommand->m_Slot].m_MemSize; @@ -756,13 +766,14 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt // issue init commands for OpenGL and SDL CCommandBuffer CmdBuffer(1024, 512); - 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_OpenGL::SCommand_Init CmdOpenGL; + CmdOpenGL.m_pTextureMemoryUsage = &m_TextureMemoryUsage; + CmdOpenGL.m_pTextureArraySize = &m_TextureArraySize; + CmdBuffer.AddCommand(CmdOpenGL); RunBuffer(&CmdBuffer); WaitForIdle(); diff --git a/src/engine/client/backend_sdl.h b/src/engine/client/backend_sdl.h index 7cf1d43cf..60fcf5a01 100644 --- a/src/engine/client/backend_sdl.h +++ b/src/engine/client/backend_sdl.h @@ -91,15 +91,21 @@ class CCommandProcessorFragment_OpenGL STATE_EMPTY = 0, STATE_TEX2D = 1, STATE_TEX3D = 2, + + MIN_GL_MAX_3D_TEXTURE_SIZE = 64, // GL_MAX_3D_TEXTURE_SIZE must be at least 64 according to the standard + MAX_ARRAYSIZE_TEX3D = IGraphics::NUMTILES_DIMENSION * IGraphics::NUMTILES_DIMENSION / MIN_GL_MAX_3D_TEXTURE_SIZE, // = 4 }; GLuint m_Tex2D; - GLuint m_Tex3D; + GLuint m_Tex3D[MAX_ARRAYSIZE_TEX3D]; int m_State; int m_Format; int m_MemSize; }; CTexture m_aTextures[CCommandBuffer::MAX_TEXTURES]; volatile int *m_pTextureMemoryUsage; + int m_MaxTexSize; + int m_Max3DTexSize; + int m_TextureArraySize; public: enum @@ -111,6 +117,7 @@ public: { SCommand_Init() : SCommand(CMD_INIT) {} volatile int *m_pTextureMemoryUsage; + int *m_pTextureArraySize; }; private: @@ -189,11 +196,13 @@ class CGraphicsBackend_SDL_OpenGL : public CGraphicsBackend_Threaded ICommandProcessor *m_pProcessor; volatile int m_TextureMemoryUsage; int m_NumScreens; + int m_TextureArraySize; public: virtual int Init(const char *pName, int *Screen, int *Width, int *Height, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight); virtual int Shutdown(); virtual int MemoryUsage() const; + virtual int GetTextureArraySize() const { return m_TextureArraySize; } virtual int GetNumScreens() const { return m_NumScreens; } diff --git a/src/engine/client/graphics_threaded.cpp b/src/engine/client/graphics_threaded.cpp index f02b52197..d9c099b92 100644 --- a/src/engine/client/graphics_threaded.cpp +++ b/src/engine/client/graphics_threaded.cpp @@ -373,6 +373,9 @@ IGraphics::CTextureHandle CGraphics_Threaded::LoadTextureRaw(int Width, int Heig // m_pCommandBuffer->AddCommand(Cmd); + // kick the buffer and wait for the result + KickCommandBuffer(); + WaitForIdle(); return CreateTextureHandle(Tex); } @@ -522,6 +525,7 @@ void CGraphics_Threaded::QuadsBegin() QuadsSetSubset(0,0,1,1,-1); QuadsSetRotation(0); SetColor(1,1,1,1); + m_TextureArrayIndex = m_pBackend->GetTextureArraySize() > 1 ? -1 : 0; } void CGraphics_Threaded::QuadsEnd() @@ -572,17 +576,36 @@ void CGraphics_Threaded::SetColor4(vec4 TopLeft, vec4 TopRight, vec4 BottomLeft, SetColorVertex(Array, 4); } +void CGraphics_Threaded::TilesetFallbackSystem(int TextureIndex) +{ + int NewTextureArrayIndex = TextureIndex / (256 / m_pBackend->GetTextureArraySize()); + if(m_TextureArrayIndex == -1) + m_TextureArrayIndex = NewTextureArrayIndex; + else if(m_TextureArrayIndex != NewTextureArrayIndex) + { + // have to switch the texture index + FlushVertices(); + m_TextureArrayIndex = NewTextureArrayIndex; + } +} + void CGraphics_Threaded::QuadsSetSubset(float TlU, float TlV, float BrU, float BrV, int TextureIndex) { dbg_assert(m_Drawing == DRAWING_QUADS, "called Graphics()->QuadsSetSubset without begin"); + // tileset fallback system + if(m_pBackend->GetTextureArraySize() > 1 && TextureIndex >= 0) + TilesetFallbackSystem(TextureIndex); + + m_State.m_TextureArrayIndex = m_TextureArrayIndex; + m_aTexture[0].u = TlU; m_aTexture[1].u = BrU; m_aTexture[0].v = TlV; m_aTexture[1].v = TlV; m_aTexture[3].u = TlU; m_aTexture[2].u = BrU; m_aTexture[3].v = BrV; m_aTexture[2].v = BrV; - m_aTexture[0].i = m_aTexture[1].i = m_aTexture[2].i = m_aTexture[3].i = (0.5f + TextureIndex) / 256.0f; + m_aTexture[0].i = m_aTexture[1].i = m_aTexture[2].i = m_aTexture[3].i = (0.5f + TextureIndex) / (256.0f/m_pBackend->GetTextureArraySize()); m_State.m_Dimension = (TextureIndex < 0) ? 2 : 3; } @@ -590,12 +613,18 @@ void CGraphics_Threaded::QuadsSetSubsetFree( float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, int TextureIndex) { + // tileset fallback system + if(m_pBackend->GetTextureArraySize() > 1 && TextureIndex >= 0) + TilesetFallbackSystem(TextureIndex); + + m_State.m_TextureArrayIndex = m_TextureArrayIndex; + m_aTexture[0].u = x0; m_aTexture[0].v = y0; m_aTexture[1].u = x1; m_aTexture[1].v = y1; m_aTexture[2].u = x2; m_aTexture[2].v = y2; m_aTexture[3].u = x3; m_aTexture[3].v = y3; - m_aTexture[0].i = m_aTexture[1].i = m_aTexture[2].i = m_aTexture[3].i = (0.5f + TextureIndex) / 256.0f; + m_aTexture[0].i = m_aTexture[1].i = m_aTexture[2].i = m_aTexture[3].i = (0.5f + TextureIndex) / (256.0f/m_pBackend->GetTextureArraySize()); m_State.m_Dimension = (TextureIndex < 0) ? 2 : 3; } diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h index 1a9cf975b..47a08a614 100644 --- a/src/engine/client/graphics_threaded.h +++ b/src/engine/client/graphics_threaded.h @@ -143,6 +143,7 @@ public: int m_WrapModeU; int m_WrapModeV; int m_Texture; + int m_TextureArrayIndex; int m_Dimension; SPoint m_ScreenTL; SPoint m_ScreenBR; @@ -316,6 +317,7 @@ public: virtual int Shutdown() = 0; virtual int MemoryUsage() const = 0; + virtual int GetTextureArraySize() const = 0; virtual int GetNumScreens() const = 0; @@ -372,6 +374,7 @@ class CGraphics_Threaded : public IEngineGraphics CTextureHandle m_InvalidTexture; + int m_TextureArrayIndex; int m_aTextureIndices[MAX_TEXTURES]; int m_FirstFreeTexture; int m_TextureMemoryUsage; @@ -429,6 +432,7 @@ public: virtual void SetColor(float r, float g, float b, float a); virtual void SetColor4(vec4 TopLeft, vec4 TopRight, vec4 BottomLeft, vec4 BottomRight); + void TilesetFallbackSystem(int TextureIndex); virtual void QuadsSetSubset(float TlU, float TlV, float BrU, float BrV, int TextureIndex = -1); virtual void QuadsSetSubsetFree( float x0, float y0, float x1, float y1, diff --git a/src/engine/graphics.h b/src/engine/graphics.h index 5d899156d..a539a8457 100644 --- a/src/engine/graphics.h +++ b/src/engine/graphics.h @@ -70,6 +70,8 @@ public: TEXLOAD_ARRAY_256 = 4, TEXLOAD_MULTI_DIMENSION = 8, TEXLOAD_LINEARMIPMAPS = 16, + + NUMTILES_DIMENSION = 16, // number of tiles in each dimension within a texture }; /* Constants: Wrap Modes */