#include "StdInc.h" #include #include #include "SDL_syswm.h" #include #include "GL2D.h" namespace GL2D { // Variables initialized by initVideo, updated by setScreenRes: static SDL_SysWMinfo wmInfo; ui32 screenWidth = 0, screenHeight = 0; // Screen/Window size // OpenGL 1.3 functions pointers PFNGLACTIVETEXTUREPROC glActiveTexture; // OpenGL 2.0 functions pointers PFNGLCREATEPROGRAMPROC glCreateProgram; PFNGLCREATESHADERPROC glCreateShader; PFNGLSHADERSOURCEPROC glShaderSource; PFNGLCOMPILESHADERPROC glCompileShader; PFNGLATTACHSHADERPROC glAttachShader; PFNGLLINKPROGRAMPROC glLinkProgram; PFNGLUSEPROGRAMPROC glUseProgram; PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; PFNGLUNIFORM1IPROC glUniform1i; PFNGLUNIFORM2IPROC glUniform2i; PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; // Shaders' sources static const char frag_palette_bitmap[] = ( "uniform usampler2DRect bitmap;" "uniform sampler1D palette;" "uniform ivec2 coordOffs;" "layout (origin_upper_left) in vec4 gl_FragCoord;" "void main(){" "gl_FragColor = texelFetch(palette, int(texelFetch(bitmap, ivec2(gl_FragCoord.xy) - coordOffs).r), 0);" "}" ); // Programs' handlers static GLuint currentProgram = 0; static GLuint colorizeProgram = 0; static GLuint paletteBitmapProgram = 0; // Uniforms handlers static GLint coord_uniform = -1; // Print out the information log for a shader object void printInfoLog(PFNGLGETPROGRAMINFOLOGPROC logFunc, GLuint object) { if (logFunc != nullptr) { GLsizei infoLogLength = 0; GLchar infoLog[1024]; logFunc(object, sizeof(infoLog)-1, &infoLogLength, infoLog); if (infoLogLength > 0) tlog1 << infoLog; } } GLuint makeShaderProgram(const char * frg_src) { // Creating a fragment shader object GLuint shader_object = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(shader_object, 1, &frg_src, nullptr); // assigning the shader source // Compiling the shader glCompileShader(shader_object); printInfoLog(glGetShaderInfoLog, shader_object); // Creating a program object GLuint program_object = glCreateProgram(); // Attaching the shader into program glAttachShader(program_object, shader_object); // Link the shaders into a complete GLSL program. glLinkProgram(program_object); printInfoLog(glGetProgramInfoLog, program_object); return program_object; } void initVideo(ui32 w, ui32 h, bool fullscreen) { SDL_VERSION(&wmInfo.version); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); if (!setScreenRes(w, h, fullscreen)) { throw std::runtime_error("Video mode setting failed\n"); } glClearColor(0, 0, 0, 0); // Black Background glClear(GL_COLOR_BUFFER_BIT); SDL_GL_SwapBuffers(); // Dynamic-linked OpenGL 1.3 and 2.0 functions - required to 2D rendeing if ( (glActiveTexture = (PFNGLACTIVETEXTUREPROC) SDL_GL_GetProcAddress("glActiveTexture")) == nullptr || (glCreateProgram = (PFNGLCREATEPROGRAMPROC) SDL_GL_GetProcAddress("glCreateProgram")) == nullptr || (glCreateShader = (PFNGLCREATESHADERPROC) SDL_GL_GetProcAddress("glCreateShader")) == nullptr || (glShaderSource = (PFNGLSHADERSOURCEPROC) SDL_GL_GetProcAddress("glShaderSource")) == nullptr || (glCompileShader = (PFNGLCOMPILESHADERPROC) SDL_GL_GetProcAddress("glCompileShader")) == nullptr || (glAttachShader = (PFNGLATTACHSHADERPROC) SDL_GL_GetProcAddress("glAttachShader")) == nullptr || (glLinkProgram = (PFNGLLINKPROGRAMPROC) SDL_GL_GetProcAddress("glLinkProgram")) == nullptr || (glUseProgram = (PFNGLUSEPROGRAMPROC) SDL_GL_GetProcAddress("glUseProgram")) == nullptr || (glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) SDL_GL_GetProcAddress("glGetUniformLocation")) == nullptr || (glUniform1i = (PFNGLUNIFORM1IPROC) SDL_GL_GetProcAddress("glUniform1i")) == nullptr || (glUniform2i = (PFNGLUNIFORM2IPROC) SDL_GL_GetProcAddress("glUniform2i")) == nullptr ) { tlog1 << "Error: OpenGL2 Extenstions are not available\n"; tlog1 << "SDL says: " << SDL_GetError() << std::endl; throw std::runtime_error("OpenGL2 Extenstions are not available\n"); } glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) SDL_GL_GetProcAddress("glGetProgramInfoLog"); // not required glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) SDL_GL_GetProcAddress("glGetShaderInfoLog"); // not required glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); glDisable(GL_DITHER); glDisable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_RECTANGLE); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); paletteBitmapProgram = makeShaderProgram(frag_palette_bitmap); GLint bitmap_uniform = glGetUniformLocation(paletteBitmapProgram, "bitmap"); GLint palette_uniform = glGetUniformLocation(paletteBitmapProgram, "palette"); coord_uniform = glGetUniformLocation(paletteBitmapProgram, "coordOffs"); glUseProgram(currentProgram = paletteBitmapProgram); glUniform1i(bitmap_uniform, 0); glUniform1i(palette_uniform, 1); #ifdef _WIN32 wglMakeCurrent(NULL, NULL); #endif } void attachToCurrentThread() { #ifdef _WIN32 HDC hdc = GetDC(wmInfo.window); wglMakeCurrent(hdc, wmInfo.hglrc); #endif } bool setScreenRes(ui32 w, ui32 h, bool fullscreen) { // Try to use the best screen depth for the display int suggestedBpp = SDL_VideoModeOK(w, h, 32, SDL_OPENGL | SDL_ANYFORMAT | (fullscreen?SDL_FULLSCREEN:0)); if(suggestedBpp == 0) { tlog1 << "Error: SDL says that " << w << "x" << h << " resolution is not available!\n"; return false; } if(suggestedBpp != 32) { tlog2 << "Note: SDL suggests to use " << suggestedBpp << " bpp instead of 32 bpp\n"; } if(SDL_SetVideoMode(w, h, suggestedBpp, SDL_OPENGL | SDL_ANYFORMAT | (fullscreen?SDL_FULLSCREEN:0)) == NULL) { tlog1 << "Error: Video mode setting failed (" << w << "x" << h << "x" << suggestedBpp << "bpp)\n"; return false; } screenWidth = w; screenHeight = h; int getwm = SDL_GetWMInfo(&wmInfo); if(getwm != 1) { tlog2 << "Something went wrong, getwm=" << getwm << std::endl; tlog2 << "SDL says: " << SDL_GetError() << std::endl; return false; } glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); // Select The Projection Matrix glLoadIdentity(); // Reset The Projection Matrix glOrtho(0, w, h, 0, 0, 1); glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix glLoadIdentity(); // Reset The Modelview Matrix glTranslatef(0.375, 0.375, 0); // Displacement trick for exact pixelization return true; } void assignTexture(ui32 slot, ui32 type, ui32 handle) { glActiveTexture(slot); glBindTexture(type, handle); } void useNoShader() { if (currentProgram != 0) { glUseProgram(currentProgram = 0); } } void useColorizeShader(const float cm[4][4]) { if (currentProgram != colorizeProgram) { glUseProgram(currentProgram = colorizeProgram); } } void usePaletteBitmapShader(si32 x, si32 y) { if (currentProgram != paletteBitmapProgram) { glUseProgram(currentProgram = paletteBitmapProgram); } glUniform2i(coord_uniform, x, y); } void usePaletteBitmapShader(si32 x, si32 y, const float cm[4][4]) { if (currentProgram != paletteBitmapProgram) { glUseProgram(currentProgram = paletteBitmapProgram); } glUniform2i(coord_uniform, x, y); } }