1 /*
2 Copyright (C) 2003-2006 Andrey Nazarov
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 /*
22  * gl_main.c
23  *
24  */
25 
26 #ifdef USE_LIBPNG
27 #include <png.h>
28 #endif
29 
30 #ifdef USE_LIBJPEG
31 #ifndef USE_LIBPNG
32 #include <setjmp.h>
33 #endif
34 #include <jpeglib.h>
35 #endif
36 
37 #include "gl_local.h"
38 #include "version.h"
39 
40 /* declare imports for this module */
41 cmdAPI_t	cmd;
42 cvarAPI_t	cvar;
43 fsAPI_t		fs;
44 commonAPI_t	com;
45 sysAPI_t	sys;
46 vidGLAPI_t	video;
47 
48 viddef_t vid;
49 glRefdef_t glr;
50 glStatic_t gl_static;
51 glconfig_t gl_config;
52 statCounters_t  c;
53 
54 int registration_sequence;
55 
56 #ifdef USE_LIBJPEG
57 cvar_t *gl_screenshot_quality;
58 #endif
59 cvar_t *gl_znear;
60 cvar_t *gl_zfar;
61 cvar_t *gl_modulate;
62 cvar_t *gl_log;
63 cvar_t *gl_drawworld;
64 cvar_t *gl_drawentities;
65 cvar_t *gl_showtris;
66 cvar_t *gl_cull_nodes;
67 cvar_t *gl_cull_models;
68 cvar_t *gl_showstats;
69 cvar_t *gl_clear;
70 cvar_t *gl_novis;
71 cvar_t *gl_lockpvs;
72 cvar_t *gl_sort;
73 cvar_t *gl_primitives;
74 cvar_t *gl_sort;
75 cvar_t *gl_subdivide;
76 cvar_t *gl_fastsky;
77 cvar_t *gl_dynamic;
78 cvar_t *gl_fullbright;
79 cvar_t *gl_mode;
80 cvar_t *gl_custom_width;
81 cvar_t *gl_custom_height;
82 cvar_t *gl_swapinterval;
83 cvar_t *gl_hwgamma;
84 cvar_t *gl_fullscreen;
85 
GL_SetupFrustum(void)86 static void GL_SetupFrustum( void ) {
87     cplane_t *f;
88     vec3_t forward, left, up;
89     vec_t fovSin, fovCos, angle;
90 
91     angle = DEG2RAD( glr.fd.fov_x / 2 );
92     fovSin = sin( angle );
93     fovCos = cos( angle );
94 
95     VectorScale( glr.viewaxis[0], fovSin, forward );
96     VectorScale( glr.viewaxis[1], fovCos, left );
97 
98     /* right side */
99     f = &glr.frustumPlanes[0];
100     VectorAdd( forward, left, f->normal );
101     f->dist = DotProduct( glr.fd.vieworg, f->normal );
102     SetPlaneSignbits( f );
103 	SetPlaneType( f );
104 
105     /* left side */
106     f = &glr.frustumPlanes[1];
107     VectorSubtract( forward, left, f->normal );
108     f->dist = DotProduct( glr.fd.vieworg, f->normal );
109     SetPlaneSignbits( f );
110 	SetPlaneType( f );
111 
112     angle = DEG2RAD( glr.fd.fov_y / 2 );
113     fovSin = sin( angle );
114     fovCos = cos( angle );
115 
116     VectorScale( glr.viewaxis[0], fovSin, forward );
117     VectorScale( glr.viewaxis[2], fovCos, up );
118 
119     /* up side */
120     f = &glr.frustumPlanes[2];
121     VectorAdd( forward, up, f->normal );
122     f->dist = DotProduct( glr.fd.vieworg, f->normal );
123     SetPlaneSignbits( f );
124 	SetPlaneType( f );
125 
126     /* down side */
127     f = &glr.frustumPlanes[3];
128     VectorSubtract( forward, up, f->normal );
129     f->dist = DotProduct( glr.fd.vieworg, f->normal );
130     SetPlaneSignbits( f );
131 	SetPlaneType( f );
132 
133 }
134 
GL_Blend(void)135 static void GL_Blend( void ) {
136     color_t color;
137 
138     if( glr.fd.blend[3] == 0 ) {
139         return;
140     }
141 
142     color[0] = glr.fd.blend[0] * 255;
143     color[1] = glr.fd.blend[1] * 255;
144     color[2] = glr.fd.blend[2] * 255;
145     color[3] = glr.fd.blend[3] * 255;
146 
147     GL_StretchPic( 0, 0, vid.width, vid.height, 0, 0, 1, 1, color,
148             r_whiteimage );
149 }
150 
GL_CullBox(vec3_t bounds[2])151 glCullResult_t GL_CullBox( vec3_t bounds[2] ) {
152     int i, bits;
153 	glCullResult_t cull;
154 
155 	if( !gl_cull_models->integer ) {
156 		return CULL_IN;
157 	}
158 
159 	cull = CULL_IN;
160     for( i = 0; i < 4; i++ ) {
161         bits = BoxOnPlaneSide( bounds[0], bounds[1], &glr.frustumPlanes[i] );
162         if( bits == BOX_BEHIND ) {
163             return CULL_OUT;
164         }
165 		if( bits != BOX_INFRONT ) {
166 			cull = CULL_CLIP;
167 		}
168     }
169 
170     return cull;
171 }
172 
GL_CullSphere(const vec3_t origin,float radius)173 glCullResult_t GL_CullSphere( const vec3_t origin, float radius ) {
174 	float dist;
175 	cplane_t *p;
176 	int i;
177 	glCullResult_t cull;
178 
179 	if( !gl_cull_models->integer ) {
180 		return CULL_IN;
181 	}
182 
183 	cull = CULL_IN;
184 	for( i = 0, p = glr.frustumPlanes; i < 4; i++, p++ ) {
185 		dist = DotProduct( origin, p->normal ) - p->dist;
186 		if( dist < -radius ) {
187 			return CULL_OUT;
188 		}
189 		if( dist <= radius ) {
190 			cull = CULL_CLIP;
191 		}
192 	}
193 
194 	return cull;
195 }
196 
GL_CullLocalBox(const vec3_t origin,vec3_t bounds[2])197 glCullResult_t GL_CullLocalBox( const vec3_t origin, vec3_t bounds[2] ) {
198 	vec3_t points[8];
199 	cplane_t *p;
200 	int i, j;
201 	vec_t dot;
202 	qboolean infront;
203 	glCullResult_t cull;
204 
205 	if( !gl_cull_models->integer ) {
206 		return CULL_IN;
207 	}
208 
209 	for( i = 0; i < 8; i++ ) {
210 		VectorCopy( origin, points[i] );
211 		VectorMA( points[i], bounds[(i>>0)&1][0], glr.entaxis[0], points[i] );
212 		VectorMA( points[i], bounds[(i>>1)&1][1], glr.entaxis[1], points[i] );
213 		VectorMA( points[i], bounds[(i>>2)&1][2], glr.entaxis[2], points[i] );
214 	}
215 
216 	cull = CULL_IN;
217 	for( i = 0, p = glr.frustumPlanes; i < 4; i++, p++ ) {
218 		infront = qfalse;
219 		for( j = 0; j < 8; j++ ) {
220 			dot = DotProduct( points[j], p->normal );
221 			if( dot >= p->dist ) {
222 				infront = qtrue;
223 				if( cull == CULL_CLIP ) {
224 					break;
225 				}
226 			} else {
227 				cull = CULL_CLIP;
228 				if( infront ) {
229 					break;
230 				}
231 			}
232 		}
233 		if( !infront ) {
234 			return CULL_OUT;
235 		}
236 	}
237 
238 	return cull;
239 }
240 
GL_DrawBox(const vec3_t origin,vec3_t bounds[2])241 void GL_DrawBox( const vec3_t origin, vec3_t bounds[2] ) {
242 	static int indices[2][4] = {
243 		{ 0, 1, 3, 2 },
244 		{ 4, 5, 7, 6 }
245 	};
246 	vec3_t points[8];
247 	int i, j;
248 
249 	qglDisable( GL_TEXTURE_2D );
250     GL_TexEnv( GL_REPLACE );
251     qglDisable( GL_DEPTH_TEST );
252     qglColor4f( 1, 1, 1, 1 );
253 
254 	for( i = 0; i < 8; i++ ) {
255 		VectorCopy( origin, points[i] );
256 		VectorMA( points[i], bounds[(i>>0)&1][0], glr.entaxis[0], points[i] );
257 		VectorMA( points[i], bounds[(i>>1)&1][1], glr.entaxis[1], points[i] );
258 		VectorMA( points[i], bounds[(i>>2)&1][2], glr.entaxis[2], points[i] );
259 	}
260 
261 	for( i = 0; i < 2; i++ ) {
262 		qglBegin( GL_LINE_LOOP );
263 		for( j = 0; j < 4; j++ ) {
264 			qglVertex3fv( points[ indices[i][j] ] );
265 		}
266 		qglEnd();
267 	}
268 
269 	qglBegin( GL_LINES );
270 	for( i = 0; i < 4; i++ ) {
271 		qglVertex3fv( points[ i     ] );
272 		qglVertex3fv( points[ i + 4 ] );
273 	}
274 	qglEnd();
275 
276 	qglEnable( GL_DEPTH_TEST );
277     qglEnable( GL_TEXTURE_2D );
278 
279 }
280 
GL_DrawSpriteModel(model_t * model)281 static void GL_DrawSpriteModel( model_t *model ) {
282 	vec3_t point;
283 	entity_t *e = glr.ent;
284 	spriteFrame_t *frame;
285 	image_t *image;
286 	int idx, bits;
287 	float alpha;
288 
289 	idx = e->frame % model->numFrames;
290 	frame = &model->sframes[idx];
291 	image = frame->image;
292 
293 	GL_TexEnv( GL_MODULATE );
294 
295 	alpha = 1;
296 	bits = GLS_DEFAULT;
297 	if( e->flags & RF_TRANSLUCENT ) {
298 		alpha = e->alpha;
299 		bits = GLS_BLEND_BLEND;
300 	}
301 
302 	GL_Bits( bits );
303 
304 	qglColor4f( 1, 1, 1, alpha );
305 
306 	GL_BindTexture( image->texnum );
307 
308 	qglBegin( GL_QUADS );
309 
310 	qglTexCoord2f( 0, 1 );
311 	VectorMA( e->origin, -frame->y, glr.viewaxis[2], point );
312 	VectorMA( point, frame->x, glr.viewaxis[1], point );
313 	qglVertex3fv( point );
314 
315 	qglTexCoord2f( 0, 0 );
316 	VectorMA( e->origin, frame->height - frame->y, glr.viewaxis[2], point );
317 	VectorMA( point, frame->x, glr.viewaxis[1], point );
318 	qglVertex3fv( point );
319 
320 	qglTexCoord2f( 1, 0 );
321 	VectorMA( e->origin, frame->height - frame->y, glr.viewaxis[2], point );
322 	VectorMA( point, frame->x - frame->width, glr.viewaxis[1], point );
323 	qglVertex3fv( point );
324 
325 	qglTexCoord2f( 1, 1 );
326 	VectorMA( e->origin, -frame->y, glr.viewaxis[2], point );
327 	VectorMA( point, frame->x - frame->width, glr.viewaxis[1], point );
328 	qglVertex3fv( point );
329 
330 	qglEnd();
331 }
332 
GL_DrawNullModel(void)333 static void GL_DrawNullModel( void ) {
334 	vec3_t point;
335 
336 	qglDisable( GL_TEXTURE_2D );
337     //qglDisable( GL_DEPTH_TEST );
338 	qglBegin( GL_LINES );
339 
340 	qglColor3f( 1, 0, 0 );
341 	qglVertex3fv( glr.ent->origin );
342 	VectorMA( glr.ent->origin, 16, glr.entaxis[0], point );
343 	qglVertex3fv( point );
344 
345 	qglColor3f( 0, 1, 0 );
346 	qglVertex3fv( glr.ent->origin );
347 	VectorMA( glr.ent->origin, 16, glr.entaxis[1], point );
348 	qglVertex3fv( point );
349 
350 	qglColor3f( 0, 0, 1 );
351 	qglVertex3fv( glr.ent->origin );
352 	VectorMA( glr.ent->origin, 16, glr.entaxis[2], point );
353 	qglVertex3fv( point );
354 
355 	qglEnd();
356 	//qglEnable( GL_DEPTH_TEST );
357 	qglEnable( GL_TEXTURE_2D );
358 }
359 
GL_DrawEntities(int mask)360 static void GL_DrawEntities( int mask ) {
361 	entity_t *ent, *last;
362 	modelType_t *model;
363 
364 	if( !gl_drawentities->integer ) {
365 		return;
366 	}
367 
368 	last = glr.fd.entities + glr.fd.num_entities;
369 	for( ent = glr.fd.entities; ent != last; ent++ ) {
370 		if( ent->flags & RF_BEAM ) {
371 			/* beams are drawn elsewhere in single batch */
372             glr.num_beams++;
373 			continue;
374 		}
375 		if( ( ent->flags & RF_TRANSLUCENT ) != mask ) {
376 			continue;
377 		}
378 
379 		glr.ent = ent;
380 		if( ent->angles[0] || ent->angles[1] || ent->angles[2] ) {
381 			glr.entrotated = qtrue;
382 			AngleVectors( ent->angles, glr.entaxis[0], glr.entaxis[1], glr.entaxis[2] );
383 			VectorInverse( glr.entaxis[1] );
384 		} else {
385 			glr.entrotated = qfalse;
386 			VectorSet( glr.entaxis[0], 1, 0, 0 );
387 			VectorSet( glr.entaxis[1], 0, 1, 0 );
388 			VectorSet( glr.entaxis[2], 0, 0, 1 );
389 		}
390 
391 		model = GL_ModelForHandle( ent->model );
392 		if( !model ) {
393 			GL_DrawNullModel();
394 			continue;
395 		}
396 
397 		switch( *model ) {
398 		case MODEL_NULL:
399 			GL_DrawNullModel();
400 			break;
401 		case MODEL_BSP:
402 			GL_DrawBspModel( ( bspSubmodel_t * )model );
403 			break;
404 		case MODEL_ALIAS:
405 			GL_DrawAliasModel( ( model_t * )model );
406 			break;
407 		case MODEL_SPRITE:
408 			GL_DrawSpriteModel( ( model_t * )model );
409 			break;
410 		default:
411 			Com_Error( ERR_FATAL, "GL_DrawEntities: bad model type: %u", *model );
412 			break;
413 		}
414 	}
415 }
416 
GL_ErrorString(GLenum err)417 static char *GL_ErrorString( GLenum err ) {
418 	char *str;
419 
420 #define MapError( x )	case x: str = #x; break;
421 
422 	switch( err ) {
423 		MapError( GL_NO_ERROR )
424 		MapError( GL_INVALID_ENUM )
425 		MapError( GL_INVALID_VALUE )
426 		MapError( GL_INVALID_OPERATION )
427 		MapError( GL_STACK_OVERFLOW )
428 		MapError( GL_STACK_UNDERFLOW )
429 		MapError( GL_OUT_OF_MEMORY )
430 		default: str = "UNKNOWN ERROR";
431 	}
432 
433 #undef MapError
434 
435 	return str;
436 }
437 
GL_RenderFrame(refdef_t * fd)438 static void GL_RenderFrame( refdef_t *fd ) {
439 	GLenum err;
440 
441 	GL_Flush2D();
442 
443     if( !r_world.name[0] && !( fd->rdflags & RDF_NOWORLDMODEL ) ) {
444         Com_Error( ERR_FATAL, "GL_RenderView: NULL worldmodel" );
445     }
446 
447 	glr.drawframe++;
448 
449     glr.fd = *fd;
450     glr.num_beams = 0;
451 
452     AngleVectors( glr.fd.viewangles, glr.viewaxis[0], glr.viewaxis[1], glr.viewaxis[2] );
453 	VectorInverse( glr.viewaxis[1] );
454 
455 	glr.scroll = -64 * ( ( glr.fd.time / 40.0f ) - ( int )( glr.fd.time / 40.0f ) );
456 	if( glr.scroll == 0 )
457 		glr.scroll = -64.0f;
458 
459     GL_Setup3D();
460 
461     if( gl_cull_nodes->integer ) {
462         GL_SetupFrustum();
463     }
464 
465 	if( !( glr.fd.rdflags & RDF_NOWORLDMODEL ) && gl_drawworld->integer ) {
466         GL_DrawWorld();
467     }
468 
469 	GL_DrawEntities( 0 );
470 
471 	GL_DrawBeams();
472 
473     GL_DrawParticles();
474 
475 	GL_DrawEntities( RF_TRANSLUCENT );
476 
477 	GL_DrawAlphaFaces();
478 
479 	/* go back into 2D mode */
480     GL_Setup2D();
481 
482     GL_Blend();
483 
484     while( ( err = qglGetError() ) != GL_NO_ERROR ) {
485 		Com_EPrintf( "GL_RenderFrame: %s\n", GL_ErrorString( err ) );
486     }
487 }
488 
GL_UpdateSwapInterval(void)489 static void GL_UpdateSwapInterval( void ) {
490 	if( gl_swapinterval->integer < 0 ) {
491 		cvar.SetInteger( "gl_swapinterval", 0 );
492 	}
493 #ifdef _WIN32
494 	if( qwglSwapIntervalEXT ) {
495 		//Com_Printf( "Setting swap interval to %d\n", gl_swapinterval->integer );
496 		qwglSwapIntervalEXT( gl_swapinterval->integer );
497 	}
498 #endif
499 
500 	gl_swapinterval->modified = qfalse;
501 }
502 
GL_BeginFrame(float stereo_separation)503 static void GL_BeginFrame( float stereo_separation ) {
504 	GLenum err;
505     int bits;
506 
507 	if( gl_log->integer ) {
508 		QGL_LogNewFrame();
509 	}
510 
511     memset( &c, 0, sizeof( c ) );
512 
513 
514     GL_Setup2D();
515 
516     bits = GL_DEPTH_BUFFER_BIT;
517     if( gl_clear->integer ) {
518         bits |= GL_COLOR_BUFFER_BIT;
519     }
520 	qglClear( bits );
521 
522     while( ( err = qglGetError() ) != GL_NO_ERROR ) {
523 		Com_EPrintf( "GL_BeginFrame: %s\n", GL_ErrorString( err ) );
524     }
525 }
526 
GL_EndFrame(void)527 static void GL_EndFrame( void ) {
528 	GLenum err;
529 
530     if( gl_showstats->integer ) {
531         Draw_Stats();
532     }
533     GL_Flush2D();
534 
535 	if( gl_swapinterval->modified ) {
536 		GL_UpdateSwapInterval();
537 	}
538 
539 	if( gl_log->modified ) {
540 		QGL_EnableLogging( gl_log->integer );
541 		gl_log->modified = qfalse;
542 	}
543 
544     while( ( err = qglGetError() ) != GL_NO_ERROR ) {
545 		Com_EPrintf( "GL_EndFrame: %s\n", GL_ErrorString( err ) );
546     }
547     video.EndFrame();
548 }
549 
550 /*
551 ==============================================================================
552 
553 						SCREEN SHOTS
554 
555 ==============================================================================
556 */
557 
558 #define SCREENSHOTS_DIRECTORY	"screenshots"
559 
560 #ifdef USE_LIBJPEG
561 
562 /*
563 ==================
564 GL_ScreenShotJPEG
565 ==================
566 */
GL_ScreenShotJPEG(const char * filename)567 static qboolean GL_ScreenShotJPEG( const char *filename ) {
568  	byte	*buffer;
569 	int		ret;
570 
571 	buffer = R_Malloc( vid.width * vid.height * 3 );
572 
573 	qglReadPixels( 0, 0, vid.width, vid.height, GL_RGB,
574             GL_UNSIGNED_BYTE, buffer );
575 
576 	ret = Image_WriteJPG( filename, buffer, vid.width, vid.height,
577             gl_screenshot_quality->integer );
578 
579 	com.Free( buffer );
580 
581 	return ret;
582 }
583 
584 #endif
585 
586 /*
587 ==================
588 GL_ScreenShotTGA
589 ==================
590 */
GL_ScreenShotTGA(const char * filename)591 static qboolean GL_ScreenShotTGA( const char *filename ) {
592 	byte	*buffer;
593 	int		ret;
594 
595 	buffer = R_Malloc( vid.width * vid.height * 3 );
596 
597 	qglReadPixels( 0, 0, vid.width, vid.height, GL_BGR,
598             GL_UNSIGNED_BYTE, buffer );
599 
600 	ret = Image_WriteTGA( filename, buffer, vid.width, vid.height );
601 
602 	com.Free( buffer );
603 
604 	return ret;
605 }
606 
607 /*
608 ==================
609 GL_ScreenShot_f
610 ==================
611 */
GL_ScreenShot_f(void)612 static void GL_ScreenShot_f( void )  {
613 	char		picname[MAX_QPATH];
614 	char		checkname[MAX_QPATH];
615 	int			i;
616 	qboolean	screenshotJPEG;
617 	qboolean	silent;
618 	qboolean	ret;
619 	char		*ext;
620 
621 	if( cmd.Argc() > 3 ) {
622 		Com_Printf( "Usage: %s [name] [silent]\n", cmd.Argv( 0 ) );
623 		return;
624 	}
625 
626 #ifdef USE_LIBJPEG
627 	if( !Q_stricmp( cmd.Argv( 0 ), "screenshotJPEG" ) ) {
628 		screenshotJPEG = qtrue;
629 		ext = ".jpg";
630 	} else
631 #endif
632 	{
633 		screenshotJPEG = qfalse;
634 		ext = ".tga";
635 	}
636 
637 	silent = qfalse;
638 	picname[0] = 0;
639 	for( i = 1; i < cmd.Argc(); i++ ) {
640 		if( !Q_stricmp( cmd.Argv( i ), "silent" ) ) {
641 			silent = qtrue;
642 			continue;
643 		}
644 
645 		if( picname[0] ) {
646 			break;
647 		}
648 
649 		Q_strncpyz( picname, cmd.Argv( i ), sizeof( picname ) );
650 
651 	}
652 
653 //
654 // find a file name to save it to
655 //
656 	if( !picname[0] ) {
657 		for( i = 0; i < 1000; i++ ) {
658 			Com_sprintf( picname, sizeof( picname ), "quake%03d%s", i, ext );
659 			Com_sprintf( checkname, sizeof( checkname ), SCREENSHOTS_DIRECTORY"/%s", picname );
660 
661 			if( fs.LoadFile( checkname, NULL ) == -1 ) {
662 				break;	// file doesn't exist
663 			}
664 
665 		}
666 
667 		if( i == 1000 )  {
668 			if( !silent ) {
669 				Com_WPrintf( "Couldn't create a screenshot, all slots full\n" );
670 			}
671 			return;
672  		}
673 	} else {
674 		COM_DefaultExtension( picname, ext, sizeof( picname ) );
675 		Com_sprintf( checkname, sizeof( checkname ), SCREENSHOTS_DIRECTORY"/%s", picname );
676 	}
677 
678 #ifdef USE_LIBJPEG
679 	if( screenshotJPEG ) {
680 		ret = GL_ScreenShotJPEG( checkname );
681 	} else
682 #endif
683 	{
684 		ret = GL_ScreenShotTGA( checkname );
685 	}
686 
687 	if( silent ) {
688 		return;
689 	}
690 
691 	if( ret ) {
692 		Com_Printf( "Wrote %s\n", picname );
693 	} else {
694 		Com_WPrintf( "Failed to write %s\n", picname );
695 	}
696 
697 }
698 
699 
GL_Strings_f(void)700 static void GL_Strings_f( void ) {
701 	Com_Printf( "GL_VENDOR: %s\n", gl_config.vendorString );
702 	Com_Printf( "GL_RENDERER: %s\n", gl_config.rendererString );
703 	Com_Printf( "GL_VERSION: %s\n", gl_config.versionString );
704 	Com_Printf( "GL_EXTENSIONS: %s\n", gl_config.extensionsString );
705 }
706 
GL_Register(void)707 static void GL_Register( void ) {
708 	cvar.Subsystem( CVAR_SYSTEM_VIDEO );
709 
710     /* misc */
711 #ifdef USE_LIBJPEG
712 	gl_screenshot_quality = cvar.Get( "gl_screenshot_quality", "100",
713             CVAR_ARCHIVE );
714 #endif
715 	gl_modulate = cvar.Get( "gl_modulate", "1", CVAR_ARCHIVE );
716 
717     /* development variables */
718 	gl_znear = cvar.Get( "gl_znear", "2", CVAR_CHEAT );
719 	gl_zfar = cvar.Get( "gl_zfar", "16384", 0 );
720 	gl_log = cvar.Get( "gl_log", "0", 0 );
721 	gl_drawworld = cvar.Get( "gl_drawworld", "1", CVAR_CHEAT );
722 	gl_drawentities = cvar.Get( "gl_drawentities", "1", CVAR_CHEAT );
723     gl_showtris = cvar.Get( "gl_showtris", "0", CVAR_CHEAT );
724     gl_showstats = cvar.Get( "gl_showstats", "0", 0 );
725     gl_cull_nodes = cvar.Get( "gl_cull_nodes", "1", 0 );
726 	gl_cull_models = cvar.Get( "gl_cull_models", "1", 0 );
727     gl_clear = cvar.Get( "gl_clear", "0", 0 );
728     gl_novis = cvar.Get( "gl_novis", "0", 0 );
729     gl_lockpvs = cvar.Get( "gl_lockpvs", "0", CVAR_CHEAT );
730     gl_primitives = cvar.Get( "gl_primitives", "0", 0 );
731 	gl_sort = cvar.Get( "gl_sort", "0", 0 );
732     gl_subdivide = cvar.Get( "gl_subdivide", "1", 0 );
733     gl_fastsky = cvar.Get( "gl_fastsky", "0", 0 );
734     gl_dynamic = cvar.Get( "gl_dynamic", "1", CVAR_ARCHIVE );
735     gl_fullbright = cvar.Get( "r_fullbright", "0", CVAR_CHEAT );
736 
737 	/* video mode */
738     gl_mode = cvar.Get( "gl_mode", "3", CVAR_ARCHIVE|CVAR_LATCHED );
739 	gl_custom_width = cvar.Get( "gl_custom_width", "640", CVAR_ARCHIVE );
740 	gl_custom_height = cvar.Get( "gl_custom_height", "480", CVAR_ARCHIVE );
741 	gl_swapinterval = cvar.Get( "gl_swapinterval", "1", CVAR_ARCHIVE );
742     gl_fullscreen = cvar.Get( "vid_fullscreen", "0",
743         CVAR_ARCHIVE|CVAR_LATCHED );
744     gl_hwgamma = cvar.Get( "vid_hwgamma", "0", CVAR_ARCHIVE|CVAR_LATCHED );
745 
746 	cmd.AddCommand( "screenshot", GL_ScreenShot_f );
747 #ifdef USE_LIBJPEG
748 	cmd.AddCommand( "screenshotJPEG", GL_ScreenShot_f );
749 #endif
750 	cmd.AddCommand( "strings", GL_Strings_f );
751 
752 	cvar.Subsystem( CVAR_SYSTEM_GENERIC );
753 }
754 
GL_Unregister(void)755 static void GL_Unregister( void ) {
756 	cmd.RemoveCommand( "screenshot" );
757 #ifdef USE_LIBJPEG
758 	cmd.RemoveCommand( "screenshotJPEG" );
759 #endif
760 	cmd.RemoveCommand( "strings" );
761 }
762 
GL_SetupExtensions(void)763 static qboolean GL_SetupExtensions( void ) {
764 	const char *extensions;
765     int integer;
766 	float value;
767 
768 	extensions = gl_config.extensionsString;
769 	if( strstr( extensions, "GL_EXT_compiled_vertex_array" ) ) {
770 		Com_Printf( "...enabling GL_EXT_compiled_vertex_array\n" );
771 	    qglLockArraysEXT = ( PFNGLLOCKARRAYSEXTPROC )qwglGetProcAddress( "glLockArraysEXT" );
772 	    qglUnlockArraysEXT = ( PFNGLUNLOCKARRAYSEXTPROC )qwglGetProcAddress( "glUnlockArraysEXT" );
773 	} else {
774 		Com_Printf( "GL_EXT_compiled_vertex_array not found\n" );
775     }
776 
777     gl_static.numTextureUnits = 1;
778 	if( strstr( extensions, "GL_ARB_multitexture" ) ) {
779         qglGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB, &integer );
780         if( integer > 1 ) {
781             Com_Printf( "...enabling GL_ARB_multitexture (%d texture units)\n", integer );
782             qglActiveTextureARB = ( PFNGLACTIVETEXTUREARBPROC )qwglGetProcAddress( "glActiveTextureARB" );
783             qglClientActiveTextureARB = ( PFNGLCLIENTACTIVETEXTUREARBPROC )qwglGetProcAddress( "glClientActiveTextureARB" );
784             qglMultiTexCoord2fvARB = ( PFNGLMULTITEXCOORD2FVARBPROC )qwglGetProcAddress( "glMultiTexCoord2fvARB" );
785             if( integer > MAX_TMUS ) {
786                 integer = MAX_TMUS;
787             }
788             gl_static.numTextureUnits = integer;
789         } else {
790             Com_Printf( "...ignoring GL_ARB_multitexture,\n"
791                     "not enough texture units supported (%d)\n", integer );
792         }
793 	} else {
794 		Com_Printf( "GL_ARB_multitexture not found\n" );
795     }
796 
797 	gl_config.maxAnisotropy = 1;
798 	if( strstr( extensions, "GL_EXT_texture_filter_anisotropic" ) ) {
799 		qglGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &value );
800 		if( value >= 2 ) {
801 			Com_Printf( "...enabling GL_EXT_texture_filter_anisotropic\n"
802 				"(max anisotropy is %.1f)\n", value );
803 			gl_config.maxAnisotropy = value;
804 		} else {
805             Com_Printf( "...ignoring GL_EXT_texture_filter_anisotropic,\n"
806                     "not enough anisotropy supported (%.1f)\n", value );
807 		}
808 	} else {
809 		Com_Printf( "GL_EXT_texture_filter_anisotropic not found\n" );
810     }
811 
812 	if( !qglActiveTextureARB ) {
813 		return qfalse;
814 	}
815 
816 
817 #ifdef _WIN32
818 	if( strstr( extensions, "WGL_EXT_swap_control" ) ) {
819 		Com_Printf( "...enabling WGL_EXT_swap_control\n" );
820 		qwglSwapIntervalEXT = ( PFNWGLSWAPINTERWALEXTPROC )qwglGetProcAddress( "wglSwapIntervalEXT" );
821 	} else {
822 		Com_Printf( "WGL_EXT_swap_control not found\n" );
823     }
824 
825 #endif
826 
827 	qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &gl_static.maxTextureSize );
828 	if( gl_static.maxTextureSize > MAX_TEXTURE_SIZE ) {
829 		gl_static.maxTextureSize = MAX_TEXTURE_SIZE;
830 	}
831 
832 	//qglGetIntegerv( GL_MAX_ELEMENTS_VERTICES, &numUnits );
833 	//Com_Printf( "GL_MAX_ELEMENTS_VERTICES: %d\n", numUnits );
834 
835 	return qtrue;
836 }
837 
GL_SetDefaultState(void)838 void GL_SetDefaultState( void ) {
839 	qglDrawBuffer( GL_BACK );
840 	qglClearColor( 0, 0, 0, 1 );
841 	qglClearDepth( 1 );
842 	qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
843 	qglEnable( GL_DEPTH_TEST );
844 	qglDepthFunc( GL_LEQUAL );
845 	qglDepthRange( 0, 1 );
846 	qglDepthMask( GL_TRUE );
847 	qglDisable( GL_BLEND );
848 	qglDisable( GL_ALPHA_TEST );
849 	qglAlphaFunc( GL_GREATER, 0.666f );
850 	qglHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
851     qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
852 
853 	qglEnableClientState( GL_VERTEX_ARRAY );
854     qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
855 
856 	GL_SelectTMU( 0 );
857 	qglEnable( GL_TEXTURE_2D );
858     GL_Bits( GLS_DEFAULT );
859 
860 	GL_UpdateSwapInterval();
861 
862 }
863 
GL_SetupRenderer(void)864 static void GL_SetupRenderer( void ) {
865     char renderer_buffer[MAX_STRING_CHARS];
866 
867 	Q_strncpyz( renderer_buffer, gl_config.rendererString,
868             sizeof( renderer_buffer ) );
869 	Q_strlwr( renderer_buffer );
870 
871 	if( strstr( renderer_buffer, "voodoo" ) ) {
872 		if( !strstr( renderer_buffer, "rush" ) ) {
873 			gl_config.renderer = GL_RENDERER_VOODOO;
874 		} else {
875 			gl_config.renderer = GL_RENDERER_VOODOO_RUSH;
876 		}
877 	} else if( strstr( renderer_buffer, "permedia" ) ) {
878 		gl_config.renderer = GL_RENDERER_PERMEDIA2;
879 	} else if ( strstr( renderer_buffer, "glint" ) ) {
880 		gl_config.renderer = GL_RENDERER_GLINT;
881 	} else if( strstr( renderer_buffer, "gdi" ) ) {
882 		gl_config.renderer = GL_RENDERER_MCD;
883 	} else if( strstr( renderer_buffer, "glzicd" ) ) {
884 		gl_config.renderer = GL_RENDERER_INTERGRAPH;
885 	} else if( strstr( renderer_buffer, "pcx2" ) ) {
886 		gl_config.renderer = GL_RENDERER_POWERVR;
887 	} else if( strstr( renderer_buffer, "verite" ) ) {
888 		gl_config.renderer = GL_RENDERER_RENDITION;
889 	} else if( strstr( renderer_buffer, "mesa dri" ) ) {
890 		gl_config.renderer = GL_RENDERER_MESADRI;
891 	} else {
892 		gl_config.renderer = GL_RENDERER_OTHER;
893 	}
894 }
895 
896 /*
897 ==================
898 R_SetMode
899 ==================
900 */
GL_SetMode(void)901 static qboolean GL_SetMode( void ) {
902 	vidSetModeResult_t result;
903     qboolean fullscreen;
904 
905 	vid.width = gl_custom_width->integer;
906 	vid.height = gl_custom_height->integer;
907     fullscreen = qfalse;
908     if( gl_fullscreen->integer ) {
909         fullscreen = qtrue;
910     }
911     result = video.SetMode( &vid.width, &vid.height, gl_mode->integer,
912             fullscreen );
913 	if( result != SETMODE_ERROR ) {
914 		gl_static.prev_mode = gl_mode->integer;
915 		cvar.SetInteger( "vid_fullscreen", result == SETMODE_FULLSCREEN );
916 		return qtrue;
917 	}
918 
919 	if( !gl_fullscreen->integer && gl_mode->integer == gl_static.prev_mode ) {
920 		return qfalse;	/* safe mode failed */
921 	}
922 
923 	cvar.SetInteger( "gl_mode", gl_static.prev_mode );
924 	cvar.SetInteger( "vid_fullscreen", 0 );
925 
926 	/* try setting it back to something safe */
927      result = video.SetMode( &vid.width, &vid.height, gl_static.prev_mode,
928              qfalse );
929 	if( result == SETMODE_ERROR ) {
930 		return qfalse;
931 	}
932 
933 	return qtrue;
934 }
935 
GL_PostInit(void)936 static void GL_PostInit( void ) {
937 	GL_InitImages();
938     GL_InitModels();
939 	GL_SetDefaultState();
940 }
941 
GL_Init(qboolean total)942 static qboolean GL_Init( qboolean total ) {
943 	Com_Printf( "GL_Init( %i )\n", total );
944 
945 	if( !total ) {
946 		GL_PostInit();
947 		return qtrue;
948 	}
949 
950 	Com_Printf( "ref_newgl " VERSION ", " __DATE__ "\n" );
951 #ifdef USE_LIBJPEG
952     Com_Printf( "w/ libjpeg v%d\n", JPEG_LIB_VERSION );
953 #endif
954 #ifdef USE_LIBPNG
955     Com_Printf( "w/ libpng v" PNG_LIBPNG_VER_STRING "\n" );
956 #endif
957 
958 	/* initialize OS-specific parts of OpenGL */
959 	if( !video.Init() ) {
960 		return qfalse;
961 	}
962 
963 	GL_Register();
964 
965 	/* set our "safe" modes */
966 	gl_static.prev_mode = 3;
967 
968 	/* create the window and set up the context */
969 	if( !GL_SetMode() ) {
970 		Com_EPrintf( "Could not revert to safe video mode\n" );
971 		goto fail;
972 	}
973 
974 	/* initialize our QGL dynamic bindings */
975 	QGL_Init();
976 
977 	gl_static.flags = video.GetFlags();
978 
979 	gl_config.vidWidth = vid.width;
980 	gl_config.vidHeight = vid.height;
981 
982 #define GET_STRING( x )  ( const char * )qglGetString( x )
983 
984 	gl_config.vendorString = GET_STRING( GL_VENDOR );
985 	gl_config.rendererString = GET_STRING( GL_RENDERER );
986 	gl_config.versionString = GET_STRING( GL_VERSION );
987 	gl_config.extensionsString = GET_STRING( GL_EXTENSIONS );
988 
989 	if( !gl_config.extensionsString || !gl_config.extensionsString[0] ) {
990 		Com_EPrintf( "No OpenGL extensions found, check your drivers\n" );
991 		goto fail;
992 	}
993 
994 	if( !GL_SetupExtensions() ) {
995 		Com_EPrintf( "Some of the required OpenGL extensions are missing\n" );
996 		goto fail;
997 	}
998 
999 	if( gl_hwgamma->integer && !( gl_static.flags & QVF_GAMMARAMP_ENABLED ) ) {
1000 		cvar.SetInteger( "vid_hwgamma", 0 );
1001 		Com_Printf( "Hardware gamma is not supported by this video driver\n" );
1002 	}
1003 
1004     GL_SetupRenderer();
1005 
1006 	QGL_EnableLogging( gl_log->integer );
1007 	gl_log->modified = qfalse;
1008 
1009     GL_PostInit();
1010 
1011 	if( (( size_t )tess.vertices) & 15 ) {
1012 		Com_WPrintf( "tess.vertices not 16 byte aligned\n" );
1013 	}
1014 
1015     gl_sort = cvar.Get( "gl_sort",
1016         gl_config.renderer == GL_RENDERER_MESADRI ? "1" : "0", 0 );
1017 
1018 	Com_Printf( "Finished GL_Init\n" );
1019 
1020     return qtrue;
1021 
1022 fail:
1023     QGL_Shutdown();
1024 	GL_Unregister();
1025 	video.Shutdown();
1026     return qfalse;
1027 }
1028 
1029 /*
1030 ===============
1031 R_Shutdown
1032 ===============
1033 */
GL_Shutdown(qboolean total)1034 void GL_Shutdown( qboolean total ) {
1035 	Com_Printf( "GL_Shutdown( %i )\n", total );
1036 
1037     Bsp_FreeWorld();
1038 	GL_ShutdownImages();
1039     GL_ShutdownModels();
1040 
1041 	if( !total ) {
1042 		return;
1043 	}
1044 
1045 	/*
1046 	** shut down OS specific OpenGL stuff like contexts, etc.
1047 	*/
1048 	video.Shutdown();
1049 
1050 	/*
1051 	** shutdown our QGL subsystem
1052 	*/
1053 	QGL_Shutdown();
1054 
1055 	GL_Unregister();
1056 
1057     memset( &gl_static, 0, sizeof( gl_static ) );
1058     memset( &gl_config, 0, sizeof( gl_config ) );
1059 }
1060 
GL_BeginRegistration(const char * name)1061 void GL_BeginRegistration( const char *name ) {
1062     char fullname[MAX_QPATH];
1063     bspTexinfo_t *texinfo, *lastexinfo;
1064 	bspLeaf_t *leaf, *lastleaf;
1065 	bspNode_t *node, *lastnode;
1066     int i;
1067 
1068 	gl_static.registering = qtrue;
1069     registration_sequence++;
1070 
1071     memset( &glr, 0, sizeof( glr ) );
1072 	glr.viewcluster1 = glr.viewcluster2 = -2;
1073 
1074 	Com_sprintf( fullname, sizeof( fullname ), "maps/%s.bsp", name );
1075 
1076 	/* check if the required world model was already loaded */
1077     if( !strcmp( r_world.name, fullname ) &&
1078             !cvar.VariableInteger( "flushmap" ) )
1079     {
1080 		lastexinfo = r_world.texinfos + r_world.numTexinfos;
1081         for( texinfo = r_world.texinfos; texinfo != lastexinfo; texinfo++ ) {
1082             texinfo->image->registration_sequence = registration_sequence;
1083         }
1084 		lastleaf = r_world.leafs + r_world.numLeafs;
1085 	    for( leaf = r_world.leafs; leaf != lastleaf; leaf++ ) {
1086             leaf->visframe = 0;
1087         }
1088 		lastnode = r_world.nodes + r_world.numNodes;
1089 	    for( node = r_world.nodes; node != lastnode; node++ ) {
1090             node->visframe = 0;
1091         }
1092         for( i = 0; i < lm.numMaps; i++ ) {
1093             lm.lightmaps[i]->registration_sequence = registration_sequence;
1094         }
1095 		Com_DPrintf( "GL_BeginRegistration: reused old world model\n" );
1096         return;
1097     }
1098 
1099     Bsp_FreeWorld();
1100     GL_BeginPostProcessing();
1101 
1102     if( !Bsp_LoadWorld( fullname ) ) {
1103         Com_Error( ERR_DROP, "Couldn't load '%s'\n", fullname );
1104     }
1105 
1106     GL_EndPostProcessing();
1107 }
1108 
GL_EndRegistration(void)1109 void GL_EndRegistration( void ) {
1110     R_FreeUnusedImages();
1111 	Model_FreeUnused();
1112 	if( scrap_dirty ) {
1113 		Scrap_Upload();
1114 	}
1115 	gl_static.registering = qfalse;
1116 }
1117 
GL_SetPalette(const byte * pal)1118 void GL_SetPalette( const byte *pal ) {
1119 	int i;
1120 
1121 	if( pal == NULL ) {
1122 		for( i = 0; i < 256; i++ ) {
1123 			gl_static.palette[i] = d_8to24table[i];
1124 		}
1125 		return;
1126 	}
1127 
1128 	for( i = 0; i < 256; i++ ) {
1129 		gl_static.palette[i] = MakeColor( pal[0], pal[1], pal[2], 255 );
1130 		pal += 3;
1131 	}
1132 }
1133 
GL_GetConfig(glconfig_t * config)1134 void GL_GetConfig( glconfig_t *config ) {
1135     *config = gl_config;
1136 }
1137 
1138 #ifndef REF_HARD_LINKED
1139 // this is only here so the functions in q_shared.c can link
1140 
Com_Printf(const char * fmt,...)1141 void Com_Printf( const char *fmt, ... ) {
1142 	va_list		argptr;
1143 	char		text[MAXPRINTMSG];
1144 
1145 	va_start( argptr, fmt );
1146 	Q_vsnprintf( text, sizeof( text ), fmt, argptr );
1147 	va_end( argptr );
1148 
1149 	com.Print( PRINT_ALL, text );
1150 }
1151 
Com_DPrintf(const char * fmt,...)1152 void Com_DPrintf( const char *fmt, ... ) {
1153 	va_list		argptr;
1154 	char		text[MAXPRINTMSG];
1155 
1156 	va_start( argptr, fmt );
1157 	Q_vsnprintf( text, sizeof( text ), fmt, argptr );
1158 	va_end( argptr );
1159 
1160 	com.Print( PRINT_DEVELOPER, text );
1161 }
1162 
Com_WPrintf(const char * fmt,...)1163 void Com_WPrintf( const char *fmt, ... ) {
1164 	va_list		argptr;
1165 	char		text[MAXPRINTMSG];
1166 
1167 	va_start( argptr, fmt );
1168 	Q_vsnprintf( text, sizeof( text ), fmt, argptr );
1169 	va_end( argptr );
1170 
1171 	com.Print( PRINT_WARNING, text );
1172 }
1173 
Com_EPrintf(const char * fmt,...)1174 void Com_EPrintf( const char *fmt, ... ) {
1175 	va_list		argptr;
1176 	char		text[MAXPRINTMSG];
1177 
1178 	va_start( argptr, fmt );
1179 	Q_vsnprintf( text, sizeof( text ), fmt, argptr );
1180 	va_end( argptr );
1181 
1182 	com.Print( PRINT_ERROR, text );
1183 }
1184 
Com_Error(comErrorType_t type,const char * error,...)1185 void Com_Error( comErrorType_t type, const char *error, ... ) {
1186 	va_list		argptr;
1187 	char		text[MAXPRINTMSG];
1188 
1189 	va_start( argptr, error );
1190 	Q_vsnprintf( text, sizeof( text ), error, argptr );
1191 	va_end( argptr );
1192 
1193 	com.Error( type, text );
1194 }
1195 
1196 #endif /* !REF_HARD_LINKED */
1197 
1198 /*
1199 =================
1200 Ref_FillAPI
1201 =================
1202 */
Ref_FillAPI(refAPI_t * api)1203 static void Ref_FillAPI( refAPI_t *api ) {
1204 	api->BeginRegistration = GL_BeginRegistration;
1205 	api->RegisterModel = GL_RegisterModel;
1206 	api->RegisterSkin = R_RegisterSkin;
1207 	api->RegisterPic = R_RegisterPic;
1208 	api->RegisterFont = GL_RegisterFont;
1209 	api->SetSky = R_SetSky;
1210 	api->EndRegistration = GL_EndRegistration;
1211 	api->GetModelSize = GL_GetModelSize;
1212 
1213 	api->RenderFrame = GL_RenderFrame;
1214 	api->LightPoint = GL_LightPoint;
1215 
1216     api->SetColor = Draw_SetColor;
1217     api->SetClipRect = Draw_SetClipRect;
1218 	api->SetScale = Draw_SetScale;
1219 	api->DrawString = Draw_String;
1220 	api->DrawChar = Draw_Char;
1221 	api->DrawGetPicSize = Draw_GetPicSize;
1222 	api->DrawGetFontSize = Draw_GetFontSize;
1223 	api->DrawPic = Draw_Pic;
1224 	api->DrawStretchPicST = Draw_StretchPicST;
1225 	api->DrawStretchPic = Draw_StretchPic;
1226 	api->DrawTileClear = Draw_TileClear;
1227 	api->DrawFill = Draw_Fill;
1228 	api->DrawStretchRaw = Draw_StretchRaw;
1229 	api->DrawFillEx = Draw_FillEx;
1230 
1231 	api->Init = GL_Init;
1232 	api->Shutdown = GL_Shutdown;
1233 
1234 	api->CinematicSetPalette = GL_SetPalette;
1235 	api->BeginFrame = GL_BeginFrame;
1236 	api->EndFrame = GL_EndFrame;
1237 
1238 	api->GetConfig = GL_GetConfig;
1239 }
1240 
1241 /*
1242 =================
1243 Ref_APISetupCallback
1244 =================
1245 */
Ref_APISetupCallback(api_type_t type,void * api)1246 qboolean Ref_APISetupCallback( api_type_t type, void *api ) {
1247 	switch( type ) {
1248 	case API_REFRESH:
1249 		Ref_FillAPI( ( refAPI_t * )api );
1250 		break;
1251 	default:
1252 		return qfalse;
1253 	}
1254 
1255 	return qtrue;
1256 }
1257 
1258 #ifndef REF_HARD_LINKED
1259 
1260 /*
1261 @@@@@@@@@@@@@@@@@@@@@
1262 moduleEntry
1263 
1264 @@@@@@@@@@@@@@@@@@@@@
1265 */
moduleEntry(int query,void * data)1266 void *moduleEntry( int query, void *data ) {
1267 	moduleInfo_t *info;
1268 	moduleCapability_t caps;
1269 	APISetupCallback_t callback;
1270 
1271 	switch( query ) {
1272 	case MQ_GETINFO:
1273 		info = ( moduleInfo_t * )data;
1274 		info->api_version = MODULES_APIVERSION;
1275 		Q_strncpyz( info->fullname, "OpenGL Refresh Driver",
1276                 sizeof( info->fullname ) );
1277 		Q_strncpyz( info->author, "Andrey Nazarov", sizeof( info->author ) );
1278 		return ( void * )qtrue;
1279 
1280 	case MQ_GETCAPS:
1281 		caps = MCP_REFRESH;
1282 		return ( void * )caps;
1283 
1284 	case MQ_SETUPAPI:
1285 		if( ( callback = ( APISetupCallback_t )data ) == NULL ) {
1286 			return NULL;
1287 		}
1288 		callback( API_CMD, &cmd );
1289 		callback( API_CVAR, &cvar );
1290 		callback( API_FS, &fs );
1291 		callback( API_COMMON, &com );
1292 		callback( API_SYSTEM, &sys );
1293 		callback( API_VIDEO_OPENGL, &video );
1294 
1295 		return ( void * )Ref_APISetupCallback;
1296 
1297 	}
1298 
1299 	/* quiet compiler warning */
1300 	return NULL;
1301 }
1302 
1303 #endif /* !REF_HARD_LINKED */
1304 
1305