From b053bc377e953db70f76d744a280e05ae3bbbf67 Mon Sep 17 00:00:00 2001 From: FunkyFr3sh Date: Wed, 9 May 2018 05:09:57 +0200 Subject: [PATCH] OpenGL: add 8bit palette conversion shader for better performance - remove pixel buffer objects - temporary remove scaling filters (need to be replaced with shaders) --- Makefile | 3 +- cnc-ddraw.vcxproj | 2 + cnc-ddraw.vcxproj.filters | 29 ++-- inc/main.h | 2 - inc/opengl.h | 64 ++++++++ src/main.c | 24 --- src/opengl.c | 196 +++++++++++++++++++++++ src/render.c | 325 +++++++++++++++++--------------------- 8 files changed, 425 insertions(+), 220 deletions(-) create mode 100644 inc/opengl.h create mode 100644 src/opengl.c diff --git a/Makefile b/Makefile index 2a0a627..5236281 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,8 @@ FILES = src/debug.c \ src/render.c \ src/render_soft.c \ src/render_dummy.c \ - src/screenshot.c + src/screenshot.c \ + src/opengl.c all: $(WINDRES) -J rc ddraw.rc ddraw.rc.o diff --git a/cnc-ddraw.vcxproj b/cnc-ddraw.vcxproj index 046fc0f..f2a42e5 100644 --- a/cnc-ddraw.vcxproj +++ b/cnc-ddraw.vcxproj @@ -15,6 +15,7 @@ + @@ -28,6 +29,7 @@ + diff --git a/cnc-ddraw.vcxproj.filters b/cnc-ddraw.vcxproj.filters index 25cedeb..f336d63 100644 --- a/cnc-ddraw.vcxproj.filters +++ b/cnc-ddraw.vcxproj.filters @@ -45,36 +45,45 @@ Source Files + + Source Files + - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + Header Files - + + Header Files + + + Header Files + + Header Files diff --git a/inc/main.h b/inc/main.h index 2f1e5d4..8b7aadb 100644 --- a/inc/main.h +++ b/inc/main.h @@ -60,7 +60,6 @@ typedef struct IDirectDrawImpl int width; int height; int bpp; - int filter; HDC hDC; int *tex; @@ -87,7 +86,6 @@ typedef struct IDirectDrawImpl BOOL incutscene; DWORD (WINAPI *renderer)(void); char screenshotKey; - BOOL opengl_pbo; BOOL fullscreen; BOOL maintas; BOOL fakecursorpos; diff --git a/inc/opengl.h b/inc/opengl.h new file mode 100644 index 0000000..806f53c --- /dev/null +++ b/inc/opengl.h @@ -0,0 +1,64 @@ +#pragma once +#include +#include +#include "glext.h" + +void OpenGL_Init(); +BOOL OpenGL_ExtExists(char *ext); +GLuint OpenGL_BuildProgram(const GLchar **vertSource, const GLchar **fragSource); + +// Program +extern PFNGLCREATEPROGRAMPROC glCreateProgram; +extern PFNGLDELETEPROGRAMPROC glDeleteProgram; +extern PFNGLUSEPROGRAMPROC glUseProgram; +extern PFNGLATTACHSHADERPROC glAttachShader; +extern PFNGLDETACHSHADERPROC glDetachShader; +extern PFNGLLINKPROGRAMPROC glLinkProgram; +extern PFNGLGETPROGRAMIVPROC glGetProgramiv; +extern PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; +extern PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; +extern PFNGLUNIFORM1IPROC glUniform1i; +extern PFNGLUNIFORM1IVPROC glUniform1iv; +extern PFNGLUNIFORM2IVPROC glUniform2iv; +extern PFNGLUNIFORM3IVPROC glUniform3iv; +extern PFNGLUNIFORM4IVPROC glUniform4iv; +extern PFNGLUNIFORM1FPROC glUniform1f; +extern PFNGLUNIFORM1FVPROC glUniform1fv; +extern PFNGLUNIFORM2FVPROC glUniform2fv; +extern PFNGLUNIFORM3FVPROC glUniform3fv; +extern PFNGLUNIFORM4FVPROC glUniform4fv; +extern PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv; +extern PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation; +extern PFNGLVERTEXATTRIB1FPROC glVertexAttrib1f; +extern PFNGLVERTEXATTRIB1FVPROC glVertexAttrib1fv; +extern PFNGLVERTEXATTRIB2FVPROC glVertexAttrib2fv; +extern PFNGLVERTEXATTRIB3FVPROC glVertexAttrib3fv; +extern PFNGLVERTEXATTRIB4FVPROC glVertexAttrib4fv; +extern PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; +extern PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray; +extern PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation; +extern PFNGLGETACTIVEUNIFORMPROC glGetActiveUniform; + +// Shader +extern PFNGLCREATESHADERPROC glCreateShader; +extern PFNGLDELETESHADERPROC glDeleteShader; +extern PFNGLSHADERSOURCEPROC glShaderSource; +extern PFNGLCOMPILESHADERPROC glCompileShader; +extern PFNGLGETSHADERIVPROC glGetShaderiv; + +// VBO +extern PFNGLGENBUFFERSPROC glGenBuffers; +extern PFNGLBINDBUFFERPROC glBindBuffer; +extern PFNGLBUFFERDATAPROC glBufferData; +extern PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; + +extern PFNGLGENBUFFERSARBPROC glGenBuffersARB; +extern PFNGLBINDBUFFERARBPROC glBindBufferARB; +extern PFNGLBUFFERDATAARBPROC glBufferDataARB; +extern PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB; +extern PFNGLMAPBUFFERARBPROC glMapBufferARB; +extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB; + +extern PFNGLACTIVETEXTUREARBPROC glActiveTexture; +extern PFNGLCLIENTACTIVETEXTUREPROC glClientActiveTexture; +extern PFNGLMULTITEXCOORD2FPROC glMultiTexCoord2f; diff --git a/src/main.c b/src/main.c index aca576f..f1b65b6 100644 --- a/src/main.c +++ b/src/main.c @@ -973,8 +973,6 @@ HRESULT WINAPI DirectDrawCreate(GUID FAR* lpGUID, LPDIRECTDRAW FAR* lplpDD, IUnk "maxfps=0\n" "; vertical synchronization, enable if you get tearing (OpenGL only)\n" "vsync=false\n" - "; scaling filter, nearest = sharp, linear = smooth (OpenGL only)\n" - "filter=nearest\n" "; automatic mouse sensitivity scaling\n" "adjmouse=false\n" "; enable C&C video resize hack, auto = auto-detect game, true = forced, false = disabled\n" @@ -988,8 +986,6 @@ HRESULT WINAPI DirectDrawCreate(GUID FAR* lpGUID, LPDIRECTDRAW FAR* lplpDD, IUnk "posY=-1\n" "; Screenshot Hotkey, default = CTRL + G\n" "screenshotKey=G\n" - "; Use Pixel Buffer Objects (OpenGL only)\n" - "opengl_pbo=false\n" "; Fake cursor position for games that use GetCursorPos and expect to be in fullscreen\n" "fakecursorpos=true\n" "; Hide WM_ACTIVATEAPP messages to prevent freezing on alt+tab (Carmageddon)\n" @@ -1000,16 +996,6 @@ HRESULT WINAPI DirectDrawCreate(GUID FAR* lpGUID, LPDIRECTDRAW FAR* lplpDD, IUnk , fh); fclose(fh); } - - GetPrivateProfileStringA("ddraw", "opengl_pbo", "FALSE", tmp, sizeof(tmp), SettingsIniPath); - if (tolower(tmp[0]) == 'n' || tolower(tmp[0]) == 'f' || tolower(tmp[0]) == 'd' || tmp[0] == '0') - { - This->opengl_pbo = FALSE; - } - else - { - This->opengl_pbo = TRUE; - } GetPrivateProfileStringA("ddraw", "windowed", "FALSE", tmp, sizeof(tmp), SettingsIniPath); if (tolower(tmp[0]) == 'n' || tolower(tmp[0]) == 'f' || tolower(tmp[0]) == 'd' || tmp[0] == '0') @@ -1078,16 +1064,6 @@ HRESULT WINAPI DirectDrawCreate(GUID FAR* lpGUID, LPDIRECTDRAW FAR* lplpDD, IUnk This->render.bpp = 0; } - GetPrivateProfileStringA("ddraw", "filter", tmp, tmp, sizeof(tmp), SettingsIniPath); - if (tolower(tmp[0]) == 'l' || tolower(tmp[3]) == 'l') - { - This->render.filter = 1; - } - else - { - This->render.filter = 0; - } - GetPrivateProfileStringA("ddraw", "adjmouse", "FALSE", tmp, sizeof(tmp), SettingsIniPath); if (tolower(tmp[0]) == 'y' || tolower(tmp[0]) == 't' || tolower(tmp[0]) == 'e' || tmp[0] == '1') { diff --git a/src/opengl.c b/src/opengl.c new file mode 100644 index 0000000..401db73 --- /dev/null +++ b/src/opengl.c @@ -0,0 +1,196 @@ +#include +#include +#include "opengl.h" + + +// Program +PFNGLCREATEPROGRAMPROC glCreateProgram = NULL; +PFNGLDELETEPROGRAMPROC glDeleteProgram = NULL; +PFNGLUSEPROGRAMPROC glUseProgram = NULL; +PFNGLATTACHSHADERPROC glAttachShader = NULL; +PFNGLDETACHSHADERPROC glDetachShader = NULL; +PFNGLLINKPROGRAMPROC glLinkProgram = NULL; +PFNGLGETPROGRAMIVPROC glGetProgramiv = NULL; +PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog = NULL; +PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = NULL; +PFNGLUNIFORM1IPROC glUniform1i = NULL; +PFNGLUNIFORM1IVPROC glUniform1iv = NULL; +PFNGLUNIFORM2IVPROC glUniform2iv = NULL; +PFNGLUNIFORM3IVPROC glUniform3iv = NULL; +PFNGLUNIFORM4IVPROC glUniform4iv = NULL; +PFNGLUNIFORM1FPROC glUniform1f = NULL; +PFNGLUNIFORM1FVPROC glUniform1fv = NULL; +PFNGLUNIFORM2FVPROC glUniform2fv = NULL; +PFNGLUNIFORM3FVPROC glUniform3fv = NULL; +PFNGLUNIFORM4FVPROC glUniform4fv = NULL; +PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv = NULL; +PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation = NULL; +PFNGLVERTEXATTRIB1FPROC glVertexAttrib1f = NULL; +PFNGLVERTEXATTRIB1FVPROC glVertexAttrib1fv = NULL; +PFNGLVERTEXATTRIB2FVPROC glVertexAttrib2fv = NULL; +PFNGLVERTEXATTRIB3FVPROC glVertexAttrib3fv = NULL; +PFNGLVERTEXATTRIB4FVPROC glVertexAttrib4fv = NULL; +PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = NULL; +PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray = NULL; +PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation = NULL; +PFNGLGETACTIVEUNIFORMPROC glGetActiveUniform = NULL; + +// Shader +PFNGLCREATESHADERPROC glCreateShader = NULL; +PFNGLDELETESHADERPROC glDeleteShader = NULL; +PFNGLSHADERSOURCEPROC glShaderSource = NULL; +PFNGLCOMPILESHADERPROC glCompileShader = NULL; +PFNGLGETSHADERIVPROC glGetShaderiv = NULL; + +// VBO +PFNGLGENBUFFERSPROC glGenBuffers = NULL; +PFNGLBINDBUFFERPROC glBindBuffer = NULL; +PFNGLBUFFERDATAPROC glBufferData = NULL; +PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = NULL; + +PFNGLGENBUFFERSARBPROC glGenBuffersARB = NULL; +PFNGLBINDBUFFERARBPROC glBindBufferARB = NULL; +PFNGLBUFFERDATAARBPROC glBufferDataARB = NULL; +PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB = NULL; +PFNGLMAPBUFFERARBPROC glMapBufferARB = NULL; +PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB = NULL; + +PFNGLACTIVETEXTUREARBPROC glActiveTexture = NULL; +PFNGLCLIENTACTIVETEXTUREPROC glClientActiveTexture = NULL; +PFNGLMULTITEXCOORD2FPROC glMultiTexCoord2f = NULL; + +void OpenGL_Init() +{ + // Program + glCreateProgram = (PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram"); + glDeleteProgram = (PFNGLDELETEPROGRAMPROC)wglGetProcAddress("glDeleteProgram"); + glUseProgram = (PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram"); + glAttachShader = (PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader"); + glDetachShader = (PFNGLDETACHSHADERPROC)wglGetProcAddress("glDetachShader"); + glLinkProgram = (PFNGLLINKPROGRAMPROC)wglGetProcAddress("glLinkProgram"); + glGetProgramiv = (PFNGLGETPROGRAMIVPROC)wglGetProcAddress("glGetProgramiv"); + glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)wglGetProcAddress("glGetShaderInfoLog"); + glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)wglGetProcAddress("glGetUniformLocation"); + glUniform1i = (PFNGLUNIFORM1IPROC)wglGetProcAddress("glUniform1i"); + glUniform1iv = (PFNGLUNIFORM1IVPROC)wglGetProcAddress("glUniform1iv"); + glUniform2iv = (PFNGLUNIFORM2IVPROC)wglGetProcAddress("glUniform2iv"); + glUniform3iv = (PFNGLUNIFORM3IVPROC)wglGetProcAddress("glUniform3iv"); + glUniform4iv = (PFNGLUNIFORM4IVPROC)wglGetProcAddress("glUniform4iv"); + glUniform1f = (PFNGLUNIFORM1FPROC)wglGetProcAddress("glUniform1f"); + glUniform1fv = (PFNGLUNIFORM1FVPROC)wglGetProcAddress("glUniform1fv"); + glUniform2fv = (PFNGLUNIFORM2FVPROC)wglGetProcAddress("glUniform2fv"); + glUniform3fv = (PFNGLUNIFORM3FVPROC)wglGetProcAddress("glUniform3fv"); + glUniform4fv = (PFNGLUNIFORM4FVPROC)wglGetProcAddress("glUniform4fv"); + glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)wglGetProcAddress("glUniformMatrix4fv"); + glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)wglGetProcAddress("glGetAttribLocation"); + glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC)wglGetProcAddress("glVertexAttrib1f"); + glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC)wglGetProcAddress("glVertexAttrib1fv"); + glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC)wglGetProcAddress("glVertexAttrib2fv"); + glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC)wglGetProcAddress("glVertexAttrib3fv"); + glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)wglGetProcAddress("glVertexAttrib4fv"); + glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glEnableVertexAttribArray"); + glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)wglGetProcAddress("glBindAttribLocation"); + + // Shader + glCreateShader = (PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader"); + glDeleteShader = (PFNGLDELETESHADERPROC)wglGetProcAddress("glDeleteShader"); + glShaderSource = (PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource"); + glCompileShader = (PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader"); + glGetShaderiv = (PFNGLGETSHADERIVPROC)wglGetProcAddress("glGetShaderiv"); + + // VBO + glGenBuffers = (PFNGLGENBUFFERSPROC)wglGetProcAddress("glGenBuffers"); + glBindBuffer = (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer"); + glBufferData = (PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData"); + glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)wglGetProcAddress("glVertexAttribPointer"); + + glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffersARB"); + glBindBufferARB = (PFNGLBINDBUFFERARBPROC)wglGetProcAddress("glBindBufferARB"); + glBufferDataARB = (PFNGLBUFFERDATAARBPROC)wglGetProcAddress("glBufferDataARB"); + glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)wglGetProcAddress("glDeleteBuffersARB"); + glMapBufferARB = (PFNGLMAPBUFFERARBPROC)wglGetProcAddress("glMapBufferARB"); + glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)wglGetProcAddress("glUnmapBufferARB"); + + glActiveTexture = (PFNGLACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTexture"); + glClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC)wglGetProcAddress("glClientActiveTexture"); + glMultiTexCoord2f = (PFNGLMULTITEXCOORD2FPROC)wglGetProcAddress("glMultiTexCoord2f"); +} + +BOOL OpenGL_ExtExists(char *ext) +{ + char *glext = (char *)glGetString(GL_EXTENSIONS); + if (glext) + { + if (strstr(glext, ext)) + return TRUE; + } + return FALSE; +} + +GLuint OpenGL_BuildProgram(const GLchar **vertSource, const GLchar **fragSource) +{ + if (!glCreateShader || !glShaderSource || !glCompileShader || !glCreateProgram || + !glAttachShader || !glLinkProgram || !glUseProgram) + return 0; + + GLuint vertShader = glCreateShader(GL_VERTEX_SHADER); + GLuint fragShader = glCreateShader(GL_FRAGMENT_SHADER); + + if (!vertShader || !fragShader) + return 0; + + glShaderSource(vertShader, 1, vertSource, NULL); + glShaderSource(fragShader, 1, fragSource, NULL); + + GLint isCompiled = 0; + + glCompileShader(vertShader); + if (glGetShaderiv) + { + glGetShaderiv(vertShader, GL_COMPILE_STATUS, &isCompiled); + if (isCompiled == GL_FALSE) + { + if (glDeleteShader) + glDeleteShader(vertShader); + + return 0; + } + } + + glCompileShader(fragShader); + if (glGetShaderiv) + { + glGetShaderiv(fragShader, GL_COMPILE_STATUS, &isCompiled); + if (isCompiled == GL_FALSE) + { + if (glDeleteShader) + glDeleteShader(fragShader); + + return 0; + } + } + + GLuint program = glCreateProgram(); + if (program) + { + glAttachShader(program, vertShader); + glAttachShader(program, fragShader); + + glLinkProgram(program); + + if (glGetProgramiv) + { + GLint isLinked = 0; + glGetProgramiv(program, GL_LINK_STATUS, &isLinked); + if (isLinked == GL_FALSE) + { + if (glDeleteProgram) + glDeleteProgram(program); + + return 0; + } + } + } + + return program; +} diff --git a/src/render.c b/src/render.c index 773c22b..81648d0 100644 --- a/src/render.c +++ b/src/render.c @@ -1,101 +1,73 @@ /* - * Copyright (c) 2010 Toni Spets - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ +* Copyright (c) 2010 Toni Spets +* +* Permission to use, copy, modify, and distribute this software for any +* purpose with or without fee is hereby granted, provided that the above +* copyright notice and this permission notice appear in all copies. +* +* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ #include #include - -#define GL_GLEXT_PROTOTYPES -#include -#include -#include "glext.h" - +#include "opengl.h" #include "main.h" #include "surface.h" +const GLchar *PaletteVertShaderSrc = + "# version 110\n" + "varying vec2 TexCoord0; \n" + "\n" + "void main(void)\n" + "{\n" + " gl_Position = ftransform(); \n" + " TexCoord0 = gl_MultiTexCoord0.xy; \n" + "}\n"; -PFNGLGENBUFFERSARBPROC pglGenBuffersARB = 0; // VBO Name Generation Procedure -PFNGLBINDBUFFERARBPROC pglBindBufferARB = 0; // VBO Bind Procedure -PFNGLBUFFERDATAARBPROC pglBufferDataARB = 0; // VBO Data Loading Procedure -PFNGLDELETEBUFFERSARBPROC pglDeleteBuffersARB = 0; // VBO Deletion Procedure -PFNGLMAPBUFFERARBPROC pglMapBufferARB = 0; // map VBO procedure -PFNGLUNMAPBUFFERARBPROC pglUnmapBufferARB = 0; // unmap VBO procedure -#define glGenBuffersARB pglGenBuffersARB -#define glBindBufferARB pglBindBufferARB -#define glBufferDataARB pglBufferDataARB -#define glDeleteBuffersARB pglDeleteBuffersARB -#define glMapBufferARB pglMapBufferARB -#define glUnmapBufferARB pglUnmapBufferARB +const GLchar *PaletteFragShaderSrc = + "//Fragment shader\n" + "#version 110\n" + "uniform sampler2D PaletteTex; \n" + "uniform sampler2D SurfaceTex; \n" + "varying vec2 TexCoord0; \n" + "\n" + "void main()\n" + "{\n" + " vec4 myindex = texture2D(SurfaceTex, TexCoord0); \n" + " vec4 texel = texture2D(PaletteTex, myindex.xy); \n" + " gl_FragColor = texel;\n" + "}\n"; -const GLenum PIXEL_FORMAT = GL_RGBA; -GLuint pboIds[2]; -GLuint textureId; -BOOL pboSupported = FALSE; +GLuint SurfaceTexId, PaletteTexId; +GLint SurfaceUniLoc, PaletteUniLoc; +GLuint PaletteConvProgram; BOOL detect_cutscene(); DWORD WINAPI render_main(void) { - int i,j; - HGLRC hRC; + HGLRC hRC = wglCreateContext(ddraw->render.hDC); + wglMakeCurrent(ddraw->render.hDC, hRC); - int tex_width = ddraw->width > 1024 ? ddraw->width : 1024; - int tex_height = ddraw->height > 1024 ? ddraw->height : 1024; - int tex_size = tex_width * tex_height * sizeof(int); - float scale_w = 1.0f; - float scale_h = 1.0f; - int *tex = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, tex_size); + OpenGL_Init(); - hRC = wglCreateContext( ddraw->render.hDC ); - wglMakeCurrent( ddraw->render.hDC, hRC ); - - char *glext = (char *)glGetString(GL_EXTENSIONS); - - if(glext) + if (OpenGL_ExtExists("WGL_EXT_swap_control")) { - if (strstr(glext, "WGL_EXT_swap_control")) + BOOL(APIENTRY *wglSwapIntervalEXT)(int) = (BOOL(APIENTRY *)(int))wglGetProcAddress("wglSwapIntervalEXT"); + if (wglSwapIntervalEXT) { - BOOL (APIENTRY *wglSwapIntervalEXT)(int) = (BOOL (APIENTRY *)(int))wglGetProcAddress("wglSwapIntervalEXT"); - if(wglSwapIntervalEXT) - { - if(ddraw->vsync) - { - wglSwapIntervalEXT(1); - } - else - { - wglSwapIntervalEXT(0); - } - } - } - if (ddraw->opengl_pbo && strstr(glext, "GL_ARB_pixel_buffer_object")) - { - glGenBuffersARB = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffersARB"); - glBindBufferARB = (PFNGLBINDBUFFERARBPROC)wglGetProcAddress("glBindBufferARB"); - glBufferDataARB = (PFNGLBUFFERDATAARBPROC)wglGetProcAddress("glBufferDataARB"); - glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC)wglGetProcAddress("glDeleteBuffersARB"); - glMapBufferARB = (PFNGLMAPBUFFERARBPROC)wglGetProcAddress("glMapBufferARB"); - glUnmapBufferARB = (PFNGLUNMAPBUFFERARBPROC)wglGetProcAddress("glUnmapBufferARB"); - - if(glGenBuffersARB && glBindBufferARB && glBufferDataARB && - glMapBufferARB && glUnmapBufferARB && glDeleteBuffersARB) - { - pboSupported = TRUE; - } + if (ddraw->vsync) + wglSwapIntervalEXT(1); + else + wglSwapIntervalEXT(0); } } @@ -103,51 +75,56 @@ DWORD WINAPI render_main(void) DWORD tick_end = 0; DWORD frame_len = 0; - if(ddraw->render.maxfps < 0) - { + if (ddraw->render.maxfps < 0) ddraw->render.maxfps = ddraw->mode.dmDisplayFrequency; - } - if(ddraw->render.maxfps > 0) - { + if (ddraw->render.maxfps > 0) frame_len = 1000.0f / ddraw->render.maxfps; - } - glGenTextures(1, &textureId); - glBindTexture(GL_TEXTURE_2D, textureId); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_width, tex_height, 0, PIXEL_FORMAT, GL_UNSIGNED_BYTE, tex); + int tex_width = ddraw->width > 1024 ? ddraw->width : 1024; + int tex_height = ddraw->height > 1024 ? ddraw->height : 1024; + int tex_size = tex_width * tex_height * sizeof(int); + int *tex = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, tex_size); + + if (!PaletteConvProgram) + PaletteConvProgram = OpenGL_BuildProgram(&PaletteVertShaderSrc, &PaletteFragShaderSrc); + + // primary surface texture + glGenTextures(1, &SurfaceTexId); + glBindTexture(GL_TEXTURE_2D, SurfaceTexId); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + if (PaletteConvProgram) + glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, tex_width, tex_height, 0, GL_RED, GL_UNSIGNED_BYTE, 0); + else + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_width, tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex); + + // palette texture + glGenTextures(1, &PaletteTexId); + glBindTexture(GL_TEXTURE_2D, PaletteTexId); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 256, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glViewport( - ddraw->render.viewport.x, ddraw->render.viewport.y, + ddraw->render.viewport.x, ddraw->render.viewport.y, ddraw->render.viewport.width, ddraw->render.viewport.height); - - if(ddraw->render.filter) - { - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); - } - else - { - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); - } - + glBindTexture(GL_TEXTURE_2D, 0); - - if(pboSupported) + + if (PaletteConvProgram) { - glGenBuffersARB(2, pboIds); - glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pboIds[0]); - glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, tex_size, 0, GL_STREAM_DRAW_ARB); - glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pboIds[1]); - glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, tex_size, 0, GL_STREAM_DRAW_ARB); - glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0); + glUseProgram(PaletteConvProgram); + SurfaceUniLoc = glGetUniformLocation(PaletteConvProgram, "SurfaceTex"); + PaletteUniLoc = glGetUniformLocation(PaletteConvProgram, "PaletteTex"); } - + glEnable(GL_TEXTURE_2D); - - - while(ddraw->render.run && WaitForSingleObject(ddraw->render.sem, INFINITE) != WAIT_FAILED) + + while (ddraw->render.run && WaitForSingleObject(ddraw->render.sem, INFINITE) != WAIT_FAILED) { #if _DEBUG static DWORD tick_fps = 0; @@ -161,122 +138,104 @@ DWORD WINAPI render_main(void) } frame_count++; #endif - - static int index = 0; - scale_w = (float)ddraw->width/tex_width; - scale_h = (float)ddraw->height/tex_height; - - index = (index + 1) % 2; - int nextIndex = (index + 1) % 2; - - if(ddraw->render.maxfps > 0) - { + + float scale_w = (float)ddraw->width / tex_width; + float scale_h = (float)ddraw->height / tex_height; + + if (ddraw->render.maxfps > 0) tick_start = timeGetTime(); + + if (PaletteConvProgram && glActiveTexture && glUniform1i) + { + glActiveTexture(GL_TEXTURE0); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, PaletteTexId); + glUniform1i(PaletteUniLoc, 0); + + glActiveTexture(GL_TEXTURE1); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, SurfaceTexId); + glUniform1i(SurfaceUniLoc, 1); } - /* convert ddraw surface to opengl texture */ - - if(pboSupported) - { - glBindTexture(GL_TEXTURE_2D, textureId); - glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pboIds[index]); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ddraw->width, ddraw->height, PIXEL_FORMAT, GL_UNSIGNED_BYTE, 0); - } - EnterCriticalSection(&ddraw->cs); - if(ddraw->primary && ddraw->primary->palette) + if (ddraw->primary && ddraw->primary->palette) { - if(ddraw->vhack && detect_cutscene()) + if (ddraw->vhack && detect_cutscene()) { scale_w *= (float)CUTSCENE_WIDTH / ddraw->width; scale_h *= (float)CUTSCENE_HEIGHT / ddraw->height; if (!ddraw->incutscene) - { ddraw->incutscene = TRUE; - } } else { if (ddraw->incutscene) - { ddraw->incutscene = FALSE; - } } - if(pboSupported) + if (PaletteConvProgram) { - glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pboIds[nextIndex]); - - glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, tex_size, 0, GL_STREAM_DRAW_ARB); - int *ptr = (int *)glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB); - if(ptr) - { - for(i=0; iheight; i++) - { - for(j=0; jwidth; j++) - { - ptr[i*ddraw->width+j] = - ddraw->primary->palette->data_bgr[((unsigned char *)ddraw->primary->surface)[i*ddraw->primary->lPitch + j*ddraw->primary->lXPitch]]; - } - } - - glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB); - } - - glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0); + glBindTexture(GL_TEXTURE_2D, PaletteTexId); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 1, GL_RGBA, GL_UNSIGNED_BYTE, ddraw->primary->palette->data_bgr); + + glBindTexture(GL_TEXTURE_2D, SurfaceTexId); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ddraw->width, ddraw->height, GL_RED, GL_UNSIGNED_BYTE, ddraw->primary->surface); } else { - for(i=0; iheight; i++) + int i, j; + for (i = 0; iheight; i++) { - for(j=0; jwidth; j++) + int i_dst = i*ddraw->width; + int i_src = i*ddraw->primary->lPitch; + + for (j = 0; jwidth; j++) { - tex[i*ddraw->width+j] = - ddraw->primary->palette->data_bgr[((unsigned char *)ddraw->primary->surface)[i*ddraw->primary->lPitch + j*ddraw->primary->lXPitch]]; + tex[i_dst + j] = + ddraw->primary->palette->data_bgr[ + ((unsigned char *)ddraw->primary->surface)[i_src + j*ddraw->primary->lXPitch]]; } } + } } - + LeaveCriticalSection(&ddraw->cs); - if (!pboSupported) + if (!PaletteConvProgram) { - glBindTexture(GL_TEXTURE_2D, textureId); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ddraw->width, ddraw->height, PIXEL_FORMAT, GL_UNSIGNED_BYTE, tex); + glBindTexture(GL_TEXTURE_2D, SurfaceTexId); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ddraw->width, ddraw->height, GL_RGBA, GL_UNSIGNED_BYTE, tex); } glBegin(GL_TRIANGLE_FAN); - glTexCoord2f(0,0); glVertex2f(-1, 1); - glTexCoord2f(scale_w,0); glVertex2f( 1, 1); - glTexCoord2f(scale_w,scale_h); glVertex2f( 1, -1); - glTexCoord2f(0,scale_h); glVertex2f(-1, -1); + glTexCoord2f(0, 0); glVertex2f(-1, 1); + glTexCoord2f(scale_w, 0); glVertex2f(1, 1); + glTexCoord2f(scale_w, scale_h); glVertex2f(1, -1); + glTexCoord2f(0, scale_h); glVertex2f(-1, -1); glEnd(); - + glBindTexture(GL_TEXTURE_2D, 0); - + SwapBuffers(ddraw->render.hDC); - if(ddraw->render.maxfps > 0) - { + if (ddraw->render.maxfps > 0) + { tick_end = timeGetTime(); - - if(tick_end - tick_start < frame_len) - { - Sleep( frame_len - (tick_end - tick_start)); - } + + if (tick_end - tick_start < frame_len) + Sleep(frame_len - (tick_end - tick_start)); } - + SetEvent(ddraw->render.ev); } HeapFree(GetProcessHeap(), 0, tex); - glDeleteTextures(1, &textureId); - - if(pboSupported) - glDeleteBuffersARB(2, pboIds); + glDeleteTextures(1, &SurfaceTexId); + glDeleteTextures(1, &PaletteTexId); wglMakeCurrent(NULL, NULL); wglDeleteContext(hRC);