From cab34b45b70983aa2e5f6c54bdbc7f41e9497c4f Mon Sep 17 00:00:00 2001 From: leilei- Date: Mon, 14 Apr 2014 04:19:18 -0400 Subject: [PATCH] - Preparing renderer_software. The theory is to somehow throw things through a TinyGL pixelbuffer with a crapload of compromises. Not there yet but still procrastinplanning on it. --- Makefile | 83 +++- code/renderersoft/sdl_glimp.c | 820 ++++++++++++++++++++++++++++++++++ 2 files changed, 902 insertions(+), 1 deletion(-) create mode 100644 code/renderersoft/sdl_glimp.c diff --git a/Makefile b/Makefile index a1252db0..1ea026fd 100644 --- a/Makefile +++ b/Makefile @@ -229,6 +229,7 @@ SDIR=$(MOUNT_DIR)/server RCOMMONDIR=$(MOUNT_DIR)/renderercommon RGL1DIR=$(MOUNT_DIR)/renderergl1 RGL2DIR=$(MOUNT_DIR)/renderergl2 +RSOFTDIR=$(MOUNT_DIR)/renderersoft ROADIR=$(MOUNT_DIR)/renderer_oa CMDIR=$(MOUNT_DIR)/qcommon SDLDIR=$(MOUNT_DIR)/sdl @@ -935,12 +936,14 @@ ifneq ($(BUILD_CLIENT),0) ifneq ($(USE_RENDERER_DLOPEN),0) TARGETS += $(B)/$(CLIENTBIN)$(FULLBINEXT) $(B)/renderer_openarena1_$(SHLIBNAME) TARGETS += $(B)/renderer_opengl1_$(SHLIBNAME) + TARGETS += $(B)/renderer_software_$(SHLIBNAME) ifneq ($(BUILD_RENDERER_OPENGL2), 0) TARGETS += $(B)/renderer_opengl2_$(SHLIBNAME) endif else TARGETS += $(B)/$(CLIENTBIN)$(FULLBINEXT) TARGETS += $(B)/$(CLIENTBIN)_opengl1$(FULLBINEXT) + TARGETS += $(B)/$(CLIENTBIN)_software$(FULLBINEXT) ifneq ($(BUILD_RENDERER_OPENGL2), 0) TARGETS += $(B)/$(CLIENTBIN)_opengl2$(FULLBINEXT) endif @@ -1288,6 +1291,7 @@ makedirs: @if [ ! -d $(B)/renderergl2 ];then $(MKDIR) $(B)/renderergl2;fi @if [ ! -d $(B)/renderergl2/glsl ];then $(MKDIR) $(B)/renderergl2/glsl;fi @if [ ! -d $(B)/renderer_oa ];then $(MKDIR) $(B)/renderer_oa;fi + @if [ ! -d $(B)/renderersoft ];then $(MKDIR) $(B)/renderersoft;fi @if [ ! -d $(B)/ded ];then $(MKDIR) $(B)/ded;fi @if [ ! -d $(B)/$(BASEGAME) ];then $(MKDIR) $(B)/$(BASEGAME);fi @if [ ! -d $(B)/$(BASEGAME)/cgame ];then $(MKDIR) $(B)/$(BASEGAME)/cgame;fi @@ -1740,6 +1744,46 @@ Q3ROBJ = \ $(B)/renderergl1/sdl_gamma.o \ $(B)/renderergl1/sdl_glimp.o + +Q3RSOFTOBJ = \ + $(B)/renderer_oa/tr_animation.o \ + $(B)/renderer_oa/tr_backend.o \ + $(B)/renderer_oa/tr_bsp.o \ + $(B)/renderer_oa/tr_cmds.o \ + $(B)/renderer_oa/tr_curve.o \ + $(B)/renderer_oa/tr_flares.o \ + $(B)/renderer_oa/tr_font.o \ + $(B)/renderer_oa/tr_image.o \ + $(B)/renderer_oa/tr_image_png.o \ + $(B)/renderer_oa/tr_image_jpg.o \ + $(B)/renderer_oa/tr_image_bmp.o \ + $(B)/renderer_oa/tr_image_tga.o \ + $(B)/renderer_oa/tr_image_pcx.o \ + $(B)/renderer_oa/tr_init.o \ + $(B)/renderer_oa/tr_light.o \ + $(B)/renderer_oa/tr_main.o \ + $(B)/renderer_oa/tr_marks.o \ + $(B)/renderer_oa/tr_mesh.o \ + $(B)/renderer_oa/tr_model.o \ + $(B)/renderer_oa/tr_model_iqm.o \ + $(B)/renderer_oa/tr_noise.o \ + $(B)/renderer_oa/tr_scene.o \ + $(B)/renderer_oa/tr_shade.o \ + $(B)/renderer_oa/tr_shade_calc.o \ + $(B)/renderer_oa/tr_shader.o \ + $(B)/renderer_oa/tr_shadows.o \ + $(B)/renderer_oa/tr_sky.o \ + $(B)/renderer_oa/tr_surface.o \ + $(B)/renderer_oa/tr_world.o \ + \ + $(B)/renderer_oa/tr_bloom.o \ + $(B)/renderer_oa/tr_extensions.o \ + \ + $(B)/renderersoft/sdl_gamma.o \ + $(B)/renderersoft/sdl_glimp.o + + + ifneq ($(USE_RENDERER_DLOPEN), 0) Q3ROBJ += \ $(B)/renderergl1/q_shared.o \ @@ -1758,6 +1802,13 @@ ifneq ($(USE_RENDERER_DLOPEN), 0) $(B)/renderergl1/puff.o \ $(B)/renderergl1/q_math.o \ $(B)/renderergl1/tr_subs.o + + Q3RSOFTOBJ += \ + $(B)/renderergl1/q_shared.o \ + $(B)/renderergl1/puff.o \ + $(B)/renderergl1/q_math.o \ + $(B)/renderergl1/tr_subs.o + endif ifneq ($(USE_INTERNAL_JPEG),0) @@ -2092,6 +2143,12 @@ $(B)/renderer_openarena1_$(SHLIBNAME): $(Q3ROAOBJ) $(JPGOBJ) $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3ROAOBJ) $(JPGOBJ) \ $(THREAD_LIBS) $(LIBSDLMAIN) $(RENDERER_LIBS) $(LIBS) +$(B)/renderer_software_$(SHLIBNAME): $(Q3RSOFTOBJ) $(JPGOBJ) + $(echo_cmd) "LD $@" + $(Q)$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(Q3RSOFTOBJ) $(JPGOBJ) \ + $(THREAD_LIBS) $(LIBSDLMAIN) $(RENDERER_LIBS) $(LIBS) + + else $(B)/$(CLIENTBIN)$(FULLBINEXT): $(Q3OBJ) $(Q3ROAOBJ) $(JPGOBJ) $(LIBSDLMAIN) $(echo_cmd) "LD $@" @@ -2110,6 +2167,12 @@ $(B)/$(CLIENTBIN)_opengl1$(FULLBINEXT): $(Q3OBJ) $(Q3ROBJ) $(JPGOBJ) $(LIBSDLMAI $(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) \ -o $@ $(Q3OBJ) $(Q3ROBJ) $(JPGOBJ) \ $(LIBSDLMAIN) $(CLIENT_LIBS) $(RENDERER_LIBS) $(LIBS) + +$(B)/$(CLIENTBIN)_software$(FULLBINEXT): $(Q3OBJ) $(Q3RSOFTOBJ) $(JPGOBJ) $(LIBSDLMAIN) + $(echo_cmd) "LD $@" + $(Q)$(CC) $(CLIENT_CFLAGS) $(CFLAGS) $(CLIENT_LDFLAGS) $(LDFLAGS) \ + -o $@ $(Q3OBJ) $(Q3RSOFTOBJ) $(JPGOBJ) \ + $(LIBSDLMAIN) $(CLIENT_LIBS) $(RENDERER_LIBS) $(LIBS) endif ifneq ($(strip $(LIBSDLMAIN)),) @@ -2631,6 +2694,22 @@ $(B)/renderer_oa/%.o: $(ROADIR)/%.c $(B)/renderer_oa/%.o: $(RCOMMONDIR)/%.c $(DO_REF_CC) +$(B)/renderersoft/%.o: $(CMDIR)/%.c + $(DO_REF_CC) + +$(B)/renderersoft/%.o: $(SDLDIR)/%.c + $(DO_REF_CC) + +$(B)/renderersoft/%.o: $(JPDIR)/%.c + $(DO_REF_CC) + +$(B)/renderersoft/%.o: $(RCOMMONDIR)/%.c + $(DO_REF_CC) + +$(B)/renderersoft/%.o: $(RSOFTDIR)/%.c + $(DO_REF_CC) + + $(B)/ded/%.o: $(ASMDIR)/%.s $(DO_AS) @@ -2754,7 +2833,7 @@ $(B)/$(MISSIONPACK)/qcommon/%.asm: $(CMDIR)/%.c $(Q3LCC) # MISC ############################################################################# -OBJ = $(Q3OBJ) $(Q3ROBJ) $(Q3R2OBJ) $(Q3ROAOBJ) $(Q3DOBJ) $(JPGOBJ) \ +OBJ = $(Q3OBJ) $(Q3ROBJ) $(Q3R2OBJ) $(Q3ROAOBJ) $(Q3RSOFTOBJ) $(Q3DOBJ) $(JPGOBJ) \ $(MPGOBJ) $(Q3GOBJ) $(Q3CGOBJ) $(MPCGOBJ) $(Q3UIOBJ) $(MPUIOBJ) \ $(MPGVMOBJ) $(Q3GVMOBJ) $(Q3CGVMOBJ) $(MPCGVMOBJ) $(Q3UIVMOBJ) $(MPUIVMOBJ) TOOLSOBJ = $(LBURGOBJ) $(Q3CPPOBJ) $(Q3RCCOBJ) $(Q3LCCOBJ) $(Q3ASMOBJ) @@ -2776,12 +2855,14 @@ ifneq ($(BUILD_CLIENT),0) $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(CLIENTBIN)$(FULLBINEXT) $(COPYBINDIR)/$(CLIENTBIN)$(FULLBINEXT) ifneq ($(USE_RENDERER_DLOPEN),0) $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/renderer_opengl1_$(SHLIBNAME) $(COPYBINDIR)/renderer_opengl1_$(SHLIBNAME) + $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/renderer_software_$(SHLIBNAME) $(COPYBINDIR)/renderer_software_$(SHLIBNAME) $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/renderer_openarena1_$(SHLIBNAME) $(COPYBINDIR)/renderer_openarena1_$(SHLIBNAME) ifneq ($(BUILD_RENDERER_OPENGL2),0) $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/renderer_opengl2_$(SHLIBNAME) $(COPYBINDIR)/renderer_opengl2_$(SHLIBNAME) endif else $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(CLIENTBIN)_opengl1$(FULLBINEXT) $(COPYBINDIR)/$(CLIENTBIN)_opengl1$(FULLBINEXT) + $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(CLIENTBIN)_software$(FULLBINEXT) $(COPYBINDIR)/$(CLIENTBIN)_software$(FULLBINEXT) ifneq ($(BUILD_RENDERER_OPENGL2),0) $(INSTALL) $(STRIP_FLAG) -m 0755 $(BR)/$(CLIENTBIN)_opengl2$(FULLBINEXT) $(COPYBINDIR)/$(CLIENTBIN)_opengl2$(FULLBINEXT) endif diff --git a/code/renderersoft/sdl_glimp.c b/code/renderersoft/sdl_glimp.c new file mode 100644 index 00000000..7b08ec90 --- /dev/null +++ b/code/renderersoft/sdl_glimp.c @@ -0,0 +1,820 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// TODO: instead, make a pixel buffer to a 8, 16 or 32bit surface +// then reroute it all through TinySDGL there +#ifdef USE_LOCAL_HEADERS +# include "SDL.h" +#else +# include +#endif + +#include +#include +#include +#include + +#include "../renderercommon/tr_common.h" +#include "../sys/sys_local.h" +#include "sdl_icon.h" + +/* Just hack it for now. */ +#ifdef MACOS_X +#include +typedef CGLContextObj QGLContext; +#define GLimp_GetCurrentContext() CGLGetCurrentContext() +#define GLimp_SetCurrentContext(ctx) CGLSetCurrentContext(ctx) +#else +typedef void *QGLContext; +#define GLimp_GetCurrentContext() (NULL) +#define GLimp_SetCurrentContext(ctx) +#endif + +static QGLContext opengl_context; + +typedef enum +{ + RSERR_OK, + + RSERR_INVALID_FULLSCREEN, + RSERR_INVALID_MODE, + + RSERR_UNKNOWN +} rserr_t; + +static SDL_Surface *screen = NULL; +static const SDL_VideoInfo *videoInfo = NULL; + +cvar_t *r_allowSoftwareGL; // Don't abort out if a hardware visual can't be obtained +cvar_t *r_allowResize; // make window resizable +cvar_t *r_centerWindow; +cvar_t *r_sdlDriver; + +void (APIENTRYP qglActiveTextureARB) (GLenum texture); +void (APIENTRYP qglClientActiveTextureARB) (GLenum texture); +void (APIENTRYP qglMultiTexCoord2fARB) (GLenum target, GLfloat s, GLfloat t); + +void (APIENTRYP qglLockArraysEXT) (GLint first, GLsizei count); +void (APIENTRYP qglUnlockArraysEXT) (void); + +/* +=============== +GLimp_Shutdown +=============== +*/ +void GLimp_Shutdown( void ) +{ + ri.IN_Shutdown(); + + SDL_QuitSubSystem( SDL_INIT_VIDEO ); + screen = NULL; +} + +/* +=============== +GLimp_Minimize + +Minimize the game so that user is back at the desktop +=============== +*/ +void GLimp_Minimize(void) +{ + SDL_WM_IconifyWindow(); +} + + +/* +=============== +GLimp_LogComment +=============== +*/ +void GLimp_LogComment( char *comment ) +{ +} + +/* +=============== +GLimp_CompareModes +=============== +*/ +static int GLimp_CompareModes( const void *a, const void *b ) +{ + const float ASPECT_EPSILON = 0.001f; + SDL_Rect *modeA = *(SDL_Rect **)a; + SDL_Rect *modeB = *(SDL_Rect **)b; + float aspectA = (float)modeA->w / (float)modeA->h; + float aspectB = (float)modeB->w / (float)modeB->h; + int areaA = modeA->w * modeA->h; + int areaB = modeB->w * modeB->h; + float aspectDiffA = fabs( aspectA - displayAspect ); + float aspectDiffB = fabs( aspectB - displayAspect ); + float aspectDiffsDiff = aspectDiffA - aspectDiffB; + + if( aspectDiffsDiff > ASPECT_EPSILON ) + return 1; + else if( aspectDiffsDiff < -ASPECT_EPSILON ) + return -1; + else + return areaA - areaB; +} + + +/* +=============== +GLimp_DetectAvailableModes +=============== +*/ +static void GLimp_DetectAvailableModes(void) +{ + char buf[ MAX_STRING_CHARS ] = { 0 }; + SDL_Rect **modes; + int numModes; + int i; + + modes = SDL_ListModes( videoInfo->vfmt, SDL_OPENGL | SDL_FULLSCREEN ); + + if( !modes ) + { + ri.Printf( PRINT_WARNING, "Can't get list of available modes\n" ); + return; + } + + if( modes == (SDL_Rect **)-1 ) + { + ri.Printf( PRINT_ALL, "Display supports any resolution\n" ); + return; // can set any resolution + } + + for( numModes = 0; modes[ numModes ]; numModes++ ); + + if( numModes > 1 ) + qsort( modes, numModes, sizeof( SDL_Rect* ), GLimp_CompareModes ); + + for( i = 0; i < numModes; i++ ) + { + const char *newModeString = va( "%ux%u ", modes[ i ]->w, modes[ i ]->h ); + + if( strlen( newModeString ) < (int)sizeof( buf ) - strlen( buf ) ) + Q_strcat( buf, sizeof( buf ), newModeString ); + else + ri.Printf( PRINT_WARNING, "Skipping mode %ux%x, buffer too small\n", modes[i]->w, modes[i]->h ); + } + + if( *buf ) + { + buf[ strlen( buf ) - 1 ] = 0; + ri.Printf( PRINT_ALL, "Available modes: '%s'\n", buf ); + ri.Cvar_Set( "r_availableModes", buf ); + } +} + +/* +=============== +GLimp_SetMode +=============== +*/ +static int GLimp_SetMode(int mode, qboolean fullscreen, qboolean noborder) +{ + const char* glstring; + int sdlcolorbits; + int colorbits, depthbits, stencilbits; + int tcolorbits, tdepthbits, tstencilbits; + int samples; + int i = 0; + SDL_Surface *vidscreen = NULL; + Uint32 flags = SDL_OPENGL; + + ri.Printf( PRINT_ALL, "Initializing OpenGL display\n"); + + if ( r_allowResize->integer ) + flags |= SDL_RESIZABLE; + + if( videoInfo == NULL ) + { + static SDL_VideoInfo sVideoInfo; + static SDL_PixelFormat sPixelFormat; + + videoInfo = SDL_GetVideoInfo( ); + + // Take a copy of the videoInfo + Com_Memcpy( &sPixelFormat, videoInfo->vfmt, sizeof( SDL_PixelFormat ) ); + sPixelFormat.palette = NULL; // Should already be the case + Com_Memcpy( &sVideoInfo, videoInfo, sizeof( SDL_VideoInfo ) ); + sVideoInfo.vfmt = &sPixelFormat; + videoInfo = &sVideoInfo; + + if( videoInfo->current_h > 0 ) + { + // Guess the display aspect ratio through the desktop resolution + // by assuming (relatively safely) that it is set at or close to + // the display's native aspect ratio + displayAspect = (float)videoInfo->current_w / (float)videoInfo->current_h; + + ri.Printf( PRINT_ALL, "Estimated display aspect: %.3f\n", displayAspect ); + } + else + { + ri.Printf( PRINT_ALL, + "Cannot estimate display aspect, assuming 1.333\n" ); + } + } + + ri.Printf (PRINT_ALL, "...setting mode %d:", mode ); + + if (mode == -2) + { + // use desktop video resolution + if( videoInfo->current_h > 0 ) + { + glConfig.vidWidth = videoInfo->current_w; + glConfig.vidHeight = videoInfo->current_h; + } + else + { + glConfig.vidWidth = 640; + glConfig.vidHeight = 480; + ri.Printf( PRINT_ALL, + "Cannot determine display resolution, assuming 640x480\n" ); + } + + glConfig.windowAspect = (float)glConfig.vidWidth / (float)glConfig.vidHeight; + } + else if ( !R_GetModeInfo( &glConfig.vidWidth, &glConfig.vidHeight, &glConfig.windowAspect, mode ) ) + { + ri.Printf( PRINT_ALL, " invalid mode\n" ); + return RSERR_INVALID_MODE; + } + ri.Printf( PRINT_ALL, " %d %d\n", glConfig.vidWidth, glConfig.vidHeight); + + if (fullscreen) + { + flags |= SDL_FULLSCREEN; + glConfig.isFullscreen = qtrue; + } + else + { + if (noborder) + flags |= SDL_NOFRAME; + + glConfig.isFullscreen = qfalse; + } + + colorbits = r_colorbits->value; + if ((!colorbits) || (colorbits >= 32)) + colorbits = 24; + + if (!r_depthbits->value) + depthbits = 24; + else + depthbits = r_depthbits->value; + stencilbits = r_stencilbits->value; + samples = r_ext_multisample->value; + + for (i = 0; i < 16; i++) + { + // 0 - default + // 1 - minus colorbits + // 2 - minus depthbits + // 3 - minus stencil + if ((i % 4) == 0 && i) + { + // one pass, reduce + switch (i / 4) + { + case 2 : + if (colorbits == 24) + colorbits = 16; + break; + case 1 : + if (depthbits == 24) + depthbits = 16; + else if (depthbits == 16) + depthbits = 8; + case 3 : + if (stencilbits == 24) + stencilbits = 16; + else if (stencilbits == 16) + stencilbits = 8; + } + } + + tcolorbits = colorbits; + tdepthbits = depthbits; + tstencilbits = stencilbits; + + if ((i % 4) == 3) + { // reduce colorbits + if (tcolorbits == 24) + tcolorbits = 16; + } + + if ((i % 4) == 2) + { // reduce depthbits + if (tdepthbits == 24) + tdepthbits = 16; + else if (tdepthbits == 16) + tdepthbits = 8; + } + + if ((i % 4) == 1) + { // reduce stencilbits + if (tstencilbits == 24) + tstencilbits = 16; + else if (tstencilbits == 16) + tstencilbits = 8; + else + tstencilbits = 0; + } + + sdlcolorbits = 4; + if (tcolorbits == 24) + sdlcolorbits = 8; + +#ifdef __sgi /* Fix for SGIs grabbing too many bits of color */ + if (sdlcolorbits == 4) + sdlcolorbits = 0; /* Use minimum size for 16-bit color */ + + /* Need alpha or else SGIs choose 36+ bit RGB mode */ + SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 1); +#endif + + SDL_GL_SetAttribute( SDL_GL_RED_SIZE, sdlcolorbits ); + SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, sdlcolorbits ); + SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, sdlcolorbits ); + SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, tdepthbits ); + SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, tstencilbits ); + + SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, samples ? 1 : 0 ); + SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, samples ); + + if(r_stereoEnabled->integer) + { + glConfig.stereoEnabled = qtrue; + SDL_GL_SetAttribute(SDL_GL_STEREO, 1); + } + else + { + glConfig.stereoEnabled = qfalse; + SDL_GL_SetAttribute(SDL_GL_STEREO, 0); + } + + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); + +#if 0 // See http://bugzilla.icculus.org/show_bug.cgi?id=3526 + // If not allowing software GL, demand accelerated + if( !r_allowSoftwareGL->integer ) + { + if( SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 ) < 0 ) + { + ri.Printf( PRINT_ALL, "Unable to guarantee accelerated " + "visual with libSDL < 1.2.10\n" ); + } + } +#endif + + if( SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, r_swapInterval->integer ) < 0 ) + ri.Printf( PRINT_ALL, "r_swapInterval requires libSDL >= 1.2.10\n" ); + +#ifdef USE_ICON + { + SDL_Surface *icon = SDL_CreateRGBSurfaceFrom( + (void *)CLIENT_WINDOW_ICON.pixel_data, + CLIENT_WINDOW_ICON.width, + CLIENT_WINDOW_ICON.height, + CLIENT_WINDOW_ICON.bytes_per_pixel * 8, + CLIENT_WINDOW_ICON.bytes_per_pixel * CLIENT_WINDOW_ICON.width, +#ifdef Q3_LITTLE_ENDIAN + 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000 +#else + 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF +#endif + ); + + SDL_WM_SetIcon( icon, NULL ); + SDL_FreeSurface( icon ); + } +#endif + + SDL_WM_SetCaption(CLIENT_WINDOW_TITLE, CLIENT_WINDOW_MIN_TITLE); + SDL_ShowCursor(0); + + if (!(vidscreen = SDL_SetVideoMode(glConfig.vidWidth, glConfig.vidHeight, colorbits, flags))) + { + ri.Printf( PRINT_DEVELOPER, "SDL_SetVideoMode failed: %s\n", SDL_GetError( ) ); + continue; + } + + opengl_context = GLimp_GetCurrentContext(); + + ri.Printf( PRINT_ALL, "Using %d/%d/%d Color bits, %d depth, %d stencil display.\n", + sdlcolorbits, sdlcolorbits, sdlcolorbits, tdepthbits, tstencilbits); + + glConfig.colorBits = tcolorbits; + glConfig.depthBits = tdepthbits; + glConfig.stencilBits = tstencilbits; + break; + } + + GLimp_DetectAvailableModes(); + + if (!vidscreen) + { + ri.Printf( PRINT_ALL, "Couldn't get a visual\n" ); + return RSERR_INVALID_MODE; + } + + screen = vidscreen; + + glstring = (char *) qglGetString (GL_RENDERER); + ri.Printf( PRINT_ALL, "GL_RENDERER: %s\n", glstring ); + + return RSERR_OK; +} + +/* +=============== +GLimp_StartDriverAndSetMode +=============== +*/ +static qboolean GLimp_StartDriverAndSetMode(int mode, qboolean fullscreen, qboolean noborder) +{ + rserr_t err; + + if (!SDL_WasInit(SDL_INIT_VIDEO)) + { + char driverName[ 64 ]; + + if (SDL_Init(SDL_INIT_VIDEO) == -1) + { + ri.Printf( PRINT_ALL, "SDL_Init( SDL_INIT_VIDEO ) FAILED (%s)\n", + SDL_GetError()); + return qfalse; + } + + SDL_VideoDriverName( driverName, sizeof( driverName ) - 1 ); + ri.Printf( PRINT_ALL, "SDL using driver \"%s\"\n", driverName ); + ri.Cvar_Set( "r_sdlDriver", driverName ); + } + + if (fullscreen && ri.Cvar_VariableIntegerValue( "in_nograb" ) ) + { + ri.Printf( PRINT_ALL, "Fullscreen not allowed with in_nograb 1\n"); + ri.Cvar_Set( "r_fullscreen", "0" ); + r_fullscreen->modified = qfalse; + fullscreen = qfalse; + } + + err = GLimp_SetMode(mode, fullscreen, noborder); + + switch ( err ) + { + case RSERR_INVALID_FULLSCREEN: + ri.Printf( PRINT_ALL, "...WARNING: fullscreen unavailable in this mode\n" ); + return qfalse; + case RSERR_INVALID_MODE: + ri.Printf( PRINT_ALL, "...WARNING: could not set the given mode (%d)\n", mode ); + return qfalse; + default: + break; + } + + return qtrue; +} + +static qboolean GLimp_HaveExtension(const char *ext) +{ + const char *ptr = Q_stristr( glConfig.extensions_string, ext ); + if (ptr == NULL) + return qfalse; + ptr += strlen(ext); + return ((*ptr == ' ') || (*ptr == '\0')); // verify it's complete string. +} + + +/* +=============== +GLimp_InitExtensions +=============== +*/ +static void GLimp_InitExtensions( void ) +{ + if ( !r_allowExtensions->integer ) + { + ri.Printf( PRINT_ALL, "* IGNORING OPENGL EXTENSIONS *\n" ); + return; + } + + ri.Printf( PRINT_ALL, "Initializing OpenGL extensions\n" ); + + glConfig.textureCompression = TC_NONE; + + // GL_EXT_texture_compression_s3tc + if ( GLimp_HaveExtension( "GL_ARB_texture_compression" ) && + GLimp_HaveExtension( "GL_EXT_texture_compression_s3tc" ) ) + { + if ( r_ext_compressed_textures->value ) + { + glConfig.textureCompression = TC_S3TC_ARB; + ri.Printf( PRINT_ALL, "...using GL_EXT_texture_compression_s3tc\n" ); + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_compression_s3tc\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_EXT_texture_compression_s3tc not found\n" ); + } + + // GL_S3_s3tc ... legacy extension before GL_EXT_texture_compression_s3tc. + if (glConfig.textureCompression == TC_NONE) + { + if ( GLimp_HaveExtension( "GL_S3_s3tc" ) ) + { + if ( r_ext_compressed_textures->value ) + { + glConfig.textureCompression = TC_S3TC; + ri.Printf( PRINT_ALL, "...using GL_S3_s3tc\n" ); + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_S3_s3tc\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_S3_s3tc not found\n" ); + } + } + + + // GL_EXT_texture_env_add + glConfig.textureEnvAddAvailable = qfalse; + if ( GLimp_HaveExtension( "EXT_texture_env_add" ) ) + { + if ( r_ext_texture_env_add->integer ) + { + glConfig.textureEnvAddAvailable = qtrue; + ri.Printf( PRINT_ALL, "...using GL_EXT_texture_env_add\n" ); + } + else + { + glConfig.textureEnvAddAvailable = qfalse; + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_env_add\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_EXT_texture_env_add not found\n" ); + } + + // GL_ARB_multitexture + qglMultiTexCoord2fARB = NULL; + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + if ( GLimp_HaveExtension( "GL_ARB_multitexture" ) ) + { + if ( r_ext_multitexture->value ) + { + qglMultiTexCoord2fARB = SDL_GL_GetProcAddress( "glMultiTexCoord2fARB" ); + qglActiveTextureARB = SDL_GL_GetProcAddress( "glActiveTextureARB" ); + qglClientActiveTextureARB = SDL_GL_GetProcAddress( "glClientActiveTextureARB" ); + + if ( qglActiveTextureARB ) + { + GLint glint = 0; + qglGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB, &glint ); + glConfig.numTextureUnits = (int) glint; + if ( glConfig.numTextureUnits > 1 ) + { + ri.Printf( PRINT_ALL, "...using GL_ARB_multitexture\n" ); + } + else + { + qglMultiTexCoord2fARB = NULL; + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + ri.Printf( PRINT_ALL, "...not using GL_ARB_multitexture, < 2 texture units\n" ); + } + } + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_ARB_multitexture\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_ARB_multitexture not found\n" ); + } + + // GL_EXT_compiled_vertex_array + if ( GLimp_HaveExtension( "GL_EXT_compiled_vertex_array" ) ) + { + if ( r_ext_compiled_vertex_array->value ) + { + ri.Printf( PRINT_ALL, "...using GL_EXT_compiled_vertex_array\n" ); + qglLockArraysEXT = ( void ( APIENTRY * )( GLint, GLint ) ) SDL_GL_GetProcAddress( "glLockArraysEXT" ); + qglUnlockArraysEXT = ( void ( APIENTRY * )( void ) ) SDL_GL_GetProcAddress( "glUnlockArraysEXT" ); + if (!qglLockArraysEXT || !qglUnlockArraysEXT) + { + ri.Error (ERR_FATAL, "bad getprocaddress"); + } + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_compiled_vertex_array\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_EXT_compiled_vertex_array not found\n" ); + } + + textureFilterAnisotropic = qfalse; + if ( GLimp_HaveExtension( "GL_EXT_texture_filter_anisotropic" ) ) + { + if ( r_ext_texture_filter_anisotropic->integer ) { + qglGetIntegerv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, (GLint *)&maxAnisotropy ); + if ( maxAnisotropy <= 0 ) { + ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not properly supported!\n" ); + maxAnisotropy = 0; + } + else + { + ri.Printf( PRINT_ALL, "...using GL_EXT_texture_filter_anisotropic (max: %i)\n", maxAnisotropy ); + textureFilterAnisotropic = qtrue; + } + } + else + { + ri.Printf( PRINT_ALL, "...ignoring GL_EXT_texture_filter_anisotropic\n" ); + } + } + else + { + ri.Printf( PRINT_ALL, "...GL_EXT_texture_filter_anisotropic not found\n" ); + } +} + +#define R_MODE_FALLBACK 3 // 640 * 480 + +/* +=============== +GLimp_Init + +This routine is responsible for initializing the OS specific portions +of OpenGL +=============== +*/ +void GLimp_Init( void ) +{ + r_allowSoftwareGL = ri.Cvar_Get( "r_allowSoftwareGL", "0", CVAR_LATCH ); + r_sdlDriver = ri.Cvar_Get( "r_sdlDriver", "", CVAR_ROM ); + r_allowResize = ri.Cvar_Get( "r_allowResize", "0", CVAR_ARCHIVE | CVAR_LATCH ); + r_centerWindow = ri.Cvar_Get( "r_centerWindow", "0", CVAR_ARCHIVE | CVAR_LATCH ); + + if( ri.Cvar_VariableIntegerValue( "com_abnormalExit" ) ) + { + ri.Cvar_Set( "r_mode", va( "%d", R_MODE_FALLBACK ) ); + ri.Cvar_Set( "r_fullscreen", "0" ); + ri.Cvar_Set( "r_centerWindow", "0" ); + ri.Cvar_Set( "com_abnormalExit", "0" ); + } + + ri.Sys_SetEnv( "SDL_VIDEO_CENTERED", r_centerWindow->integer ? "1" : "" ); + + ri.Sys_GLimpInit( ); + + // Create the window and set up the context + if(GLimp_StartDriverAndSetMode(r_mode->integer, r_fullscreen->integer, r_noborder->integer)) + goto success; + + // Try again, this time in a platform specific "safe mode" + ri.Sys_GLimpSafeInit( ); + + if(GLimp_StartDriverAndSetMode(r_mode->integer, r_fullscreen->integer, qfalse)) + goto success; + + // Finally, try the default screen resolution + if( r_mode->integer != R_MODE_FALLBACK ) + { + ri.Printf( PRINT_ALL, "Setting r_mode %d failed, falling back on r_mode %d\n", + r_mode->integer, R_MODE_FALLBACK ); + + if(GLimp_StartDriverAndSetMode(R_MODE_FALLBACK, qfalse, qfalse)) + goto success; + } + + // Nothing worked, give up + ri.Error( ERR_FATAL, "GLimp_Init() - could not load OpenGL subsystem" ); + +success: + // This values force the UI to disable driver selection + glConfig.driverType = GLDRV_ICD; + glConfig.hardwareType = GLHW_GENERIC; + glConfig.deviceSupportsGamma = SDL_SetGamma( 1.0f, 1.0f, 1.0f ) >= 0; + + // Mysteriously, if you use an NVidia graphics card and multiple monitors, + // SDL_SetGamma will incorrectly return false... the first time; ask + // again and you get the correct answer. This is a suspected driver bug, see + // http://bugzilla.icculus.org/show_bug.cgi?id=4316 + glConfig.deviceSupportsGamma = SDL_SetGamma( 1.0f, 1.0f, 1.0f ) >= 0; + + if ( -1 == r_ignorehwgamma->integer) + glConfig.deviceSupportsGamma = 1; + + if ( 1 == r_ignorehwgamma->integer) + glConfig.deviceSupportsGamma = 0; + + // get our config strings + Q_strncpyz( glConfig.vendor_string, (char *) qglGetString (GL_VENDOR), sizeof( glConfig.vendor_string ) ); + Q_strncpyz( glConfig.renderer_string, (char *) qglGetString (GL_RENDERER), sizeof( glConfig.renderer_string ) ); + if (*glConfig.renderer_string && glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] == '\n') + glConfig.renderer_string[strlen(glConfig.renderer_string) - 1] = 0; + Q_strncpyz( glConfig.version_string, (char *) qglGetString (GL_VERSION), sizeof( glConfig.version_string ) ); + Q_strncpyz( glConfig.extensions_string, (char *) qglGetString (GL_EXTENSIONS), sizeof( glConfig.extensions_string ) ); + + // initialize extensions + GLimp_InitExtensions( ); + + ri.Cvar_Get( "r_availableModes", "", CVAR_ROM ); + + // This depends on SDL_INIT_VIDEO, hence having it here + ri.IN_Init( ); +} + + +/* +=============== +GLimp_EndFrame + +Responsible for doing a swapbuffers +=============== +*/ +void GLimp_EndFrame( void ) +{ + // don't flip if drawing to front buffer + if ( Q_stricmp( r_drawBuffer->string, "GL_FRONT" ) != 0 ) + { + SDL_GL_SwapBuffers(); + } + + if( r_fullscreen->modified ) + { + qboolean fullscreen; + qboolean needToToggle = qtrue; + qboolean sdlToggled = qfalse; + SDL_Surface *s = SDL_GetVideoSurface( ); + + if( s ) + { + // Find out the current state + fullscreen = !!( s->flags & SDL_FULLSCREEN ); + + if( r_fullscreen->integer && ri.Cvar_VariableIntegerValue( "in_nograb" ) ) + { + ri.Printf( PRINT_ALL, "Fullscreen not allowed with in_nograb 1\n"); + ri.Cvar_Set( "r_fullscreen", "0" ); + r_fullscreen->modified = qfalse; + } + + // Is the state we want different from the current state? + needToToggle = !!r_fullscreen->integer != fullscreen; + + if( needToToggle ) + sdlToggled = SDL_WM_ToggleFullScreen( s ); + } + + if( needToToggle ) + { + // SDL_WM_ToggleFullScreen didn't work, so do it the slow way + if( !sdlToggled ) + ri.Cmd_ExecuteText(EXEC_APPEND, "vid_restart\n"); + + ri.IN_Restart( ); + } + + r_fullscreen->modified = qfalse; + } +}