diff --git a/bam.lua b/bam.lua
index 8df58b7b2..6859b66d3 100644
--- a/bam.lua
+++ b/bam.lua
@@ -18,6 +18,7 @@ Import("other/freetype.lua")
Import("other/curl.lua")
Import("other/opusfile.lua")
Import("other/mysql.lua")
+Import("other/glew.lua")
--- Setup Config -------
config = NewConfig()
@@ -31,6 +32,7 @@ config:Add(FreeType.OptFind("freetype", true))
config:Add(Curl.OptFind("curl", true))
config:Add(Opusfile.OptFind("opusfile", true))
config:Add(Mysql.OptFind("mysql", false))
+config:Add(Glew.OptFind("glew", true))
config:Add(OptString("websockets", false))
config:Finalize("config.lua")
@@ -144,6 +146,7 @@ if family == "windows" then
if platform == "win32" then
table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/freetype/windows/lib32/libfreetype.dll"))
table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/sdl/windows/lib32/SDL2.dll"))
+ table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/glew/windows/lib32/glew32.dll"))
table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/curl/windows/lib32/libcurl.dll"))
table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/opus/windows/lib32/libwinpthread-1.dll"))
table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/opus/windows/lib32/libgcc_s_sjlj-1.dll"))
@@ -153,6 +156,7 @@ if family == "windows" then
else
table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/freetype/windows/lib64/libfreetype.dll"))
table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/sdl/windows/lib64/SDL2.dll"))
+ table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/glew/windows/lib64/glew32.dll"))
table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/curl/windows/lib64/libcurl.dll"))
table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/opus/windows/lib64/libwinpthread-1.dll"))
table.insert(client_depends, CopyToDirectory(".", "ddnet-libs/opus/windows/lib64/libogg.dll"))
@@ -333,6 +337,7 @@ function build(settings)
end
config.sdl:Apply(client_settings)
+ config.glew:Apply(client_settings)
config.freetype:Apply(client_settings)
config.curl:Apply(client_settings)
config.opusfile:Apply(client_settings)
diff --git a/other/glew.lua b/other/glew.lua
new file mode 100644
index 000000000..4f4d280e6
--- /dev/null
+++ b/other/glew.lua
@@ -0,0 +1,71 @@
+Glew = {
+ OptFind = function (name, required)
+ local check = function(option, settings)
+ option.value = false
+ option.use_winlib = 0
+ option.use_macosxframwork = 0
+
+ if platform == "win32" then
+ option.value = true
+ option.use_winlib = 32
+ elseif platform == "win64" then
+ option.value = true
+ option.use_winlib = 64
+ elseif platform == "macosx" and string.find(settings.config_name, "32") then
+ option.value = true
+ option.use_macosxframwork = 32
+ elseif platform == "macosx" and string.find(settings.config_name, "64") then
+ option.value = true
+ option.use_macosxframwork = 64
+ elseif platform == "linux" and arch == "ia32" then
+ option.value = true
+ elseif platform == "linux" and arch == "amd64" then
+ option.value = true
+ end
+ end
+
+ local apply = function(option, settings)
+ settings.cc.includes:Add("ddnet-libs/glew/include")
+
+ if option.use_winlib > 0 then
+ if option.use_winlib == 32 then
+ settings.link.libpath:Add("ddnet-libs/glew/windows/lib32")
+ elseif option.use_winlib == 64 then
+ settings.link.libpath:Add("ddnet-libs/glew/windows/lib64")
+ end
+
+ settings.link.libs:Add("glew32")
+ elseif option.use_macosxframwork > 0 then
+ --todo
+ else
+ settings.link.libs:Add("GLEW")
+ end
+ end
+
+ local save = function(option, output)
+ output:option(option, "value")
+ output:option(option, "use_winlib")
+ end
+
+ local display = function(option)
+ if option.value == true then
+ if option.use_winlib == 32 then return "using supplied win32 libraries" end
+ if option.use_winlib == 64 then return "using supplied win64 libraries" end
+ return "using value"
+ else
+ if option.required then
+ return "not found (required)"
+ else
+ return "not found (optional)"
+ end
+ end
+ end
+
+ local o = MakeOption(name, 0, check, save, display)
+ o.Apply = apply
+ o.include_path = nil
+ o.lib_path = nil
+ o.required = required
+ return o
+ end
+}
diff --git a/shader/quad.frag b/shader/quad.frag
new file mode 100644
index 000000000..9ac182517
--- /dev/null
+++ b/shader/quad.frag
@@ -0,0 +1,16 @@
+#version 330
+
+uniform int isTextured;
+uniform sampler2D textureSampler;
+
+smooth in vec2 texCoord;
+smooth in vec4 vertColor;
+
+void main()
+{
+ if(isTextured == 1) {
+ vec4 tex = texture2D(textureSampler, texCoord);
+ gl_FragColor = tex * vertColor;
+ }
+ else gl_FragColor = vertColor;
+}
\ No newline at end of file
diff --git a/shader/quad.vert b/shader/quad.vert
new file mode 100644
index 000000000..27f9766ea
--- /dev/null
+++ b/shader/quad.vert
@@ -0,0 +1,17 @@
+#version 330
+
+layout (location = 0) in vec3 inVertex;
+layout (location = 1) in vec2 inVertexTexCoord;
+layout (location = 2) in vec4 inVertexColor;
+
+uniform mat4 Pos;
+
+smooth out vec2 texCoord;
+smooth out vec4 vertColor;
+
+void main()
+{
+ gl_Position = Pos * vec4(inVertex, 1.0);
+ texCoord = inVertexTexCoord;
+ vertColor = inVertexColor;
+}
\ No newline at end of file
diff --git a/src/engine/client/backend_sdl.cpp b/src/engine/client/backend_sdl.cpp
index 1e2dad36d..8bdfa442a 100644
--- a/src/engine/client/backend_sdl.cpp
+++ b/src/engine/client/backend_sdl.cpp
@@ -6,6 +6,7 @@
#define WINVER 0x0501
#endif
+#include "GL/glew.h"
#include
#include
#include
@@ -38,6 +39,9 @@
#include "graphics_threaded.h"
#include "backend_sdl.h"
+#include "opengl_sl_program.h"
+#include "opengl_sl.h"
+
// ------------ CGraphicsBackend_Threaded
void CGraphicsBackend_Threaded::ThreadFunc(void *pUser)
@@ -309,7 +313,7 @@ void CCommandProcessorFragment_OpenGL::Cmd_Texture_Create(const CCommandBuffer::
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
gluBuild2DMipmaps(GL_TEXTURE_2D, StoreOglformat, Width, Height, Oglformat, GL_UNSIGNED_BYTE, pTexData);
}
-
+
// calculate memory usage
m_aTextures[pCommand->m_Slot].m_MemSize = Width*Height*pCommand->m_PixelSize;
while(Width > 2 && Height > 2)
@@ -419,6 +423,406 @@ bool CCommandProcessorFragment_OpenGL::RunCommand(const CCommandBuffer::SCommand
return true;
}
+// ------------ CCommandProcessorFragment_OpenGL3_3
+
+int CCommandProcessorFragment_OpenGL3_3::TexFormatToOpenGLFormat(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;
+}
+
+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;
+
+ pTmpData = (unsigned char *)mem_alloc(NewWidth*NewHeight*Bpp, 1);
+
+ int c = 0;
+ for(int y = 0; y < NewHeight; y++)
+ for(int x = 0; x < NewWidth; x++, c++)
+ {
+ pTmpData[c*Bpp] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, 0, ScaleW, ScaleH, Bpp);
+ pTmpData[c*Bpp+1] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, 1, ScaleW, ScaleH, Bpp);
+ pTmpData[c*Bpp+2] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, 2, ScaleW, ScaleH, Bpp);
+ if(Bpp == 4)
+ pTmpData[c*Bpp+3] = Sample(Width, Height, pData, x*ScaleW, y*ScaleH, 3, ScaleW, ScaleH, Bpp);
+ }
+
+ return pTmpData;
+}
+
+void CCommandProcessorFragment_OpenGL3_3::SetState(const CCommandBuffer::SState &State)
+{
+ // blend
+ switch(State.m_BlendMode)
+ {
+ case CCommandBuffer::BLEND_NONE:
+ glDisable(GL_BLEND);
+ break;
+ case CCommandBuffer::BLEND_ALPHA:
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ break;
+ case CCommandBuffer::BLEND_ADDITIVE:
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+ break;
+ default:
+ dbg_msg("render", "unknown blendmode %d\n", State.m_BlendMode);
+ };
+
+ // clip
+ if(State.m_ClipEnable)
+ {
+ glScissor(State.m_ClipX, State.m_ClipY, State.m_ClipW, State.m_ClipH);
+ glEnable(GL_SCISSOR_TEST);
+ }
+ else
+ glDisable(GL_SCISSOR_TEST);
+
+ // texture
+ if(State.m_Texture >= 0 && State.m_Texture < CCommandBuffer::MAX_TEXTURES)
+ {
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, m_aTextures[State.m_Texture].m_Tex);
+ glBindSampler(0, m_aTextures[State.m_Texture].m_Sampler);
+ m_QuadProgram->SetUniform(m_QuadProgram->m_LocIsTextured, (int)1);
+ m_QuadProgram->SetUniform(m_QuadProgram->m_LocTextureSampler, (int)0);
+
+ switch (State.m_WrapMode)
+ {
+ case CCommandBuffer::WRAP_REPEAT:
+ glSamplerParameteri(m_aTextures[State.m_Texture].m_Sampler, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glSamplerParameteri(m_aTextures[State.m_Texture].m_Sampler, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ break;
+ case CCommandBuffer::WRAP_CLAMP:
+ glSamplerParameteri(m_aTextures[State.m_Texture].m_Sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glSamplerParameteri(m_aTextures[State.m_Texture].m_Sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ break;
+ default:
+ dbg_msg("render", "unknown wrapmode %d\n", State.m_WrapMode);
+ };
+ }
+ else {
+ m_QuadProgram->SetUniform(m_QuadProgram->m_LocIsTextured, (int)0);
+ }
+
+ // screen mapping
+ //ortho matrix... we only need this projection... so no real need just made all structs here..
+ struct vec4{
+ vec4() {}
+ vec4(float a, float b, float c, float d) : x(a), y(b), z(c), w(d) {}
+ vec4(vec4& v) : x(v.x), y(v.y), z(v.z), w(v.w) {}
+ float x;
+ float y;
+ float z;
+ float w;
+ };
+
+ struct mat4{
+ mat4(vec4& r1, vec4& r2, vec4& r3, vec4& r4) { r[0] = r1; r[1] = r2; r[2] = r3; r[3] = r4; }
+ vec4 r[4];
+ };
+
+ vec4 r1( (2.f/(State.m_ScreenBR.x - State.m_ScreenTL.x)), 0, 0, -((State.m_ScreenBR.x + State.m_ScreenTL.x)/(State.m_ScreenBR.x - State.m_ScreenTL.x)));
+ vec4 r2( 0, (2.f/(State.m_ScreenTL.y - State.m_ScreenBR.y)), 0, -((State.m_ScreenTL.y + State.m_ScreenBR.y)/(State.m_ScreenTL.y - State.m_ScreenBR.y)));
+ vec4 r3( 0, 0, -(2.f/(9.f)), -((11.f)/(9.f)));
+ vec4 r4( 0, 0, 0, 1.f);
+
+ mat4 m(r1,r2,r3,r4);
+
+ glUniformMatrix4fv(m_QuadProgram->m_LocPos, 1, true, (float*)&m);
+}
+
+void CCommandProcessorFragment_OpenGL3_3::Cmd_Init(const SCommand_Init *pCommand)
+{
+ m_pTextureMemoryUsage = pCommand->m_pTextureMemoryUsage;
+ m_QuadProgram = new CGLSLQuadProgram;
+
+ CGLSL QuadVertexShader;
+ CGLSL QuadFragmentShader;
+ QuadVertexShader.LoadShader("./shader/quad.vert", GL_VERTEX_SHADER);
+ QuadFragmentShader.LoadShader("./shader/quad.frag", GL_FRAGMENT_SHADER);
+
+ m_QuadProgram->CreateProgram();
+ m_QuadProgram->AddShader(&QuadVertexShader);
+ m_QuadProgram->AddShader(&QuadFragmentShader);
+ m_QuadProgram->LinkProgram();
+
+ //detach shader, they are not needed anymore after linking
+ m_QuadProgram->DetachShader(&QuadVertexShader);
+ m_QuadProgram->DetachShader(&QuadFragmentShader);
+
+ m_QuadProgram->UseProgram();
+
+ m_QuadProgram->m_LocPos = m_QuadProgram->GetUniformLoc("Pos");
+ m_QuadProgram->m_LocIsTextured = m_QuadProgram->GetUniformLoc("isTextured");
+ m_QuadProgram->m_LocTextureSampler = m_QuadProgram->GetUniformLoc("textureSampler");
+
+ glActiveTexture(GL_TEXTURE0);
+ //glEnableClientState(GL_VERTEX_ARRAY);
+
+ glGenBuffers(1, &QuadDrawBufferID);
+ glGenVertexArrays(1, &QuadDrawVertexID);
+ glBindVertexArray(QuadDrawVertexID);
+ glEnableVertexAttribArray(0);
+ glEnableVertexAttribArray(1);
+ glEnableVertexAttribArray(2);
+}
+
+void CCommandProcessorFragment_OpenGL3_3::Cmd_Shutdown(const SCommand_Shutdown *pCommand)
+{
+ m_pTextureMemoryUsage = pCommand->m_pTextureMemoryUsage;
+ delete m_QuadProgram;
+
+ glBindVertexArray(0);
+ glDeleteBuffers(1, &QuadDrawBufferID);
+ glDeleteVertexArrays(1, &QuadDrawVertexID);
+}
+
+void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Update(const CCommandBuffer::SCommand_Texture_Update *pCommand)
+{
+ glBindTexture(GL_TEXTURE_2D, m_aTextures[pCommand->m_Slot].m_Tex);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, pCommand->m_X, pCommand->m_Y, pCommand->m_Width, pCommand->m_Height,
+ TexFormatToOpenGLFormat(pCommand->m_Format), GL_UNSIGNED_BYTE, pCommand->m_pData);
+ mem_free(pCommand->m_pData);
+}
+
+void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Destroy(const CCommandBuffer::SCommand_Texture_Destroy *pCommand)
+{
+ glDeleteTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex);
+ glDeleteSamplers(1, &m_aTextures[pCommand->m_Slot].m_Sampler);
+ *m_pTextureMemoryUsage -= m_aTextures[pCommand->m_Slot].m_MemSize;
+}
+
+void CCommandProcessorFragment_OpenGL3_3::Cmd_Texture_Create(const CCommandBuffer::SCommand_Texture_Create *pCommand)
+{
+ int Width = pCommand->m_Width;
+ int Height = pCommand->m_Height;
+ void *pTexData = pCommand->m_pData;
+
+ // 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(Width > MaxTexSize || Height > MaxTexSize)
+ {
+ do
+ {
+ Width>>=1;
+ Height>>=1;
+ }
+ while(Width > MaxTexSize || Height > MaxTexSize);
+
+ void *pTmpData = Rescale(pCommand->m_Width, pCommand->m_Height, Width, Height, pCommand->m_Format, static_cast(pCommand->m_pData));
+ mem_free(pTexData);
+ pTexData = pTmpData;
+ }
+ else if(Width > 16 && Height > 16 && (pCommand->m_Flags&CCommandBuffer::TEXFLAG_QUALITY) == 0)
+ {
+ Width>>=1;
+ Height>>=1;
+
+ void *pTmpData = Rescale(pCommand->m_Width, pCommand->m_Height, Width, Height, pCommand->m_Format, static_cast(pCommand->m_pData));
+ mem_free(pTexData);
+ pTexData = pTmpData;
+ }
+ }
+
+ int Oglformat = TexFormatToOpenGLFormat(pCommand->m_Format);
+ int StoreOglformat = TexFormatToOpenGLFormat(pCommand->m_StoreFormat);
+
+#if defined(__ANDROID__)
+ StoreOglformat = Oglformat;
+#else
+ if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_COMPRESSED)
+ {
+ switch(StoreOglformat)
+ {
+ case GL_RGB: StoreOglformat = GL_COMPRESSED_RGB; break;
+ case GL_RED: StoreOglformat = GL_COMPRESSED_ALPHA; break;
+ case GL_RGBA: StoreOglformat = GL_COMPRESSED_RGBA; break;
+ default: StoreOglformat = GL_COMPRESSED_RGBA;
+ }
+ }
+#endif
+ glActiveTexture(GL_TEXTURE0);
+ glGenTextures(1, &m_aTextures[pCommand->m_Slot].m_Tex);
+ glBindTexture(GL_TEXTURE_2D, m_aTextures[pCommand->m_Slot].m_Tex);
+
+ glGenSamplers(1, &m_aTextures[pCommand->m_Slot].m_Sampler);
+ glBindSampler(0, m_aTextures[pCommand->m_Slot].m_Sampler);
+
+
+ if(Oglformat == GL_RED) {
+ //Bind the texture 2D.
+ GLint swizzleMask[] = {GL_ONE, GL_ONE, GL_ONE, GL_RED};
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
+ }
+
+ if(pCommand->m_Flags&CCommandBuffer::TEXFLAG_NOMIPMAPS)
+ {
+ glSamplerParameteri(m_aTextures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glSamplerParameteri(m_aTextures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexImage2D(GL_TEXTURE_2D, 0, StoreOglformat, Width, Height, 0, Oglformat, GL_UNSIGNED_BYTE, pTexData);
+ }
+ else
+ {
+ glSamplerParameteri(m_aTextures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glSamplerParameteri(m_aTextures[pCommand->m_Slot].m_Sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ gluBuild2DMipmaps(GL_TEXTURE_2D, StoreOglformat, Width, Height, Oglformat, GL_UNSIGNED_BYTE, pTexData);
+ }
+
+ // calculate memory usage
+ m_aTextures[pCommand->m_Slot].m_MemSize = Width*Height*pCommand->m_PixelSize;
+ while(Width > 2 && Height > 2)
+ {
+ Width>>=1;
+ Height>>=1;
+ m_aTextures[pCommand->m_Slot].m_MemSize += Width*Height*pCommand->m_PixelSize;
+ }
+ *m_pTextureMemoryUsage += m_aTextures[pCommand->m_Slot].m_MemSize;
+
+ mem_free(pTexData);
+}
+
+void CCommandProcessorFragment_OpenGL3_3::Cmd_Clear(const CCommandBuffer::SCommand_Clear *pCommand)
+{
+ glClearColor(pCommand->m_Color.r, pCommand->m_Color.g, pCommand->m_Color.b, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+void CCommandProcessorFragment_OpenGL3_3::Cmd_Render(const CCommandBuffer::SCommand_Render *pCommand)
+{
+ SetState(pCommand->m_State);
+
+ int Count = 0;
+ switch(pCommand->m_PrimType)
+ {
+ case CCommandBuffer::PRIMTYPE_QUADS:
+ Count = pCommand->m_PrimCount*4;
+ break;
+ case CCommandBuffer::PRIMTYPE_LINES:
+ Count = pCommand->m_PrimCount*2;
+ break;
+ case CCommandBuffer::PRIMTYPE_TRIANGLES:
+ Count = pCommand->m_PrimCount*3;
+ break;
+ };
+
+ glBindBuffer(GL_ARRAY_BUFFER, QuadDrawBufferID);
+ glBindVertexArray(QuadDrawVertexID);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 9 * Count, (char*)pCommand->m_pVertices, GL_STATIC_DRAW);
+
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(CCommandBuffer::SVertex), 0);
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(CCommandBuffer::SVertex), (void*)(sizeof(float) * 3));
+ glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(CCommandBuffer::SVertex), (void*)(sizeof(float) * 5));
+ //glBindBuffer(GL_ARRAY_BUFFER, 0);
+ /*glVertexPointer(3, GL_FLOAT, sizeof(CCommandBuffer::SVertex), (char*)pCommand->m_pVertices);
+ glTexCoordPointer(2, GL_FLOAT, sizeof(CCommandBuffer::SVertex), (char*)pCommand->m_pVertices + sizeof(float)*3);
+ glColorPointer(4, GL_FLOAT, sizeof(CCommandBuffer::SVertex), (char*)pCommand->m_pVertices + sizeof(float)*5);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glEnableClientState(GL_COLOR_ARRAY);*/
+
+ switch(pCommand->m_PrimType)
+ {
+ case CCommandBuffer::PRIMTYPE_QUADS:
+#if defined(__ANDROID__)
+ for( unsigned i = 0, j = pCommand->m_PrimCount; i < j; i++ )
+ glDrawArrays(GL_TRIANGLE_FAN, i*4, 4);
+#else
+ glDrawArrays(GL_QUADS, 0, pCommand->m_PrimCount*4);
+#endif
+ break;
+ case CCommandBuffer::PRIMTYPE_LINES:
+ glDrawArrays(GL_LINES, 0, pCommand->m_PrimCount*2);
+ break;
+ case CCommandBuffer::PRIMTYPE_TRIANGLES:
+ glDrawArrays(GL_TRIANGLES, 0, pCommand->m_PrimCount*3);
+ break;
+ default:
+ dbg_msg("render", "unknown primtype %d\n", pCommand->m_Cmd);
+ };
+}
+
+void CCommandProcessorFragment_OpenGL3_3::Cmd_Screenshot(const CCommandBuffer::SCommand_Screenshot *pCommand)
+{
+ // fetch image data
+ GLint aViewport[4] = {0,0,0,0};
+ glGetIntegerv(GL_VIEWPORT, aViewport);
+
+ int w = aViewport[2];
+ int h = aViewport[3];
+
+ // we allocate one more row to use when we are flipping the texture
+ unsigned char *pPixelData = (unsigned char *)mem_alloc(w*(h+1)*3, 1);
+ unsigned char *pTempRow = pPixelData+w*h*3;
+
+ // fetch the pixels
+ GLint Alignment;
+ glGetIntegerv(GL_PACK_ALIGNMENT, &Alignment);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glReadPixels(0,0, w, h, GL_RGB, GL_UNSIGNED_BYTE, pPixelData);
+ glPixelStorei(GL_PACK_ALIGNMENT, Alignment);
+
+ // flip the pixel because opengl works from bottom left corner
+ for(int y = 0; y < h/2; y++)
+ {
+ mem_copy(pTempRow, pPixelData+y*w*3, w*3);
+ mem_copy(pPixelData+y*w*3, pPixelData+(h-y-1)*w*3, w*3);
+ mem_copy(pPixelData+(h-y-1)*w*3, pTempRow,w*3);
+ }
+
+ // fill in the information
+ pCommand->m_pImage->m_Width = w;
+ pCommand->m_pImage->m_Height = h;
+ pCommand->m_pImage->m_Format = CImageInfo::FORMAT_RGB;
+ pCommand->m_pImage->m_pData = pPixelData;
+}
+
+CCommandProcessorFragment_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;
+ default: return false;
+ }
+
+ return true;
+}
+
// ------------ CCommandProcessorFragment_SDL
@@ -530,10 +934,15 @@ void CCommandProcessor_SDL_OpenGL::RunBuffer(CCommandBuffer *pBuffer)
const CCommandBuffer::SCommand *pBaseCommand = pBuffer->GetCommand(&CmdIndex);
if(pBaseCommand == 0x0)
break;
-
- if(m_OpenGL.RunCommand(pBaseCommand))
- continue;
-
+
+ if(m_UseOpenGL3_3) {
+ if(m_OpenGL3_3.RunCommand(pBaseCommand))
+ continue;
+ }
+ else {
+ if(m_OpenGL.RunCommand(pBaseCommand))
+ continue;
+ }
if(m_SDL.RunCommand(pBaseCommand))
continue;
@@ -547,7 +956,7 @@ void CCommandProcessor_SDL_OpenGL::RunBuffer(CCommandBuffer *pBuffer)
// ------------ CGraphicsBackend_SDL_OpenGL
int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidth, int *pHeight, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight)
-{
+{
if(!SDL_WasInit(SDL_INIT_VIDEO))
{
if(SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
@@ -562,6 +971,20 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt
#endif
}
+ m_UseOpenGL3_3 = false;
+ if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE) == 0) {
+ if (SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3) == 0 && SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3) == 0) {
+ m_UseOpenGL3_3 = true;
+ int vMaj, vMin;
+ SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &vMaj);
+ SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &vMin);
+ dbg_msg("gfx", "Using OpenGL version %d.%d.", vMaj, vMin);
+ }
+ else {
+ dbg_msg("gfx", "Couldn't create OpenGL 3.3 context.");
+ }
+ }
+
// set screen
SDL_Rect ScreenPos;
m_NumScreens = SDL_GetNumVideoDisplays();
@@ -679,6 +1102,11 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt
dbg_msg("gfx", "unable to create OpenGL context: %s", SDL_GetError());
return -1;
}
+
+ //support graphic cards that are pretty old(and linux)
+ glewExperimental = GL_TRUE;
+ if (GLEW_OK != glewInit())
+ return -1;
SDL_GL_GetDrawableSize(m_pWindow, pWidth, pHeight);
SDL_GL_SetSwapInterval(Flags&IGraphicsBackend::INITFLAG_VSYNC ? 1 : 0);
@@ -686,19 +1114,35 @@ int CGraphicsBackend_SDL_OpenGL::Init(const char *pName, int *Screen, int *pWidt
// start the command processor
m_pProcessor = new CCommandProcessor_SDL_OpenGL;
+ ((CCommandProcessor_SDL_OpenGL*)m_pProcessor)->UseOpenGL3_3(m_UseOpenGL3_3);
StartProcessor(m_pProcessor);
// 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);
- RunBuffer(&CmdBuffer);
- WaitForIdle();
+ if(m_UseOpenGL3_3) {
+ //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;
+ 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);
+ RunBuffer(&CmdBuffer);
+ WaitForIdle();
+ }
SDL_ShowWindow(m_pWindow);
SetWindowScreen(g_Config.m_GfxScreen);
@@ -711,6 +1155,10 @@ int CGraphicsBackend_SDL_OpenGL::Shutdown()
{
// issue a shutdown command
CCommandBuffer CmdBuffer(1024, 512);
+ if(m_UseOpenGL3_3){
+ CCommandProcessorFragment_OpenGL3_3::SCommand_Shutdown Cmd;
+ CmdBuffer.AddCommand(Cmd);
+ }
CCommandProcessorFragment_SDL::SCommand_Shutdown Cmd;
CmdBuffer.AddCommand(Cmd);
RunBuffer(&CmdBuffer);
diff --git a/src/engine/client/backend_sdl.h b/src/engine/client/backend_sdl.h
index fa3316eb8..fca1175a5 100644
--- a/src/engine/client/backend_sdl.h
+++ b/src/engine/client/backend_sdl.h
@@ -117,6 +117,66 @@ public:
bool RunCommand(const CCommandBuffer::SCommand * pBaseCommand);
};
+
+class CGLSLProgram;
+class CGLSLQuadProgram;
+// takes care of opengl 3.2 related rendering
+class CCommandProcessorFragment_OpenGL3_3
+{
+ struct CTexture
+ {
+ GLuint m_Tex;
+ GLuint m_Sampler;
+ int m_MemSize;
+ };
+ CTexture m_aTextures[CCommandBuffer::MAX_TEXTURES];
+ volatile int *m_pTextureMemoryUsage;
+
+ CGLSLQuadProgram* m_QuadProgram;
+
+ GLuint QuadDrawVertexID;
+ GLuint QuadDrawBufferID;
+public:
+ enum
+ {
+ CMD_INIT = CCommandBuffer::CMDGROUP_PLATFORM_OPENGL3_3,
+ CMD_SHUTDOWN,
+ };
+
+ struct SCommand_Init : public CCommandBuffer::SCommand
+ {
+ SCommand_Init() : SCommand(CMD_INIT) {}
+ volatile int *m_pTextureMemoryUsage;
+ };
+
+ struct SCommand_Shutdown : public CCommandBuffer::SCommand
+ {
+ SCommand_Shutdown() : SCommand(CMD_SHUTDOWN) {}
+ 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_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);
+
+public:
+ CCommandProcessorFragment_OpenGL3_3();
+
+ bool RunCommand(const CCommandBuffer::SCommand * pBaseCommand);
+};
+
// takes care of sdl related commands
class CCommandProcessorFragment_SDL
{
@@ -159,9 +219,13 @@ public:
class CCommandProcessor_SDL_OpenGL : public CGraphicsBackend_Threaded::ICommandProcessor
{
CCommandProcessorFragment_OpenGL m_OpenGL;
+ CCommandProcessorFragment_OpenGL3_3 m_OpenGL3_3;
CCommandProcessorFragment_SDL m_SDL;
CCommandProcessorFragment_General m_General;
+
+ bool m_UseOpenGL3_3;
public:
+ void UseOpenGL3_3(bool Use) { m_UseOpenGL3_3 = Use; }
virtual void RunBuffer(CCommandBuffer *pBuffer);
};
@@ -173,6 +237,8 @@ class CGraphicsBackend_SDL_OpenGL : public CGraphicsBackend_Threaded
ICommandProcessor *m_pProcessor;
volatile int m_TextureMemoryUsage;
int m_NumScreens;
+
+ bool m_UseOpenGL3_3;
public:
virtual int Init(const char *pName, int *Screen, int *pWidth, int *pHeight, int FsaaSamples, int Flags, int *pDesktopWidth, int *pDesktopHeight);
virtual int Shutdown();
diff --git a/src/engine/client/graphics_threaded.h b/src/engine/client/graphics_threaded.h
index bc14fba3a..82f8da3e7 100644
--- a/src/engine/client/graphics_threaded.h
+++ b/src/engine/client/graphics_threaded.h
@@ -59,6 +59,7 @@ 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,
diff --git a/src/engine/client/opengl_sl.cpp b/src/engine/client/opengl_sl.cpp
new file mode 100644
index 000000000..08466cd96
--- /dev/null
+++ b/src/engine/client/opengl_sl.cpp
@@ -0,0 +1,75 @@
+#include "opengl_sl.h"
+#include
+#include
+#include
+#include
+
+bool CGLSL::LoadShader(const char* pFile, int Type) {
+ if (m_IsLoaded) return true;
+ IOHANDLE f;
+ //support read text in system.h/cpp
+ f = (IOHANDLE)fopen(pFile, "rt");
+
+ std::vector Lines;
+ char buff[500];
+ if (f) {
+ //support fgets in system.h/cpp
+ while (fgets(buff, 500, (FILE*)f)) Lines.push_back(buff);
+ io_close(f);
+
+ const char** ShaderCode = new const char*[Lines.size()];
+
+ for (int i = 0; i < Lines.size(); ++i) {
+ ShaderCode[i] = Lines[i].c_str();
+ }
+
+ GLuint shader = glCreateShader(Type);
+
+ glShaderSource(shader, Lines.size(), ShaderCode, NULL);
+ glCompileShader(shader);
+
+ delete[] ShaderCode;
+
+ int CompilationStatus;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &CompilationStatus);
+
+ if (CompilationStatus == GL_FALSE) {
+ char buff[3000];
+
+ GLint maxLength = 0;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
+
+ glGetShaderInfoLog(shader, maxLength, &maxLength, buff);
+
+ dbg_msg("GLSL", buff);
+ glDeleteShader(shader);
+ return false;
+ }
+ m_Type = Type;
+ m_IsLoaded = true;
+
+ m_ShaderID = shader;
+
+ return true;
+ }
+ else return false;
+
+}
+
+void CGLSL::DeleteShader() {
+ if (!IsLoaded()) return;
+ m_IsLoaded = false;
+ glDeleteShader(m_ShaderID);
+}
+
+bool CGLSL::IsLoaded() {
+ return m_IsLoaded;
+}
+
+GLuint CGLSL::GetShaderID() {
+ return m_ShaderID;
+}
+
+CGLSL::CGLSL(){
+ m_IsLoaded = false;
+}
\ No newline at end of file
diff --git a/src/engine/client/opengl_sl.h b/src/engine/client/opengl_sl.h
new file mode 100644
index 000000000..3bc5039e5
--- /dev/null
+++ b/src/engine/client/opengl_sl.h
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "GL/glew.h"
+
+class CGLSL {
+public:
+ bool LoadShader(const char* pFile, int Type);
+ void DeleteShader();
+
+ bool IsLoaded();
+ GLuint GetShaderID();
+
+ CGLSL();
+private:
+ GLuint m_ShaderID;
+ int m_Type;
+ bool m_IsLoaded;
+};
\ No newline at end of file
diff --git a/src/engine/client/opengl_sl_program.cpp b/src/engine/client/opengl_sl_program.cpp
new file mode 100644
index 000000000..005c66256
--- /dev/null
+++ b/src/engine/client/opengl_sl_program.cpp
@@ -0,0 +1,82 @@
+#include "opengl_sl_program.h"
+#include "opengl_sl.h"
+#include
+
+void CGLSLProgram::CreateProgram() {
+ m_ProgramID = glCreateProgram();
+}
+
+void CGLSLProgram::DeleteProgram() {
+ if (!m_IsLinked) return;
+ m_IsLinked = false;
+ glDeleteProgram(m_ProgramID);
+}
+
+bool CGLSLProgram::AddShader(CGLSL* pShader) {
+ if (pShader->IsLoaded()) {
+ glAttachShader(m_ProgramID, pShader->GetShaderID());
+ return true;
+ }
+ return false;
+}
+
+void CGLSLProgram::DetachShader(CGLSL* pShader) {
+ if (pShader->IsLoaded()) {
+ glDetachShader(m_ProgramID, pShader->GetShaderID());
+ }
+}
+
+void CGLSLProgram::LinkProgram() {
+ glLinkProgram(m_ProgramID);
+ int LinkStatus;
+ glGetProgramiv(m_ProgramID, GL_LINK_STATUS, &LinkStatus);
+ m_IsLinked = LinkStatus == GL_TRUE;
+ if (!m_IsLinked) {
+ char sInfoLog[1024];
+ char sFinalMessage[1536];
+ int iLogLength;
+ glGetProgramInfoLog(m_ProgramID, 1024, &iLogLength, sInfoLog);
+ str_format(sFinalMessage, 1536, "Error! Shader program wasn't linked! The linker returned:\n\n%s", sInfoLog);
+ dbg_msg("GLSL Program", sFinalMessage);
+ }
+}
+
+void CGLSLProgram::SetUniformVec4(int Loc, int Count, const float* Value) {
+ glUniform4fv(Loc, Count, Value);
+}
+
+void CGLSLProgram::SetUniform(int Loc, const int Value) {
+ glUniform1i(Loc, Value);
+}
+
+void CGLSLProgram::SetUniform(int Loc, const unsigned int Value) {
+ glUniform1ui(Loc, Value);
+}
+
+void CGLSLProgram::SetUniform(int Loc, const float Value) {
+ glUniform1f(Loc, Value);
+}
+
+void CGLSLProgram::SetUniform(int Loc, const bool Value) {
+ glUniform1i(Loc, (int)Value);
+}
+
+int CGLSLProgram::GetUniformLoc(const char* Name) {
+ return glGetUniformLocation(m_ProgramID, Name);
+}
+
+void CGLSLProgram::UseProgram() {
+ if(m_IsLinked) glUseProgram(m_ProgramID);
+}
+
+GLuint CGLSLProgram::GetProgramID() {
+ return m_ProgramID;
+}
+
+CGLSLProgram::CGLSLProgram() {
+ m_IsLinked = false;
+}
+
+CGLSLProgram::~CGLSLProgram() {
+ DeleteProgram();
+}
\ No newline at end of file
diff --git a/src/engine/client/opengl_sl_program.h b/src/engine/client/opengl_sl_program.h
new file mode 100644
index 000000000..f67866340
--- /dev/null
+++ b/src/engine/client/opengl_sl_program.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include "GL/glew.h"
+
+class CGLSL;
+
+class CGLSLProgram {
+public:
+ void CreateProgram();
+ void DeleteProgram();
+
+ bool AddShader(CGLSL* pShader);
+
+ void LinkProgram();
+ void UseProgram();
+ GLuint GetProgramID();
+
+ void DetachShader(CGLSL* pShader);
+
+ //Support various types
+ void SetUniformVec4(int Loc, int Count, const float* Value);
+ void SetUniform(int Loc, const int Value);
+ void SetUniform(int Loc, const unsigned int Value);
+ void SetUniform(int Loc, const bool Value);
+ void SetUniform(int Loc, const float Value);
+
+ //for performance reason we do not use SetUniform with using strings... save the Locations of the variables instead
+ int GetUniformLoc(const char* Name);
+
+ CGLSLProgram();
+ ~CGLSLProgram();
+
+protected:
+ GLuint m_ProgramID;
+ bool m_IsLinked;
+};
+
+class CGLSLQuadProgram : public CGLSLProgram {
+public:
+ int m_LocPos;
+ int m_LocIsTextured;
+ int m_LocTextureSampler;
+
+};
\ No newline at end of file