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