From c3b29fa23e6fed19f5bec8c142eccae9deb28bf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C5=82a=C5=BCej=20Szczygie=C5=82?= Date: Thu, 7 Mar 2024 18:19:32 +0100 Subject: [PATCH] OpenGL: Use framebuffer in GL(ES)2, fixes, code refactor OpenGL(ES) 2 changes: - render to texture, - rename "UseWindowSizeForFullScreen" to "FixedRenderingSize", - change framebuffer size instead of screen resolution for "FixedRenderingSize" option, - fix gamma in some locations (#68, apply gamma in post-processing), - MSAA is no longer available for OpenGL(ES) 2, - fix textures brightness due to incorrect texture format conversion, - fix triple-buffering flickering in some menu animations or loading screen, - some code refactor, --- Need For Speed II SE/nfs2se.conf.template | 15 +- src/Glide2x.c | 51 +- src/Glide2x/OpenGL1.c | 47 +- src/Glide2x/OpenGL2.c | 895 +++++++++++++++------- src/Wrapper.c | 63 +- 5 files changed, 718 insertions(+), 353 deletions(-) diff --git a/Need For Speed II SE/nfs2se.conf.template b/Need For Speed II SE/nfs2se.conf.template index bb363e9..8625937 100644 --- a/Need For Speed II SE/nfs2se.conf.template +++ b/Need For Speed II SE/nfs2se.conf.template @@ -18,13 +18,16 @@ # 0 - VSync disabled # 1 - VSync enabled (default) # >1 - VSync enabled, limit the framerate -#MSAA (Multisample antialiasing): +#MSAA (Multisample antialiasing, OpenGL 1 only): # 0 - Don't change (default) # 1 - Disable MSAA # 2, 4, 8, 16 - Enable MSAA. If not supported, the game probably won't run. -#UseWindowSizeForFullScreen: -# 0 - Don't change screen size (default) -# 1 - Use screen size from "WindowSize" +#FixedRenderingSize: +# 0 - Window size determines game rendering size (default) +# 1 - Fixed game rendering size (value is specified in "WindowSize"): +# - OpenGL 1 - window has fixed size, full screen will change screen resolution +# - OpenGL(ES) 2 - framebuffer has fixed size +# 2 - Same as "1", but OpenGL(ES) 2 renderer doesn't use linear image upscaling #WindowSize: # Type your own window size (default: 640x480) #KeepAspectRatio: @@ -61,7 +64,7 @@ # 0 - Original samplerate - 22050Hz (default) # 1 - Linear interpolated sound to 44100Hz (artificial highs) #UseGlBleginGlEnd: -# Use glBegin(), glEnd() instead of glDrawArrays() - can be slower, disabled by default +# Use glBegin(), glEnd() instead of glDrawArrays() in OpenGL 1 - can be slower, disabled by default #Port1: # TCP and UDP port (default: 1030) #Port2: @@ -75,7 +78,7 @@ #StartInFullScreen=1 #VSync=-1 #MSAA=4 -#UseWindowSizeForFullScreen=0 +#FixedRenderingSize=1 #WindowSize=640x480 #KeepAspectRatio=1 #LinearTextureFiltering=1 diff --git a/src/Glide2x.c b/src/Glide2x.c index 5bfb4ae..c92eab9 100644 --- a/src/Glide2x.c +++ b/src/Glide2x.c @@ -1,7 +1,10 @@ // SPDX-License-Identifier: MIT -static void handleDpr(); -static void swapBufferCommon(); +#include "Glide2x.h" + +static inline void handleDpr(); +static inline BOOL clearUnusedArea(int32_t xOffset, int32_t yOffset, int32_t visibleWidth, int32_t visibleHeight); +static inline void convertColor(GrColor_t color, uint8_t *alpha, float *r, float *g, float *b, float *a); #ifdef OPENGL1X #include "Glide2x/OpenGL1.c" @@ -9,7 +12,7 @@ static void swapBufferCommon(); #include "Glide2x/OpenGL2.c" #endif -static void handleDpr() +static inline void handleDpr() { extern double dpr; SDL_GetWindowSize(sdlWin, &winWidth, &winHeight); @@ -19,25 +22,11 @@ static void handleDpr() winWidth *= dpr; winHeight *= dpr; } -static void swapBufferCommon() +static inline BOOL clearUnusedArea(int32_t xOffset, int32_t yOffset, int32_t visibleWidth, int32_t visibleHeight) { - if (windowResized) - { - grClipWindow(0, 0, 640, 480); - windowResized = false; - } - else - { - drawTriangles(); - } - if (keepAspectRatio && (xOffset > 0 || yOffset > 0)) { - GLint scissorBox[4] = {0, 0, winWidth, winHeight}; - glGetIntegerv(GL_SCISSOR_BOX, scissorBox); - - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); if (xOffset > 0) { glScissor(0, 0, xOffset, winHeight); @@ -53,14 +42,26 @@ static void swapBufferCommon() glScissor(0, 0, winWidth, winHeight - visibleHeight - yOffset); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - glScissor(0, yOffset + visibleHeight, winWidth, yOffset); + glScissor(0, yOffset + visibleHeight, winWidth, yOffset + 1); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); } - - glScissor(scissorBox[0], scissorBox[1], scissorBox[2], scissorBox[3]); + return true; + } + return false; +} +static inline void convertColor(GrColor_t color, uint8_t *alpha, float *r, float *g, float *b, float *a) +{ + /* Game uses ARGB color format */ + *r = ((color & 0x00FF0000) >> 16) / 255.0f; + *g = ((color & 0x0000FF00) >> 8) / 255.0f; + *b = ((color & 0x000000FF) ) / 255.0f; + if (a) + { + if (alpha) + *a = *alpha / 255.0f; + else + *a = 1.0f; } - - SDL_GL_SwapWindow(sdlWin); } REALIGN STDCALL void grFogTable(const GrFog_t ft[GR_FOG_TABLE_SIZE]) @@ -90,7 +91,7 @@ REALIGN STDCALL void grFogTable(const GrFog_t ft[GR_FOG_TABLE_SIZE]) for (i = 0; i < GR_FOG_TABLE_SIZE; ++i) for (j = intStartEnd[i]; j < intStartEnd[i + 1]; ++j) - fogTable[j] = (uint8_t)(glideFogTable[i] + (glideFogTable[i + 1] - glideFogTable[i]) * (j - intStartEnd[i]) / intEndMinusStart[i]); + g_fogTable[j] = (uint8_t)(glideFogTable[i] + (glideFogTable[i + 1] - glideFogTable[i]) * (j - intStartEnd[i]) / intEndMinusStart[i]); // printf("grFogTable\n"); } diff --git a/src/Glide2x/OpenGL1.c b/src/Glide2x/OpenGL1.c index 2ca7918..efd4909 100644 --- a/src/Glide2x/OpenGL1.c +++ b/src/Glide2x/OpenGL1.c @@ -8,6 +8,10 @@ void SetBrightness(float); +#include + +BOOL contextError = false; + #define MaxTriangles 0x000400 #define TextureMem 0x200000 #define VertexSnap 0x0C0000 @@ -52,7 +56,7 @@ typedef struct } TextureInfo; static TextureInfo textures[TextureMem >> 2]; -static uint8_t *lfb, textureMem[TextureMem], fogTable[0x10000]; +static uint8_t *lfb, textureMem[TextureMem], g_fogTable[0x10000]; static uint32_t *palette, tmpTexture[0x400]; static uint32_t trianglesCount, maxTexIdx; @@ -74,15 +78,6 @@ static void setTextureFiltering() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } -static inline void convertColor(GrColor_t color, float *r, float *g, float *b, float *a) -{ - /* Game uses ARGB color format */ - *a = ((color & 0xFF000000) >> 24) / 255.0; - *r = ((color & 0x00FF0000) >> 16) / 255.0; - *g = ((color & 0x0000FF00) >> 8) / 255.0; - *b = ((color & 0x000000FF) ) / 255.0; -} - static inline void drawTriangles() { if (trianglesCount) @@ -165,7 +160,7 @@ REALIGN STDCALL void grClipWindow(uint32_t minX, uint32_t minY, uint32_t maxX, u REALIGN STDCALL void grBufferClear(GrColor_t color, GrAlpha_t alpha, uint16_t depth) { float r, g , b, a; - convertColor(color, &r, &g, &b, &a); + convertColor(color, &alpha, &r, &g, &b, &a); // printf("grBufferClear: %X %X %X [%d]\n", color, alpha, depth, trianglesCount); @@ -189,7 +184,23 @@ REALIGN STDCALL void grChromakeyValue(GrColor_t value) REALIGN STDCALL void grBufferSwap(int swap_interval) { // printf("grBufferSwap: [%d]\n", trianglesCount); - swapBufferCommon(); + + if (windowResized) + { + grClipWindow(0, 0, 640, 480); + windowResized = false; + } + else + { + drawTriangles(); + } + + GLint scissorBox[4] = {}; + glGetIntegerv(GL_SCISSOR_BOX, scissorBox); + if (clearUnusedArea(xOffset, yOffset, visibleWidth, visibleHeight)) + glScissor(scissorBox[0], scissorBox[1], scissorBox[2], scissorBox[3]); + + SDL_GL_SwapWindow(sdlWin); } REALIGN STDCALL void grColorCombine(GrCombineFunction_t function, GrCombineFactor_t factor, GrCombineLocal_t local, GrCombineOther_t other, BOOL invert) { @@ -237,7 +248,7 @@ REALIGN STDCALL void grDrawTriangle(const GrVertex *a, const GrVertex *b, const glColor4f(grVertex->r / 255.0f, grVertex->g / 255.0f, grVertex->b / 255.0f, grVertex->a / 255.0f); if (p_glFogCoordf) - p_glFogCoordf(fogTable[(uint16_t)(1.0f / grVertex->oow)] / 255.0f); + p_glFogCoordf(g_fogTable[(uint16_t)(1.0f / grVertex->oow)] / 255.0f); glTexCoord4f(grVertex->tmuvtx[0].sow / 256.0f, grVertex->tmuvtx[0].tow / 256.0f, 0.0f, grVertex->oow); glVertex3f(grVertex->x - VertexSnap, grVertex->y - VertexSnap, grVertex->oow); } @@ -254,7 +265,7 @@ REALIGN STDCALL void grDrawTriangle(const GrVertex *a, const GrVertex *b, const colorValues[trianglesCount].vertex[i].b = grVertex->b / 255.0f; colorValues[trianglesCount].vertex[i].a = grVertex->a / 255.0f; - fogCoord[trianglesCount].vertex[i] = fogTable[(uint16_t)(1.0f / grVertex->oow)] / 255.0f; + fogCoord[trianglesCount].vertex[i] = g_fogTable[(uint16_t)(1.0f / grVertex->oow)] / 255.0f; textureCoord[trianglesCount].vertex[i].s = grVertex->tmuvtx[0].sow / 256.0f; textureCoord[trianglesCount].vertex[i].t = grVertex->tmuvtx[0].tow / 256.0f; @@ -286,8 +297,8 @@ REALIGN STDCALL void grDrawLine(const GrVertex *a, const GrVertex *b) REALIGN STDCALL void grFogColorValue(GrColor_t fogcolor) { float fogColor[4]; - convertColor(fogcolor, fogColor + 0, fogColor + 1, fogColor + 2, fogColor + 3); drawTriangles(); + convertColor(fogcolor, NULL, &fogColor[0], &fogColor[1], &fogColor[2], &fogColor[3]); glFogfv(GL_FOG_COLOR, fogColor); // printf("grFogColorValue: 0x%.8X [%d]\n", fogcolor, trianglesCount); } @@ -377,6 +388,12 @@ REALIGN STDCALL void grSstWinClose(void) REALIGN STDCALL BOOL grSstWinOpen(uint32_t hWnd, GrScreenResolution_t screen_resolution, GrScreenRefresh_t refresh_rate, GrColorFormat_t color_format, GrOriginLocation_t origin_location, int nColBuffers, int nAuxBuffers) { glCtx = SDL_GL_CreateContext(sdlWin); + if (!glCtx) + { + contextError = true; + raise(SIGABRT); + } + handleDpr(); if (vSync >= 0) diff --git a/src/Glide2x/OpenGL2.c b/src/Glide2x/OpenGL2.c index bf97f08..9aa1bed 100644 --- a/src/Glide2x/OpenGL2.c +++ b/src/Glide2x/OpenGL2.c @@ -6,34 +6,48 @@ #include #ifdef GLES2 - #include +# include #else - #include - - static PFNGLGETSHADERIVPROC glGetShaderiv; - static PFNGLGETPROGRAMIVPROC glGetProgramiv; - static PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; - static PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; - static PFNGLCREATESHADERPROC glCreateShader; - static PFNGLSHADERSOURCEPROC glShaderSource; - static PFNGLCOMPILESHADERPROC glCompileShader; - static PFNGLCREATEPROGRAMPROC glCreateProgram; - static PFNGLATTACHSHADERPROC glAttachShader; - static PFNGLLINKPROGRAMPROC glLinkProgram; - static PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation; - static PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; - static PFNGLUSEPROGRAMPROC glUseProgram; - static PFNGLUNIFORM1IPROC glUniform1i; - static PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv; - static PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; - static PFNGLUNIFORM4FPROC glUniform4f; - static PFNGLUNIFORM1FPROC glUniform1f; - static PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; +# include +static PFNGLGETSHADERIVPROC glGetShaderiv; +static PFNGLGETPROGRAMIVPROC glGetProgramiv; +static PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; +static PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; +static PFNGLCREATESHADERPROC glCreateShader; +static PFNGLDELETESHADERPROC glDeleteShader; +static PFNGLSHADERSOURCEPROC glShaderSource; +static PFNGLCOMPILESHADERPROC glCompileShader; +static PFNGLCREATEPROGRAMPROC glCreateProgram; +static PFNGLDELETEPROGRAMPROC glDeleteProgram; +static PFNGLATTACHSHADERPROC glAttachShader; +static PFNGLLINKPROGRAMPROC glLinkProgram; +static PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation; +static PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; +static PFNGLUSEPROGRAMPROC glUseProgram; +static PFNGLUNIFORM1IPROC glUniform1i; +static PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv; +static PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; +static PFNGLUNIFORM3FPROC glUniform3f; +static PFNGLUNIFORM1FPROC glUniform1f; +static PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; +static PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray; +static PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; +static PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; +static PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; +static PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers; +static PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer; +static PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage; +static PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer; +static PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus; +static PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers; +static PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers; #endif #include +BOOL contextError = false; BOOL shaderError = false; +BOOL framebufferError = false; #ifdef WIN32 #undef near @@ -100,7 +114,6 @@ const char g_vShaderSrc[] = "gl_Position = uMatrix * aPosition;" "}" ; - const char g_fShaderSrc[] = #ifdef GLES2 "precision mediump float;" @@ -115,27 +128,60 @@ const char g_fShaderSrc[] = "uniform sampler2D uTextureSampler;" "uniform float uTextureEnabled;" "uniform float uFogEnabled;" - "uniform vec4 uFogColor;" - "uniform float uGamma;" + "uniform vec3 uFogColor;" "void main()" "{" - "vec4 ret = vColor;" - - "vec4 texture = uTextureEnabled * texture2D(uTextureSampler, (vTexCoord.st / 256.0) / vTexCoord.q);" - "ret *= (1.0 - uTextureEnabled) + vec4(texture.b, texture.g, texture.r, texture.a);" + "vec4 texture = uTextureEnabled * texture2D(uTextureSampler, vTexCoord.st / vTexCoord.q);" + "vec4 ret = vColor * ((1.0 - uTextureEnabled) + texture);" "if (ret.a <= 16.0 / 255.0)" "discard;" - "ret = mix(uFogColor, ret, 1.0 - (1.0 - vFog) * uFogEnabled);" - - "ret.rgb = pow(ret.rgb, vec3(1.0 / uGamma));" + "ret.rgb = mix(uFogColor, ret.rgb, 1.0 - (1.0 - vFog) * uFogEnabled);" "gl_FragColor = ret;" "}" ; +const char g_vShaderDispSrc[] = +#ifdef GLES2 + "precision mediump float;" +#else + "#version 110\n" +#endif + + "attribute vec2 aPosition;" + "attribute vec2 aTexCoord;" + + "varying vec2 vTexCoord;" + + "void main()" + "{" + "vTexCoord = aTexCoord;" + "gl_Position = vec4(aPosition, 0.0, 1.0);" + "}" +; +const char g_fShaderDispSrc[] = +#ifdef GLES2 + "precision mediump float;" +#else + "#version 110\n" +#endif + + "varying vec2 vTexCoord;" + + "uniform sampler2D uTextureSampler;" + "uniform float uGamma;" + + "void main()" + "{" + "vec4 texture = texture2D(uTextureSampler, vTexCoord);" + "texture.rgb = pow(texture.rgb, vec3(1.0 / uGamma));" + "gl_FragColor = texture;" + "}" +; + #define MaxTriangles 0x000400 #define TextureMem 0x200000 #define VertexSnap 0x0C0000 @@ -167,40 +213,62 @@ typedef struct float x, y, z; } vertex[3]; } Vertices; -static ColorValues colorValues[MaxTriangles]; -static FogCoord fogCoord[MaxTriangles]; -static TextureCoord textureCoord[MaxTriangles]; -static Vertices vertices[MaxTriangles]; +static ColorValues g_colorValues[MaxTriangles]; +static FogCoord g_fogCoord[MaxTriangles]; +static TextureCoord g_textureCoord[MaxTriangles]; +static Vertices g_vertices[MaxTriangles]; + +static float g_textureCoordDisp[4][2] = { + {0.0f, 1.0f}, + {0.0f, 0.0f}, + {1.0f, 1.0f}, + {1.0f, 0.0f}, +}; +static float g_verticesDisp[4][2] = { + {-1.0f, +1.0f}, + {-1.0f, -1.0f}, + {+1.0f, +1.0f}, + {+1.0f, -1.0f}, +}; typedef struct { - uint8_t *data; - uint32_t *palette; + void *data; + void *palette; GrTextureFormat_t fmt; uint32_t size; uint32_t id; } TextureInfo; -static TextureInfo textures[TextureMem >> 2]; +static TextureInfo g_textures[TextureMem >> 2]; -static uint8_t *lfb, textureMem[TextureMem], fogTable[0x10000]; -static uint32_t *palette, tmpTexture[256 * 256 /* 0x400 for grTexSource */]; -static uint32_t trianglesCount; +static uint8_t *g_lfb, g_textureMem[TextureMem], g_fogTable[0x10000]; +static uint32_t *g_palette, g_tmpTexture[0x400]; +static uint32_t g_trianglesCount; -static int32_t xOffset, yOffset, visibleWidth, visibleHeight; -static SDL_GLContext glCtx; +static SDL_GLContext g_glCtx; -extern BOOL keepAspectRatio, needRecreateGl, windowResized, linearFiltering; -extern int32_t vSync, winWidth, winHeight; +extern BOOL keepAspectRatio, needRecreateGl, windowResized, linearFiltering, fixedFramebufferSize, framebufferLinearFiltering; +extern int32_t vSync, winWidth, winHeight, initialWinWidth, initialWinHeight; extern SDL_Window *sdlWin; -/* GLSL */ +/* GLSL game */ static GLuint g_vShader, g_fShader, g_shaderProgram; -static GLint g_aPositionLoc, g_aTexCoordLoc, g_aColorLoc, g_aFogLoc, g_uMatrixLoc, g_uTextureEnabledLoc, g_uFogEnabledLoc, g_uFogColorLoc, g_uGammaLoc; +static GLint g_aPositionLoc, g_aTexCoordLoc, g_aColorLoc, g_aFogLoc, g_uMatrixLoc, g_uTextureEnabledLoc, g_uFogEnabledLoc, g_uFogColorLoc; + +/* GLSL display */ +static GLuint g_vShaderDisp, g_fShaderDisp, g_shaderProgramDisp; +static GLint g_aPositionLocDisp, g_aTexCoordLocDisp, g_uGammaLocDisp; + +/* Framebuffer */ +static uint32_t g_framebuffer; +static uint32_t g_framebufferTexture; +static uint32_t g_framebufferDepth; +static int32_t g_framebufferHeight; /* GLSL config */ static BOOL g_textureEnabled; static BOOL g_fogEnabled; -static float g_fogColor[4]; +static float g_fogColor[3]; static float g_gammaValue; /* GL config */ @@ -227,19 +295,19 @@ static BOOL checkShaderCompilation(GLuint shader) } return true; } -static BOOL checkShaderProgram() +static BOOL checkShaderProgram(GLuint program) { GLint status = 0; - glGetProgramiv(g_shaderProgram, GL_LINK_STATUS, &status); + glGetProgramiv(program, GL_LINK_STATUS, &status); if (!status) { GLint maxLen = 0; GLsizei len = 0; - glGetProgramiv(g_shaderProgram, GL_INFO_LOG_LENGTH, &maxLen); + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLen); if (maxLen > 1) { GLchar *log = (GLchar *)malloc(maxLen); - glGetProgramInfoLog(g_shaderProgram, maxLen, &len, log); + glGetProgramInfoLog(program, maxLen, &len, log); fprintf(stderr, "%s\n", log); free(log); } @@ -250,55 +318,211 @@ static BOOL checkShaderProgram() static inline BOOL loadShaders() { - const GLint vShaderLen = sizeof(g_vShaderSrc) - 1; - const GLint fShaderLen = sizeof(g_fShaderSrc) - 1; + { + const GLint vShaderLen = sizeof(g_vShaderSrc) - 1; + const GLint fShaderLen = sizeof(g_fShaderSrc) - 1; - const GLchar *vShaderSrc = g_vShaderSrc; - const GLchar *fShaderSrc = g_fShaderSrc; + const GLchar *vShaderSrc = g_vShaderSrc; + const GLchar *fShaderSrc = g_fShaderSrc; - g_vShader = glCreateShader(GL_VERTEX_SHADER); - g_fShader = glCreateShader(GL_FRAGMENT_SHADER); + g_vShader = glCreateShader(GL_VERTEX_SHADER); + g_fShader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(g_vShader, 1, &vShaderSrc, &vShaderLen); - glShaderSource(g_fShader, 1, &fShaderSrc, &fShaderLen); + glShaderSource(g_vShader, 1, &vShaderSrc, &vShaderLen); + glShaderSource(g_fShader, 1, &fShaderSrc, &fShaderLen); - glCompileShader(g_vShader); - if (!checkShaderCompilation(g_vShader)) - return false; - glCompileShader(g_fShader); - if (!checkShaderCompilation(g_fShader)) - return false; + glCompileShader(g_vShader); + if (!checkShaderCompilation(g_vShader)) + return false; + glCompileShader(g_fShader); + if (!checkShaderCompilation(g_fShader)) + return false; - g_shaderProgram = glCreateProgram(); + g_shaderProgram = glCreateProgram(); - glAttachShader(g_shaderProgram, g_vShader); - glAttachShader(g_shaderProgram, g_fShader); + glAttachShader(g_shaderProgram, g_vShader); + glAttachShader(g_shaderProgram, g_fShader); - glLinkProgram(g_shaderProgram); - if (!checkShaderProgram()) - return false; + glLinkProgram(g_shaderProgram); + if (!checkShaderProgram(g_shaderProgram)) + return false; + + g_aPositionLoc = glGetAttribLocation(g_shaderProgram, "aPosition"); + g_aTexCoordLoc = glGetAttribLocation(g_shaderProgram, "aTexCoord"); + g_aColorLoc = glGetAttribLocation(g_shaderProgram, "aColor"); + g_aFogLoc = glGetAttribLocation(g_shaderProgram, "aFog"); + g_uMatrixLoc = glGetUniformLocation(g_shaderProgram, "uMatrix"); + + g_uTextureEnabledLoc = glGetUniformLocation(g_shaderProgram, "uTextureEnabled"); + g_uFogEnabledLoc = glGetUniformLocation(g_shaderProgram, "uFogEnabled"); + g_uFogColorLoc = glGetUniformLocation(g_shaderProgram, "uFogColor"); + + glUseProgram(g_shaderProgram); + glUniform1i(glGetUniformLocation(g_shaderProgram, "uTextureSampler"), 0); + glUseProgram(0); + } + + { + const GLint vShaderLen = sizeof(g_vShaderDispSrc) - 1; + const GLint fShaderLen = sizeof(g_fShaderDispSrc) - 1; + + const GLchar *vShaderSrc = g_vShaderDispSrc; + const GLchar *fShaderSrc = g_fShaderDispSrc; + + g_vShaderDisp = glCreateShader(GL_VERTEX_SHADER); + g_fShaderDisp = glCreateShader(GL_FRAGMENT_SHADER); + + glShaderSource(g_vShaderDisp, 1, &vShaderSrc, &vShaderLen); + glShaderSource(g_fShaderDisp, 1, &fShaderSrc, &fShaderLen); + + glCompileShader(g_vShaderDisp); + if (!checkShaderCompilation(g_vShaderDisp)) + return false; + glCompileShader(g_fShaderDisp); + if (!checkShaderCompilation(g_fShaderDisp)) + return false; + + g_shaderProgramDisp = glCreateProgram(); + + glAttachShader(g_shaderProgramDisp, g_vShaderDisp); + glAttachShader(g_shaderProgramDisp, g_fShaderDisp); - g_aPositionLoc = glGetAttribLocation(g_shaderProgram, "aPosition"); - g_aTexCoordLoc = glGetAttribLocation(g_shaderProgram, "aTexCoord"); - g_aColorLoc = glGetAttribLocation(g_shaderProgram, "aColor"); - g_aFogLoc = glGetAttribLocation(g_shaderProgram, "aFog"); - g_uMatrixLoc = glGetUniformLocation(g_shaderProgram, "uMatrix"); + glLinkProgram(g_shaderProgramDisp); + if (!checkShaderProgram(g_shaderProgramDisp)) + return false; - g_uTextureEnabledLoc = glGetUniformLocation(g_shaderProgram, "uTextureEnabled"); - g_uFogEnabledLoc = glGetUniformLocation(g_shaderProgram, "uFogEnabled"); - g_uFogColorLoc = glGetUniformLocation(g_shaderProgram, "uFogColor"); - g_uGammaLoc = glGetUniformLocation(g_shaderProgram, "uGamma"); + g_aPositionLocDisp = glGetAttribLocation(g_shaderProgramDisp, "aPosition"); + g_aTexCoordLocDisp = glGetAttribLocation(g_shaderProgramDisp, "aTexCoord"); - glUseProgram(g_shaderProgram); + g_uGammaLocDisp = glGetUniformLocation(g_shaderProgramDisp, "uGamma"); - glUniform1i(glGetUniformLocation(g_shaderProgram, "uTextureSampler"), 0); + glUseProgram(g_shaderProgramDisp); + glUniform1i(glGetUniformLocation(g_shaderProgramDisp, "uTextureSampler"), 0); + glUseProgram(0); + } return true; } +static void destroyFrameBuffer() +{ + if (g_framebufferDepth != 0) + { + glDeleteRenderbuffers(1, &g_framebufferDepth); + g_framebufferDepth = 0; + } + if (g_framebufferTexture != 0) + { + glDeleteTextures(1, &g_framebufferTexture); + g_framebufferTexture = 0; + } + if (g_framebuffer != 0) + { + glDeleteFramebuffers(1, &g_framebuffer); + g_framebuffer = 0; + } + g_framebufferHeight = 0; +} +static void createFrameBuffer() +{ + int32_t shorterEdge = fixedFramebufferSize ? SDL_min(initialWinWidth, initialWinHeight) : SDL_min(winWidth, winHeight); + if (g_framebufferHeight == shorterEdge) + return; + + int32_t w = shorterEdge * 4 / 3; + int32_t h = shorterEdge; + + destroyFrameBuffer(); + + glGenFramebuffers(1, &g_framebuffer); + glBindFramebuffer(GL_FRAMEBUFFER, g_framebuffer); + + glGenTextures(1, &g_framebufferTexture); + glBindTexture(GL_TEXTURE_2D, g_framebufferTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (!fixedFramebufferSize || !framebufferLinearFiltering) ? GL_NEAREST : GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, g_framebufferTexture, 0); + glBindTexture(GL_TEXTURE_2D, 0); + + glGenRenderbuffers(1, &g_framebufferDepth); + glBindRenderbuffer(GL_RENDERBUFFER, g_framebufferDepth); +#ifdef GLES2 + if (strstr((const char *)glGetString(GL_EXTENSIONS), "GL_OES_depth24") != NULL) + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, w, h); + else + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, w, h); +#else + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, w, h); +#endif + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, g_framebufferDepth); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + framebufferError = true; + raise(SIGABRT); + } + + g_framebufferHeight = shorterEdge; +} + +static void useGameProgram(BOOL gameProgram) +{ + if (gameProgram) + { + glEnable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + + glBindFramebuffer(GL_FRAMEBUFFER, g_framebuffer); + + glDisableVertexAttribArray(g_aPositionLocDisp); + glDisableVertexAttribArray(g_aTexCoordLocDisp); + + glUseProgram(g_shaderProgram); + + glEnableVertexAttribArray(g_aPositionLoc); + glEnableVertexAttribArray(g_aTexCoordLoc); + glEnableVertexAttribArray(g_aColorLoc); + glEnableVertexAttribArray(g_aFogLoc); + + glVertexAttribPointer(g_aPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, g_vertices); + glVertexAttribPointer(g_aTexCoordLoc, 4, GL_FLOAT, GL_FALSE, 0, g_textureCoord); + glVertexAttribPointer(g_aColorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, g_colorValues); + glVertexAttribPointer(g_aFogLoc, 1, GL_UNSIGNED_BYTE, GL_TRUE, 0, g_fogCoord); + } + else + { + glDisable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glDisableVertexAttribArray(g_aPositionLoc); + glDisableVertexAttribArray(g_aTexCoordLoc); + glDisableVertexAttribArray(g_aColorLoc); + glDisableVertexAttribArray(g_aFogLoc); + + glUseProgram(g_shaderProgramDisp); + + glEnableVertexAttribArray(g_aPositionLocDisp); + glEnableVertexAttribArray(g_aTexCoordLocDisp); + + glVertexAttribPointer(g_aPositionLocDisp, 2, GL_FLOAT, GL_FALSE, 0, g_verticesDisp); + glVertexAttribPointer(g_aTexCoordLocDisp, 2, GL_FLOAT, GL_FALSE, 0, g_textureCoordDisp); + } +} + static void createContext() { - glCtx = SDL_GL_CreateContext(sdlWin); + g_glCtx = SDL_GL_CreateContext(sdlWin); + if (!g_glCtx) + { + contextError = true; + raise(SIGABRT); + } #ifndef GLES2 glGetShaderiv = SDL_GL_GetProcAddress("glGetShaderiv"); @@ -306,9 +530,11 @@ static void createContext() glGetShaderInfoLog = SDL_GL_GetProcAddress("glGetShaderInfoLog"); glGetProgramInfoLog = SDL_GL_GetProcAddress("glGetProgramInfoLog"); glCreateShader = SDL_GL_GetProcAddress("glCreateShader"); + glDeleteShader = SDL_GL_GetProcAddress("glDeleteShader"); glShaderSource = SDL_GL_GetProcAddress("glShaderSource"); glCompileShader = SDL_GL_GetProcAddress("glCompileShader"); glCreateProgram = SDL_GL_GetProcAddress("glCreateProgram"); + glDeleteProgram = SDL_GL_GetProcAddress("glDeleteProgram"); glAttachShader = SDL_GL_GetProcAddress("glAttachShader"); glLinkProgram = SDL_GL_GetProcAddress("glLinkProgram"); glGetAttribLocation = SDL_GL_GetProcAddress("glGetAttribLocation"); @@ -317,18 +543,66 @@ static void createContext() glUniform1i = SDL_GL_GetProcAddress("glUniform1i"); glUniformMatrix4fv = SDL_GL_GetProcAddress("glUniformMatrix4fv"); glVertexAttribPointer = SDL_GL_GetProcAddress("glVertexAttribPointer"); - glUniform4f = SDL_GL_GetProcAddress("glUniform4f"); + glUniform3f = SDL_GL_GetProcAddress("glUniform3f"); glUniform1f = SDL_GL_GetProcAddress("glUniform1f"); glEnableVertexAttribArray = SDL_GL_GetProcAddress("glEnableVertexAttribArray"); + glDisableVertexAttribArray = SDL_GL_GetProcAddress("glDisableVertexAttribArray"); + glGenFramebuffers = SDL_GL_GetProcAddress("glGenFramebuffers"); + glBindFramebuffer = SDL_GL_GetProcAddress("glBindFramebuffer"); + glFramebufferTexture2D = SDL_GL_GetProcAddress("glFramebufferTexture2D"); + glGenRenderbuffers = SDL_GL_GetProcAddress("glGenRenderbuffers"); + glBindRenderbuffer = SDL_GL_GetProcAddress("glBindRenderbuffer"); + glRenderbufferStorage = SDL_GL_GetProcAddress("glRenderbufferStorage"); + glFramebufferRenderbuffer = SDL_GL_GetProcAddress("glFramebufferRenderbuffer"); + glCheckFramebufferStatus = SDL_GL_GetProcAddress("glCheckFramebufferStatus"); + glDeleteFramebuffers = SDL_GL_GetProcAddress("glDeleteFramebuffers"); + glDeleteRenderbuffers = SDL_GL_GetProcAddress("glDeleteRenderbuffers"); + + BOOL ok = true; + ok &= !!glGetShaderiv; + ok &= !!glGetProgramiv; + ok &= !!glGetShaderInfoLog; + ok &= !!glGetProgramInfoLog; + ok &= !!glCreateShader; + ok &= !!glDeleteShader; + ok &= !!glShaderSource; + ok &= !!glCompileShader; + ok &= !!glCreateProgram; + ok &= !!glDeleteProgram; + ok &= !!glAttachShader; + ok &= !!glLinkProgram; + ok &= !!glGetAttribLocation; + ok &= !!glGetUniformLocation; + ok &= !!glUseProgram; + ok &= !!glUniform1i; + ok &= !!glUniformMatrix4fv; + ok &= !!glVertexAttribPointer; + ok &= !!glUniform3f; + ok &= !!glUniform1f; + ok &= !!glEnableVertexAttribArray; + ok &= !!glDisableVertexAttribArray; + ok &= !!glGenFramebuffers; + ok &= !!glBindFramebuffer; + ok &= !!glFramebufferTexture2D; + ok &= !!glGenRenderbuffers; + ok &= !!glBindRenderbuffer; + ok &= !!glRenderbufferStorage; + ok &= !!glFramebufferRenderbuffer; + ok &= !!glCheckFramebufferStatus; + ok &= !!glDeleteRenderbuffers; + ok &= !!glDeleteFramebuffers; + if (!ok) + { + contextError = true; + raise(SIGABRT); + } #endif if (vSync >= 0) SDL_GL_SetSwapInterval(vSync); glEnable(GL_SCISSOR_TEST); - glEnable(GL_DEPTH_TEST); glDisable(GL_DITHER); - glEnable(GL_BLEND); glDepthFunc(GL_LEQUAL); @@ -337,16 +611,34 @@ static void createContext() shaderError = true; raise(SIGABRT); } +} +static void destroyContext() +{ + uint32_t i; + + glUseProgram(0); + + destroyFrameBuffer(); + + for (i = 0; i < (TextureMem >> 2); ++i) + { + TextureInfo *ti = &g_textures[i]; + if (ti->id != 0) + glDeleteTextures(1, &ti->id); + } + + glDeleteProgram(g_shaderProgram); + glDeleteShader(g_fShader); + glDeleteShader(g_vShader); + + glDeleteProgram(g_shaderProgramDisp); + glDeleteShader(g_fShaderDisp); + glDeleteShader(g_vShaderDisp); - glEnableVertexAttribArray(g_aPositionLoc); - glEnableVertexAttribArray(g_aTexCoordLoc); - glEnableVertexAttribArray(g_aColorLoc); - glEnableVertexAttribArray(g_aFogLoc); + SDL_GL_DeleteContext(g_glCtx); + g_glCtx = NULL; - glVertexAttribPointer(g_aPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, vertices); - glVertexAttribPointer(g_aTexCoordLoc, 4, GL_FLOAT, GL_FALSE, 0, textureCoord); - glVertexAttribPointer(g_aColorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colorValues); - glVertexAttribPointer(g_aFogLoc, 1, GL_UNSIGNED_BYTE, GL_TRUE, 0, fogCoord); + g_trianglesCount = 0; } static void setTextureFiltering() @@ -360,7 +652,6 @@ static void setTextureFiltering() static void uploadTexture(TextureInfo *ti) { - uint16_t *data = (uint16_t *)ti->data; BOOL newTexture = (ti->id == 0); if (newTexture) @@ -372,66 +663,68 @@ static void uploadTexture(TextureInfo *ti) if (newTexture) setTextureFiltering(); - const uint32_t loopSize = ti->size * ti->size * 4; - uint8_t *tmpTexture8 = (uint8_t *)tmpTexture; - uint32_t i, j; switch (ti->fmt) { + case GR_TEXFMT_P_8: + if (newTexture) + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ti->size, ti->size, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + ti->palette = NULL; + break; case GR_TEXFMT_RGB_565: - { - for (i = 0, j = 0; i < loopSize; i += 4, ++j) - { - tmpTexture8[i + 0] = (data[j] << 3) & 0xF8; - tmpTexture8[i + 1] = (data[j] >> 3) & 0xFC; - tmpTexture8[i + 2] = (data[j] >> 8) & 0xF8; - tmpTexture8[i + 3] = 0xFF; - } + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, ti->size, ti->size, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, ti->data); break; - } case GR_TEXFMT_ARGB_1555: - { - for (i = 0, j = 0; i < loopSize; i += 4, ++j) - { - tmpTexture8[i + 0] = (data[j] << 3) & 0xF8; - tmpTexture8[i + 1] = (data[j] >> 2) & 0xF8; - tmpTexture8[i + 2] = (data[j] >> 7) & 0xF8; - tmpTexture8[i + 3] = (data[j] >> 15) * 255; - } + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ti->size, ti->size, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, ti->data); break; - } case GR_TEXFMT_ARGB_4444: - { - for (i = 0, j = 0; i < loopSize; i += 4, ++j) - { - tmpTexture8[i + 0] = (data[j] << 4) & 0xF0; - tmpTexture8[i + 1] = (data[j] >> 0) & 0xF0; - tmpTexture8[i + 2] = (data[j] >> 4) & 0xF0; - tmpTexture8[i + 3] = (data[j] >> 8) & 0xF0; - } + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ti->size, ti->size, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, ti->data); break; - } } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ti->size, ti->size, 0, GL_RGBA, GL_UNSIGNED_BYTE, (ti->fmt == GR_TEXFMT_P_8) ? NULL : tmpTexture); } -/**/ - -static inline void convertColor(GrColor_t color, float *r, float *g, float *b, float *a) +static void recreateContext() { - /* Game uses ARGB color format */ - *a = ((color & 0xFF000000) >> 24) / 255.0; - *r = ((color & 0x00FF0000) >> 16) / 255.0; - *g = ((color & 0x0000FF00) >> 8) / 255.0; - *b = ((color & 0x000000FF) ) / 255.0; + uint32_t i; + + destroyContext(); + + createContext(); + + // Restore textures + for (i = 0; i < (TextureMem >> 2); ++i) + { + TextureInfo *ti = &g_textures[i]; + if (ti->id == 0) + continue; + + ti->id = 0; + uploadTexture(ti); + } + + // Restore config + { + glDepthMask(g_depthMask); + glBlendFunc(GL_SRC_ALPHA, g_blendFuncDFactor); + + glUseProgram(g_shaderProgram); + glUniform1f(g_uTextureEnabledLoc, g_textureEnabled); + glUniform1f(g_uFogEnabledLoc, g_fogEnabled); + glUniform3f(g_uFogColorLoc, g_fogColor[0], g_fogColor[1], g_fogColor[2]); + glUseProgram(0); + + glUseProgram(g_shaderProgramDisp); + glUniform1f(g_uGammaLocDisp, g_gammaValue); + glUseProgram(0); + } } static inline void drawTriangles() { - if (trianglesCount) - { - glDrawArrays(GL_TRIANGLES, 0, trianglesCount * 3); - trianglesCount = 0; - } + if (g_trianglesCount == 0) + return; + + glDrawArrays(GL_TRIANGLES, 0, g_trianglesCount * 3); + g_trianglesCount = 0; } /**/ @@ -449,7 +742,7 @@ REALIGN STDCALL void grAlphaBlendFunction(GrAlphaBlendFnc_t rgb_sf, GrAlphaBlend break; } glBlendFunc(GL_SRC_ALPHA, g_blendFuncDFactor); -// printf("grAlphaBlendFunction: %d %d %d %d\n", rgb_sf, rgb_df, alpha_sf, alpha_df); +// fprintf(stderr, "grAlphaBlendFunction: %d %d %d %d\n", rgb_sf, rgb_df, alpha_sf, alpha_df); } REALIGN STDCALL void grAlphaCombine(GrCombineFunction_t function, GrCombineFactor_t factor, GrCombineLocal_t local, GrCombineOther_t other, BOOL invert) { @@ -459,61 +752,45 @@ REALIGN STDCALL void grAlphaCombine(GrCombineFunction_t function, GrCombineFacto else g_textureEnabled = 0.0f; glUniform1f(g_uTextureEnabledLoc, g_textureEnabled); -// printf("grAlphaCombine: %d\n", (other == GR_COMBINE_OTHER_TEXTURE)); +// fprintf(stderr, "grAlphaCombine: %d\n", (other == GR_COMBINE_OTHER_TEXTURE)); } REALIGN STDCALL void grAlphaTestFunction(GrCmpFnc_t function) { -// printf("grAlphaTestFunction: %X\n", function); +// fprintf(stderr, "grAlphaTestFunction: %X\n", function); } REALIGN STDCALL void grAlphaTestReferenceValue(GrAlpha_t value) { -// printf("grAlphaTestReferenceValue: %f\n", value / 255.0f); +// fprintf(stderr, "grAlphaTestReferenceValue: %f\n", value / 255.0f); } REALIGN STDCALL void grClipWindow(uint32_t minX, uint32_t minY, uint32_t maxX, uint32_t maxY) { - float widthRatio = winWidth / 640.0f; - float heightRatio = winHeight / 480.0f; - - if (keepAspectRatio) - { - if (widthRatio > heightRatio) - widthRatio = heightRatio; - else if (heightRatio > widthRatio) - heightRatio = widthRatio; + float ratio = g_framebufferHeight / 480.0f; - xOffset = winWidth / 2 - widthRatio * 320; - yOffset = winHeight / 2 - heightRatio * 240; + int32_t scaledMinX = minX * ratio; + int32_t scaledMinY = minY * ratio; + int32_t scaledMaxX = maxX * ratio + 0.5f; + int32_t scaledMaxY = maxY * ratio + 0.5f; - visibleWidth = 640 * widthRatio + 0.5f; - visibleHeight = 480 * heightRatio + 0.5f; - } +// fprintf(stderr, "grClipWindow: %d %d %d %d [%d]\n", minX, minY, maxX, maxY, g_trianglesCount); - int32_t scaledMinX = minX * widthRatio; - int32_t scaledMinY = minY * heightRatio; - int32_t scaledMaxX = maxX * widthRatio + 0.5f; - int32_t scaledMaxY = maxY * heightRatio + 0.5f; + drawTriangles(); -// printf("grClipWindow: %d %d %d %d [%d]\n", minX, minY, maxX, maxY, trianglesCount); + glViewport(scaledMinX, g_framebufferHeight - scaledMaxY, scaledMaxX - scaledMinX, scaledMaxY - scaledMinY); + glScissor (scaledMinX, g_framebufferHeight - scaledMaxY, scaledMaxX - scaledMinX, scaledMaxY - scaledMinY); - drawTriangles(); + glLineWidth((ratio == 1.0f) ? 1.0f : 2.0f * ratio); matrixLoadIdentity(); - matrixOrtho(scaledMinX, scaledMaxX, scaledMaxY, scaledMinY, Near, Far); - glViewport(scaledMinX + xOffset, winHeight - scaledMaxY - yOffset, scaledMaxX - scaledMinX, scaledMaxY - scaledMinY); - glScissor (scaledMinX + xOffset, winHeight - scaledMaxY - yOffset, scaledMaxX - scaledMinX, scaledMaxY - scaledMinY); - - matrixScale2(widthRatio, heightRatio); - glLineWidth(widthRatio + heightRatio); - + matrixScale2(ratio, ratio); glUniformMatrix4fv(g_uMatrixLoc, 1, GL_FALSE, g_matrix); } REALIGN STDCALL void grBufferClear(GrColor_t color, GrAlpha_t alpha, uint16_t depth) { float r, g , b, a; - convertColor(color, &r, &g, &b, &a); + convertColor(color, &alpha, &r, &g, &b, &a); -// printf("grBufferClear: %X %X %X [%d]\n", color, alpha, depth, trianglesCount); +// fprintf(stderr, "grBufferClear: %X %X %X [%d]\n", color, alpha, depth, g_trianglesCount); drawTriangles(); @@ -528,100 +805,104 @@ REALIGN STDCALL void grBufferClear(GrColor_t color, GrAlpha_t alpha, uint16_t de } REALIGN STDCALL void grChromakeyMode(GrChromakeyMode_t mode) { -// printf("grChromakeyMode: %X\n", mode); +// fprintf(stderr, "grChromakeyMode: %X\n", mode); // chromaKeyEnabled = mode; } REALIGN STDCALL void grChromakeyValue(GrColor_t value) { -// printf("grChromakeyValue: %X\n", value); +// fprintf(stderr, "grChromakeyValue: %X\n", value); // chromaKeyValue = value;//(value & 0x0000FF00) | ((value & 0x00FF0000) >> 16) | ((value & 0x000000FF) << 16); } REALIGN STDCALL void grBufferSwap(int swap_interval) { -// printf("grBufferSwap: [%d]\n", trianglesCount); +// fprintf(stderr, "grBufferSwap: [%d]\n", g_trianglesCount); -#ifdef GLES2 - if (needRecreateGl) - { - uint32_t i; - - // Destroy old context - if (glCtx) - { - for (i = 0; i < (TextureMem >> 2); ++i) - { - TextureInfo *ti = &textures[i]; - if (ti->id != 0) - glDeleteTextures(1, &ti->id); - } + drawTriangles(); - glUseProgram(0); + useGameProgram(false); - glDetachShader(g_shaderProgram, g_fShader); - glDetachShader(g_shaderProgram, g_vShader); + GLint viewportSize[4] = {}; + glGetIntegerv(GL_VIEWPORT, viewportSize); - glDeleteProgram(g_shaderProgram); + GLint scissorBox[4] = {}; + glGetIntegerv(GL_SCISSOR_BOX, scissorBox); - glDeleteShader(g_fShader); - glDeleteShader(g_vShader); + int32_t xOffset = 0, yOffset = 0; + int32_t visibleWidth = 0, visibleHeight = 0; + float widthRatio = winWidth / 640.0f; + float heightRatio = winHeight / 480.0f; - SDL_GL_DeleteContext(glCtx); - } + if (keepAspectRatio) + { + if (widthRatio > heightRatio) + widthRatio = heightRatio; + else if (heightRatio > widthRatio) + heightRatio = widthRatio; - trianglesCount = 0; + xOffset = winWidth / 2 - widthRatio * 320; + yOffset = winHeight / 2 - heightRatio * 240; - createContext(); + visibleWidth = 640 * widthRatio + 0.5f; + visibleHeight = 480 * heightRatio + 0.5f; + } - // Restore textures - for (i = 0; i < (TextureMem >> 2); ++i) - { - TextureInfo *ti = &textures[i]; - if (ti->id == 0) - continue; + clearUnusedArea(xOffset, yOffset, visibleWidth, visibleHeight); - ti->id = 0; - uploadTexture(ti); - } + int32_t scaledMaxX = 640.0f * widthRatio + 0.5f; + int32_t scaledMaxY = 480.0f * heightRatio + 0.5f; + glViewport(xOffset, winHeight - scaledMaxY - yOffset, scaledMaxX, scaledMaxY); + glScissor (xOffset, winHeight - scaledMaxY - yOffset, scaledMaxX, scaledMaxY); - // Restore config - { - glUniform1f(g_uTextureEnabledLoc, g_textureEnabled); - glUniform1f(g_uFogEnabledLoc, g_fogEnabled); - glUniform4f(g_uFogColorLoc, g_fogColor[0], g_fogColor[1], g_fogColor[2], g_fogColor[3]); - glUniform1f(g_uGammaLoc, g_gammaValue); + glBindTexture(GL_TEXTURE_2D, g_framebufferTexture); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindTexture(GL_TEXTURE_2D, 0); - glDepthMask(g_depthMask); - glBlendFunc(GL_SRC_ALPHA, g_blendFuncDFactor); - } + SDL_GL_SwapWindow(sdlWin); + if (needRecreateGl) + { + recreateContext(); needRecreateGl = false; windowResized = true; } -#endif + else + { + useGameProgram(true); + } - swapBufferCommon(); + if (windowResized) + { + createFrameBuffer(); + grClipWindow(0, 0, 640, 480); + windowResized = false; + } + else + { + glViewport(viewportSize[0], viewportSize[1], viewportSize[2], viewportSize[3]); + glScissor(scissorBox[0], scissorBox[1], scissorBox[2], scissorBox[3]); + } } REALIGN STDCALL void grColorCombine(GrCombineFunction_t function, GrCombineFactor_t factor, GrCombineLocal_t local, GrCombineOther_t other, BOOL invert) { -// printf("grColorCombine\n"); +// fprintf(stderr, "grColorCombine\n"); } REALIGN STDCALL void grCullMode(GrCullMode_t mode) { -// printf("grCullMode: %d\n", mode); +// fprintf(stderr, "grCullMode: %d\n", mode); } REALIGN STDCALL void grDepthBiasLevel(int16_t level) { -// printf("grDepthBiasLevel: %d\n", level); +// fprintf(stderr, "grDepthBiasLevel: %d\n", level); } REALIGN STDCALL void grDepthBufferFunction(GrCmpFnc_t function) { // drawTriangles(); // glDepthFunc(GL_NEVER + function); -// printf("grDepthBufferFunction: %X\n", function); +// fprintf(stderr, "grDepthBufferFunction: %X\n", function); } REALIGN STDCALL void grDepthBufferMode(GrDepthBufferMode_t mode) { -// printf("grDepthBufferMode: %X\n", mode); +// fprintf(stderr, "grDepthBufferMode: %X\n", mode); } REALIGN STDCALL void grDepthMask(BOOL mask) { @@ -629,37 +910,37 @@ REALIGN STDCALL void grDepthMask(BOOL mask) g_depthMask = mask; glDepthMask(g_depthMask); -// printf("grDepthMask: %d [%d]\n", mask, trianglesCount); +// fprintf(stderr, "grDepthMask: %d [%d]\n", mask, g_trianglesCount); } REALIGN STDCALL void grDitherMode(GrDitherMode_t mode) { -// printf("grDitherMode: %d\n", mode); +// fprintf(stderr, "grDitherMode: %d\n", mode); } REALIGN STDCALL void grDrawTriangle(const GrVertex *a, const GrVertex *b, const GrVertex *c) { -// printf("grDrawTriangle\n"); +// fprintf(stderr, "grDrawTriangle\n"); const GrVertex *grVertices[3] = {a, b, c}; uint32_t i; for (i = 0; i < 3; ++i) { const GrVertex *grVertex = grVertices[i]; - colorValues[trianglesCount].vertex[i].r = grVertex->r; - colorValues[trianglesCount].vertex[i].g = grVertex->g; - colorValues[trianglesCount].vertex[i].b = grVertex->b; - colorValues[trianglesCount].vertex[i].a = grVertex->a; + g_colorValues[g_trianglesCount].vertex[i].r = grVertex->r; + g_colorValues[g_trianglesCount].vertex[i].g = grVertex->g; + g_colorValues[g_trianglesCount].vertex[i].b = grVertex->b; + g_colorValues[g_trianglesCount].vertex[i].a = grVertex->a; - fogCoord[trianglesCount].vertex[i] = 255 - fogTable[(uint16_t)(1.0f / grVertex->oow)]; + g_fogCoord[g_trianglesCount].vertex[i] = 255 - g_fogTable[(uint16_t)(1.0f / grVertex->oow)]; - textureCoord[trianglesCount].vertex[i].s = grVertex->tmuvtx[0].sow; - textureCoord[trianglesCount].vertex[i].t = grVertex->tmuvtx[0].tow; - textureCoord[trianglesCount].vertex[i].q = grVertex->oow; + g_textureCoord[g_trianglesCount].vertex[i].s = grVertex->tmuvtx[0].sow / 256.0f; + g_textureCoord[g_trianglesCount].vertex[i].t = grVertex->tmuvtx[0].tow / 256.0f; + g_textureCoord[g_trianglesCount].vertex[i].q = grVertex->oow; - vertices[trianglesCount].vertex[i].x = grVertex->x - VertexSnap; - vertices[trianglesCount].vertex[i].y = grVertex->y - VertexSnap; - vertices[trianglesCount].vertex[i].z = grVertex->oow; + g_vertices[g_trianglesCount].vertex[i].x = grVertex->x - VertexSnap; + g_vertices[g_trianglesCount].vertex[i].y = grVertex->y - VertexSnap; + g_vertices[g_trianglesCount].vertex[i].z = grVertex->oow; } - if (++trianglesCount >= MaxTriangles) + if (++g_trianglesCount >= MaxTriangles) { drawTriangles(); // fprintf(stderr, "Too many triangles!\n"); @@ -667,46 +948,38 @@ REALIGN STDCALL void grDrawTriangle(const GrVertex *a, const GrVertex *b, const } REALIGN STDCALL void grDrawLine(const GrVertex *a, const GrVertex *b) { -// printf("grDrawLine: [%d]\n", trianglesCount); +// fprintf(stderr, "grDrawLine: [%d]\n", g_trianglesCount); drawTriangles(); - ColorValues lineColorValues; - Vertices lineVertices; - const GrVertex *grVertices[2] = {a, b}; uint32_t i; for (i = 0; i < 2; ++i) { - lineColorValues.vertex[i].r = grVertices[i]->r; - lineColorValues.vertex[i].g = grVertices[i]->g; - lineColorValues.vertex[i].b = grVertices[i]->b; - lineColorValues.vertex[i].a = grVertices[i]->a; - - lineVertices.vertex[i].x = grVertices[i]->x - VertexSnap; - lineVertices.vertex[i].y = grVertices[i]->y - VertexSnap; - lineVertices.vertex[i].z = grVertices[i]->oow; + g_colorValues->vertex[i].r = grVertices[i]->r; + g_colorValues->vertex[i].g = grVertices[i]->g; + g_colorValues->vertex[i].b = grVertices[i]->b; + g_colorValues->vertex[i].a = grVertices[i]->a; + + g_vertices->vertex[i].x = grVertices[i]->x - VertexSnap; + g_vertices->vertex[i].y = grVertices[i]->y - VertexSnap; + g_vertices->vertex[i].z = grVertices[i]->oow; } - - glVertexAttribPointer(g_aPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, &lineVertices); - glVertexAttribPointer(g_aColorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, &lineColorValues); - glDrawArrays(GL_LINES, 0, 2); - - glVertexAttribPointer(g_aPositionLoc, 3, GL_FLOAT, GL_FALSE, 0, vertices); - glVertexAttribPointer(g_aColorLoc, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, colorValues); } REALIGN STDCALL void grFogColorValue(GrColor_t fogcolor) { - convertColor(fogcolor, g_fogColor + 0, g_fogColor + 1, g_fogColor + 2, g_fogColor + 3); drawTriangles(); - glUniform4f(g_uFogColorLoc, g_fogColor[0], g_fogColor[1], g_fogColor[2], g_fogColor[3]); -// printf("grFogColorValue: 0x%.8X [%d]\n", fogcolor, trianglesCount); + + convertColor(fogcolor, NULL, &g_fogColor[0], &g_fogColor[1], &g_fogColor[2], NULL); + glUniform3f(g_uFogColorLoc, g_fogColor[0], g_fogColor[1], g_fogColor[2]); + +// fprintf(stderr, "grFogColorValue: 0x%.8X [%d]\n", fogcolor, g_trianglesCount); } REALIGN STDCALL void grFogMode(GrFogMode_t mode) { switch (mode) { - case GR_FOG_DISABLE: // Is it necessary to disable fog? + case GR_FOG_DISABLE: g_fogEnabled = 0.0f; break; case GR_FOG_WITH_TABLE: @@ -714,24 +987,29 @@ REALIGN STDCALL void grFogMode(GrFogMode_t mode) break; } glUniform1f(g_uFogEnabledLoc, g_fogEnabled); -// printf("grFogMode: %X\n", mode); +// fprintf(stderr, "grFogMode: %X\n", mode); } REALIGN STDCALL void grGammaCorrectionValue(float value) { + if (g_gammaValue == value) + return; + g_gammaValue = value; - glUniform1f(g_uGammaLoc, g_gammaValue); + + useGameProgram(false); + glUniform1f(g_uGammaLocDisp, g_gammaValue); + useGameProgram(true); } REALIGN STDCALL void grGlideInit(void) { -// printf("grGlideInit\n"); +// fprintf(stderr, "grGlideInit\n"); } REALIGN STDCALL void grGlideShutdown(void) { - SDL_GL_DeleteContext(glCtx); - palette = NULL; - glCtx = NULL; + destroyContext(); + g_palette = NULL; -// printf("grGlideShutdown\n"); +// fprintf(stderr, "grGlideShutdown\n"); } REALIGN STDCALL BOOL grLfbLock(GrLock_t type, GrBuffer_t buffer, GrLfbWriteMode_t writeMode, GrOriginLocation_t origin, BOOL pixelPipeline, GrLfbInfo_t *info) { @@ -739,7 +1017,7 @@ REALIGN STDCALL BOOL grLfbLock(GrLock_t type, GrBuffer_t buffer, GrLfbWriteMode_ memset(info, 0, sizeof(GrLfbInfo_t)); if (type == GR_LFB_WRITE_ONLY) { - info->lfbPtr = lfb = (uint8_t *)malloc(640*480*2); + info->lfbPtr = g_lfb = (uint8_t *)malloc(640*480*2); info->strideInBytes = 2; return true; } @@ -748,21 +1026,21 @@ REALIGN STDCALL BOOL grLfbLock(GrLock_t type, GrBuffer_t buffer, GrLfbWriteMode_ REALIGN STDCALL BOOL grLfbUnlock(GrLock_t type, GrBuffer_t buffer) { //TODO Remove this - free(lfb); - lfb = NULL; + free(g_lfb); + g_lfb = NULL; return true; } REALIGN STDCALL void grRenderBuffer(GrBuffer_t buffer) { -// printf("grRenderBuffer\n"); +// fprintf(stderr, "grRenderBuffer\n"); } REALIGN STDCALL void grSstIdle(void) { -// printf("grSstIdle\n"); +// fprintf(stderr, "grSstIdle\n"); } REALIGN STDCALL BOOL grSstIsBusy(void) { -// printf("grSstIsBusy\n"); +// fprintf(stderr, "grSstIsBusy\n"); return false; } REALIGN STDCALL BOOL grSstQueryHardware(GrHwConfiguration *hwconfig) @@ -771,20 +1049,22 @@ REALIGN STDCALL BOOL grSstQueryHardware(GrHwConfiguration *hwconfig) } REALIGN STDCALL void grSstSelect(int which_sst) { -// printf("grSstSelect: %d\n", which_sst); +// fprintf(stderr, "grSstSelect: %d\n", which_sst); } REALIGN STDCALL uint32_t grSstStatus(void) { -// printf("grSstStatus\n"); +// fprintf(stderr, "grSstStatus\n"); return 0x0FFFF03F; } REALIGN STDCALL void grSstWinClose(void) { -// printf("grSstWinClose\n"); +// fprintf(stderr, "grSstWinClose\n"); } REALIGN STDCALL BOOL grSstWinOpen(uint32_t hWnd, GrScreenResolution_t screen_resolution, GrScreenRefresh_t refresh_rate, GrColorFormat_t color_format, GrOriginLocation_t origin_location, int nColBuffers, int nAuxBuffers) { createContext(); + createFrameBuffer(); + useGameProgram(true); handleDpr(); @@ -813,37 +1093,63 @@ REALIGN STDCALL void grTexClampMode(GrChipID_t tmu, GrTextureClampMode_t s_clamp } REALIGN STDCALL void grTexCombine(GrChipID_t tmu, GrCombineFunction_t rgb_function, GrCombineFactor_t rgb_factor, GrCombineFunction_t alpha_function, GrCombineFactor_t alpha_factor, BOOL rgb_invert, BOOL alpha_invert) { -// printf("grTexCombine\n"); +// fprintf(stderr, "grTexCombine\n"); } REALIGN STDCALL void grTexCombineFunction(GrChipID_t tmu, GrTextureCombineFnc_t fnc) { -// printf("grTexCombineFunction\n"); +// fprintf(stderr, "grTexCombineFunction\n"); } REALIGN STDCALL void grTexDownloadMipMap(GrChipID_t tmu, uint32_t startAddress, uint32_t evenOdd, GrTexInfo *info) { - TextureInfo *ti = &textures[startAddress >> 2]; - ti->data = &textureMem[startAddress]; + TextureInfo *ti = &g_textures[startAddress >> 2]; + ti->data = &g_textureMem[startAddress]; ti->palette = NULL; ti->fmt = info->format; ti->size = 256 >> info->largeLod; - memcpy(ti->data, info->data, ti->size * ti->size * (ti->fmt == GR_TEXFMT_P_8 ? 1 : 2)); + uint16_t *dataIn = (uint16_t *)info->data; + uint16_t *dataOut = (uint16_t *)ti->data; drawTriangles(); + // ARGB -> RGBA conversion or copy + uint32_t sqrSize = ti->size * ti->size, i; + switch (ti->fmt) + { + case GR_TEXFMT_ARGB_1555: + { + for (i = 0; i < sqrSize; ++i) + { + uint16_t value = dataIn[i]; + dataOut[i] = (value << 1) | (value >> 15); + } + break; + } + case GR_TEXFMT_ARGB_4444: + for (i = 0; i < sqrSize; ++i) + { + uint16_t value = dataIn[i]; + dataOut[i] = (value << 4) | (value >> 12); + } + break; + default: + memcpy(dataOut, dataIn, ti->size * ti->size * (ti->fmt == GR_TEXFMT_P_8 ? 1 : 2)); + break; + } + uploadTexture(ti); -// printf("grTexDownloadMipMap: 0x%.8X %d\n", startAddress, maxTexIdx); +// fprintf(stderr, "grTexDownloadMipMap: 0x%.8X %d\n", startAddress, maxTexIdx); } REALIGN STDCALL void grTexDownloadTable(GrChipID_t tmu, GrTexTable_t type, void *data) { if (type == GR_TEXTABLE_PALETTE) - palette = (uint32_t *)data; + g_palette = (uint32_t *)data; } REALIGN STDCALL void grTexFilterMode(GrChipID_t tmu, GrTextureFilterMode_t minfilter_mode, GrTextureFilterMode_t magfilter_mode) { /* Always linear */ -// printf("grTexFilterMode: %d\n", minfilter_mode); +// fprintf(stderr, "grTexFilterMode: %d\n", minfilter_mode); } REALIGN STDCALL uint32_t grTexMaxAddress(GrChipID_t tmu) { @@ -859,10 +1165,10 @@ REALIGN STDCALL void grTexMipMapMode(GrChipID_t tmu, GrMipMapMode_t mode, BOOL l } REALIGN STDCALL void grTexSource(GrChipID_t tmu, uint32_t startAddress, uint32_t evenOdd, GrTexInfo *info) { - TextureInfo *ti = &textures[startAddress >> 2]; + TextureInfo *ti = &g_textures[startAddress >> 2]; drawTriangles(); glBindTexture(GL_TEXTURE_2D, ti->id); - if (info->format == GR_TEXFMT_P_8 && palette && ti->palette != palette) + if (info->format == GR_TEXFMT_P_8 && g_palette && ti->palette != g_palette) { // Update only when palette or texture changes (let's assume every palette has different pointer) // When texture changes, palette is NULL @@ -870,8 +1176,11 @@ REALIGN STDCALL void grTexSource(GrChipID_t tmu, uint32_t startAddress, uint32_t uint32_t size = 256 >> info->largeLod; uint32_t sqrSize = size * size, i; for (i = 0; i < sqrSize; ++i) - tmpTexture[i] = palette[data[i]]; - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, GL_RGBA, GL_UNSIGNED_BYTE, tmpTexture); - ti->palette = palette; + { + uint32_t value = g_palette[data[i]]; + g_tmpTexture[i] = ((value >> 16) & 0x000000FF) | ((value << 16) & 0x00FF0000) | (value & 0xFF00FF00); + } + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size, size, GL_RGBA, GL_UNSIGNED_BYTE, g_tmpTexture); + ti->palette = g_palette; } } diff --git a/src/Wrapper.c b/src/Wrapper.c index 0535a61..945110c 100644 --- a/src/Wrapper.c +++ b/src/Wrapper.c @@ -204,15 +204,29 @@ static void signal_handler(int sig) return; } + extern BOOL contextError; #ifndef OPENGL1X extern BOOL shaderError; - if (sig == SIGABRT && shaderError) + extern BOOL framebufferError; +#endif // OPENGL1X + if (contextError) { SDL_SetWindowFullscreen(sdlWin, SDL_FALSE); - SDL_ShowSimpleMessageBox(0, "GLSL error", "Error loading shaders, see console output!", NULL); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "OpenGL", "Can't create context!", NULL); + } +#ifndef OPENGL1X + else if (shaderError) + { + SDL_SetWindowFullscreen(sdlWin, SDL_FALSE); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "OpenGL", "Error loading shaders, see console output!", NULL); + } + else if (framebufferError) + { + SDL_SetWindowFullscreen(sdlWin, SDL_FALSE); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "OpenGL", "Can't create framebuffer!", NULL); } - else #endif // OPENGL1X + else { fprintf(stderr, "Application closed with a signal: %d\n", sig); fflush(stderr); @@ -226,14 +240,18 @@ static void signal_handler(int sig) static BOOL startInFullScreen = true; int32_t joystickAxes[2][12] = {{0, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0}, {0, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0}}; -int32_t winWidth = 640, winHeight = 480, joystickAxisValueShift[2] = {0}, vSync = 1; -int32_t joystick0EscButton = -1, joystick0ResetButton = -1; +int32_t initialWinWidth = 640, initialWinHeight = 480, winWidth, winHeight, vSync = 1; +int32_t joystickAxisValueShift[2] = {0}, joystick0EscButton = -1, joystick0ResetButton = -1; BOOL useSpringForceFeedbackEffect = false; BOOL useHapticPolar = false; int32_t forceFeedbackDevice = -1; BOOL linearSoundInterpolation = false, useGlBleginGlEnd = false, keepAspectRatio = true, linearFiltering = true; uint32_t fullScreenFlag = SDL_WINDOW_FULLSCREEN_DESKTOP, broadcast = 0xFFFFFFFF; uint16_t PORT1 = 1030, PORT2 = 1029; +#ifndef OPENGL1X +BOOL fixedFramebufferSize = false; +BOOL framebufferLinearFiltering = true; +#endif int32_t ignoreJoyIdx = -1; @@ -281,7 +299,9 @@ void WrapperInit(void) initializeSDL2(); #endif +#ifdef OPENGL1X uint32_t msaa = 0; +#endif FILE *f = NULL; int i; @@ -419,19 +439,30 @@ void WrapperInit(void) startInFullScreen = !!atoi(line + 18); else if (!strncasecmp("VSync=", line, 6)) vSync = atoi(line + 6); +#ifdef OPENGL1X else if (!strncasecmp("MSAA=", line, 5)) { msaa = atoi(line + 5); if (msaa > 16 || (msaa & (msaa - 1))) msaa = 0; } - else if (!strncasecmp("UseWindowSizeForFullScreen=", line, 27)) +#endif + else if (!strncasecmp("FixedRenderingSize=", line, 19)) { - if (atoi(line + 27)) + int val = atoi(line + 19); + if (val == 1 || val == 2) + { +#ifdef OPENGL1X fullScreenFlag = SDL_WINDOW_FULLSCREEN; +#else + fixedFramebufferSize = true; + if (val == 2) + framebufferLinearFiltering = false; +#endif + } } else if (!strncasecmp("WindowSize=", line, 11)) - sscanf(line + 11, "%dx%d", &winWidth, &winHeight); + sscanf(line + 11, "%dx%d", &initialWinWidth, &initialWinHeight); else if (!strncasecmp("KeepAspectRatio=", line, 16)) sscanf(line + 16, "%d", &keepAspectRatio); else if (!strncasecmp("LinearTextureFiltering=", line, 23)) @@ -524,12 +555,13 @@ void WrapperInit(void) # endif SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); -#endif +#else if (msaa) { SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, msaa == 1 ? 0 : 1); SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, msaa); } +#endif #ifndef WIN32 for (i = 0; i < 4; ++i) { @@ -612,17 +644,20 @@ REALIGN STDCALL SDL_Window *WrapperCreateWindow(WindowProc windowProc) checkGameDirs(); - const int windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | (startInFullScreen ? fullScreenFlag : 0) | SDL_WINDOW_ALLOW_HIGHDPI; - sdlWin = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, winWidth, winHeight, windowFlags); + int windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_ALLOW_HIGHDPI | (startInFullScreen ? fullScreenFlag : 0); + if (fullScreenFlag == SDL_WINDOW_FULLSCREEN_DESKTOP) + windowFlags |= SDL_WINDOW_RESIZABLE; + sdlWin = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, initialWinWidth, initialWinHeight, windowFlags); if (!sdlWin) { + const char errorText[] = "Cannot create window: %s\nCheck the OpenGL drivers and the game settings!"; const char *error = SDL_GetError(); - int bufferSize = strlen(error) + 71; + size_t bufferSize = strlen(error) + sizeof(errorText) - 2; char *buffer = (char *)malloc(bufferSize); - snprintf(buffer, bufferSize, "Cannot create window: %s\nCheck the OpenGL drivers and the game settings!", error); + snprintf(buffer, bufferSize, errorText, error); SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title, buffer, NULL); free(buffer); - exit(0); + exit(-1); } SDL_GetWindowSize(sdlWin, &winWidth, &winHeight);