win_glimp.cpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245
  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. /*
  21. ** WIN_GLIMP.C
  22. **
  23. ** This file contains ALL Win32 specific stuff having to do with the
  24. ** OpenGL refresh. When a port is being made the following functions
  25. ** must be implemented by the port:
  26. **
  27. ** GLimp_SwapBuffers
  28. ** GLimp_Init
  29. ** GLimp_Shutdown
  30. ** GLimp_SetGamma
  31. **
  32. ** Note that the GLW_xxx functions are Windows specific GL-subsystem
  33. ** related functions that are relevant ONLY to win_glimp.c
  34. */
  35. #ifndef USE_SDL
  36. #include "../../idlib/precompiled.h"
  37. #pragma hdrstop
  38. #include "win_local.h"
  39. #include "rc/AFEditor_resource.h"
  40. #include "rc/doom_resource.h"
  41. #include "../../renderer/tr_local.h"
  42. static void GLW_InitExtensions( void );
  43. // WGL_ARB_extensions_string
  44. PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB;
  45. // WGL_EXT_swap_interval
  46. PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
  47. // WGL_ARB_pixel_format
  48. PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB;
  49. PFNWGLGETPIXELFORMATATTRIBFVARBPROC wglGetPixelFormatAttribfvARB;
  50. PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
  51. // WGL_ARB_pbuffer
  52. PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB;
  53. PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB;
  54. PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB;
  55. PFNWGLDESTROYPBUFFERARBPROC wglDestroyPbufferARB;
  56. PFNWGLQUERYPBUFFERARBPROC wglQueryPbufferARB;
  57. // WGL_ARB_render_texture
  58. PFNWGLBINDTEXIMAGEARBPROC wglBindTexImageARB;
  59. PFNWGLRELEASETEXIMAGEARBPROC wglReleaseTexImageARB;
  60. PFNWGLSETPBUFFERATTRIBARBPROC wglSetPbufferAttribARB;
  61. /* ARB_pixel_format */
  62. #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
  63. #define WGL_DRAW_TO_WINDOW_ARB 0x2001
  64. #define WGL_DRAW_TO_BITMAP_ARB 0x2002
  65. #define WGL_ACCELERATION_ARB 0x2003
  66. #define WGL_NEED_PALETTE_ARB 0x2004
  67. #define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005
  68. #define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006
  69. #define WGL_SWAP_METHOD_ARB 0x2007
  70. #define WGL_NUMBER_OVERLAYS_ARB 0x2008
  71. #define WGL_NUMBER_UNDERLAYS_ARB 0x2009
  72. #define WGL_TRANSPARENT_ARB 0x200A
  73. #define WGL_SHARE_DEPTH_ARB 0x200C
  74. #define WGL_SHARE_STENCIL_ARB 0x200D
  75. #define WGL_SHARE_ACCUM_ARB 0x200E
  76. #define WGL_SUPPORT_GDI_ARB 0x200F
  77. #define WGL_SUPPORT_OPENGL_ARB 0x2010
  78. #define WGL_DOUBLE_BUFFER_ARB 0x2011
  79. #define WGL_STEREO_ARB 0x2012
  80. #define WGL_PIXEL_TYPE_ARB 0x2013
  81. #define WGL_COLOR_BITS_ARB 0x2014
  82. #define WGL_RED_BITS_ARB 0x2015
  83. #define WGL_RED_SHIFT_ARB 0x2016
  84. #define WGL_GREEN_BITS_ARB 0x2017
  85. #define WGL_GREEN_SHIFT_ARB 0x2018
  86. #define WGL_BLUE_BITS_ARB 0x2019
  87. #define WGL_BLUE_SHIFT_ARB 0x201A
  88. #define WGL_ALPHA_BITS_ARB 0x201B
  89. #define WGL_ALPHA_SHIFT_ARB 0x201C
  90. #define WGL_ACCUM_BITS_ARB 0x201D
  91. #define WGL_ACCUM_RED_BITS_ARB 0x201E
  92. #define WGL_ACCUM_GREEN_BITS_ARB 0x201F
  93. #define WGL_ACCUM_BLUE_BITS_ARB 0x2020
  94. #define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
  95. #define WGL_DEPTH_BITS_ARB 0x2022
  96. #define WGL_STENCIL_BITS_ARB 0x2023
  97. #define WGL_AUX_BUFFERS_ARB 0x2024
  98. #define WGL_NO_ACCELERATION_ARB 0x2025
  99. #define WGL_GENERIC_ACCELERATION_ARB 0x2026
  100. #define WGL_FULL_ACCELERATION_ARB 0x2027
  101. #define WGL_SWAP_EXCHANGE_ARB 0x2028
  102. #define WGL_SWAP_COPY_ARB 0x2029
  103. #define WGL_SWAP_UNDEFINED_ARB 0x202A
  104. #define WGL_TYPE_RGBA_ARB 0x202B
  105. #define WGL_TYPE_COLORINDEX_ARB 0x202C
  106. #define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037
  107. #define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038
  108. #define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039
  109. #define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A
  110. #define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B
  111. /* ARB_multisample */
  112. #define WGL_SAMPLE_BUFFERS_ARB 0x2041
  113. #define WGL_SAMPLES_ARB 0x2042
  114. //
  115. // function declaration
  116. //
  117. bool QGL_Init( const char *dllname );
  118. void QGL_Shutdown( void );
  119. /*
  120. ========================
  121. GLimp_GetOldGammaRamp
  122. ========================
  123. */
  124. static void GLimp_SaveGamma( void ) {
  125. HDC hDC;
  126. BOOL success;
  127. hDC = GetDC( GetDesktopWindow() );
  128. success = GetDeviceGammaRamp( hDC, win32.oldHardwareGamma );
  129. common->DPrintf( "...getting default gamma ramp: %s\n", success ? "success" : "failed" );
  130. ReleaseDC( GetDesktopWindow(), hDC );
  131. }
  132. /*
  133. ========================
  134. GLimp_RestoreGamma
  135. ========================
  136. */
  137. static void GLimp_RestoreGamma( void ) {
  138. HDC hDC;
  139. BOOL success;
  140. // if we never read in a reasonable looking
  141. // table, don't write it out
  142. if ( win32.oldHardwareGamma[0][255] == 0 ) {
  143. return;
  144. }
  145. hDC = GetDC( GetDesktopWindow() );
  146. success = SetDeviceGammaRamp( hDC, win32.oldHardwareGamma );
  147. common->DPrintf ( "...restoring hardware gamma: %s\n", success ? "success" : "failed" );
  148. ReleaseDC( GetDesktopWindow(), hDC );
  149. }
  150. /*
  151. ========================
  152. GLimp_SetGamma
  153. The renderer calls this when the user adjusts r_gamma or r_brightness
  154. ========================
  155. */
  156. void GLimp_SetGamma( unsigned short red[256], unsigned short green[256], unsigned short blue[256] ) {
  157. unsigned short table[3][256];
  158. int i;
  159. if ( !win32.hDC ) {
  160. return;
  161. }
  162. for ( i = 0; i < 256; i++ ) {
  163. table[0][i] = red[i];
  164. table[1][i] = green[i];
  165. table[2][i] = blue[i];
  166. }
  167. if ( !SetDeviceGammaRamp( win32.hDC, table ) ) {
  168. common->Printf( "WARNING: SetDeviceGammaRamp failed.\n" );
  169. }
  170. }
  171. /*
  172. =============================================================================
  173. WglExtension Grabbing
  174. This is gross -- creating a window just to get a context to get the wgl extensions
  175. =============================================================================
  176. */
  177. /*
  178. ====================
  179. FakeWndProc
  180. Only used to get wglExtensions
  181. ====================
  182. */
  183. LONG WINAPI FakeWndProc (
  184. HWND hWnd,
  185. UINT uMsg,
  186. WPARAM wParam,
  187. LPARAM lParam) {
  188. if ( uMsg == WM_DESTROY ) {
  189. PostQuitMessage(0);
  190. }
  191. if ( uMsg != WM_CREATE ) {
  192. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  193. }
  194. const static PIXELFORMATDESCRIPTOR pfd = {
  195. sizeof(PIXELFORMATDESCRIPTOR),
  196. 1,
  197. PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
  198. PFD_TYPE_RGBA,
  199. 24,
  200. 0, 0, 0, 0, 0, 0,
  201. 8, 0,
  202. 0, 0, 0, 0,
  203. 24, 8,
  204. 0,
  205. PFD_MAIN_PLANE,
  206. 0,
  207. 0,
  208. 0,
  209. 0,
  210. };
  211. int pixelFormat;
  212. HDC hDC;
  213. HGLRC hGLRC;
  214. hDC = GetDC(hWnd);
  215. // Set up OpenGL
  216. pixelFormat = ChoosePixelFormat(hDC, &pfd);
  217. SetPixelFormat(hDC, pixelFormat, &pfd);
  218. hGLRC = qwglCreateContext(hDC);
  219. qwglMakeCurrent(hDC, hGLRC);
  220. // free things
  221. wglMakeCurrent(NULL, NULL);
  222. wglDeleteContext(hGLRC);
  223. ReleaseDC(hWnd, hDC);
  224. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  225. }
  226. /*
  227. ==================
  228. GLW_GetWGLExtensionsWithFakeWindow
  229. ==================
  230. */
  231. void GLW_CheckWGLExtensions( HDC hDC ) {
  232. wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)
  233. GLimp_ExtensionPointer("wglGetExtensionsStringARB");
  234. if ( wglGetExtensionsStringARB ) {
  235. glConfig.wgl_extensions_string = (const char *) wglGetExtensionsStringARB(hDC);
  236. } else {
  237. glConfig.wgl_extensions_string = "";
  238. }
  239. // WGL_EXT_swap_control
  240. wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) GLimp_ExtensionPointer( "wglSwapIntervalEXT" );
  241. r_swapInterval.SetModified(); // force a set next frame
  242. // WGL_ARB_pixel_format
  243. wglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)GLimp_ExtensionPointer("wglGetPixelFormatAttribivARB");
  244. wglGetPixelFormatAttribfvARB = (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)GLimp_ExtensionPointer("wglGetPixelFormatAttribfvARB");
  245. wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)GLimp_ExtensionPointer("wglChoosePixelFormatARB");
  246. // WGL_ARB_pbuffer
  247. wglCreatePbufferARB = (PFNWGLCREATEPBUFFERARBPROC)GLimp_ExtensionPointer("wglCreatePbufferARB");
  248. wglGetPbufferDCARB = (PFNWGLGETPBUFFERDCARBPROC)GLimp_ExtensionPointer("wglGetPbufferDCARB");
  249. wglReleasePbufferDCARB = (PFNWGLRELEASEPBUFFERDCARBPROC)GLimp_ExtensionPointer("wglReleasePbufferDCARB");
  250. wglDestroyPbufferARB = (PFNWGLDESTROYPBUFFERARBPROC)GLimp_ExtensionPointer("wglDestroyPbufferARB");
  251. wglQueryPbufferARB = (PFNWGLQUERYPBUFFERARBPROC)GLimp_ExtensionPointer("wglQueryPbufferARB");
  252. // WGL_ARB_render_texture
  253. wglBindTexImageARB = (PFNWGLBINDTEXIMAGEARBPROC)GLimp_ExtensionPointer("wglBindTexImageARB");
  254. wglReleaseTexImageARB = (PFNWGLRELEASETEXIMAGEARBPROC)GLimp_ExtensionPointer("wglReleaseTexImageARB");
  255. wglSetPbufferAttribARB = (PFNWGLSETPBUFFERATTRIBARBPROC)GLimp_ExtensionPointer("wglSetPbufferAttribARB");
  256. }
  257. /*
  258. ==================
  259. GLW_GetWGLExtensionsWithFakeWindow
  260. ==================
  261. */
  262. static void GLW_GetWGLExtensionsWithFakeWindow( void ) {
  263. HWND hWnd;
  264. MSG msg;
  265. // Create a window for the sole purpose of getting
  266. // a valid context to get the wglextensions
  267. hWnd = CreateWindow(WIN32_FAKE_WINDOW_CLASS_NAME, GAME_NAME,
  268. WS_OVERLAPPEDWINDOW,
  269. 40, 40,
  270. 640,
  271. 480,
  272. NULL, NULL, win32.hInstance, NULL );
  273. if ( !hWnd ) {
  274. common->FatalError( "GLW_GetWGLExtensionsWithFakeWindow: Couldn't create fake window" );
  275. }
  276. HDC hDC = GetDC( hWnd );
  277. HGLRC gRC = wglCreateContext( hDC );
  278. wglMakeCurrent( hDC, gRC );
  279. GLW_CheckWGLExtensions( hDC );
  280. wglDeleteContext( gRC );
  281. ReleaseDC( hWnd, hDC );
  282. DestroyWindow( hWnd );
  283. while ( GetMessage( &msg, NULL, 0, 0 ) ) {
  284. TranslateMessage( &msg );
  285. DispatchMessage( &msg );
  286. }
  287. }
  288. //=============================================================================
  289. /*
  290. ====================
  291. GLW_WM_CREATE
  292. ====================
  293. */
  294. void GLW_WM_CREATE( HWND hWnd ) {
  295. }
  296. /*
  297. ====================
  298. GLW_InitDriver
  299. Set the pixelformat for the window before it is
  300. shown, and create the rendering context
  301. ====================
  302. */
  303. static bool GLW_InitDriver( glimpParms_t parms ) {
  304. PIXELFORMATDESCRIPTOR src =
  305. {
  306. sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
  307. 1, // version number
  308. PFD_DRAW_TO_WINDOW | // support window
  309. PFD_SUPPORT_OPENGL | // support OpenGL
  310. PFD_DOUBLEBUFFER, // double buffered
  311. PFD_TYPE_RGBA, // RGBA type
  312. 32, // 32-bit color depth
  313. 0, 0, 0, 0, 0, 0, // color bits ignored
  314. 8, // 8 bit destination alpha
  315. 0, // shift bit ignored
  316. 0, // no accumulation buffer
  317. 0, 0, 0, 0, // accum bits ignored
  318. 24, // 24-bit z-buffer
  319. 8, // 8-bit stencil buffer
  320. 0, // no auxiliary buffer
  321. PFD_MAIN_PLANE, // main layer
  322. 0, // reserved
  323. 0, 0, 0 // layer masks ignored
  324. };
  325. common->Printf( "Initializing OpenGL driver\n" );
  326. //
  327. // get a DC for our window if we don't already have one allocated
  328. //
  329. if ( win32.hDC == NULL ) {
  330. common->Printf( "...getting DC: " );
  331. if ( ( win32.hDC = GetDC( win32.hWnd ) ) == NULL ) {
  332. common->Printf( "^3failed^0\n" );
  333. return false;
  334. }
  335. common->Printf( "succeeded\n" );
  336. }
  337. // the multisample path uses the wgl
  338. if ( wglChoosePixelFormatARB && parms.multiSamples > 1 ) {
  339. int iAttributes[20];
  340. FLOAT fAttributes[] = {0, 0};
  341. UINT numFormats;
  342. // FIXME: specify all the other stuff
  343. iAttributes[0] = WGL_SAMPLE_BUFFERS_ARB;
  344. iAttributes[1] = 1;
  345. iAttributes[2] = WGL_SAMPLES_ARB;
  346. iAttributes[3] = parms.multiSamples;
  347. iAttributes[4] = WGL_DOUBLE_BUFFER_ARB;
  348. iAttributes[5] = TRUE;
  349. iAttributes[6] = WGL_STENCIL_BITS_ARB;
  350. iAttributes[7] = 8;
  351. iAttributes[8] = WGL_DEPTH_BITS_ARB;
  352. iAttributes[9] = 24;
  353. iAttributes[10] = WGL_RED_BITS_ARB;
  354. iAttributes[11] = 8;
  355. iAttributes[12] = WGL_BLUE_BITS_ARB;
  356. iAttributes[13] = 8;
  357. iAttributes[14] = WGL_GREEN_BITS_ARB;
  358. iAttributes[15] = 8;
  359. iAttributes[16] = WGL_ALPHA_BITS_ARB;
  360. iAttributes[17] = 8;
  361. iAttributes[18] = 0;
  362. iAttributes[19] = 0;
  363. wglChoosePixelFormatARB( win32.hDC, iAttributes, fAttributes, 1, &win32.pixelformat, &numFormats );
  364. } else {
  365. // this is the "classic" choose pixel format path
  366. // eventually we may need to have more fallbacks, but for
  367. // now, ask for everything
  368. if ( parms.stereo ) {
  369. common->Printf( "...attempting to use stereo\n" );
  370. src.dwFlags |= PFD_STEREO;
  371. }
  372. //
  373. // choose, set, and describe our desired pixel format. If we're
  374. // using a minidriver then we need to bypass the GDI functions,
  375. // otherwise use the GDI functions.
  376. //
  377. if ( ( win32.pixelformat = ChoosePixelFormat( win32.hDC, &src ) ) == 0 ) {
  378. common->Printf( "...^3GLW_ChoosePFD failed^0\n");
  379. return false;
  380. }
  381. common->Printf( "...PIXELFORMAT %d selected\n", win32.pixelformat );
  382. }
  383. // get the full info
  384. DescribePixelFormat( win32.hDC, win32.pixelformat, sizeof( win32.pfd ), &win32.pfd );
  385. glConfig.colorBits = win32.pfd.cColorBits;
  386. glConfig.depthBits = win32.pfd.cDepthBits;
  387. glConfig.stencilBits = win32.pfd.cStencilBits;
  388. // XP seems to set this incorrectly
  389. if ( !glConfig.stencilBits ) {
  390. glConfig.stencilBits = 8;
  391. }
  392. // the same SetPixelFormat is used either way
  393. if ( SetPixelFormat( win32.hDC, win32.pixelformat, &win32.pfd ) == FALSE ) {
  394. common->Printf( "...^3SetPixelFormat failed^0\n", win32.hDC );
  395. return false;
  396. }
  397. //
  398. // startup the OpenGL subsystem by creating a context and making it current
  399. //
  400. common->Printf( "...creating GL context: " );
  401. if ( ( win32.hGLRC = qwglCreateContext( win32.hDC ) ) == 0 ) {
  402. common->Printf( "^3failed^0\n" );
  403. return false;
  404. }
  405. common->Printf( "succeeded\n" );
  406. common->Printf( "...making context current: " );
  407. if ( !qwglMakeCurrent( win32.hDC, win32.hGLRC ) ) {
  408. qwglDeleteContext( win32.hGLRC );
  409. win32.hGLRC = NULL;
  410. common->Printf( "^3failed^0\n" );
  411. return false;
  412. }
  413. common->Printf( "succeeded\n" );
  414. return true;
  415. }
  416. /*
  417. ====================
  418. GLW_CreateWindowClasses
  419. ====================
  420. */
  421. static void GLW_CreateWindowClasses( void ) {
  422. WNDCLASS wc;
  423. //
  424. // register the window class if necessary
  425. //
  426. if ( win32.windowClassRegistered ) {
  427. return;
  428. }
  429. memset( &wc, 0, sizeof( wc ) );
  430. wc.style = 0;
  431. wc.lpfnWndProc = (WNDPROC) MainWndProc;
  432. wc.cbClsExtra = 0;
  433. wc.cbWndExtra = 0;
  434. wc.hInstance = win32.hInstance;
  435. wc.hIcon = LoadIcon( win32.hInstance, MAKEINTRESOURCE(IDI_ICON1));
  436. wc.hCursor = LoadCursor (NULL,IDC_ARROW);
  437. wc.hbrBackground = (struct HBRUSH__ *)COLOR_GRAYTEXT;
  438. wc.lpszMenuName = 0;
  439. wc.lpszClassName = WIN32_WINDOW_CLASS_NAME;
  440. if ( !RegisterClass( &wc ) ) {
  441. common->FatalError( "GLW_CreateWindow: could not register window class" );
  442. }
  443. common->Printf( "...registered window class\n" );
  444. // now register the fake window class that is only used
  445. // to get wgl extensions
  446. wc.style = 0;
  447. wc.lpfnWndProc = (WNDPROC) FakeWndProc;
  448. wc.cbClsExtra = 0;
  449. wc.cbWndExtra = 0;
  450. wc.hInstance = win32.hInstance;
  451. wc.hIcon = LoadIcon( win32.hInstance, MAKEINTRESOURCE(IDI_ICON1));
  452. wc.hCursor = LoadCursor (NULL,IDC_ARROW);
  453. wc.hbrBackground = (struct HBRUSH__ *)COLOR_GRAYTEXT;
  454. wc.lpszMenuName = 0;
  455. wc.lpszClassName = WIN32_FAKE_WINDOW_CLASS_NAME;
  456. if ( !RegisterClass( &wc ) ) {
  457. common->FatalError( "GLW_CreateWindow: could not register window class" );
  458. }
  459. common->Printf( "...registered fake window class\n" );
  460. win32.windowClassRegistered = true;
  461. }
  462. /*
  463. =======================
  464. GLW_CreateWindow
  465. Responsible for creating the Win32 window.
  466. If cdsFullscreen is true, it won't have a border
  467. =======================
  468. */
  469. static bool GLW_CreateWindow( glimpParms_t parms ) {
  470. int stylebits;
  471. int x, y, w, h;
  472. int exstyle;
  473. //
  474. // compute width and height
  475. //
  476. if ( parms.fullScreen ) {
  477. exstyle = WS_EX_TOPMOST;
  478. stylebits = WS_POPUP|WS_VISIBLE|WS_SYSMENU;
  479. x = 0;
  480. y = 0;
  481. w = parms.width;
  482. h = parms.height;
  483. } else {
  484. RECT r;
  485. // adjust width and height for window border
  486. r.bottom = parms.height;
  487. r.left = 0;
  488. r.top = 0;
  489. r.right = parms.width;
  490. exstyle = 0;
  491. stylebits = WINDOW_STYLE|WS_SYSMENU;
  492. AdjustWindowRect (&r, stylebits, FALSE);
  493. w = r.right - r.left;
  494. h = r.bottom - r.top;
  495. x = win32.win_xpos.GetInteger();
  496. y = win32.win_ypos.GetInteger();
  497. // adjust window coordinates if necessary
  498. // so that the window is completely on screen
  499. if ( x + w > win32.desktopWidth ) {
  500. x = ( win32.desktopWidth - w );
  501. }
  502. if ( y + h > win32.desktopHeight ) {
  503. y = ( win32.desktopHeight - h );
  504. }
  505. if ( x < 0 ) {
  506. x = 0;
  507. }
  508. if ( y < 0 ) {
  509. y = 0;
  510. }
  511. }
  512. win32.hWnd = CreateWindowEx (
  513. exstyle,
  514. WIN32_WINDOW_CLASS_NAME,
  515. GAME_NAME,
  516. stylebits,
  517. x, y, w, h,
  518. NULL,
  519. NULL,
  520. win32.hInstance,
  521. NULL);
  522. if ( !win32.hWnd ) {
  523. common->Printf( "^3GLW_CreateWindow() - Couldn't create window^0\n" );
  524. return false;
  525. }
  526. ::SetTimer( win32.hWnd, 0, 100, NULL );
  527. ShowWindow( win32.hWnd, SW_SHOW );
  528. UpdateWindow( win32.hWnd );
  529. common->Printf( "...created window @ %d,%d (%dx%d)\n", x, y, w, h );
  530. if ( !GLW_InitDriver( parms ) ) {
  531. ShowWindow( win32.hWnd, SW_HIDE );
  532. DestroyWindow( win32.hWnd );
  533. win32.hWnd = NULL;
  534. return false;
  535. }
  536. SetForegroundWindow( win32.hWnd );
  537. SetFocus( win32.hWnd );
  538. glConfig.isFullscreen = parms.fullScreen;
  539. return true;
  540. }
  541. static void PrintCDSError( int value ) {
  542. switch ( value ) {
  543. case DISP_CHANGE_RESTART:
  544. common->Printf( "restart required\n" );
  545. break;
  546. case DISP_CHANGE_BADPARAM:
  547. common->Printf( "bad param\n" );
  548. break;
  549. case DISP_CHANGE_BADFLAGS:
  550. common->Printf( "bad flags\n" );
  551. break;
  552. case DISP_CHANGE_FAILED:
  553. common->Printf( "DISP_CHANGE_FAILED\n" );
  554. break;
  555. case DISP_CHANGE_BADMODE:
  556. common->Printf( "bad mode\n" );
  557. break;
  558. case DISP_CHANGE_NOTUPDATED:
  559. common->Printf( "not updated\n" );
  560. break;
  561. default:
  562. common->Printf( "unknown error %d\n", value );
  563. break;
  564. }
  565. }
  566. /*
  567. ===================
  568. GLW_SetFullScreen
  569. ===================
  570. */
  571. static bool GLW_SetFullScreen( glimpParms_t parms ) {
  572. #if 0
  573. // for some reason, bounds checker claims that windows is
  574. // writing past the bounds of dm in the get display frequency call
  575. union {
  576. DEVMODE dm;
  577. byte filler[1024];
  578. } hack;
  579. #endif
  580. DEVMODE dm;
  581. int cdsRet;
  582. DEVMODE devmode;
  583. int modeNum;
  584. bool matched;
  585. // first make sure the user is not trying to select a mode that his card/monitor can't handle
  586. matched = false;
  587. for ( modeNum = 0 ; ; modeNum++ ) {
  588. if ( !EnumDisplaySettings( NULL, modeNum, &devmode ) ) {
  589. if ( matched ) {
  590. // we got a resolution match, but not a frequency match
  591. // so disable the frequency requirement
  592. common->Printf( "...^3%dhz is unsupported at %dx%d^0\n", parms.displayHz, parms.width, parms.height );
  593. parms.displayHz = 0;
  594. break;
  595. }
  596. common->Printf( "...^3%dx%d is unsupported in 32 bit^0\n", parms.width, parms.height );
  597. return false;
  598. }
  599. if ( (int)devmode.dmPelsWidth >= parms.width
  600. && (int)devmode.dmPelsHeight >= parms.height
  601. && devmode.dmBitsPerPel == 32 ) {
  602. matched = true;
  603. if ( parms.displayHz == 0 || devmode.dmDisplayFrequency == parms.displayHz ) {
  604. break;
  605. }
  606. }
  607. }
  608. memset( &dm, 0, sizeof( dm ) );
  609. dm.dmSize = sizeof( dm );
  610. dm.dmPelsWidth = parms.width;
  611. dm.dmPelsHeight = parms.height;
  612. dm.dmBitsPerPel = 32;
  613. dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
  614. if ( parms.displayHz != 0 ) {
  615. dm.dmDisplayFrequency = parms.displayHz;
  616. dm.dmFields |= DM_DISPLAYFREQUENCY;
  617. }
  618. common->Printf( "...calling CDS: " );
  619. // try setting the exact mode requested, because some drivers don't report
  620. // the low res modes in EnumDisplaySettings, but still work
  621. if ( ( cdsRet = ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) ) == DISP_CHANGE_SUCCESSFUL ) {
  622. common->Printf( "ok\n" );
  623. win32.cdsFullscreen = true;
  624. return true;
  625. }
  626. //
  627. // the exact mode failed, so scan EnumDisplaySettings for the next largest mode
  628. //
  629. common->Printf( "^3failed^0, " );
  630. PrintCDSError( cdsRet );
  631. common->Printf( "...trying next higher resolution:" );
  632. // we could do a better matching job here...
  633. for ( modeNum = 0 ; ; modeNum++ ) {
  634. if ( !EnumDisplaySettings( NULL, modeNum, &devmode ) ) {
  635. break;
  636. }
  637. if ( (int)devmode.dmPelsWidth >= parms.width
  638. && (int)devmode.dmPelsHeight >= parms.height
  639. && devmode.dmBitsPerPel == 32 ) {
  640. if ( ( cdsRet = ChangeDisplaySettings( &devmode, CDS_FULLSCREEN ) ) == DISP_CHANGE_SUCCESSFUL ) {
  641. common->Printf( "ok\n" );
  642. win32.cdsFullscreen = true;
  643. return true;
  644. }
  645. break;
  646. }
  647. }
  648. common->Printf( "\n...^3no high res mode found^0\n" );
  649. return false;
  650. }
  651. /*
  652. ===================
  653. GLimp_Init
  654. This is the platform specific OpenGL initialization function. It
  655. is responsible for loading OpenGL, initializing it,
  656. creating a window of the appropriate size, doing
  657. fullscreen manipulations, etc. Its overall responsibility is
  658. to make sure that a functional OpenGL subsystem is operating
  659. when it returns to the ref.
  660. If there is any failure, the renderer will revert back to safe
  661. parameters and try again.
  662. ===================
  663. */
  664. bool GLimp_Init( glimpParms_t parms ) {
  665. const char *driverName;
  666. HDC hDC;
  667. common->Printf( "Initializing OpenGL subsystem\n" );
  668. // check our desktop attributes
  669. hDC = GetDC( GetDesktopWindow() );
  670. win32.desktopBitsPixel = GetDeviceCaps( hDC, BITSPIXEL );
  671. win32.desktopWidth = GetDeviceCaps( hDC, HORZRES );
  672. win32.desktopHeight = GetDeviceCaps( hDC, VERTRES );
  673. ReleaseDC( GetDesktopWindow(), hDC );
  674. // we can't run in a window unless it is 32 bpp
  675. if ( win32.desktopBitsPixel < 32 && !parms.fullScreen ) {
  676. common->Printf("^3Windowed mode requires 32 bit desktop depth^0\n");
  677. return false;
  678. }
  679. // save the hardware gamma so it can be
  680. // restored on exit
  681. GLimp_SaveGamma();
  682. // create our window classes if we haven't already
  683. GLW_CreateWindowClasses();
  684. // this will load the dll and set all our qgl* function pointers,
  685. // but doesn't create a window
  686. // r_glDriver is only intended for using instrumented OpenGL
  687. // dlls. Normal users should never have to use it, and it is
  688. // not archived.
  689. driverName = r_glDriver.GetString()[0] ? r_glDriver.GetString() : "opengl32";
  690. if ( !QGL_Init( driverName ) ) {
  691. common->Printf( "^3GLimp_Init() could not load r_glDriver \"%s\"^0\n", driverName );
  692. return false;
  693. }
  694. // getting the wgl extensions involves creating a fake window to get a context,
  695. // which is pretty disgusting, and seems to mess with the AGP VAR allocation
  696. GLW_GetWGLExtensionsWithFakeWindow();
  697. // try to change to fullscreen
  698. if ( parms.fullScreen ) {
  699. if ( !GLW_SetFullScreen( parms ) ) {
  700. GLimp_Shutdown();
  701. return false;
  702. }
  703. }
  704. // try to create a window with the correct pixel format
  705. // and init the renderer context
  706. if ( !GLW_CreateWindow( parms ) ) {
  707. GLimp_Shutdown();
  708. return false;
  709. }
  710. // wglSwapinterval, etc
  711. GLW_CheckWGLExtensions( win32.hDC );
  712. // check logging
  713. GLimp_EnableLogging( ( r_logFile.GetInteger() != 0 ) );
  714. return true;
  715. }
  716. /*
  717. ===================
  718. GLimp_SetScreenParms
  719. Sets up the screen based on passed parms..
  720. ===================
  721. */
  722. bool GLimp_SetScreenParms( glimpParms_t parms ) {
  723. int exstyle;
  724. int stylebits;
  725. int x, y, w, h;
  726. DEVMODE dm;
  727. memset( &dm, 0, sizeof( dm ) );
  728. dm.dmSize = sizeof( dm );
  729. dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
  730. if ( parms.displayHz != 0 ) {
  731. dm.dmDisplayFrequency = parms.displayHz;
  732. dm.dmFields |= DM_DISPLAYFREQUENCY;
  733. }
  734. win32.cdsFullscreen = parms.fullScreen;
  735. glConfig.isFullscreen = parms.fullScreen;
  736. if ( parms.fullScreen ) {
  737. exstyle = WS_EX_TOPMOST;
  738. stylebits = WS_POPUP|WS_VISIBLE|WS_SYSMENU;
  739. SetWindowLong( win32.hWnd, GWL_STYLE, stylebits );
  740. SetWindowLong( win32.hWnd, GWL_EXSTYLE, exstyle );
  741. dm.dmPelsWidth = parms.width;
  742. dm.dmPelsHeight = parms.height;
  743. dm.dmBitsPerPel = 32;
  744. x = y = w = h = 0;
  745. } else {
  746. RECT r;
  747. // adjust width and height for window border
  748. r.bottom = parms.height;
  749. r.left = 0;
  750. r.top = 0;
  751. r.right = parms.width;
  752. w = r.right - r.left;
  753. h = r.bottom - r.top;
  754. x = win32.win_xpos.GetInteger();
  755. y = win32.win_ypos.GetInteger();
  756. // adjust window coordinates if necessary
  757. // so that the window is completely on screen
  758. if ( x + w > win32.desktopWidth ) {
  759. x = ( win32.desktopWidth - w );
  760. }
  761. if ( y + h > win32.desktopHeight ) {
  762. y = ( win32.desktopHeight - h );
  763. }
  764. if ( x < 0 ) {
  765. x = 0;
  766. }
  767. if ( y < 0 ) {
  768. y = 0;
  769. }
  770. dm.dmPelsWidth = win32.desktopWidth;
  771. dm.dmPelsHeight = win32.desktopHeight;
  772. dm.dmBitsPerPel = win32.desktopBitsPixel;
  773. exstyle = 0;
  774. stylebits = WINDOW_STYLE|WS_SYSMENU;
  775. AdjustWindowRect (&r, stylebits, FALSE);
  776. SetWindowLong( win32.hWnd, GWL_STYLE, stylebits );
  777. SetWindowLong( win32.hWnd, GWL_EXSTYLE, exstyle );
  778. common->Printf( "%i %i %i %i\n", x, y, w, h );
  779. }
  780. bool ret = ( ChangeDisplaySettings( &dm, parms.fullScreen ? CDS_FULLSCREEN : 0 ) == DISP_CHANGE_SUCCESSFUL );
  781. SetWindowPos( win32.hWnd, parms.fullScreen ? HWND_TOPMOST : HWND_NOTOPMOST, x, y, w, h, parms.fullScreen ? SWP_NOSIZE | SWP_NOMOVE : SWP_SHOWWINDOW );
  782. return ret;
  783. }
  784. /*
  785. ===================
  786. GLimp_Shutdown
  787. This routine does all OS specific shutdown procedures for the OpenGL
  788. subsystem.
  789. ===================
  790. */
  791. void GLimp_Shutdown( void ) {
  792. const char *success[] = { "failed", "success" };
  793. int retVal;
  794. common->Printf( "Shutting down OpenGL subsystem\n" );
  795. // set current context to NULL
  796. if ( qwglMakeCurrent ) {
  797. retVal = qwglMakeCurrent( NULL, NULL ) != 0;
  798. common->Printf( "...wglMakeCurrent( NULL, NULL ): %s\n", success[retVal] );
  799. }
  800. // delete HGLRC
  801. if ( win32.hGLRC ) {
  802. retVal = qwglDeleteContext( win32.hGLRC ) != 0;
  803. common->Printf( "...deleting GL context: %s\n", success[retVal] );
  804. win32.hGLRC = NULL;
  805. }
  806. // release DC
  807. if ( win32.hDC ) {
  808. retVal = ReleaseDC( win32.hWnd, win32.hDC ) != 0;
  809. common->Printf( "...releasing DC: %s\n", success[retVal] );
  810. win32.hDC = NULL;
  811. }
  812. // destroy window
  813. if ( win32.hWnd ) {
  814. common->Printf( "...destroying window\n" );
  815. ShowWindow( win32.hWnd, SW_HIDE );
  816. DestroyWindow( win32.hWnd );
  817. win32.hWnd = NULL;
  818. }
  819. // reset display settings
  820. if ( win32.cdsFullscreen ) {
  821. common->Printf( "...resetting display\n" );
  822. ChangeDisplaySettings( 0, 0 );
  823. win32.cdsFullscreen = false;
  824. }
  825. // close the thread so the handle doesn't dangle
  826. if ( win32.renderThreadHandle ) {
  827. common->Printf( "...closing smp thread\n" );
  828. CloseHandle( win32.renderThreadHandle );
  829. win32.renderThreadHandle = NULL;
  830. }
  831. // restore gamma
  832. GLimp_RestoreGamma();
  833. // shutdown QGL subsystem
  834. QGL_Shutdown();
  835. }
  836. /*
  837. =====================
  838. GLimp_SwapBuffers
  839. =====================
  840. */
  841. void GLimp_SwapBuffers( void ) {
  842. //
  843. // wglSwapinterval is a windows-private extension,
  844. // so we must check for it here instead of portably
  845. //
  846. if ( r_swapInterval.IsModified() ) {
  847. r_swapInterval.ClearModified();
  848. if ( wglSwapIntervalEXT ) {
  849. wglSwapIntervalEXT( r_swapInterval.GetInteger() );
  850. }
  851. }
  852. qwglSwapBuffers( win32.hDC );
  853. //Sys_DebugPrintf( "*** SwapBuffers() ***\n" );
  854. }
  855. /*
  856. ===========================================================
  857. SMP acceleration
  858. ===========================================================
  859. */
  860. //#define REALLOC_DC
  861. /*
  862. ===================
  863. GLimp_ActivateContext
  864. ===================
  865. */
  866. void GLimp_ActivateContext( void ) {
  867. if ( !qwglMakeCurrent( win32.hDC, win32.hGLRC ) ) {
  868. win32.wglErrors++;
  869. }
  870. }
  871. /*
  872. ===================
  873. GLimp_DeactivateContext
  874. ===================
  875. */
  876. void GLimp_DeactivateContext( void ) {
  877. qglFinish();
  878. if ( !qwglMakeCurrent( win32.hDC, NULL ) ) {
  879. win32.wglErrors++;
  880. }
  881. #ifdef REALLOC_DC
  882. // makeCurrent NULL frees the DC, so get another
  883. if ( ( win32.hDC = GetDC( win32.hWnd ) ) == NULL ) {
  884. win32.wglErrors++;
  885. }
  886. #endif
  887. }
  888. /*
  889. ===================
  890. GLimp_RenderThreadWrapper
  891. ===================
  892. */
  893. static void GLimp_RenderThreadWrapper( void ) {
  894. win32.glimpRenderThread();
  895. // unbind the context before we die
  896. qwglMakeCurrent( win32.hDC, NULL );
  897. }
  898. /*
  899. =======================
  900. GLimp_SpawnRenderThread
  901. Returns false if the system only has a single processor
  902. =======================
  903. */
  904. bool GLimp_SpawnRenderThread( void (*function)( void ) ) {
  905. SYSTEM_INFO info;
  906. // check number of processors
  907. GetSystemInfo( &info );
  908. if ( info.dwNumberOfProcessors < 2 ) {
  909. return false;
  910. }
  911. // create the IPC elements
  912. win32.renderCommandsEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  913. win32.renderCompletedEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  914. win32.renderActiveEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  915. win32.glimpRenderThread = function;
  916. win32.renderThreadHandle = CreateThread(
  917. NULL, // LPSECURITY_ATTRIBUTES lpsa,
  918. 0, // DWORD cbStack,
  919. (LPTHREAD_START_ROUTINE)GLimp_RenderThreadWrapper, // LPTHREAD_START_ROUTINE lpStartAddr,
  920. 0, // LPVOID lpvThreadParm,
  921. 0, // DWORD fdwCreate,
  922. &win32.renderThreadId );
  923. if ( !win32.renderThreadHandle ) {
  924. common->Error( "GLimp_SpawnRenderThread: failed" );
  925. }
  926. SetThreadPriority( win32.renderThreadHandle, THREAD_PRIORITY_ABOVE_NORMAL );
  927. #if 0
  928. // make sure they always run on different processors
  929. SetThreadAffinityMask( GetCurrentThread, 1 );
  930. SetThreadAffinityMask( win32.renderThreadHandle, 2 );
  931. #endif
  932. return true;
  933. }
  934. //#define DEBUG_PRINTS
  935. /*
  936. ===================
  937. GLimp_BackEndSleep
  938. ===================
  939. */
  940. void *GLimp_BackEndSleep( void ) {
  941. void *data;
  942. #ifdef DEBUG_PRINTS
  943. OutputDebugString( "-->GLimp_BackEndSleep\n" );
  944. #endif
  945. ResetEvent( win32.renderActiveEvent );
  946. // after this, the front end can exit GLimp_FrontEndSleep
  947. SetEvent( win32.renderCompletedEvent );
  948. WaitForSingleObject( win32.renderCommandsEvent, INFINITE );
  949. ResetEvent( win32.renderCompletedEvent );
  950. ResetEvent( win32.renderCommandsEvent );
  951. data = win32.smpData;
  952. // after this, the main thread can exit GLimp_WakeRenderer
  953. SetEvent( win32.renderActiveEvent );
  954. #ifdef DEBUG_PRINTS
  955. OutputDebugString( "<--GLimp_BackEndSleep\n" );
  956. #endif
  957. return data;
  958. }
  959. /*
  960. ===================
  961. GLimp_FrontEndSleep
  962. ===================
  963. */
  964. void GLimp_FrontEndSleep( void ) {
  965. #ifdef DEBUG_PRINTS
  966. OutputDebugString( "-->GLimp_FrontEndSleep\n" );
  967. #endif
  968. WaitForSingleObject( win32.renderCompletedEvent, INFINITE );
  969. #ifdef DEBUG_PRINTS
  970. OutputDebugString( "<--GLimp_FrontEndSleep\n" );
  971. #endif
  972. }
  973. volatile bool renderThreadActive;
  974. /*
  975. ===================
  976. GLimp_WakeBackEnd
  977. ===================
  978. */
  979. void GLimp_WakeBackEnd( void *data ) {
  980. int r;
  981. #ifdef DEBUG_PRINTS
  982. OutputDebugString( "-->GLimp_WakeBackEnd\n" );
  983. #endif
  984. win32.smpData = data;
  985. if ( renderThreadActive ) {
  986. common->FatalError( "GLimp_WakeBackEnd: already active" );
  987. }
  988. r = WaitForSingleObject( win32.renderActiveEvent, 0 );
  989. if ( r == WAIT_OBJECT_0 ) {
  990. common->FatalError( "GLimp_WakeBackEnd: already signaled" );
  991. }
  992. r = WaitForSingleObject( win32.renderCommandsEvent, 0 );
  993. if ( r == WAIT_OBJECT_0 ) {
  994. common->FatalError( "GLimp_WakeBackEnd: commands already signaled" );
  995. }
  996. // after this, the renderer can continue through GLimp_RendererSleep
  997. SetEvent( win32.renderCommandsEvent );
  998. r = WaitForSingleObject( win32.renderActiveEvent, 5000 );
  999. if ( r == WAIT_TIMEOUT ) {
  1000. common->FatalError( "GLimp_WakeBackEnd: WAIT_TIMEOUT" );
  1001. }
  1002. #ifdef DEBUG_PRINTS
  1003. OutputDebugString( "<--GLimp_WakeBackEnd\n" );
  1004. #endif
  1005. }
  1006. //===================================================================
  1007. /*
  1008. ===================
  1009. GLimp_ExtensionPointer
  1010. Returns a function pointer for an OpenGL extension entry point
  1011. ===================
  1012. */
  1013. GLExtension_t GLimp_ExtensionPointer( const char *name ) {
  1014. void (*proc)(void);
  1015. proc = (GLExtension_t)qwglGetProcAddress( name );
  1016. if ( !proc ) {
  1017. common->Printf( "Couldn't find proc address for: %s\n", name );
  1018. }
  1019. return proc;
  1020. }
  1021. #endif