2
0

GL2D.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. #include "StdInc.h"
  2. #include <SDL.h>
  3. #include <SDL_video.h>
  4. #include <SDL_syswm.h>
  5. #include <SDL_opengl.h>
  6. #if __unix__
  7. # if !SDL_VIDEO_OPENGL_GLX
  8. # error SDL_VIDEO_OPENGL_GLX required
  9. # endif
  10. # include <GL/glx.h>
  11. # define _GLX 1
  12. #endif
  13. #include "GL2D.h"
  14. namespace GL2D
  15. {
  16. // Variables initialized by initVideo, updated by setScreenRes:
  17. static SDL_SysWMinfo wmInfo;
  18. #if _GLX
  19. static GLXContext glxCtx;
  20. #endif
  21. ui32 screenWidth = 0, screenHeight = 0; // Screen/Window size
  22. // OpenGL 1.3 functions pointers
  23. PFNGLACTIVETEXTUREPROC glActiveTexture;
  24. // OpenGL 2.0 functions pointers
  25. PFNGLCREATEPROGRAMPROC glCreateProgram;
  26. PFNGLCREATESHADERPROC glCreateShader;
  27. PFNGLDELETESHADERPROC glDeleteShader;
  28. PFNGLSHADERSOURCEPROC glShaderSource;
  29. PFNGLCOMPILESHADERPROC glCompileShader;
  30. PFNGLGETSHADERIVPROC glGetShaderiv;
  31. PFNGLATTACHSHADERPROC glAttachShader;
  32. PFNGLLINKPROGRAMPROC glLinkProgram;
  33. PFNGLGETPROGRAMIVPROC glGetProgramiv;
  34. PFNGLUSEPROGRAMPROC glUseProgram;
  35. PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
  36. PFNGLUNIFORM1IPROC glUniform1i;
  37. PFNGLUNIFORM2IPROC glUniform2i;
  38. PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
  39. PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
  40. // Shaders' sources
  41. static const char frag_palette_bitmap[] = (
  42. "#version 150\n"
  43. "uniform usampler2DRect bitmap;"
  44. "uniform sampler1D palette;"
  45. "uniform ivec2 coordOffs;"
  46. "layout (origin_upper_left) in vec4 gl_FragCoord;"
  47. "void main(){"
  48. "gl_FragColor = texelFetch(palette, int(texelFetch(bitmap, ivec2(gl_FragCoord.xy) - coordOffs).r), 0);"
  49. "}"
  50. );
  51. // Programs' handlers
  52. static GLuint currentProgram = 0;
  53. static GLuint colorizeProgram = 0;
  54. static GLuint paletteBitmapProgram = 0;
  55. // Uniforms handlers
  56. static GLint coord_uniform = -1;
  57. // Print out the information log for a shader object
  58. void printInfoLog(PFNGLGETPROGRAMINFOLOGPROC logFunc, GLuint object, GLint status)
  59. {
  60. if (logFunc != nullptr)
  61. {
  62. GLsizei infoLogLength = 0;
  63. GLchar infoLog[1024];
  64. logFunc(object, sizeof(infoLog)-1, &infoLogLength, infoLog);
  65. if (infoLogLength > 0) (status ? tlog0 : tlog1) << infoLog;
  66. }
  67. }
  68. GLuint makeShaderProgram(const char * frg_src)
  69. {
  70. // Creating a fragment shader object
  71. GLuint shader_object = glCreateShader(GL_FRAGMENT_SHADER);
  72. if (shader_object == 0) return 0;
  73. glShaderSource(shader_object, 1, &frg_src, nullptr); // assigning the shader source
  74. glCompileShader(shader_object); // Compiling the shader
  75. GLint ret;
  76. glGetShaderiv(shader_object, GL_COMPILE_STATUS, &ret);
  77. printInfoLog(glGetShaderInfoLog, shader_object, ret);
  78. if (ret == GL_TRUE)
  79. {
  80. GLuint program_object = glCreateProgram(); // Creating a program object
  81. glAttachShader(program_object, shader_object); // Attaching the shader into program
  82. // Link the shaders into a complete GLSL program.
  83. glLinkProgram(program_object);
  84. glGetProgramiv(shader_object, GL_LINK_STATUS, &ret);
  85. printInfoLog(glGetProgramInfoLog, program_object, ret);
  86. if (ret == GL_TRUE) return program_object;
  87. }
  88. glDeleteShader(shader_object);
  89. return 0;
  90. }
  91. void initVideo(ui32 w, ui32 h, bool fullscreen)
  92. {
  93. SDL_VERSION(&wmInfo.version);
  94. SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
  95. if (!setScreenRes(w, h, fullscreen))
  96. {
  97. throw std::runtime_error("Video mode setting failed\n");
  98. }
  99. glClearColor(0, 0, 0, 0); // Black Background
  100. glClear(GL_COLOR_BUFFER_BIT);
  101. SDL_GL_SwapBuffers();
  102. // Dynamic-linked OpenGL 1.3 and 2.0 functions - required to 2D rendeing
  103. if ( (glActiveTexture = (PFNGLACTIVETEXTUREPROC) SDL_GL_GetProcAddress("glActiveTexture")) == nullptr
  104. || (glCreateProgram = (PFNGLCREATEPROGRAMPROC) SDL_GL_GetProcAddress("glCreateProgram")) == nullptr
  105. || (glCreateShader = (PFNGLCREATESHADERPROC) SDL_GL_GetProcAddress("glCreateShader")) == nullptr
  106. || (glDeleteShader = (PFNGLDELETESHADERPROC) SDL_GL_GetProcAddress("glDeleteShader")) == nullptr
  107. || (glShaderSource = (PFNGLSHADERSOURCEPROC) SDL_GL_GetProcAddress("glShaderSource")) == nullptr
  108. || (glCompileShader = (PFNGLCOMPILESHADERPROC) SDL_GL_GetProcAddress("glCompileShader")) == nullptr
  109. || (glGetShaderiv = (PFNGLGETSHADERIVPROC) SDL_GL_GetProcAddress("glGetShaderiv")) == nullptr
  110. || (glAttachShader = (PFNGLATTACHSHADERPROC) SDL_GL_GetProcAddress("glAttachShader")) == nullptr
  111. || (glLinkProgram = (PFNGLLINKPROGRAMPROC) SDL_GL_GetProcAddress("glLinkProgram")) == nullptr
  112. || (glGetProgramiv = (PFNGLGETPROGRAMIVPROC) SDL_GL_GetProcAddress("glGetProgramiv")) == nullptr
  113. || (glUseProgram = (PFNGLUSEPROGRAMPROC) SDL_GL_GetProcAddress("glUseProgram")) == nullptr
  114. || (glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) SDL_GL_GetProcAddress("glGetUniformLocation")) == nullptr
  115. || (glUniform1i = (PFNGLUNIFORM1IPROC) SDL_GL_GetProcAddress("glUniform1i")) == nullptr
  116. || (glUniform2i = (PFNGLUNIFORM2IPROC) SDL_GL_GetProcAddress("glUniform2i")) == nullptr
  117. )
  118. {
  119. tlog1 << "Error: OpenGL2 Extenstions are not available\n";
  120. tlog1 << "SDL says: " << SDL_GetError() << std::endl;
  121. throw std::runtime_error("OpenGL2 Extenstions are not available\n");
  122. }
  123. glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) SDL_GL_GetProcAddress("glGetProgramInfoLog"); // not required
  124. glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) SDL_GL_GetProcAddress("glGetShaderInfoLog"); // not required
  125. glDisable(GL_DEPTH_TEST);
  126. glDisable(GL_LIGHTING);
  127. glDisable(GL_DITHER);
  128. glDisable(GL_TEXTURE_2D);
  129. glEnable(GL_TEXTURE_RECTANGLE);
  130. glEnable(GL_BLEND);
  131. glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  132. paletteBitmapProgram = makeShaderProgram(frag_palette_bitmap);
  133. if (paletteBitmapProgram == 0)
  134. {
  135. throw std::runtime_error("OpenGL shader for palleted bitmaps is not compiled\n");
  136. }
  137. GLint bitmap_uniform = glGetUniformLocation(paletteBitmapProgram, "bitmap");
  138. GLint palette_uniform = glGetUniformLocation(paletteBitmapProgram, "palette");
  139. coord_uniform = glGetUniformLocation(paletteBitmapProgram, "coordOffs");
  140. glUseProgram(currentProgram = paletteBitmapProgram);
  141. glUniform1i(bitmap_uniform, 0);
  142. glUniform1i(palette_uniform, 1);
  143. // unhook OpenGL context from display context/window
  144. #ifdef _WIN32
  145. wglMakeCurrent(NULL, NULL);
  146. #elif _GLX
  147. glxCtx = glXGetCurrentContext();
  148. if (glxCtx == nullptr)
  149. {
  150. throw std::runtime_error("SDL didn't create GLX context!\n");
  151. }
  152. if (!glXMakeCurrent(wmInfo.info.x11.display, None, nullptr))
  153. {
  154. throw std::runtime_error("glXMakeCurrent failed (unhook GL context)\n");
  155. }
  156. #endif
  157. }
  158. void attachToCurrentThread()
  159. {
  160. #ifdef _WIN32
  161. HDC hdc = GetDC(wmInfo.window);
  162. wglMakeCurrent(hdc, wmInfo.hglrc);
  163. #elif _GLX
  164. if (!glXMakeCurrent(wmInfo.info.x11.display, wmInfo.info.x11.window, glxCtx))
  165. {
  166. throw std::runtime_error("attachToCurrentThread: glXMakeCurrent failed\n");
  167. }
  168. #endif
  169. }
  170. bool setScreenRes(ui32 w, ui32 h, bool fullscreen)
  171. {
  172. // Try to use the best screen depth for the display
  173. int suggestedBpp = SDL_VideoModeOK(w, h, 32, SDL_OPENGL | SDL_ANYFORMAT | (fullscreen?SDL_FULLSCREEN:0));
  174. if(suggestedBpp == 0)
  175. {
  176. tlog1 << "Error: SDL says that " << w << "x" << h << " resolution is not available!\n";
  177. return false;
  178. }
  179. if(suggestedBpp != 32)
  180. {
  181. tlog2 << "Note: SDL suggests to use " << suggestedBpp << " bpp instead of 32 bpp\n";
  182. }
  183. if(SDL_SetVideoMode(w, h, suggestedBpp, SDL_OPENGL | SDL_ANYFORMAT | (fullscreen?SDL_FULLSCREEN:0)) == NULL)
  184. {
  185. tlog1 << "Error: Video mode setting failed (" << w << "x" << h << "x" << suggestedBpp << "bpp)\n";
  186. return false;
  187. }
  188. screenWidth = w; screenHeight = h;
  189. int getwm = SDL_GetWMInfo(&wmInfo);
  190. if(getwm != 1)
  191. {
  192. tlog2 << "Something went wrong, getwm=" << getwm << std::endl;
  193. tlog2 << "SDL says: " << SDL_GetError() << std::endl;
  194. return false;
  195. }
  196. glViewport(0, 0, w, h);
  197. glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
  198. glLoadIdentity(); // Reset The Projection Matrix
  199. glOrtho(0, w, h, 0, 0, 1);
  200. glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
  201. glLoadIdentity(); // Reset The Modelview Matrix
  202. glTranslatef(0.375, 0.375, 0); // Displacement trick for exact pixelization
  203. return true;
  204. }
  205. void assignTexture(ui32 slot, ui32 type, ui32 handle)
  206. {
  207. glActiveTexture(slot);
  208. glBindTexture(type, handle);
  209. }
  210. void useNoShader()
  211. {
  212. if (currentProgram != 0) {
  213. glUseProgram(currentProgram = 0);
  214. }
  215. }
  216. void useColorizeShader(const float cm[4][4])
  217. {
  218. if (currentProgram != colorizeProgram) {
  219. glUseProgram(currentProgram = colorizeProgram);
  220. }
  221. }
  222. void usePaletteBitmapShader(si32 x, si32 y)
  223. {
  224. if (currentProgram != paletteBitmapProgram) {
  225. glUseProgram(currentProgram = paletteBitmapProgram);
  226. }
  227. glUniform2i(coord_uniform, x, y);
  228. }
  229. void usePaletteBitmapShader(si32 x, si32 y, const float cm[4][4])
  230. {
  231. if (currentProgram != paletteBitmapProgram) {
  232. glUseProgram(currentProgram = paletteBitmapProgram);
  233. }
  234. glUniform2i(coord_uniform, x, y);
  235. }
  236. }