summaryrefslogtreecommitdiff
path: root/source/gl_main.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/gl_main.c
Initial import of the new Q2PRO tree.
Diffstat (limited to 'source/gl_main.c')
-rw-r--r--source/gl_main.c1225
1 files changed, 1225 insertions, 0 deletions
diff --git a/source/gl_main.c b/source/gl_main.c
new file mode 100644
index 0000000..9e4b6d7
--- /dev/null
+++ b/source/gl_main.c
@@ -0,0 +1,1225 @@
+/*
+Copyright (C) 2003-2006 Andrey Nazarov
+
+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.
+
+*/
+
+/*
+ * gl_main.c
+ *
+ */
+
+#include "gl_local.h"
+
+#ifdef USE_PNG
+#include <png.h>
+#endif
+
+#if 0
+#ifdef USE_JPEG
+#ifndef USE_PNG
+#include <setjmp.h>
+#endif
+#include <stdio.h>
+#include <jpeglib.h>
+#endif
+#endif
+
+
+/* declare imports for this module */
+cmdAPI_t cmd;
+cvarAPI_t cvar;
+fsAPI_t fs;
+commonAPI_t com;
+sysAPI_t sys;
+videoAPI_t video;
+
+glRefdef_t glr;
+glStatic_t gl_static;
+glconfig_t gl_config;
+statCounters_t c;
+
+int registration_sequence;
+
+#ifdef USE_JPEG
+cvar_t *gl_screenshot_quality;
+#endif
+cvar_t *gl_znear;
+cvar_t *gl_zfar;
+cvar_t *gl_modulate;
+cvar_t *gl_log;
+cvar_t *gl_drawworld;
+cvar_t *gl_drawentities;
+cvar_t *gl_showtris;
+cvar_t *gl_cull_nodes;
+cvar_t *gl_cull_models;
+cvar_t *gl_showstats;
+cvar_t *gl_clear;
+cvar_t *gl_novis;
+cvar_t *gl_lockpvs;
+cvar_t *gl_sort;
+cvar_t *gl_primitives;
+cvar_t *gl_sort;
+cvar_t *gl_subdivide;
+cvar_t *gl_fastsky;
+cvar_t *gl_dynamic;
+cvar_t *gl_fullbright;
+cvar_t *gl_mode;
+cvar_t *gl_custom_width;
+cvar_t *gl_custom_height;
+cvar_t *gl_hwgamma;
+cvar_t *gl_fullscreen;
+
+static void GL_SetupFrustum( void ) {
+ cplane_t *f;
+ vec3_t forward, left, up;
+ vec_t fovSin, fovCos, angle;
+
+ angle = DEG2RAD( glr.fd.fov_x / 2 );
+ fovSin = sin( angle );
+ fovCos = cos( angle );
+
+ VectorScale( glr.viewaxis[0], fovSin, forward );
+ VectorScale( glr.viewaxis[1], fovCos, left );
+
+ /* right side */
+ f = &glr.frustumPlanes[0];
+ VectorAdd( forward, left, f->normal );
+ f->dist = DotProduct( glr.fd.vieworg, f->normal );
+ SetPlaneSignbits( f );
+ SetPlaneType( f );
+
+ /* left side */
+ f = &glr.frustumPlanes[1];
+ VectorSubtract( forward, left, f->normal );
+ f->dist = DotProduct( glr.fd.vieworg, f->normal );
+ SetPlaneSignbits( f );
+ SetPlaneType( f );
+
+ angle = DEG2RAD( glr.fd.fov_y / 2 );
+ fovSin = sin( angle );
+ fovCos = cos( angle );
+
+ VectorScale( glr.viewaxis[0], fovSin, forward );
+ VectorScale( glr.viewaxis[2], fovCos, up );
+
+ /* up side */
+ f = &glr.frustumPlanes[2];
+ VectorAdd( forward, up, f->normal );
+ f->dist = DotProduct( glr.fd.vieworg, f->normal );
+ SetPlaneSignbits( f );
+ SetPlaneType( f );
+
+ /* down side */
+ f = &glr.frustumPlanes[3];
+ VectorSubtract( forward, up, f->normal );
+ f->dist = DotProduct( glr.fd.vieworg, f->normal );
+ SetPlaneSignbits( f );
+ SetPlaneType( f );
+
+}
+
+static void GL_Blend( void ) {
+ color_t color;
+
+ if( glr.fd.blend[3] == 0 ) {
+ return;
+ }
+
+ color[0] = glr.fd.blend[0] * 255;
+ color[1] = glr.fd.blend[1] * 255;
+ color[2] = glr.fd.blend[2] * 255;
+ color[3] = glr.fd.blend[3] * 255;
+
+ GL_StretchPic( 0, 0, gl_config.vidWidth, gl_config.vidHeight, 0, 0, 1, 1,
+ color, r_whiteimage );
+}
+
+glCullResult_t GL_CullBox( vec3_t bounds[2] ) {
+ int i, bits;
+ glCullResult_t cull;
+
+ if( !gl_cull_models->integer ) {
+ return CULL_IN;
+ }
+
+ cull = CULL_IN;
+ for( i = 0; i < 4; i++ ) {
+ bits = BoxOnPlaneSide( bounds[0], bounds[1], &glr.frustumPlanes[i] );
+ if( bits == BOX_BEHIND ) {
+ return CULL_OUT;
+ }
+ if( bits != BOX_INFRONT ) {
+ cull = CULL_CLIP;
+ }
+ }
+
+ return cull;
+}
+
+glCullResult_t GL_CullSphere( const vec3_t origin, float radius ) {
+ float dist;
+ cplane_t *p;
+ int i;
+ glCullResult_t cull;
+
+ if( !gl_cull_models->integer ) {
+ return CULL_IN;
+ }
+
+ cull = CULL_IN;
+ for( i = 0, p = glr.frustumPlanes; i < 4; i++, p++ ) {
+ dist = DotProduct( origin, p->normal ) - p->dist;
+ if( dist < -radius ) {
+ return CULL_OUT;
+ }
+ if( dist <= radius ) {
+ cull = CULL_CLIP;
+ }
+ }
+
+ return cull;
+}
+
+glCullResult_t GL_CullLocalBox( const vec3_t origin, vec3_t bounds[2] ) {
+ vec3_t points[8];
+ cplane_t *p;
+ int i, j;
+ vec_t dot;
+ qboolean infront;
+ glCullResult_t cull;
+
+ if( !gl_cull_models->integer ) {
+ return CULL_IN;
+ }
+
+ for( i = 0; i < 8; i++ ) {
+ VectorCopy( origin, points[i] );
+ VectorMA( points[i], bounds[(i>>0)&1][0], glr.entaxis[0], points[i] );
+ VectorMA( points[i], bounds[(i>>1)&1][1], glr.entaxis[1], points[i] );
+ VectorMA( points[i], bounds[(i>>2)&1][2], glr.entaxis[2], points[i] );
+ }
+
+ cull = CULL_IN;
+ for( i = 0, p = glr.frustumPlanes; i < 4; i++, p++ ) {
+ infront = qfalse;
+ for( j = 0; j < 8; j++ ) {
+ dot = DotProduct( points[j], p->normal );
+ if( dot >= p->dist ) {
+ infront = qtrue;
+ if( cull == CULL_CLIP ) {
+ break;
+ }
+ } else {
+ cull = CULL_CLIP;
+ if( infront ) {
+ break;
+ }
+ }
+ }
+ if( !infront ) {
+ return CULL_OUT;
+ }
+ }
+
+ return cull;
+}
+
+void GL_DrawBox( const vec3_t origin, vec3_t bounds[2] ) {
+ static int indices[2][4] = {
+ { 0, 1, 3, 2 },
+ { 4, 5, 7, 6 }
+ };
+ vec3_t points[8];
+ int i, j;
+
+ qglDisable( GL_TEXTURE_2D );
+ GL_TexEnv( GL_REPLACE );
+ qglDisable( GL_DEPTH_TEST );
+ qglColor4f( 1, 1, 1, 1 );
+
+ for( i = 0; i < 8; i++ ) {
+ VectorCopy( origin, points[i] );
+ VectorMA( points[i], bounds[(i>>0)&1][0], glr.entaxis[0], points[i] );
+ VectorMA( points[i], bounds[(i>>1)&1][1], glr.entaxis[1], points[i] );
+ VectorMA( points[i], bounds[(i>>2)&1][2], glr.entaxis[2], points[i] );
+ }
+
+ for( i = 0; i < 2; i++ ) {
+ qglBegin( GL_LINE_LOOP );
+ for( j = 0; j < 4; j++ ) {
+ qglVertex3fv( points[ indices[i][j] ] );
+ }
+ qglEnd();
+ }
+
+ qglBegin( GL_LINES );
+ for( i = 0; i < 4; i++ ) {
+ qglVertex3fv( points[ i ] );
+ qglVertex3fv( points[ i + 4 ] );
+ }
+ qglEnd();
+
+ qglEnable( GL_DEPTH_TEST );
+ qglEnable( GL_TEXTURE_2D );
+
+}
+
+static void GL_DrawSpriteModel( model_t *model ) {
+ vec3_t point;
+ entity_t *e = glr.ent;
+ spriteFrame_t *frame;
+ image_t *image;
+ int idx, bits;
+ float alpha;
+
+ idx = e->frame % model->numFrames;
+ frame = &model->sframes[idx];
+ image = frame->image;
+
+ GL_TexEnv( GL_MODULATE );
+
+ alpha = 1;
+ bits = GLS_DEFAULT;
+ if( e->flags & RF_TRANSLUCENT ) {
+ alpha = e->alpha;
+ bits = GLS_BLEND_BLEND;
+ }
+
+ GL_Bits( bits );
+
+ qglColor4f( 1, 1, 1, alpha );
+
+ GL_BindTexture( image->texnum );
+
+ qglBegin( GL_QUADS );
+
+ qglTexCoord2f( 0, 1 );
+ VectorMA( e->origin, -frame->y, glr.viewaxis[2], point );
+ VectorMA( point, frame->x, glr.viewaxis[1], point );
+ qglVertex3fv( point );
+
+ qglTexCoord2f( 0, 0 );
+ VectorMA( e->origin, frame->height - frame->y, glr.viewaxis[2], point );
+ VectorMA( point, frame->x, glr.viewaxis[1], point );
+ qglVertex3fv( point );
+
+ qglTexCoord2f( 1, 0 );
+ VectorMA( e->origin, frame->height - frame->y, glr.viewaxis[2], point );
+ VectorMA( point, frame->x - frame->width, glr.viewaxis[1], point );
+ qglVertex3fv( point );
+
+ qglTexCoord2f( 1, 1 );
+ VectorMA( e->origin, -frame->y, glr.viewaxis[2], point );
+ VectorMA( point, frame->x - frame->width, glr.viewaxis[1], point );
+ qglVertex3fv( point );
+
+ qglEnd();
+}
+
+static void GL_DrawNullModel( void ) {
+ vec3_t point;
+
+ qglDisable( GL_TEXTURE_2D );
+ //qglDisable( GL_DEPTH_TEST );
+ qglBegin( GL_LINES );
+
+ qglColor3f( 1, 0, 0 );
+ qglVertex3fv( glr.ent->origin );
+ VectorMA( glr.ent->origin, 16, glr.entaxis[0], point );
+ qglVertex3fv( point );
+
+ qglColor3f( 0, 1, 0 );
+ qglVertex3fv( glr.ent->origin );
+ VectorMA( glr.ent->origin, 16, glr.entaxis[1], point );
+ qglVertex3fv( point );
+
+ qglColor3f( 0, 0, 1 );
+ qglVertex3fv( glr.ent->origin );
+ VectorMA( glr.ent->origin, 16, glr.entaxis[2], point );
+ qglVertex3fv( point );
+
+ qglEnd();
+ //qglEnable( GL_DEPTH_TEST );
+ qglEnable( GL_TEXTURE_2D );
+}
+
+static void GL_DrawEntities( int mask ) {
+ entity_t *ent, *last;
+ modelType_t *model;
+
+ if( !gl_drawentities->integer ) {
+ return;
+ }
+
+ last = glr.fd.entities + glr.fd.num_entities;
+ for( ent = glr.fd.entities; ent != last; ent++ ) {
+ if( ent->flags & RF_BEAM ) {
+ /* beams are drawn elsewhere in single batch */
+ glr.num_beams++;
+ continue;
+ }
+ if( ( ent->flags & RF_TRANSLUCENT ) != mask ) {
+ continue;
+ }
+
+ glr.ent = ent;
+ if( ent->angles[0] || ent->angles[1] || ent->angles[2] ) {
+ glr.entrotated = qtrue;
+ AngleVectors( ent->angles, glr.entaxis[0], glr.entaxis[1], glr.entaxis[2] );
+ VectorInverse( glr.entaxis[1] );
+ } else {
+ glr.entrotated = qfalse;
+ VectorSet( glr.entaxis[0], 1, 0, 0 );
+ VectorSet( glr.entaxis[1], 0, 1, 0 );
+ VectorSet( glr.entaxis[2], 0, 0, 1 );
+ }
+
+ model = GL_ModelForHandle( ent->model );
+ if( !model ) {
+ GL_DrawNullModel();
+ continue;
+ }
+
+ switch( *model ) {
+ case MODEL_NULL:
+ GL_DrawNullModel();
+ break;
+ case MODEL_BSP:
+ GL_DrawBspModel( ( bspSubmodel_t * )model );
+ break;
+ case MODEL_ALIAS:
+ GL_DrawAliasModel( ( model_t * )model );
+ break;
+ case MODEL_SPRITE:
+ GL_DrawSpriteModel( ( model_t * )model );
+ break;
+ default:
+ Com_Error( ERR_FATAL, "GL_DrawEntities: bad model type: %u", *model );
+ break;
+ }
+ }
+}
+
+static char *GL_ErrorString( GLenum err ) {
+ char *str;
+
+#define MapError( x ) case x: str = #x; break;
+
+ switch( err ) {
+ MapError( GL_NO_ERROR )
+ MapError( GL_INVALID_ENUM )
+ MapError( GL_INVALID_VALUE )
+ MapError( GL_INVALID_OPERATION )
+ MapError( GL_STACK_OVERFLOW )
+ MapError( GL_STACK_UNDERFLOW )
+ MapError( GL_OUT_OF_MEMORY )
+ default: str = "UNKNOWN ERROR";
+ }
+
+#undef MapError
+
+ return str;
+}
+
+static void GL_RenderFrame( refdef_t *fd ) {
+ GLenum err;
+
+ GL_Flush2D();
+
+ if( !r_world.name[0] && !( fd->rdflags & RDF_NOWORLDMODEL ) ) {
+ Com_Error( ERR_FATAL, "GL_RenderView: NULL worldmodel" );
+ }
+
+ glr.drawframe++;
+
+ glr.fd = *fd;
+ glr.num_beams = 0;
+
+ if( !gl_dynamic->integer ) {
+ glr.fd.num_dlights = 0;
+ }
+
+ AngleVectors( glr.fd.viewangles, glr.viewaxis[0], glr.viewaxis[1], glr.viewaxis[2] );
+ VectorInverse( glr.viewaxis[1] );
+
+ glr.scroll = -64 * ( ( glr.fd.time / 40.0f ) - ( int )( glr.fd.time / 40.0f ) );
+ if( glr.scroll == 0 )
+ glr.scroll = -64.0f;
+
+ GL_Setup3D();
+
+ if( gl_cull_nodes->integer ) {
+ GL_SetupFrustum();
+ }
+
+ if( !( glr.fd.rdflags & RDF_NOWORLDMODEL ) && gl_drawworld->integer ) {
+ GL_DrawWorld();
+ }
+
+ GL_DrawEntities( 0 );
+
+ GL_DrawBeams();
+
+ GL_DrawParticles();
+
+ GL_DrawEntities( RF_TRANSLUCENT );
+
+ GL_DrawAlphaFaces();
+
+ /* go back into 2D mode */
+ GL_Setup2D();
+
+ GL_Blend();
+
+ while( ( err = qglGetError() ) != GL_NO_ERROR ) {
+ Com_EPrintf( "GL_RenderFrame: %s\n", GL_ErrorString( err ) );
+ }
+}
+
+static void GL_BeginFrame( void ) {
+ GLenum err;
+
+ if( gl_log->integer ) {
+ QGL_LogNewFrame();
+ }
+
+ memset( &c, 0, sizeof( c ) );
+
+ GL_Setup2D();
+
+ if( gl_clear->integer ) {
+ qglClear( GL_COLOR_BUFFER_BIT );
+ }
+
+ while( ( err = qglGetError() ) != GL_NO_ERROR ) {
+ Com_EPrintf( "GL_BeginFrame: %s\n", GL_ErrorString( err ) );
+ }
+}
+
+static void GL_EndFrame( void ) {
+ GLenum err;
+
+ if( gl_showstats->integer ) {
+ Draw_Stats();
+ }
+ GL_Flush2D();
+
+ if( gl_log->modified ) {
+ QGL_EnableLogging( gl_log->integer );
+ gl_log->modified = qfalse;
+ }
+
+ while( ( err = qglGetError() ) != GL_NO_ERROR ) {
+ Com_EPrintf( "GL_EndFrame: %s\n", GL_ErrorString( err ) );
+ }
+ video.EndFrame();
+}
+
+/*
+==============================================================================
+
+ SCREEN SHOTS
+
+==============================================================================
+*/
+
+#define SCREENSHOTS_DIRECTORY "screenshots"
+
+#ifdef USE_JPEG
+
+/*
+==================
+GL_ScreenShotJPEG
+==================
+*/
+static qboolean GL_ScreenShotJPEG( const char *filename ) {
+ byte *buffer;
+ int ret;
+
+ buffer = fs.AllocTempMem( gl_config.vidWidth * gl_config.vidHeight * 3 );
+
+ qglReadPixels( 0, 0, gl_config.vidWidth, gl_config.vidHeight, GL_RGB,
+ GL_UNSIGNED_BYTE, buffer );
+
+ ret = Image_WriteJPG( filename, buffer, gl_config.vidWidth,
+ gl_config.vidHeight, gl_screenshot_quality->integer );
+
+ fs.FreeFile( buffer );
+
+ return ret;
+}
+
+#endif
+
+/*
+==================
+GL_ScreenShotTGA
+==================
+*/
+static qboolean GL_ScreenShotTGA( const char *filename ) {
+ byte *buffer;
+ int ret;
+
+ buffer = fs.AllocTempMem( gl_config.vidWidth * gl_config.vidHeight * 3 );
+
+ qglReadPixels( 0, 0, gl_config.vidWidth, gl_config.vidHeight, GL_BGR,
+ GL_UNSIGNED_BYTE, buffer );
+
+ ret = Image_WriteTGA( filename, buffer, gl_config.vidWidth,
+ gl_config.vidHeight );
+
+ fs.FreeFile( buffer );
+
+ return ret;
+}
+
+/*
+==================
+GL_ScreenShot_f
+==================
+*/
+static void GL_ScreenShot_f( void ) {
+ char picname[MAX_QPATH];
+ char checkname[MAX_QPATH];
+ int i;
+ qboolean screenshotJPEG;
+ qboolean silent;
+ qboolean ret;
+ char *ext;
+
+ if( cmd.Argc() > 3 ) {
+ Com_Printf( "Usage: %s [name] [silent]\n", cmd.Argv( 0 ) );
+ return;
+ }
+
+#ifdef USE_JPEG
+ if( !Q_stricmp( cmd.Argv( 0 ), "screenshotJPEG" ) ) {
+ screenshotJPEG = qtrue;
+ ext = ".jpg";
+ } else
+#endif
+ {
+ screenshotJPEG = qfalse;
+ ext = ".tga";
+ }
+
+ silent = qfalse;
+ picname[0] = 0;
+ for( i = 1; i < cmd.Argc(); i++ ) {
+ if( !Q_stricmp( cmd.Argv( i ), "silent" ) ) {
+ silent = qtrue;
+ continue;
+ }
+
+ if( picname[0] ) {
+ break;
+ }
+
+ Q_strncpyz( picname, cmd.Argv( i ), sizeof( picname ) );
+
+ }
+
+//
+// find a file name to save it to
+//
+ if( !picname[0] ) {
+ for( i = 0; i < 1000; i++ ) {
+ Com_sprintf( picname, sizeof( picname ), "quake%03d%s", i, ext );
+ Com_sprintf( checkname, sizeof( checkname ), SCREENSHOTS_DIRECTORY"/%s", picname );
+
+ if( fs.LoadFile( checkname, NULL ) == -1 ) {
+ break; // file doesn't exist
+ }
+
+ }
+
+ if( i == 1000 ) {
+ if( !silent ) {
+ Com_WPrintf( "Couldn't create a screenshot, all slots full\n" );
+ }
+ return;
+ }
+ } else {
+ COM_DefaultExtension( picname, ext, sizeof( picname ) );
+ Com_sprintf( checkname, sizeof( checkname ), SCREENSHOTS_DIRECTORY"/%s", picname );
+ }
+
+#ifdef USE_JPEG
+ if( screenshotJPEG ) {
+ ret = GL_ScreenShotJPEG( checkname );
+ } else
+#endif
+ {
+ ret = GL_ScreenShotTGA( checkname );
+ }
+
+ if( silent ) {
+ return;
+ }
+
+ if( ret ) {
+ Com_Printf( "Wrote %s\n", picname );
+ } else {
+ Com_WPrintf( "Failed to write %s\n", picname );
+ }
+
+}
+
+
+static void GL_Strings_f( void ) {
+ Com_Printf( "GL_VENDOR: %s\n", gl_config.vendorString );
+ Com_Printf( "GL_RENDERER: %s\n", gl_config.rendererString );
+ Com_Printf( "GL_VERSION: %s\n", gl_config.versionString );
+ Com_Printf( "GL_EXTENSIONS: %s\n", gl_config.extensionsString );
+}
+
+// ==============================================================================
+
+
+static void GL_ModeChanged( int width, int height, int flags,
+ int rowbytes, void *pixels )
+{
+ gl_config.vidWidth = width;
+ gl_config.vidHeight = height;
+ gl_config.flags = flags;
+}
+
+static void GL_Register( void ) {
+ cvar.Subsystem( CVAR_SYSTEM_VIDEO );
+
+ /* misc */
+#ifdef USE_JPEG
+ gl_screenshot_quality = cvar.Get( "gl_screenshot_quality", "100",
+ CVAR_ARCHIVE );
+#endif
+ gl_modulate = cvar.Get( "gl_modulate", "1", CVAR_ARCHIVE );
+ gl_hwgamma = cvar.Get( "vid_hwgamma", "0", CVAR_ARCHIVE|CVAR_LATCHED );
+
+ /* development variables */
+ gl_znear = cvar.Get( "gl_znear", "2", CVAR_CHEAT );
+ gl_zfar = cvar.Get( "gl_zfar", "16384", 0 );
+ gl_log = cvar.Get( "gl_log", "0", 0 );
+ gl_drawworld = cvar.Get( "gl_drawworld", "1", CVAR_CHEAT );
+ gl_drawentities = cvar.Get( "gl_drawentities", "1", CVAR_CHEAT );
+ gl_showtris = cvar.Get( "gl_showtris", "0", CVAR_CHEAT );
+ gl_showstats = cvar.Get( "gl_showstats", "0", 0 );
+ gl_cull_nodes = cvar.Get( "gl_cull_nodes", "1", 0 );
+ gl_cull_models = cvar.Get( "gl_cull_models", "1", 0 );
+ gl_clear = cvar.Get( "gl_clear", "0", 0 );
+ gl_novis = cvar.Get( "gl_novis", "0", 0 );
+ gl_lockpvs = cvar.Get( "gl_lockpvs", "0", CVAR_CHEAT );
+ gl_primitives = cvar.Get( "gl_primitives", "0", 0 );
+ gl_sort = cvar.Get( "gl_sort", "0", 0 );
+ gl_subdivide = cvar.Get( "gl_subdivide", "1", 0 );
+ gl_fastsky = cvar.Get( "gl_fastsky", "0", 0 );
+ gl_dynamic = cvar.Get( "gl_dynamic", "2", CVAR_ARCHIVE );
+ gl_fullbright = cvar.Get( "r_fullbright", "0", CVAR_CHEAT );
+
+ cmd.AddCommand( "screenshot", GL_ScreenShot_f );
+#ifdef USE_JPEG
+ cmd.AddCommand( "screenshotJPEG", GL_ScreenShot_f );
+#endif
+ cmd.AddCommand( "strings", GL_Strings_f );
+
+ cvar.Subsystem( CVAR_SYSTEM_GENERIC );
+}
+
+static void GL_Unregister( void ) {
+ cmd.RemoveCommand( "screenshot" );
+#ifdef USE_JPEG
+ cmd.RemoveCommand( "screenshotJPEG" );
+#endif
+ cmd.RemoveCommand( "strings" );
+
+}
+
+static qboolean GL_SetupExtensions( void ) {
+ const char *extensions;
+ int integer;
+ float value;
+
+ extensions = gl_config.extensionsString;
+ if( strstr( extensions, "GL_EXT_compiled_vertex_array" ) ) {
+ Com_Printf( "...enabling GL_EXT_compiled_vertex_array\n" );
+ qglLockArraysEXT = ( PFNGLLOCKARRAYSEXTPROC )qwglGetProcAddress( "glLockArraysEXT" );
+ qglUnlockArraysEXT = ( PFNGLUNLOCKARRAYSEXTPROC )qwglGetProcAddress( "glUnlockArraysEXT" );
+ } else {
+ Com_Printf( "GL_EXT_compiled_vertex_array not found\n" );
+ }
+
+ gl_static.numTextureUnits = 1;
+ if( strstr( extensions, "GL_ARB_multitexture" ) ) {
+ qglGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB, &integer );
+ if( integer > 1 ) {
+ Com_Printf( "...enabling GL_ARB_multitexture (%d texture units)\n", integer );
+ qglActiveTextureARB = ( PFNGLACTIVETEXTUREARBPROC )qwglGetProcAddress( "glActiveTextureARB" );
+ qglClientActiveTextureARB = ( PFNGLCLIENTACTIVETEXTUREARBPROC )qwglGetProcAddress( "glClientActiveTextureARB" );
+ qglMultiTexCoord2fvARB = ( PFNGLMULTITEXCOORD2FVARBPROC )qwglGetProcAddress( "glMultiTexCoord2fvARB" );
+ if( integer > MAX_TMUS ) {
+ integer = MAX_TMUS;
+ }
+ gl_static.numTextureUnits = integer;
+ } else {
+ Com_Printf( "...ignoring GL_ARB_multitexture,\n"
+ "not enough texture units supported (%d)\n", integer );
+ }
+ } else {
+ Com_Printf( "GL_ARB_multitexture not found\n" );
+ }
+
+ gl_config.maxAnisotropy = 1;
+ if( strstr( extensions, "GL_EXT_texture_filter_anisotropic" ) ) {
+ qglGetFloatv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &value );
+ if( value >= 2 ) {
+ Com_Printf( "...enabling GL_EXT_texture_filter_anisotropic\n"
+ "(max anisotropy is %.1f)\n", value );
+ gl_config.maxAnisotropy = value;
+ } else {
+ Com_Printf( "...ignoring GL_EXT_texture_filter_anisotropic,\n"
+ "not enough anisotropy supported (%.1f)\n", value );
+ }
+ } else {
+ Com_Printf( "GL_EXT_texture_filter_anisotropic not found\n" );
+ }
+
+ if( !qglActiveTextureARB ) {
+ return qfalse;
+ }
+
+ qglGetIntegerv( GL_MAX_TEXTURE_SIZE, &gl_static.maxTextureSize );
+ if( gl_static.maxTextureSize > MAX_TEXTURE_SIZE ) {
+ gl_static.maxTextureSize = MAX_TEXTURE_SIZE;
+ }
+
+ return qtrue;
+}
+
+void GL_SetDefaultState( void ) {
+ qglDrawBuffer( GL_BACK );
+ qglClearColor( 0, 0, 0, 1 );
+ qglClearDepth( 1 );
+ qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+ qglEnable( GL_DEPTH_TEST );
+ qglDepthFunc( GL_LEQUAL );
+ qglDepthRange( 0, 1 );
+ qglDepthMask( GL_TRUE );
+ qglDisable( GL_BLEND );
+ qglDisable( GL_ALPHA_TEST );
+ qglAlphaFunc( GL_GREATER, 0.666f );
+ qglHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
+ qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
+
+ qglEnableClientState( GL_VERTEX_ARRAY );
+ qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
+
+ GL_SelectTMU( 0 );
+ qglEnable( GL_TEXTURE_2D );
+ GL_Bits( GLS_DEFAULT );
+}
+
+static void GL_SetupRenderer( void ) {
+ char renderer_buffer[MAX_STRING_CHARS];
+
+ Q_strncpyz( renderer_buffer, gl_config.rendererString,
+ sizeof( renderer_buffer ) );
+ Q_strlwr( renderer_buffer );
+
+ if( strstr( renderer_buffer, "voodoo" ) ) {
+ if( !strstr( renderer_buffer, "rush" ) ) {
+ gl_config.renderer = GL_RENDERER_VOODOO;
+ } else {
+ gl_config.renderer = GL_RENDERER_VOODOO_RUSH;
+ }
+ } else if( strstr( renderer_buffer, "permedia" ) ) {
+ gl_config.renderer = GL_RENDERER_PERMEDIA2;
+ } else if ( strstr( renderer_buffer, "glint" ) ) {
+ gl_config.renderer = GL_RENDERER_GLINT;
+ } else if( strstr( renderer_buffer, "gdi" ) ) {
+ gl_config.renderer = GL_RENDERER_MCD;
+ } else if( strstr( renderer_buffer, "glzicd" ) ) {
+ gl_config.renderer = GL_RENDERER_INTERGRAPH;
+ } else if( strstr( renderer_buffer, "pcx2" ) ) {
+ gl_config.renderer = GL_RENDERER_POWERVR;
+ } else if( strstr( renderer_buffer, "verite" ) ) {
+ gl_config.renderer = GL_RENDERER_RENDITION;
+ } else if( strstr( renderer_buffer, "mesa dri" ) ) {
+ gl_config.renderer = GL_RENDERER_MESADRI;
+ } else {
+ gl_config.renderer = GL_RENDERER_OTHER;
+ }
+}
+
+static void GL_PostInit( void ) {
+ GL_InitImages();
+ GL_InitModels();
+ GL_SetDefaultState();
+}
+
+static qboolean GL_Init( qboolean total ) {
+ Com_DPrintf( "GL_Init( %i )\n", total );
+
+ if( !total ) {
+ GL_PostInit();
+ return qtrue;
+ }
+
+ Com_Printf( "ref_gl " VERSION ", " __DATE__ "\n" );
+#if 0
+#ifdef USE_JPEG
+ Com_Printf( "w/ libjpeg v%d\n", JPEG_LIB_VERSION );
+#endif
+#ifdef USE_PNG
+ Com_Printf( "w/ libpng v" PNG_LIBPNG_VER_STRING "\n" );
+#endif
+#endif
+
+ /* initialize OS-specific parts of OpenGL */
+ /* create the window and set up the context */
+ if( !video.Init() ) {
+ return qfalse;
+ }
+
+ GL_Register();
+
+ /* initialize our QGL dynamic bindings */
+ QGL_Init();
+
+#define GET_STRING( x ) ( const char * )qglGetString( x )
+
+ gl_config.vendorString = GET_STRING( GL_VENDOR );
+ gl_config.rendererString = GET_STRING( GL_RENDERER );
+ gl_config.versionString = GET_STRING( GL_VERSION );
+ gl_config.extensionsString = GET_STRING( GL_EXTENSIONS );
+
+ if( !gl_config.extensionsString || !gl_config.extensionsString[0] ) {
+ Com_EPrintf( "No OpenGL extensions found, check your drivers\n" );
+ goto fail;
+ }
+
+ if( !GL_SetupExtensions() ) {
+ Com_EPrintf( "Some of the required OpenGL extensions are missing\n" );
+ goto fail;
+ }
+
+ if( gl_hwgamma->integer && !( gl_config.flags & QVF_GAMMARAMP ) ) {
+ cvar.SetInteger( "vid_hwgamma", 0 );
+ Com_Printf( "Hardware gamma is not supported by this video driver\n" );
+ }
+
+ GL_SetupRenderer();
+
+ QGL_EnableLogging( gl_log->integer );
+ gl_log->modified = qfalse;
+
+ GL_PostInit();
+
+ if( (( size_t )tess.vertices) & 15 ) {
+ Com_WPrintf( "tess.vertices not 16 byte aligned\n" );
+ }
+
+ gl_sort = cvar.Get( "gl_sort",
+ gl_config.renderer == GL_RENDERER_MESADRI ? "1" : "0", 0 );
+
+ Com_DPrintf( "Finished GL_Init\n" );
+
+ return qtrue;
+
+fail:
+ QGL_Shutdown();
+ GL_Unregister();
+ video.Shutdown();
+ return qfalse;
+}
+
+/*
+===============
+R_Shutdown
+===============
+*/
+void GL_Shutdown( qboolean total ) {
+ Com_DPrintf( "GL_Shutdown( %i )\n", total );
+
+ Bsp_FreeWorld();
+ GL_ShutdownImages();
+ GL_ShutdownModels();
+
+ if( !total ) {
+ return;
+ }
+
+ /*
+ ** shut down OS specific OpenGL stuff like contexts, etc.
+ */
+ video.Shutdown();
+
+ /*
+ ** shutdown our QGL subsystem
+ */
+ QGL_Shutdown();
+
+ GL_Unregister();
+
+ memset( &gl_static, 0, sizeof( gl_static ) );
+ memset( &gl_config, 0, sizeof( gl_config ) );
+}
+
+void GL_BeginRegistration( const char *name ) {
+ char fullname[MAX_QPATH];
+ bspTexinfo_t *texinfo, *lastexinfo;
+ bspLeaf_t *leaf, *lastleaf;
+ bspNode_t *node, *lastnode;
+ int i;
+
+ gl_static.registering = qtrue;
+ registration_sequence++;
+
+ memset( &glr, 0, sizeof( glr ) );
+ glr.viewcluster1 = glr.viewcluster2 = -2;
+
+ Com_sprintf( fullname, sizeof( fullname ), "maps/%s.bsp", name );
+
+ /* check if the required world model was already loaded */
+ if( !strcmp( r_world.name, fullname ) &&
+ !cvar.VariableInteger( "flushmap" ) )
+ {
+ lastexinfo = r_world.texinfos + r_world.numTexinfos;
+ for( texinfo = r_world.texinfos; texinfo != lastexinfo; texinfo++ ) {
+ texinfo->image->registration_sequence = registration_sequence;
+ }
+ lastleaf = r_world.leafs + r_world.numLeafs;
+ for( leaf = r_world.leafs; leaf != lastleaf; leaf++ ) {
+ leaf->visframe = 0;
+ }
+ lastnode = r_world.nodes + r_world.numNodes;
+ for( node = r_world.nodes; node != lastnode; node++ ) {
+ node->visframe = 0;
+ }
+ for( i = 0; i < lm.numMaps; i++ ) {
+ lm.lightmaps[i]->registration_sequence = registration_sequence;
+ }
+ Com_DPrintf( "GL_BeginRegistration: reused old world model\n" );
+ return;
+ }
+
+ Bsp_FreeWorld();
+ GL_BeginPostProcessing();
+
+ if( !Bsp_LoadWorld( fullname ) ) {
+ Com_Error( ERR_DROP, "Couldn't load '%s'\n", fullname );
+ }
+
+ GL_EndPostProcessing();
+}
+
+void GL_EndRegistration( void ) {
+ R_FreeUnusedImages();
+ Model_FreeUnused();
+ if( scrap_dirty ) {
+ Scrap_Upload();
+ }
+ gl_static.registering = qfalse;
+}
+
+void GL_SetPalette( const byte *pal ) {
+ int i;
+
+ if( pal == NULL ) {
+ for( i = 0; i < 256; i++ ) {
+ gl_static.palette[i] = d_8to24table[i];
+ }
+ return;
+ }
+
+ for( i = 0; i < 256; i++ ) {
+ gl_static.palette[i] = MakeColor( pal[0], pal[1], pal[2], 255 );
+ pal += 3;
+ }
+}
+
+void GL_GetConfig( glconfig_t *config ) {
+ *config = gl_config;
+}
+
+#ifndef REF_HARD_LINKED
+// this is only here so the functions in q_shared.c can link
+
+void Com_Printf( const char *fmt, ... ) {
+ va_list argptr;
+ char text[MAXPRINTMSG];
+
+ va_start( argptr, fmt );
+ Q_vsnprintf( text, sizeof( text ), fmt, argptr );
+ va_end( argptr );
+
+ com.Print( PRINT_ALL, text );
+}
+
+void Com_DPrintf( const char *fmt, ... ) {
+ va_list argptr;
+ char text[MAXPRINTMSG];
+
+ va_start( argptr, fmt );
+ Q_vsnprintf( text, sizeof( text ), fmt, argptr );
+ va_end( argptr );
+
+ com.Print( PRINT_DEVELOPER, text );
+}
+
+void Com_WPrintf( const char *fmt, ... ) {
+ va_list argptr;
+ char text[MAXPRINTMSG];
+
+ va_start( argptr, fmt );
+ Q_vsnprintf( text, sizeof( text ), fmt, argptr );
+ va_end( argptr );
+
+ com.Print( PRINT_WARNING, text );
+}
+
+void Com_EPrintf( const char *fmt, ... ) {
+ va_list argptr;
+ char text[MAXPRINTMSG];
+
+ va_start( argptr, fmt );
+ Q_vsnprintf( text, sizeof( text ), fmt, argptr );
+ va_end( argptr );
+
+ com.Print( PRINT_ERROR, text );
+}
+
+void Com_Error( comErrorType_t type, const char *error, ... ) {
+ va_list argptr;
+ char text[MAXPRINTMSG];
+
+ va_start( argptr, error );
+ Q_vsnprintf( text, sizeof( text ), error, argptr );
+ va_end( argptr );
+
+ com.Error( type, text );
+}
+
+#endif /* !REF_HARD_LINKED */
+
+/*
+=================
+Ref_FillAPI
+=================
+*/
+static void Ref_FillAPI( refAPI_t *api ) {
+ api->BeginRegistration = GL_BeginRegistration;
+ api->RegisterModel = GL_RegisterModel;
+ api->RegisterSkin = R_RegisterSkin;
+ api->RegisterPic = R_RegisterPic;
+ api->RegisterFont = GL_RegisterFont;
+ api->SetSky = R_SetSky;
+ api->EndRegistration = GL_EndRegistration;
+ api->GetModelSize = GL_GetModelSize;
+
+ api->RenderFrame = GL_RenderFrame;
+ api->LightPoint = GL_LightPoint;
+
+ api->SetColor = Draw_SetColor;
+ api->SetClipRect = Draw_SetClipRect;
+ api->SetScale = Draw_SetScale;
+ api->DrawString = Draw_String;
+ api->DrawChar = Draw_Char;
+ api->DrawGetPicSize = Draw_GetPicSize;
+ api->DrawGetFontSize = Draw_GetFontSize;
+ api->DrawPic = Draw_Pic;
+ api->DrawStretchPicST = Draw_StretchPicST;
+ api->DrawStretchPic = Draw_StretchPic;
+ api->DrawTileClear = Draw_TileClear;
+ api->DrawFill = Draw_Fill;
+ api->DrawStretchRaw = Draw_StretchRaw;
+ api->DrawFillEx = Draw_FillEx;
+
+ api->Init = GL_Init;
+ api->Shutdown = GL_Shutdown;
+
+ api->CinematicSetPalette = GL_SetPalette;
+ api->BeginFrame = GL_BeginFrame;
+ api->EndFrame = GL_EndFrame;
+ api->ModeChanged = GL_ModeChanged;
+
+ api->GetConfig = GL_GetConfig;
+}
+
+/*
+=================
+Ref_APISetupCallback
+=================
+*/
+qboolean Ref_APISetupCallback( api_type_t type, void *api ) {
+ switch( type ) {
+ case API_REFRESH:
+ Ref_FillAPI( ( refAPI_t * )api );
+ break;
+ default:
+ return qfalse;
+ }
+
+ return qtrue;
+}
+
+#ifndef REF_HARD_LINKED
+
+/*
+@@@@@@@@@@@@@@@@@@@@@
+moduleEntry
+
+@@@@@@@@@@@@@@@@@@@@@
+*/
+EXPORTED void *moduleEntry( int query, void *data ) {
+ moduleInfo_t *info;
+ moduleCapability_t caps;
+ APISetupCallback_t callback;
+
+ switch( query ) {
+ case MQ_GETINFO:
+ info = ( moduleInfo_t * )data;
+ info->api_version = MODULES_APIVERSION;
+ Q_strncpyz( info->fullname, "OpenGL Refresh Driver",
+ sizeof( info->fullname ) );
+ Q_strncpyz( info->author, "Andrey Nazarov", sizeof( info->author ) );
+ return ( void * )qtrue;
+
+ case MQ_GETCAPS:
+ caps = MCP_REFRESH;
+ return ( void * )caps;
+
+ case MQ_SETUPAPI:
+ if( ( callback = ( APISetupCallback_t )data ) == NULL ) {
+ return NULL;
+ }
+ callback( API_CMD, &cmd );
+ callback( API_CVAR, &cvar );
+ callback( API_FS, &fs );
+ callback( API_COMMON, &com );
+ callback( API_SYSTEM, &sys );
+ callback( API_VIDEO_OPENGL, &video );
+
+ return ( void * )Ref_APISetupCallback;
+
+ }
+
+ /* quiet compiler warning */
+ return NULL;
+}
+
+#endif /* !REF_HARD_LINKED */
+