glimp.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. #ifdef USE_SDL
  21. #include "../idlib/precompiled.h"
  22. #include <SDL_syswm.h>
  23. #include "../framework/Licensee.h"
  24. #include "../renderer/tr_local.h"
  25. #if !defined(ID_GL_HARDLINK) && defined(__linux__)
  26. #include "linux/local.h"
  27. #endif
  28. #ifdef __WINDOWS__
  29. #include "win32/win_local.h"
  30. #endif
  31. idCVar in_nograb("in_nograb", "0", CVAR_SYSTEM | CVAR_NOCHEAT, "prevents input grabbing");
  32. idCVar r_waylandcompat("r_waylandcompat", "0", CVAR_SYSTEM | CVAR_NOCHEAT | CVAR_ARCHIVE, "wayland compatible framebuffer");
  33. bool g_inputGrabbed = false;
  34. static SDL_Window *window = NULL;
  35. static SDL_GLContext context = NULL;
  36. //
  37. // function declaration
  38. //
  39. #ifdef __WINDOWS__
  40. bool QGL_Init( const char *dllname );
  41. void QGL_Shutdown( void );
  42. #endif
  43. /*
  44. ===================
  45. GLimp_Init
  46. ===================
  47. */
  48. bool GLimp_Init(glimpParms_t parms) {
  49. common->Printf("Initializing OpenGL subsystem\n");
  50. #if !defined(ID_GL_HARDLINK) && defined(__linux__)
  51. if ( !GLimp_dlopen() ) {
  52. return false;
  53. }
  54. #endif
  55. #ifdef __WINDOWS__
  56. const char *driverName;
  57. // r_glDriver is only intended for using instrumented OpenGL
  58. // dlls. Normal users should never have to use it, and it is
  59. // not archived.
  60. driverName = r_glDriver.GetString()[0] ? r_glDriver.GetString() : "opengl32";
  61. if ( !QGL_Init( driverName ) ) {
  62. common->Printf( "^3GLimp_Init() could not load r_glDriver \"%s\"^0\n", driverName );
  63. return false;
  64. }
  65. #endif
  66. assert(SDL_WasInit(SDL_INIT_VIDEO));
  67. Uint32 flags = SDL_WINDOW_OPENGL;
  68. #ifndef __WINDOWS__ // HACK: windows starts windowed then switches to fullscreen below.
  69. if (parms.fullScreen)
  70. flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
  71. #endif
  72. int colorbits = 24;
  73. int depthbits = 24;
  74. int stencilbits = 8;
  75. for (int i = 0; i < 16; i++) {
  76. // 0 - default
  77. // 1 - minus colorbits
  78. // 2 - minus depthbits
  79. // 3 - minus stencil
  80. if ((i % 4) == 0 && i) {
  81. // one pass, reduce
  82. switch (i / 4) {
  83. case 2 :
  84. if (colorbits == 24)
  85. colorbits = 16;
  86. break;
  87. case 1 :
  88. if (depthbits == 24)
  89. depthbits = 16;
  90. else if (depthbits == 16)
  91. depthbits = 8;
  92. case 3 :
  93. if (stencilbits == 24)
  94. stencilbits = 16;
  95. else if (stencilbits == 16)
  96. stencilbits = 8;
  97. }
  98. }
  99. int tcolorbits = colorbits;
  100. int tdepthbits = depthbits;
  101. int tstencilbits = stencilbits;
  102. if ((i % 4) == 3) {
  103. // reduce colorbits
  104. if (tcolorbits == 24)
  105. tcolorbits = 16;
  106. }
  107. if ((i % 4) == 2) {
  108. // reduce depthbits
  109. if (tdepthbits == 24)
  110. tdepthbits = 16;
  111. else if (tdepthbits == 16)
  112. tdepthbits = 8;
  113. }
  114. if ((i % 4) == 1) {
  115. // reduce stencilbits
  116. if (tstencilbits == 24)
  117. tstencilbits = 16;
  118. else if (tstencilbits == 16)
  119. tstencilbits = 8;
  120. else
  121. tstencilbits = 0;
  122. }
  123. int channelcolorbits = 4;
  124. if (tcolorbits == 24)
  125. channelcolorbits = 8;
  126. SDL_GL_SetAttribute(SDL_GL_RED_SIZE, channelcolorbits);
  127. SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, channelcolorbits);
  128. SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, channelcolorbits);
  129. SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
  130. SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, tdepthbits);
  131. SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, tstencilbits);
  132. if (r_waylandcompat.GetBool())
  133. SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0);
  134. else
  135. SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, channelcolorbits);
  136. SDL_GL_SetAttribute(SDL_GL_STEREO, parms.stereo ? 1 : 0);
  137. SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, parms.multiSamples ? 1 : 0);
  138. SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, parms.multiSamples);
  139. #ifdef __WINDOWS__ // flush out any outstanding messages.
  140. SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
  141. SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE);
  142. #endif
  143. window = SDL_CreateWindow(GAME_NAME,
  144. SDL_WINDOWPOS_UNDEFINED,
  145. SDL_WINDOWPOS_UNDEFINED,
  146. parms.width, parms.height, flags);
  147. #ifdef __WINDOWS__ // HACK: windows fullscreeen doesn't get focus properly, this is a work around.
  148. // Switch to fullscreen now if needed, this works around a weird focus bug in SDL2
  149. if (parms.fullScreen)
  150. SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN);
  151. // flush out the event queue so we set the hWnd etc. for id
  152. win32.hWnd = NULL;
  153. while (Sys_GetEvent().evType != SE_NONE) {}
  154. SDL_EventState(SDL_SYSWMEVENT, SDL_DISABLE);
  155. #endif
  156. context = SDL_GL_CreateContext(window);
  157. if (!window) {
  158. common->DPrintf("Couldn't set GL mode %d/%d/%d: %s",
  159. channelcolorbits, tdepthbits, tstencilbits, SDL_GetError());
  160. continue;
  161. }
  162. if (SDL_GL_SetSwapInterval(r_swapInterval.GetInteger()) < 0)
  163. common->Warning("SDL_GL_SWAP_CONTROL not supported");
  164. #if 0 // TODO: make the engine render to the specified size but live in native res window.
  165. glConfig.vidWidth = parms.width;
  166. glConfig.vidHeight = parms.height;
  167. #else
  168. SDL_GetWindowSize(window, &glConfig.vidWidth, &glConfig.vidHeight);
  169. #endif
  170. glConfig.isFullscreen = (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) == SDL_WINDOW_FULLSCREEN;
  171. common->Printf("Using %d color bits, %d depth, %d stencil display\n",
  172. channelcolorbits, tdepthbits, tstencilbits);
  173. glConfig.colorBits = tcolorbits;
  174. glConfig.depthBits = tdepthbits;
  175. glConfig.stencilBits = tstencilbits;
  176. glConfig.displayFrequency = 0;
  177. break;
  178. }
  179. if (!window) {
  180. common->Warning("No usable GL mode found: %s", SDL_GetError());
  181. return false;
  182. }
  183. return true;
  184. }
  185. /*
  186. ===================
  187. GLimp_SetScreenParms
  188. ===================
  189. */
  190. bool GLimp_SetScreenParms(glimpParms_t parms) {
  191. common->DPrintf("TODO: GLimp_ActivateContext\n");
  192. return true;
  193. }
  194. /*
  195. ===================
  196. GLimp_Shutdown
  197. ===================
  198. */
  199. void GLimp_Shutdown() {
  200. common->Printf("Shutting down OpenGL subsystem\n");
  201. if (context) {
  202. SDL_GL_DeleteContext(context);
  203. context = NULL;
  204. }
  205. if (window) {
  206. SDL_DestroyWindow(window);
  207. window = NULL;
  208. }
  209. #ifdef __WINDOWS__
  210. // shutdown QGL subsystem
  211. QGL_Shutdown();
  212. #endif
  213. }
  214. /*
  215. ===================
  216. GLimp_SwapBuffers
  217. ===================
  218. */
  219. void GLimp_SwapBuffers() {
  220. SDL_GL_SwapWindow(window);
  221. }
  222. /*
  223. =================
  224. GLimp_SetGamma
  225. =================
  226. */
  227. void GLimp_SetGamma(unsigned short red[256], unsigned short green[256], unsigned short blue[256]) {
  228. if (!window) {
  229. common->Warning("GLimp_SetGamma called without window");
  230. return;
  231. }
  232. if (SDL_SetWindowGammaRamp(window, red, green, blue))
  233. common->Warning("Couldn't set gamma ramp: %s", SDL_GetError());
  234. }
  235. /*
  236. =================
  237. GLimp_ActivateContext
  238. =================
  239. */
  240. void GLimp_ActivateContext() {
  241. common->DPrintf("TODO: GLimp_ActivateContext\n");
  242. }
  243. /*
  244. =================
  245. GLimp_DeactivateContext
  246. =================
  247. */
  248. void GLimp_DeactivateContext() {
  249. common->DPrintf("TODO: GLimp_DeactivateContext\n");
  250. }
  251. #ifndef __WINDOWS__
  252. /*
  253. =================
  254. GLimp_EnableLogging
  255. =================
  256. */
  257. void GLimp_EnableLogging(bool stat) { }
  258. #endif
  259. /*
  260. ===================
  261. GLimp_ExtensionPointer
  262. ===================
  263. */
  264. GLExtension_t GLimp_ExtensionPointer(const char *name) {
  265. assert(SDL_WasInit(SDL_INIT_VIDEO));
  266. return (GLExtension_t)SDL_GL_GetProcAddress(name);
  267. }
  268. void GLimp_GrabInput(int flags) {
  269. if (!window) {
  270. common->Warning("GLimp_GrabInput called without window");
  271. return;
  272. }
  273. bool shouldGrab = true;
  274. bool hasFocus = SDL_GetKeyboardFocus() == window;
  275. if ( in_nograb.GetBool() ) {
  276. shouldGrab = false;
  277. }
  278. // if fullscreen, we always want the mouse
  279. const bool fullscreen = (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) != 0;
  280. if ( !fullscreen ) {
  281. if ( (flags & GRAB_ENABLE) != GRAB_ENABLE) {
  282. shouldGrab = false;
  283. }
  284. if ( !hasFocus ) {
  285. shouldGrab = false;
  286. }
  287. }
  288. if (shouldGrab && (flags & GRAB_REENABLE) )
  289. shouldGrab = false;
  290. g_inputGrabbed = SDL_GetWindowGrab(window) == SDL_TRUE;
  291. if (shouldGrab != g_inputGrabbed) {
  292. SDL_SetWindowGrab(window, shouldGrab ? SDL_TRUE : SDL_FALSE);
  293. g_inputGrabbed = SDL_GetWindowGrab(window) == SDL_TRUE;
  294. }
  295. const bool relativeMouseMode = SDL_GetRelativeMouseMode();
  296. if (shouldGrab != relativeMouseMode) {
  297. SDL_SetRelativeMouseMode(shouldGrab ? SDL_TRUE : SDL_FALSE);
  298. }
  299. const bool shown = SDL_ShowCursor(-1) == SDL_ENABLE;
  300. const bool shouldShow = !shouldGrab;
  301. if (shouldShow != shown) {
  302. SDL_ShowCursor(shouldShow ? SDL_ENABLE : SDL_DISABLE);
  303. }
  304. }
  305. #endif