summaryrefslogtreecommitdiff
path: root/source/cl_ref.c
diff options
context:
space:
mode:
authorAndrey Nazarov <skuller@skuller.net>2007-08-14 20:18:08 +0000
committerAndrey Nazarov <skuller@skuller.net>2007-08-14 20:18:08 +0000
commitf294db4ccf45f6274e65260dd6f9a2c5faa94313 (patch)
treee8cf1ba2bfe9c8417eec17faf912442f52fc4ef2 /source/cl_ref.c
Initial import of the new Q2PRO tree.
Diffstat (limited to 'source/cl_ref.c')
-rw-r--r--source/cl_ref.c433
1 files changed, 433 insertions, 0 deletions
diff --git a/source/cl_ref.c b/source/cl_ref.c
new file mode 100644
index 0000000..56bd56b
--- /dev/null
+++ b/source/cl_ref.c
@@ -0,0 +1,433 @@
+/*
+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.
+
+*/
+
+// Main windowed and fullscreen graphics interface module. This module
+// is used for both the software and OpenGL rendering versions of the
+// Quake refresh engine.
+
+
+#include "cl_local.h"
+#include "vid_public.h"
+#include "vid_local.h"
+
+// Structure containing functions exported from refresh DLL
+refAPI_t ref;
+
+// Console variables that we need to access from this module
+cvar_t *vid_ref; // Name of Refresh DLL loaded
+cvar_t *vid_placement;
+cvar_t *vid_modelist;
+cvar_t *vid_fullscreen;
+
+#define MODE_PLACEMENT 1
+#define MODE_FULLSCREEN 2
+#define MODE_MODELIST 4
+#define MODE_REFRESH 8
+
+static int mode_changed;
+
+
+#ifdef REF_HARD_LINKED
+qboolean Ref_APISetupCallback( api_type_t type, void *api );
+#else
+// Global variables used internally by this module
+static void *reflib_library; // Handle to refresh DLL
+#endif
+
+/*
+==========================================================================
+
+HELPER FUNCTIONS
+
+==========================================================================
+*/
+
+// 640x480 800x600 1024x768
+// 640x480@75
+// 640x480@75:32
+// 640x480:32@75
+void Video_GetModeFS( vrect_t *rc, int *freq, int *depth ) {
+ char *s = vid_modelist->string;
+ int mode = 1;
+ int w = 640, h = 480, hz = 0, bpp = 0;
+
+ while( *s ) {
+ w = strtoul( s, &s, 10 );
+ if( *s != 'x' ) {
+ Com_DPrintf( "Mode %d is malformed\n", mode );
+ goto malformed;
+ }
+ h = strtoul( s + 1, &s, 10 );
+ if( *s == '@' ) {
+ hz = strtoul( s + 1, &s, 10 );
+ if( *s == ':' ) {
+ bpp = strtoul( s + 1, &s, 10 );
+ }
+ } else if( *s == ':' ) {
+ bpp = strtoul( s + 1, &s, 10 );
+ if( *s == '@' ) {
+ hz = strtoul( s + 1, &s, 10 );
+ }
+ }
+ if( mode == vid_fullscreen->integer ) {
+ break;
+ }
+ if( *s == 0 ) {
+ Com_DPrintf( "Mode %d not found\n", vid_fullscreen->integer );
+ break;
+ }
+ s++;
+ mode++;
+ }
+
+ // sanity check
+ if( w < 1 || w > 8192 || h < 1 || h > 8192 ) {
+ Com_DPrintf( "Mode %dx%d doesn't look sane\n", w, h );
+malformed:
+ w = 640;
+ h = 480;
+ hz = 0;
+ bpp = 0;
+ }
+
+ rc->x = 0;
+ rc->y = 0;
+ rc->width = w;
+ rc->height = h;
+
+ if( freq ) {
+ *freq = hz;
+ }
+ if( depth ) {
+ *depth = bpp;
+ }
+}
+
+// 640x480
+// 640x480+0
+// 640x480+0+0
+void Video_GetPlacement( vrect_t *rc ) {
+ char *s = vid_placement->string;
+ int w = 640, h = 480, x = 0, y = 0;
+
+ w = strtoul( s, &s, 10 );
+ if( *s != 'x' ) {
+ Com_DPrintf( "Placement string is malformed\n" );
+ goto malformed;
+ }
+ h = strtoul( s + 1, &s, 10 );
+ if( *s == '+' ) {
+ x = strtoul( s + 1, &s, 10 );
+ if( *s == '+' ) {
+ y = strtoul( s + 1, &s, 10 );
+ }
+ }
+
+ // sanity check
+ if( x < 0 || x > 8192 || y < 0 || y > 8192 ) {
+ x = 0;
+ y = 0;
+ }
+ if( w < 1 || w > 8192 || h < 1 || h > 8192 ) {
+malformed:
+ w = 640;
+ h = 480;
+ }
+
+ rc->x = x;
+ rc->y = y;
+ rc->width = w;
+ rc->height = h;
+}
+
+
+void Video_SetPlacement( vrect_t *rc ) {
+ char buffer[MAX_QPATH];
+
+ Com_sprintf( buffer, sizeof( buffer ), "%dx%d+%d+%d",
+ rc->width, rc->height, rc->x, rc->y );
+ Cvar_Set( "vid_placement", buffer );
+}
+
+/*
+==========================================================================
+
+LOADING / SHUTDOWN
+
+==========================================================================
+*/
+
+/*
+==============
+CL_FreeRefresh
+==============
+*/
+static void CL_FreeRefresh( void ) {
+#ifndef REF_HARD_LINKED
+ Sys_FreeLibrary( reflib_library );
+ reflib_library = NULL;
+#endif
+ memset( &ref, 0, sizeof( ref ) );
+ cls.ref_initialized = qfalse;
+}
+
+#ifndef REF_HARD_LINKED
+
+/*
+==============
+CL_RefSetupCallback
+==============
+*/
+static qboolean CL_RefSetupCallback( api_type_t type, void *api ) {
+ switch( type ) {
+ case API_CMD:
+ Cmd_FillAPI( ( cmdAPI_t * )api );
+ break;
+ case API_CVAR:
+ Cvar_FillAPI( ( cvarAPI_t * )api );
+ break;
+ case API_FS:
+ FS_FillAPI( ( fsAPI_t * )api );
+ break;
+ case API_COMMON:
+ Com_FillAPI( ( commonAPI_t * )api );
+ break;
+ case API_SYSTEM:
+ Sys_FillAPI( ( sysAPI_t * )api );
+ break;
+ case API_VIDEO_SOFTWARE:
+ Video_FillSWAPI( ( videoAPI_t * )api );
+ break;
+ case API_VIDEO_OPENGL:
+ Video_FillGLAPI( ( videoAPI_t * )api );
+ break;
+ default:
+ Com_Error( ERR_FATAL, "CL_RefSetupCallback: bad api type" );
+ }
+
+ return qtrue;
+}
+
+#endif
+
+/*
+==============
+CL_LoadRefresh
+==============
+*/
+static qboolean CL_LoadRefresh( const char *name ) {
+#ifndef REF_HARD_LINKED
+ char path[MAX_OSPATH];
+ moduleEntry_t entry;
+ moduleInfo_t info;
+ moduleCapability_t caps;
+ APISetupCallback_t callback;
+#endif
+
+ if( cls.ref_initialized ) {
+ ref.Shutdown( qtrue );
+ CL_FreeRefresh();
+ }
+
+ Com_Printf( "------- Loading %s -------\n", name );
+
+#ifdef REF_HARD_LINKED
+#ifdef SOFTWARE_RENDERER
+ Video_FillSWAPI( &video );
+#else
+ Video_FillGLAPI( &video );
+#endif
+
+ Ref_APISetupCallback( API_REFRESH, &ref );
+#else
+
+ Com_sprintf( path, sizeof( path ), "%s" PATH_SEP_STRING "%s" LIBSUFFIX,
+ sys_refdir->string, name );
+ entry = Sys_LoadLibrary( path, "moduleEntry", &reflib_library );
+ if( !entry ) {
+ Com_WPrintf( "Couldn't load %s\n", name );
+ return qfalse;
+ }
+
+ entry( MQ_GETINFO, &info );
+ if( info.api_version != MODULES_APIVERSION ) {
+ Com_WPrintf( "%s has incompatible api_version: %i, should be %i\n",
+ name, info.api_version, MODULES_APIVERSION );
+ goto fail;
+ }
+
+ caps = ( moduleCapability_t )entry( MQ_GETCAPS, NULL );
+ if( !( caps & MCP_REFRESH ) ) {
+ Com_WPrintf( "%s doesn't have REFRESH capability\n", name );
+ goto fail;
+ }
+
+ callback = ( APISetupCallback_t )entry( MQ_SETUPAPI, ( void * )CL_RefSetupCallback );
+ if( !callback ) {
+ Com_WPrintf( "%s returned NULL callback\n", name );
+ goto fail;
+ }
+
+ callback( API_REFRESH, &ref );
+#endif
+
+ cls.ref_initialized = qtrue;
+ if( !ref.Init( qtrue ) ) {
+ goto fail;
+ }
+
+ Com_Printf( "------------------------------------\n" );
+
+ return qtrue;
+
+fail:
+ CL_FreeRefresh();
+ return qfalse;
+}
+
+/*
+============
+CL_PumpEvents
+============
+*/
+void CL_PumpEvents( void ) {
+ if( !cls.ref_initialized ) {
+ return;
+ }
+
+ Video_PumpEvents();
+
+ if( mode_changed ) {
+#ifndef REF_HARD_LINKED
+ if( mode_changed & MODE_REFRESH ) {
+ Cbuf_AddText( "vid_restart\n" );
+ } else
+#endif
+ if( mode_changed & MODE_FULLSCREEN ) {
+ Video_ModeChanged();
+ } else {
+ if( vid_fullscreen->integer ) {
+ if( mode_changed & MODE_MODELIST ) {
+ Video_ModeChanged();
+ }
+ } else {
+ if( mode_changed & MODE_PLACEMENT ) {
+ Video_ModeChanged();
+ }
+ }
+ }
+ mode_changed = 0;
+ }
+}
+
+static void vid_placement_changed( cvar_t *self ) {
+ mode_changed |= MODE_PLACEMENT;
+}
+
+static void vid_fullscreen_changed( cvar_t *self ) {
+ mode_changed |= MODE_FULLSCREEN;
+}
+
+static void vid_modelist_changed( cvar_t *self ) {
+ mode_changed |= MODE_MODELIST;
+}
+
+#ifndef REF_HARD_LINKED
+static void vid_ref_changed( cvar_t *self ) {
+ mode_changed |= MODE_REFRESH;
+}
+#endif
+
+/*
+============
+CL_InitRefresh
+============
+*/
+void CL_InitRefresh( void ) {
+ if( cls.ref_initialized ) {
+ return;
+ }
+
+ // Create the video variables so we know how to start the graphics drivers
+ vid_placement = Cvar_Get( "vid_placement", "640x480", CVAR_ARCHIVE );
+ vid_fullscreen = Cvar_Get( "vid_fullscreen", "0", CVAR_ARCHIVE );
+ vid_modelist = Cvar_Get( "vid_modelist", "640x480", CVAR_ARCHIVE );
+
+#ifdef REF_HARD_LINKED
+ vid_ref = Cvar_Get( "vid_ref", DEFAULT_REFRESH_DRIVER, CVAR_ROM );
+ if( !CL_LoadRefresh( "ref_" DEFAULT_REFRESH_DRIVER ) ) {
+ Com_Error( ERR_FATAL, "Couldn't load built-in video driver!" );
+ }
+#else
+ vid_ref = Cvar_Get( "vid_ref", DEFAULT_REFRESH_DRIVER, CVAR_ARCHIVE );
+
+ // Start the graphics mode and load refresh DLL
+ while( 1 ) {
+ char buffer[MAX_QPATH];
+
+ Com_sprintf( buffer, sizeof( buffer ), "ref_%s", vid_ref->string );
+ if( CL_LoadRefresh( buffer ) ) {
+ break;
+ }
+
+ if( !strcmp( vid_ref->string, DEFAULT_REFRESH_DRIVER ) ) {
+ Com_Error( ERR_FATAL, "Couldn't fall back to %s driver!", buffer );
+ }
+
+ Com_Printf( "Falling back to default refresh...\n" );
+ Cvar_Set( "vid_ref", DEFAULT_REFRESH_DRIVER );
+ }
+#endif
+
+ vid_placement->changed = vid_placement_changed;
+ vid_fullscreen->changed = vid_fullscreen_changed;
+ vid_modelist->changed = vid_modelist_changed;
+#ifndef REF_HARD_LINKED
+ vid_ref->changed = vid_ref_changed;
+#endif
+
+ mode_changed = 0;
+}
+
+/*
+============
+CL_ShutdownRefresh
+============
+*/
+void CL_ShutdownRefresh( void ) {
+ if( !cls.ref_initialized ) {
+ return;
+ }
+
+ vid_placement->changed = NULL;
+ vid_fullscreen->changed = NULL;
+ vid_modelist->changed = NULL;
+#ifndef REF_HARD_LINKED
+ vid_ref->changed = NULL;
+#endif
+
+ ref.Shutdown( qtrue );
+ CL_FreeRefresh();
+
+ Z_LeakTest( TAG_RENDERER );
+}
+
+
+