2
0

GL2D.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  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 << "GL2D Error: OpenGL2 Extenstions are not available\n";
  120. tlog1 << "SDL says: " << SDL_GetError() << std::endl;
  121. throw std::runtime_error("initVideo failed - 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("initVideo failed - GL shader for palleted bitmaps isn't 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. if (!wglMakeCurrent(NULL, NULL))
  146. {
  147. tlog1 << "GL2D Error: wglMakeCurrent failed while unhooking GL context\n";
  148. tlog1 << "WinAPI returns error code = " << GetLastError() << std::endl;
  149. throw std::runtime_error("initVideo failed - wglMakeCurrent\n");
  150. }
  151. #elif _GLX
  152. glxCtx = glXGetCurrentContext();
  153. if (glxCtx == nullptr)
  154. {
  155. tlog1 << "GL2D Error: glXGetCurrentContext returns NULL\n";
  156. throw std::runtime_error("initVideo failed - SDL didn't create GLX context?!\n");
  157. }
  158. if (!glXMakeCurrent(wmInfo.info.x11.display, None, nullptr))
  159. {
  160. tlog1 << "GL2D Error: glXMakeCurrent failed while unhooking GL context\n";
  161. throw std::runtime_error("initVideo failed - glXMakeCurrent\n");
  162. }
  163. #endif
  164. }
  165. void attachToCurrentThread()
  166. {
  167. #ifdef _WIN32
  168. HDC hdc = GetDC(wmInfo.window);
  169. if (!wglMakeCurrent(hdc, wmInfo.hglrc))
  170. {
  171. tlog1 << "GL2D Error: wglMakeCurrent failed while hooking GL context\n";
  172. tlog1 << "WinAPI returns error code = " << GetLastError() << std::endl;
  173. throw std::runtime_error("attachToCurrentThread: wglMakeCurrent failed\n");
  174. }
  175. #elif _GLX
  176. if (!glXMakeCurrent(wmInfo.info.x11.display, wmInfo.info.x11.window, glxCtx))
  177. {
  178. tlog1 << "GL2D Error: glXMakeCurrent failed while hooking GL context\n";
  179. throw std::runtime_error("attachToCurrentThread: glXMakeCurrent failed\n");
  180. }
  181. #endif
  182. }
  183. bool setScreenRes(ui32 w, ui32 h, bool fullscreen)
  184. {
  185. // Try to use the best screen depth for the display
  186. int suggestedBpp = SDL_VideoModeOK(w, h, 32, SDL_OPENGL | SDL_ANYFORMAT | (fullscreen?SDL_FULLSCREEN:0));
  187. if(suggestedBpp == 0)
  188. {
  189. tlog1 << "GL2D Error: SDL says that " << w << "x" << h << " resolution is not available!\n";
  190. return false;
  191. }
  192. if(suggestedBpp != 32)
  193. {
  194. tlog2 << "GL2D Warning: SDL suggests to use " << suggestedBpp << " bpp instead of 32 bpp\n";
  195. }
  196. if(SDL_SetVideoMode(w, h, suggestedBpp, SDL_OPENGL | SDL_ANYFORMAT | (fullscreen?SDL_FULLSCREEN:0)) == NULL)
  197. {
  198. tlog1 << "GL2D Error: Video mode setting failed (" << w << "x" << h << "x" << suggestedBpp << "bpp)\n";
  199. return false;
  200. }
  201. screenWidth = w; screenHeight = h;
  202. int getwm = SDL_GetWMInfo(&wmInfo);
  203. if (getwm != 1)
  204. {
  205. tlog1 << "GL2D Error: SDL_GetWMInfo returns " << getwm << std::endl;
  206. tlog1 << "SDL says: " << SDL_GetError() << std::endl;
  207. return false;
  208. }
  209. glViewport(0, 0, w, h);
  210. glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
  211. glLoadIdentity(); // Reset The Projection Matrix
  212. glOrtho(0, w, h, 0, 0, 1);
  213. glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
  214. glLoadIdentity(); // Reset The Modelview Matrix
  215. glTranslatef(0.375, 0.375, 0); // Displacement trick for exact pixelization
  216. return true;
  217. }
  218. void assignTexture(ui32 slot, ui32 type, ui32 handle)
  219. {
  220. glActiveTexture(slot);
  221. glBindTexture(type, handle);
  222. }
  223. void useNoShader()
  224. {
  225. if (currentProgram != 0) {
  226. glUseProgram(currentProgram = 0);
  227. }
  228. }
  229. void useColorizeShader(const float cm[4][4])
  230. {
  231. if (currentProgram != colorizeProgram) {
  232. glUseProgram(currentProgram = colorizeProgram);
  233. }
  234. }
  235. void usePaletteBitmapShader(si32 x, si32 y)
  236. {
  237. if (currentProgram != paletteBitmapProgram) {
  238. glUseProgram(currentProgram = paletteBitmapProgram);
  239. }
  240. glUniform2i(coord_uniform, x, y);
  241. }
  242. void usePaletteBitmapShader(si32 x, si32 y, const float cm[4][4])
  243. {
  244. if (currentProgram != paletteBitmapProgram) {
  245. glUseProgram(currentProgram = paletteBitmapProgram);
  246. }
  247. glUniform2i(coord_uniform, x, y);
  248. }
  249. }