123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617 |
- /*
- Copyright (C) 1997-2001 Id Software, Inc.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- /*
- ** GLW_IMP.C
- **
- ** This file contains ALL Win32 specific stuff having to do with the
- ** OpenGL refresh. When a port is being made the following functions
- ** must be implemented by the port:
- **
- ** GLimp_EndFrame
- ** GLimp_Init
- ** GLimp_Shutdown
- ** GLimp_SwitchFullscreen
- **
- */
- #include <assert.h>
- #include <windows.h>
- #include "../ref_gl/gl_local.h"
- #include "glw_win.h"
- #include "winquake.h"
- static qboolean GLimp_SwitchFullscreen( int width, int height );
- qboolean GLimp_InitGL (void);
- glwstate_t glw_state;
- extern cvar_t *vid_fullscreen;
- extern cvar_t *vid_ref;
- static qboolean VerifyDriver( void )
- {
- char buffer[1024];
- strcpy( buffer, qglGetString( GL_RENDERER ) );
- strlwr( buffer );
- if ( strcmp( buffer, "gdi generic" ) == 0 )
- if ( !glw_state.mcd_accelerated )
- return false;
- return true;
- }
- /*
- ** VID_CreateWindow
- */
- #define WINDOW_CLASS_NAME "Quake 2"
- qboolean VID_CreateWindow( int width, int height, qboolean fullscreen )
- {
- WNDCLASS wc;
- RECT r;
- cvar_t *vid_xpos, *vid_ypos;
- int stylebits;
- int x, y, w, h;
- int exstyle;
- /* Register the frame class */
- wc.style = 0;
- wc.lpfnWndProc = (WNDPROC)glw_state.wndproc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hInstance = glw_state.hInstance;
- wc.hIcon = 0;
- wc.hCursor = LoadCursor (NULL,IDC_ARROW);
- wc.hbrBackground = (void *)COLOR_GRAYTEXT;
- wc.lpszMenuName = 0;
- wc.lpszClassName = WINDOW_CLASS_NAME;
- if (!RegisterClass (&wc) )
- ri.Sys_Error (ERR_FATAL, "Couldn't register window class");
- if (fullscreen)
- {
- exstyle = WS_EX_TOPMOST;
- stylebits = WS_POPUP|WS_VISIBLE;
- }
- else
- {
- exstyle = 0;
- stylebits = WINDOW_STYLE;
- }
- r.left = 0;
- r.top = 0;
- r.right = width;
- r.bottom = height;
- AdjustWindowRect (&r, stylebits, FALSE);
- w = r.right - r.left;
- h = r.bottom - r.top;
- if (fullscreen)
- {
- x = 0;
- y = 0;
- }
- else
- {
- vid_xpos = ri.Cvar_Get ("vid_xpos", "0", 0);
- vid_ypos = ri.Cvar_Get ("vid_ypos", "0", 0);
- x = vid_xpos->value;
- y = vid_ypos->value;
- }
- glw_state.hWnd = CreateWindowEx (
- exstyle,
- WINDOW_CLASS_NAME,
- "Quake 2",
- stylebits,
- x, y, w, h,
- NULL,
- NULL,
- glw_state.hInstance,
- NULL);
- if (!glw_state.hWnd)
- ri.Sys_Error (ERR_FATAL, "Couldn't create window");
-
- ShowWindow( glw_state.hWnd, SW_SHOW );
- UpdateWindow( glw_state.hWnd );
- // init all the gl stuff for the window
- if (!GLimp_InitGL ())
- {
- ri.Con_Printf( PRINT_ALL, "VID_CreateWindow() - GLimp_InitGL failed\n");
- return false;
- }
- SetForegroundWindow( glw_state.hWnd );
- SetFocus( glw_state.hWnd );
- // let the sound and input subsystems know about the new window
- ri.Vid_NewWindow (width, height);
- return true;
- }
- /*
- ** GLimp_SetMode
- */
- rserr_t GLimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
- {
- int width, height;
- const char *win_fs[] = { "W", "FS" };
- ri.Con_Printf( PRINT_ALL, "Initializing OpenGL display\n");
- ri.Con_Printf (PRINT_ALL, "...setting mode %d:", mode );
- if ( !ri.Vid_GetModeInfo( &width, &height, mode ) )
- {
- ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
- return rserr_invalid_mode;
- }
- ri.Con_Printf( PRINT_ALL, " %d %d %s\n", width, height, win_fs[fullscreen] );
- // destroy the existing window
- if (glw_state.hWnd)
- {
- GLimp_Shutdown ();
- }
- // do a CDS if needed
- if ( fullscreen )
- {
- DEVMODE dm;
- ri.Con_Printf( PRINT_ALL, "...attempting fullscreen\n" );
- memset( &dm, 0, sizeof( dm ) );
- dm.dmSize = sizeof( dm );
- dm.dmPelsWidth = width;
- dm.dmPelsHeight = height;
- dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
- if ( gl_bitdepth->value != 0 )
- {
- dm.dmBitsPerPel = gl_bitdepth->value;
- dm.dmFields |= DM_BITSPERPEL;
- ri.Con_Printf( PRINT_ALL, "...using gl_bitdepth of %d\n", ( int ) gl_bitdepth->value );
- }
- else
- {
- HDC hdc = GetDC( NULL );
- int bitspixel = GetDeviceCaps( hdc, BITSPIXEL );
- ri.Con_Printf( PRINT_ALL, "...using desktop display depth of %d\n", bitspixel );
- ReleaseDC( 0, hdc );
- }
- ri.Con_Printf( PRINT_ALL, "...calling CDS: " );
- if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) == DISP_CHANGE_SUCCESSFUL )
- {
- *pwidth = width;
- *pheight = height;
- gl_state.fullscreen = true;
- ri.Con_Printf( PRINT_ALL, "ok\n" );
- if ( !VID_CreateWindow (width, height, true) )
- return rserr_invalid_mode;
- return rserr_ok;
- }
- else
- {
- *pwidth = width;
- *pheight = height;
- ri.Con_Printf( PRINT_ALL, "failed\n" );
- ri.Con_Printf( PRINT_ALL, "...calling CDS assuming dual monitors:" );
- dm.dmPelsWidth = width * 2;
- dm.dmPelsHeight = height;
- dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
- if ( gl_bitdepth->value != 0 )
- {
- dm.dmBitsPerPel = gl_bitdepth->value;
- dm.dmFields |= DM_BITSPERPEL;
- }
- /*
- ** our first CDS failed, so maybe we're running on some weird dual monitor
- ** system
- */
- if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) != DISP_CHANGE_SUCCESSFUL )
- {
- ri.Con_Printf( PRINT_ALL, " failed\n" );
- ri.Con_Printf( PRINT_ALL, "...setting windowed mode\n" );
- ChangeDisplaySettings( 0, 0 );
- *pwidth = width;
- *pheight = height;
- gl_state.fullscreen = false;
- if ( !VID_CreateWindow (width, height, false) )
- return rserr_invalid_mode;
- return rserr_invalid_fullscreen;
- }
- else
- {
- ri.Con_Printf( PRINT_ALL, " ok\n" );
- if ( !VID_CreateWindow (width, height, true) )
- return rserr_invalid_mode;
- gl_state.fullscreen = true;
- return rserr_ok;
- }
- }
- }
- else
- {
- ri.Con_Printf( PRINT_ALL, "...setting windowed mode\n" );
- ChangeDisplaySettings( 0, 0 );
- *pwidth = width;
- *pheight = height;
- gl_state.fullscreen = false;
- if ( !VID_CreateWindow (width, height, false) )
- return rserr_invalid_mode;
- }
- return rserr_ok;
- }
- /*
- ** GLimp_Shutdown
- **
- ** This routine does all OS specific shutdown procedures for the OpenGL
- ** subsystem. Under OpenGL this means NULLing out the current DC and
- ** HGLRC, deleting the rendering context, and releasing the DC acquired
- ** for the window. The state structure is also nulled out.
- **
- */
- void GLimp_Shutdown( void )
- {
- if ( qwglMakeCurrent && !qwglMakeCurrent( NULL, NULL ) )
- ri.Con_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - wglMakeCurrent failed\n");
- if ( glw_state.hGLRC )
- {
- if ( qwglDeleteContext && !qwglDeleteContext( glw_state.hGLRC ) )
- ri.Con_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - wglDeleteContext failed\n");
- glw_state.hGLRC = NULL;
- }
- if (glw_state.hDC)
- {
- if ( !ReleaseDC( glw_state.hWnd, glw_state.hDC ) )
- ri.Con_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - ReleaseDC failed\n" );
- glw_state.hDC = NULL;
- }
- if (glw_state.hWnd)
- {
- DestroyWindow ( glw_state.hWnd );
- glw_state.hWnd = NULL;
- }
- if ( glw_state.log_fp )
- {
- fclose( glw_state.log_fp );
- glw_state.log_fp = 0;
- }
- UnregisterClass (WINDOW_CLASS_NAME, glw_state.hInstance);
- if ( gl_state.fullscreen )
- {
- ChangeDisplaySettings( 0, 0 );
- gl_state.fullscreen = false;
- }
- }
- /*
- ** GLimp_Init
- **
- ** This routine is responsible for initializing the OS specific portions
- ** of OpenGL. Under Win32 this means dealing with the pixelformats and
- ** doing the wgl interface stuff.
- */
- qboolean GLimp_Init( void *hinstance, void *wndproc )
- {
- #define OSR2_BUILD_NUMBER 1111
- OSVERSIONINFO vinfo;
- vinfo.dwOSVersionInfoSize = sizeof(vinfo);
- glw_state.allowdisplaydepthchange = false;
- if ( GetVersionEx( &vinfo) )
- {
- if ( vinfo.dwMajorVersion > 4 )
- {
- glw_state.allowdisplaydepthchange = true;
- }
- else if ( vinfo.dwMajorVersion == 4 )
- {
- if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
- {
- glw_state.allowdisplaydepthchange = true;
- }
- else if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
- {
- if ( LOWORD( vinfo.dwBuildNumber ) >= OSR2_BUILD_NUMBER )
- {
- glw_state.allowdisplaydepthchange = true;
- }
- }
- }
- }
- else
- {
- ri.Con_Printf( PRINT_ALL, "GLimp_Init() - GetVersionEx failed\n" );
- return false;
- }
- glw_state.hInstance = ( HINSTANCE ) hinstance;
- glw_state.wndproc = wndproc;
- return true;
- }
- qboolean GLimp_InitGL (void)
- {
- PIXELFORMATDESCRIPTOR pfd =
- {
- sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
- 1, // version number
- PFD_DRAW_TO_WINDOW | // support window
- PFD_SUPPORT_OPENGL | // support OpenGL
- PFD_DOUBLEBUFFER, // double buffered
- PFD_TYPE_RGBA, // RGBA type
- 24, // 24-bit color depth
- 0, 0, 0, 0, 0, 0, // color bits ignored
- 0, // no alpha buffer
- 0, // shift bit ignored
- 0, // no accumulation buffer
- 0, 0, 0, 0, // accum bits ignored
- 32, // 32-bit z-buffer
- 0, // no stencil buffer
- 0, // no auxiliary buffer
- PFD_MAIN_PLANE, // main layer
- 0, // reserved
- 0, 0, 0 // layer masks ignored
- };
- int pixelformat;
- cvar_t *stereo;
-
- stereo = ri.Cvar_Get( "cl_stereo", "0", 0 );
- /*
- ** set PFD_STEREO if necessary
- */
- if ( stereo->value != 0 )
- {
- ri.Con_Printf( PRINT_ALL, "...attempting to use stereo\n" );
- pfd.dwFlags |= PFD_STEREO;
- gl_state.stereo_enabled = true;
- }
- else
- {
- gl_state.stereo_enabled = false;
- }
- /*
- ** figure out if we're running on a minidriver or not
- */
- if ( strstr( gl_driver->string, "opengl32" ) != 0 )
- glw_state.minidriver = false;
- else
- glw_state.minidriver = true;
- /*
- ** Get a DC for the specified window
- */
- if ( glw_state.hDC != NULL )
- ri.Con_Printf( PRINT_ALL, "GLimp_Init() - non-NULL DC exists\n" );
- if ( ( glw_state.hDC = GetDC( glw_state.hWnd ) ) == NULL )
- {
- ri.Con_Printf( PRINT_ALL, "GLimp_Init() - GetDC failed\n" );
- return false;
- }
- if ( glw_state.minidriver )
- {
- if ( (pixelformat = qwglChoosePixelFormat( glw_state.hDC, &pfd)) == 0 )
- {
- ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglChoosePixelFormat failed\n");
- return false;
- }
- if ( qwglSetPixelFormat( glw_state.hDC, pixelformat, &pfd) == FALSE )
- {
- ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglSetPixelFormat failed\n");
- return false;
- }
- qwglDescribePixelFormat( glw_state.hDC, pixelformat, sizeof( pfd ), &pfd );
- }
- else
- {
- if ( ( pixelformat = ChoosePixelFormat( glw_state.hDC, &pfd)) == 0 )
- {
- ri.Con_Printf (PRINT_ALL, "GLimp_Init() - ChoosePixelFormat failed\n");
- return false;
- }
- if ( SetPixelFormat( glw_state.hDC, pixelformat, &pfd) == FALSE )
- {
- ri.Con_Printf (PRINT_ALL, "GLimp_Init() - SetPixelFormat failed\n");
- return false;
- }
- DescribePixelFormat( glw_state.hDC, pixelformat, sizeof( pfd ), &pfd );
- if ( !( pfd.dwFlags & PFD_GENERIC_ACCELERATED ) )
- {
- extern cvar_t *gl_allow_software;
- if ( gl_allow_software->value )
- glw_state.mcd_accelerated = true;
- else
- glw_state.mcd_accelerated = false;
- }
- else
- {
- glw_state.mcd_accelerated = true;
- }
- }
- /*
- ** report if stereo is desired but unavailable
- */
- if ( !( pfd.dwFlags & PFD_STEREO ) && ( stereo->value != 0 ) )
- {
- ri.Con_Printf( PRINT_ALL, "...failed to select stereo pixel format\n" );
- ri.Cvar_SetValue( "cl_stereo", 0 );
- gl_state.stereo_enabled = false;
- }
- /*
- ** startup the OpenGL subsystem by creating a context and making
- ** it current
- */
- if ( ( glw_state.hGLRC = qwglCreateContext( glw_state.hDC ) ) == 0 )
- {
- ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglCreateContext failed\n");
- goto fail;
- }
- if ( !qwglMakeCurrent( glw_state.hDC, glw_state.hGLRC ) )
- {
- ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglMakeCurrent failed\n");
- goto fail;
- }
- if ( !VerifyDriver() )
- {
- ri.Con_Printf( PRINT_ALL, "GLimp_Init() - no hardware acceleration detected\n" );
- goto fail;
- }
- /*
- ** print out PFD specifics
- */
- ri.Con_Printf( PRINT_ALL, "GL PFD: color(%d-bits) Z(%d-bit)\n", ( int ) pfd.cColorBits, ( int ) pfd.cDepthBits );
- return true;
- fail:
- if ( glw_state.hGLRC )
- {
- qwglDeleteContext( glw_state.hGLRC );
- glw_state.hGLRC = NULL;
- }
- if ( glw_state.hDC )
- {
- ReleaseDC( glw_state.hWnd, glw_state.hDC );
- glw_state.hDC = NULL;
- }
- return false;
- }
- /*
- ** GLimp_BeginFrame
- */
- void GLimp_BeginFrame( float camera_separation )
- {
- if ( gl_bitdepth->modified )
- {
- if ( gl_bitdepth->value != 0 && !glw_state.allowdisplaydepthchange )
- {
- ri.Cvar_SetValue( "gl_bitdepth", 0 );
- ri.Con_Printf( PRINT_ALL, "gl_bitdepth requires Win95 OSR2.x or WinNT 4.x\n" );
- }
- gl_bitdepth->modified = false;
- }
- if ( camera_separation < 0 && gl_state.stereo_enabled )
- {
- qglDrawBuffer( GL_BACK_LEFT );
- }
- else if ( camera_separation > 0 && gl_state.stereo_enabled )
- {
- qglDrawBuffer( GL_BACK_RIGHT );
- }
- else
- {
- qglDrawBuffer( GL_BACK );
- }
- }
- /*
- ** GLimp_EndFrame
- **
- ** Responsible for doing a swapbuffers and possibly for other stuff
- ** as yet to be determined. Probably better not to make this a GLimp
- ** function and instead do a call to GLimp_SwapBuffers.
- */
- void GLimp_EndFrame (void)
- {
- int err;
- err = qglGetError();
- assert( err == GL_NO_ERROR );
- if ( stricmp( gl_drawbuffer->string, "GL_BACK" ) == 0 )
- {
- if ( !qwglSwapBuffers( glw_state.hDC ) )
- ri.Sys_Error( ERR_FATAL, "GLimp_EndFrame() - SwapBuffers() failed!\n" );
- }
- }
- /*
- ** GLimp_AppActivate
- */
- void GLimp_AppActivate( qboolean active )
- {
- if ( active )
- {
- SetForegroundWindow( glw_state.hWnd );
- ShowWindow( glw_state.hWnd, SW_RESTORE );
- }
- else
- {
- if ( vid_fullscreen->value )
- ShowWindow( glw_state.hWnd, SW_MINIMIZE );
- }
- }
|