1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 
21 // Main windowed and fullscreen graphics interface module. This module
22 // is used for both the software and OpenGL rendering versions of the
23 // Quake refresh engine.
24 
25 
26 #include "client.h"
27 #include "vid_public.h"
28 
29 // Structure containing functions exported from refresh DLL
30 refAPI_t	ref;
31 
32 // Console variables that we need to access from this module
33 cvar_t		*vid_ref;			// Name of Refresh DLL loaded
34 cvar_t		*vid_autorestart;
35 
36 #ifdef REF_HARD_LINKED
37 qboolean Ref_APISetupCallback( api_type_t type, void *api );
38 #else
39 // Global variables used internally by this module
40 static void		*reflib_library;		// Handle to refresh DLL
41 #endif
42 
43 /*
44 ==========================================================================
45 
46 LOADING / SHUTDOWN
47 
48 ==========================================================================
49 */
50 
51 /*
52 ==============
53 CL_FreeRefresh
54 ==============
55 */
CL_FreeRefresh(void)56 static void CL_FreeRefresh( void ) {
57 #ifndef REF_HARD_LINKED
58 	Sys_FreeModule( reflib_library );
59 	reflib_library = NULL;
60 #endif
61 	memset( &ref, 0, sizeof( ref ) );
62 	cls.ref_initialized = qfalse;
63 }
64 
65 #ifndef REF_HARD_LINKED
66 
67 /*
68 ==============
69 CL_RefSetupCallback
70 ==============
71 */
CL_RefSetupCallback(api_type_t type,void * api)72 static qboolean CL_RefSetupCallback( api_type_t type, void *api ) {
73 	switch( type ) {
74 	case API_CMD:
75 		Cmd_FillAPI( ( cmdAPI_t * )api );
76 		break;
77 	case API_CVAR:
78 		Cvar_FillAPI( ( cvarAPI_t * )api );
79 		break;
80 	case API_FS:
81 		FS_FillAPI( ( fsAPI_t * )api );
82 		break;
83 	case API_COMMON:
84 		Com_FillAPI( ( commonAPI_t * )api );
85 		break;
86 	case API_SYSTEM:
87 		Sys_FillAPI( ( sysAPI_t * )api );
88 		break;
89 	case API_VIDEO_SOFTWARE:
90 		Video_FillSWAPI( ( vidSWAPI_t * )api );
91 		break;
92 #ifndef _WIN32_WCE
93 	case API_VIDEO_OPENGL:
94 		Video_FillGLAPI( ( vidGLAPI_t * )api );
95 		break;
96 #endif
97 	default:
98 		Com_Error( ERR_FATAL, "CL_RefSetupCallback: bad api type" );
99 	}
100 
101 	return qtrue;
102 }
103 
104 #endif
105 
106 /*
107 ==============
108 CL_LoadRefresh
109 ==============
110 */
CL_LoadRefresh(const char * name)111 static qboolean CL_LoadRefresh( const char *name ) {
112 #ifndef REF_HARD_LINKED
113 	moduleEntry_t entry;
114 	moduleInfo_t info;
115 	moduleCapability_t caps;
116 	APISetupCallback_t callback;
117 #endif
118 
119 	if( cls.ref_initialized ) {
120 		ref.Shutdown( qtrue );
121 		CL_FreeRefresh();
122 	}
123 
124 	Com_Printf( "------- Loading %s -------\n", name );
125 
126 #ifdef REF_HARD_LINKED
127 #ifdef SOFTWARE_RENDERER
128 	Video_FillSWAPI( &video );
129 #else
130 	Video_FillGLAPI( &video );
131 #endif
132 
133 	Ref_APISetupCallback( API_REFRESH, &ref );
134 #else
135 
136 	if( ( entry = Sys_LoadModule( name, &reflib_library ) ) == NULL ) {
137 		Com_WPrintf( "Couldn't load %s\n", name );
138 		return qfalse;
139 	}
140 
141 	entry( MQ_GETINFO, &info );
142 	if( info.api_version != MODULES_APIVERSION ) {
143 		Com_WPrintf( "%s has incompatible api_version: %i, should be %i\n",
144 			name, info.api_version, MODULES_APIVERSION );
145 		goto fail;
146 	}
147 
148 	caps = ( moduleCapability_t )entry( MQ_GETCAPS, NULL );
149 	if( !( caps & MCP_REFRESH ) ) {
150 		Com_WPrintf( "%s doesn't have REFRESH capability\n", name );
151 		goto fail;
152 	}
153 
154 	callback = ( APISetupCallback_t )entry( MQ_SETUPAPI, ( void * )CL_RefSetupCallback );
155 	if( !callback ) {
156 		Com_WPrintf( "%s returned NULL callback\n", name );
157 		goto fail;
158 	}
159 
160 	callback( API_REFRESH, &ref );
161 #endif
162 
163 	cls.ref_initialized = qtrue;
164 	if( !ref.Init( qtrue ) ) {
165 		goto fail;
166 	}
167 
168 	Com_Printf( "------------------------------------\n" );
169 
170 	return qtrue;
171 
172 fail:
173 	CL_FreeRefresh();
174 	return qfalse;
175 }
176 
177 /*
178 ============
179 CL_PumpEvents
180 ============
181 */
CL_PumpEvents(void)182 void CL_PumpEvents( void ) {
183 	if( !cls.ref_initialized ) {
184         return;
185     }
186 
187 	Video_PumpEvents();
188 
189     if( cvar_latchedModified & ( 1 << CVAR_SYSTEM_VIDEO ) ) {
190         if( vid_autorestart->integer ) {
191             Cbuf_AddText( "vid_restart\n" );
192         }
193         cvar_latchedModified &= ~( 1 << CVAR_SYSTEM_VIDEO );
194     }
195 
196 }
197 
198 #if( defined REF_HARD_LINKED ) && ( defined OPENGL_RENDERER )
199 #define DEFAULT_REFRESH_DRIVER	"newgl"
200 #else
201 #define DEFAULT_REFRESH_DRIVER	"soft"
202 #endif
203 
204 /*
205 ============
206 CL_InitRefresh
207 ============
208 */
CL_InitRefresh(void)209 void CL_InitRefresh( void ) {
210 	if( cls.ref_initialized ) {
211 		return;
212 	}
213 
214 	/* Create the video variables so we know how to start the graphics drivers */
215 	vid_autorestart = Cvar_Get( "vid_autorestart", "0", 0 );
216 
217 #ifdef REF_HARD_LINKED
218 	vid_ref = Cvar_Get( "vid_ref", DEFAULT_REFRESH_DRIVER, CVAR_ROM );
219 	if( !CL_LoadRefresh( "ref_" DEFAULT_REFRESH_DRIVER ) ) {
220 		Com_Error( ERR_FATAL, "Couldn't load built-in video driver!" );
221 	}
222 #else
223 	vid_ref = Cvar_Get( "vid_ref", DEFAULT_REFRESH_DRIVER, CVAR_ARCHIVE|CVAR_LATCHED );
224 	vid_ref->subsystem = CVAR_SYSTEM_VIDEO;
225 
226 	/* Start the graphics mode and load refresh DLL */
227 	while( 1 ) {
228 		char buffer[MAX_QPATH];
229 
230 		if( !strcmp( vid_ref->string, "gl" ) ) {
231 			/* Temporary hack until I port ref_gl to the new refresh API */
232 			strcpy( buffer, "ref_newgl" );
233 		} else {
234 			Com_sprintf( buffer, sizeof( buffer ), "ref_%s", vid_ref->string );
235 		}
236 		if( CL_LoadRefresh( buffer ) ) {
237 			break;
238 		}
239 
240 		if( !strcmp( vid_ref->string, DEFAULT_REFRESH_DRIVER ) ) {
241 			Com_Error( ERR_FATAL, "Couldn't fall back to %s driver!", buffer );
242 		}
243 
244 		Com_Printf( "Falling back to default...\n" );
245 		Cvar_Set( "vid_ref", DEFAULT_REFRESH_DRIVER );
246 	}
247 #endif
248 
249 	cvar_latchedModified &= ~( 1 << CVAR_SYSTEM_VIDEO );
250 
251 }
252 
253 /*
254 ============
255 CL_ShutdownRefresh
256 ============
257 */
CL_ShutdownRefresh(void)258 void CL_ShutdownRefresh( void ) {
259 	if( !cls.ref_initialized ) {
260 		return;
261 	}
262 
263 	ref.Shutdown( qtrue );
264 	CL_FreeRefresh();
265 
266 	Z_LeakTest( TAG_RENDERER );
267 }
268 
269 
270 
271