mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-05-13 05:56:56 +03:00
1704 lines
41 KiB
C
1704 lines
41 KiB
C
/*
|
|
===========================================================================
|
|
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
|
|
===========================================================================
|
|
*/
|
|
|
|
#ifdef USE_LOCAL_HEADERS
|
|
# include "SDL.h"
|
|
#else
|
|
# include <SDL.h>
|
|
#endif
|
|
|
|
#if !SDL_VERSION_ATLEAST(1, 2, 10)
|
|
#define SDL_GL_ACCELERATED_VISUAL 15
|
|
#define SDL_GL_SWAP_CONTROL 16
|
|
#elif MINSDL_PATCH >= 10
|
|
#error Code block no longer necessary, please remove
|
|
#endif
|
|
|
|
#ifdef SMP
|
|
# include <SDL_thread.h>
|
|
# ifdef SDL_VIDEO_DRIVER_X11
|
|
# include <X11/Xlib.h>
|
|
# endif
|
|
#endif
|
|
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
|
|
#include "tr_local.h"
|
|
#include "../client/client.h"
|
|
#include "../sys/sys_local.h"
|
|
#include "../sdl/sdl_icon.h"
|
|
#include "SDL_syswm.h"
|
|
|
|
#if defined(WIN32)
|
|
#include <GL/wglew.h>
|
|
#else
|
|
#include <GL/glxew.h>
|
|
#endif
|
|
|
|
/* Just hack it for now. */
|
|
#ifdef MACOS_X
|
|
#include <OpenGL/OpenGL.h>
|
|
typedef CGLContextObj QGLContext;
|
|
|
|
static QGLContext opengl_context;
|
|
|
|
static void GLimp_GetCurrentContext(void)
|
|
{
|
|
opengl_context = CGLGetCurrentContext();
|
|
}
|
|
|
|
#ifdef SMP
|
|
static void GLimp_SetCurrentContext(qboolean enable)
|
|
{
|
|
if(enable)
|
|
{
|
|
CGLSetCurrentContext(opengl_context);
|
|
}
|
|
else
|
|
{
|
|
CGLSetCurrentContext(NULL);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#elif SDL_VIDEO_DRIVER_X11
|
|
|
|
#include <GL/glx.h>
|
|
typedef struct
|
|
{
|
|
GLXContext ctx;
|
|
Display *dpy;
|
|
GLXDrawable drawable;
|
|
} QGLContext_t;
|
|
typedef QGLContext_t QGLContext;
|
|
|
|
static QGLContext opengl_context;
|
|
|
|
static void GLimp_GetCurrentContext(void)
|
|
{
|
|
opengl_context.ctx = glXGetCurrentContext();
|
|
opengl_context.dpy = glXGetCurrentDisplay();
|
|
opengl_context.drawable = glXGetCurrentDrawable();
|
|
}
|
|
|
|
#ifdef SMP
|
|
static void GLimp_SetCurrentContext(qboolean enable)
|
|
{
|
|
if(enable)
|
|
glXMakeCurrent(opengl_context.dpy, opengl_context.drawable, opengl_context.ctx);
|
|
else
|
|
glXMakeCurrent(opengl_context.dpy, None, NULL);
|
|
}
|
|
#endif
|
|
|
|
#elif _WIN32
|
|
|
|
typedef struct
|
|
{
|
|
HDC hDC; // handle to device context
|
|
HGLRC hGLRC; // handle to GL rendering context
|
|
} QGLContext_t;
|
|
typedef QGLContext_t QGLContext;
|
|
|
|
static QGLContext opengl_context;
|
|
|
|
static void GLimp_GetCurrentContext(void)
|
|
{
|
|
SDL_SysWMinfo info;
|
|
|
|
SDL_VERSION(&info.version);
|
|
if(!SDL_GetWMInfo(&info))
|
|
{
|
|
ri.Printf(PRINT_WARNING, "Failed to obtain HWND from SDL (InputRegistry)");
|
|
return;
|
|
}
|
|
|
|
opengl_context.hDC = GetDC(info.window);
|
|
opengl_context.hGLRC = info.hglrc;
|
|
}
|
|
|
|
#ifdef SMP
|
|
static void GLimp_SetCurrentContext(qboolean enable)
|
|
{
|
|
if(enable)
|
|
wglMakeCurrent(opengl_context.hDC, opengl_context.hGLRC);
|
|
else
|
|
wglMakeCurrent(opengl_context.hDC, NULL);
|
|
}
|
|
#endif
|
|
#else
|
|
static void GLimp_GetCurrentContext(void)
|
|
{
|
|
}
|
|
|
|
#ifdef SMP
|
|
static void GLimp_SetCurrentContext(qboolean enable)
|
|
{
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#ifdef SMP
|
|
/*
|
|
===========================================================
|
|
|
|
SMP acceleration
|
|
|
|
===========================================================
|
|
*/
|
|
|
|
/*
|
|
* I have no idea if this will even work...most platforms don't offer
|
|
* thread-safe OpenGL libraries, and it looks like the original Linux
|
|
* code counted on each thread claiming the GL context with glXMakeCurrent(),
|
|
* which you can't currently do in SDL. We'll just have to hope for the best.
|
|
*/
|
|
|
|
static SDL_mutex *smpMutex = NULL;
|
|
static SDL_cond *renderCommandsEvent = NULL;
|
|
static SDL_cond *renderCompletedEvent = NULL;
|
|
static void (*renderThreadFunction) (void) = NULL;
|
|
static SDL_Thread *renderThread = NULL;
|
|
|
|
/*
|
|
===============
|
|
GLimp_RenderThreadWrapper
|
|
===============
|
|
*/
|
|
static int GLimp_RenderThreadWrapper(void *arg)
|
|
{
|
|
// These printfs cause race conditions which mess up the console output
|
|
Com_Printf("Render thread starting\n");
|
|
|
|
renderThreadFunction();
|
|
|
|
GLimp_SetCurrentContext(qfalse);
|
|
|
|
Com_Printf("Render thread terminating\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
GLimp_SpawnRenderThread
|
|
===============
|
|
*/
|
|
qboolean GLimp_SpawnRenderThread(void (*function) (void))
|
|
{
|
|
static qboolean warned = qfalse;
|
|
|
|
if(!warned)
|
|
{
|
|
Com_Printf("WARNING: You enable r_smp at your own risk!\n");
|
|
warned = qtrue;
|
|
}
|
|
|
|
#if !defined(MACOS_X) && !defined(WIN32) && !defined (SDL_VIDEO_DRIVER_X11)
|
|
return qfalse; /* better safe than sorry for now. */
|
|
#endif
|
|
|
|
if(renderThread != NULL) /* hopefully just a zombie at this point... */
|
|
{
|
|
Com_Printf("Already a render thread? Trying to clean it up...\n");
|
|
GLimp_ShutdownRenderThread();
|
|
}
|
|
|
|
smpMutex = SDL_CreateMutex();
|
|
if(smpMutex == NULL)
|
|
{
|
|
Com_Printf("smpMutex creation failed: %s\n", SDL_GetError());
|
|
GLimp_ShutdownRenderThread();
|
|
return qfalse;
|
|
}
|
|
|
|
renderCommandsEvent = SDL_CreateCond();
|
|
if(renderCommandsEvent == NULL)
|
|
{
|
|
Com_Printf("renderCommandsEvent creation failed: %s\n", SDL_GetError());
|
|
GLimp_ShutdownRenderThread();
|
|
return qfalse;
|
|
}
|
|
|
|
renderCompletedEvent = SDL_CreateCond();
|
|
if(renderCompletedEvent == NULL)
|
|
{
|
|
Com_Printf("renderCompletedEvent creation failed: %s\n", SDL_GetError());
|
|
GLimp_ShutdownRenderThread();
|
|
return qfalse;
|
|
}
|
|
|
|
renderThreadFunction = function;
|
|
renderThread = SDL_CreateThread(GLimp_RenderThreadWrapper, NULL);
|
|
if(renderThread == NULL)
|
|
{
|
|
ri.Printf(PRINT_ALL, "SDL_CreateThread() returned %s", SDL_GetError());
|
|
GLimp_ShutdownRenderThread();
|
|
return qfalse;
|
|
}
|
|
else
|
|
{
|
|
// tma 01/09/07: don't think this is necessary anyway?
|
|
//
|
|
// !!! FIXME: No detach API available in SDL!
|
|
//ret = pthread_detach( renderThread );
|
|
//if ( ret ) {
|
|
//ri.Printf( PRINT_ALL, "pthread_detach returned %d: %s", ret, strerror( ret ) );
|
|
//}
|
|
}
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
GLimp_ShutdownRenderThread
|
|
===============
|
|
*/
|
|
void GLimp_ShutdownRenderThread(void)
|
|
{
|
|
if(renderThread != NULL)
|
|
{
|
|
SDL_WaitThread(renderThread, NULL);
|
|
renderThread = NULL;
|
|
}
|
|
|
|
if(smpMutex != NULL)
|
|
{
|
|
SDL_DestroyMutex(smpMutex);
|
|
smpMutex = NULL;
|
|
}
|
|
|
|
if(renderCommandsEvent != NULL)
|
|
{
|
|
SDL_DestroyCond(renderCommandsEvent);
|
|
renderCommandsEvent = NULL;
|
|
}
|
|
|
|
if(renderCompletedEvent != NULL)
|
|
{
|
|
SDL_DestroyCond(renderCompletedEvent);
|
|
renderCompletedEvent = NULL;
|
|
}
|
|
|
|
renderThreadFunction = NULL;
|
|
}
|
|
|
|
static volatile void *smpData = NULL;
|
|
static volatile qboolean smpDataReady;
|
|
|
|
/*
|
|
===============
|
|
GLimp_RendererSleep
|
|
===============
|
|
*/
|
|
void *GLimp_RendererSleep(void)
|
|
{
|
|
void *data = NULL;
|
|
|
|
GLimp_SetCurrentContext(qfalse);
|
|
|
|
SDL_LockMutex(smpMutex);
|
|
{
|
|
smpData = NULL;
|
|
smpDataReady = qfalse;
|
|
|
|
// after this, the front end can exit GLimp_FrontEndSleep
|
|
SDL_CondSignal(renderCompletedEvent);
|
|
|
|
while(!smpDataReady)
|
|
SDL_CondWait(renderCommandsEvent, smpMutex);
|
|
|
|
data = (void *)smpData;
|
|
}
|
|
SDL_UnlockMutex(smpMutex);
|
|
|
|
GLimp_SetCurrentContext(qtrue);
|
|
|
|
return data;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
GLimp_FrontEndSleep
|
|
===============
|
|
*/
|
|
void GLimp_FrontEndSleep(void)
|
|
{
|
|
SDL_LockMutex(smpMutex);
|
|
{
|
|
while(smpData)
|
|
SDL_CondWait(renderCompletedEvent, smpMutex);
|
|
}
|
|
SDL_UnlockMutex(smpMutex);
|
|
|
|
GLimp_SetCurrentContext(qtrue);
|
|
}
|
|
|
|
/*
|
|
===============
|
|
GLimp_WakeRenderer
|
|
===============
|
|
*/
|
|
void GLimp_WakeRenderer(void *data)
|
|
{
|
|
GLimp_SetCurrentContext(qfalse);
|
|
|
|
SDL_LockMutex(smpMutex);
|
|
{
|
|
assert(smpData == NULL);
|
|
smpData = data;
|
|
smpDataReady = qtrue;
|
|
|
|
// after this, the renderer can continue through GLimp_RendererSleep
|
|
SDL_CondSignal(renderCommandsEvent);
|
|
}
|
|
SDL_UnlockMutex(smpMutex);
|
|
}
|
|
|
|
#else
|
|
|
|
// No SMP - stubs
|
|
void GLimp_RenderThreadWrapper(void *arg)
|
|
{
|
|
}
|
|
|
|
qboolean GLimp_SpawnRenderThread(void (*function) (void))
|
|
{
|
|
ri.Printf(PRINT_WARNING, "ERROR: SMP support was disabled at compile time\n");
|
|
return qfalse;
|
|
}
|
|
|
|
void GLimp_ShutdownRenderThread(void)
|
|
{
|
|
}
|
|
|
|
void *GLimp_RendererSleep(void)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
void GLimp_FrontEndSleep(void)
|
|
{
|
|
}
|
|
|
|
void GLimp_WakeRenderer(void *data)
|
|
{
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
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_allowResize; // make window resizable
|
|
cvar_t *r_centerWindow;
|
|
cvar_t *r_sdlDriver;
|
|
|
|
/*
|
|
===============
|
|
GLimp_Shutdown
|
|
===============
|
|
*/
|
|
void GLimp_Shutdown(void)
|
|
{
|
|
ri.IN_Shutdown();
|
|
|
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
|
screen = NULL;
|
|
|
|
#if defined(SMP)
|
|
if(renderThread != NULL)
|
|
{
|
|
Com_Printf("Destroying renderer thread...\n");
|
|
GLimp_ShutdownRenderThread();
|
|
}
|
|
#endif
|
|
|
|
Com_Memset(&glConfig, 0, sizeof(glConfig));
|
|
Com_Memset(&glState, 0, sizeof(glState));
|
|
}
|
|
|
|
/*
|
|
===============
|
|
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);
|
|
}
|
|
}
|
|
|
|
static void GLimp_InitOpenGL3xContext()
|
|
{
|
|
int retVal;
|
|
const char *success[] = { "failed", "success" };
|
|
|
|
if(!r_glCoreProfile->integer)
|
|
return;
|
|
|
|
GLimp_GetCurrentContext();
|
|
|
|
// try to initialize an OpenGL 3.0 context
|
|
#if defined(WIN32)
|
|
if(WGLEW_ARB_create_context || wglewIsSupported("WGL_ARB_create_context"))
|
|
{
|
|
int attribs[256]; // should be really enough
|
|
int numAttribs;
|
|
|
|
/*
|
|
int attribs[] =
|
|
{
|
|
WGL_CONTEXT_MAJOR_VERSION_ARB, r_glMinMajorVersion->integer,
|
|
WGL_CONTEXT_MINOR_VERSION_ARB, r_glMinMinorVersion->integer,
|
|
WGL_CONTEXT_FLAGS_ARB,
|
|
WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,// | WGL_CONTEXT_DEBUG_BIT_ARB,
|
|
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
|
|
0
|
|
};
|
|
*/
|
|
|
|
memset(attribs, 0, sizeof(attribs));
|
|
numAttribs = 0;
|
|
|
|
attribs[numAttribs++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
|
|
attribs[numAttribs++] = r_glMinMajorVersion->integer;
|
|
|
|
attribs[numAttribs++] = WGL_CONTEXT_MINOR_VERSION_ARB;
|
|
attribs[numAttribs++] = r_glMinMinorVersion->integer;
|
|
|
|
|
|
if(WGLEW_ARB_create_context_profile)
|
|
{
|
|
attribs[numAttribs++] = WGL_CONTEXT_FLAGS_ARB;
|
|
|
|
#if 0
|
|
if(GLXEW_ARB_debug_output)
|
|
{
|
|
attribs[numAttribs++] = WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | WGL_CONTEXT_DEBUG_BIT_ARB;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
attribs[numAttribs++] = WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
|
|
}
|
|
|
|
attribs[numAttribs++] = WGL_CONTEXT_PROFILE_MASK_ARB;
|
|
attribs[numAttribs++] = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
|
|
}
|
|
|
|
// set current context to NULL
|
|
retVal = wglMakeCurrent(opengl_context.hDC, NULL) != 0;
|
|
ri.Printf(PRINT_ALL, "...wglMakeCurrent( %p, %p ): %s\n", opengl_context.hDC, NULL, success[retVal]);
|
|
|
|
// delete HGLRC
|
|
if(opengl_context.hGLRC)
|
|
{
|
|
retVal = wglDeleteContext(opengl_context.hGLRC) != 0;
|
|
ri.Printf(PRINT_ALL, "...deleting standard GL context: %s\n", success[retVal]);
|
|
opengl_context.hGLRC = NULL;
|
|
}
|
|
|
|
ri.Printf(PRINT_ALL, "...initializing OpenGL %i.%i context ", r_glMinMajorVersion->integer, r_glMinMinorVersion->integer);
|
|
|
|
opengl_context.hGLRC = wglCreateContextAttribsARB(opengl_context.hDC, 0, attribs);
|
|
|
|
if(wglMakeCurrent(opengl_context.hDC, opengl_context.hGLRC))
|
|
{
|
|
ri.Printf(PRINT_ALL, " done\n");
|
|
glConfig.driverType = GLDRV_OPENGL3;
|
|
}
|
|
else
|
|
{
|
|
ri.Error(ERR_FATAL, "Could not initialize OpenGL %i.%i context\n"
|
|
"Make sure your graphics card supports OpenGL %i.%i or newer",
|
|
r_glMinMajorVersion->integer, r_glMinMinorVersion->integer,
|
|
r_glMinMajorVersion->integer, r_glMinMinorVersion->integer);
|
|
}
|
|
}
|
|
#elif 0 //defined(__linux__)
|
|
|
|
// TODO
|
|
|
|
/*
|
|
// GLX_ARB_create_context
|
|
#ifndef GLX_ARB_create_context
|
|
#define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001
|
|
#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
|
|
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
|
|
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
|
|
#define GLX_CONTEXT_FLAGS_ARB 0x2094
|
|
|
|
extern GLXContext (APIENTRY * glXCreateContextAttribsARB) (Display *dpy, GLXFBConfig config, GLXContext share_context, Bool direct, const int *attrib_list);
|
|
*/
|
|
|
|
glXCreateContextAttribsARB = SDL_GL_GetProcAddress("glXCreateContextAttribsARB");
|
|
if(glXCreateContextAttribsARB)
|
|
{
|
|
int attribs[3];
|
|
|
|
ri.Printf(PRINT_ALL, "Initializing OpenGL 3.0 context...");
|
|
|
|
attribs[0] = WGL_CONTEXT_MAJOR_VERSION_ARB;
|
|
attribs[1] = 3;
|
|
attribs[2] = 0; //terminate first pair
|
|
|
|
opengl_context->hGLRC = glXCreateContextAttribsARB(opengl_context->, attribs);
|
|
if(wglMakeCurrent(opengl_context->hDC, opengl_context->hGLRC))
|
|
{
|
|
ri.Printf(PRINT_ALL, " done\n");
|
|
glConfig.driverType = GLDRV_OPENGL3;
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, " failed\n");
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
===============
|
|
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 i = 0;
|
|
SDL_Surface *vidscreen = NULL;
|
|
Uint32 flags = SDL_OPENGL;
|
|
GLenum glewResult;
|
|
|
|
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(!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;
|
|
|
|
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;
|
|
|
|
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_DOUBLEBUFFER, 1);
|
|
|
|
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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
glewResult = glewInit();
|
|
if(GLEW_OK != glewResult)
|
|
{
|
|
// glewInit failed, something is seriously wrong
|
|
ri.Error(ERR_FATAL, "GLW_StartOpenGL() - could not load OpenGL subsystem: %s", glewGetErrorString(glewResult));
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "Using GLEW %s\n", glewGetString(GLEW_VERSION));
|
|
}
|
|
|
|
GLimp_InitOpenGL3xContext();
|
|
|
|
GLimp_DetectAvailableModes();
|
|
|
|
if(!vidscreen)
|
|
{
|
|
ri.Printf(PRINT_ALL, "Couldn't get a visual\n");
|
|
return RSERR_INVALID_MODE;
|
|
}
|
|
|
|
screen = vidscreen;
|
|
|
|
glstring = (char *)glGetString(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];
|
|
|
|
ri.Printf(PRINT_ALL, "SDL_Init( SDL_INIT_VIDEO )... ");
|
|
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) == -1)
|
|
{
|
|
ri.Printf(PRINT_ALL, "SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) 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;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
GLimp_InitExtensions
|
|
===============
|
|
*/
|
|
static void GLimp_InitExtensions(void)
|
|
{
|
|
ri.Printf(PRINT_ALL, "Initializing OpenGL extensions\n");
|
|
|
|
// GL_ARB_multitexture
|
|
if(glConfig.driverType != GLDRV_OPENGL3)
|
|
{
|
|
if(GLEW_ARB_multitexture)
|
|
{
|
|
glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &glConfig.numTextureUnits);
|
|
|
|
if(glConfig.numTextureUnits > 1)
|
|
{
|
|
ri.Printf(PRINT_ALL, "...using GL_ARB_multitexture\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Error(ERR_FATAL, "...not using GL_ARB_multitexture, < 2 texture units\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ri.Error(ERR_FATAL, "...GL_ARB_multitexture not found\n");
|
|
}
|
|
}
|
|
|
|
|
|
// GL_ARB_depth_texture
|
|
if(GLEW_ARB_depth_texture)
|
|
{
|
|
ri.Printf(PRINT_ALL, "...using GL_ARB_depth_texture\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Error(ERR_FATAL, "...GL_ARB_depth_texture not found\n");
|
|
}
|
|
|
|
// GL_ARB_texture_cube_map
|
|
if(GLEW_ARB_texture_cube_map)
|
|
{
|
|
glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, &glConfig2.maxCubeMapTextureSize);
|
|
ri.Printf(PRINT_ALL, "...using GL_ARB_texture_cube_map\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Error(ERR_FATAL, "...GL_ARB_texture_cube_map not found\n");
|
|
}
|
|
GL_CheckErrors();
|
|
|
|
// GL_ARB_vertex_program
|
|
if(GLEW_ARB_vertex_program)
|
|
{
|
|
ri.Printf(PRINT_ALL, "...using GL_ARB_vertex_program\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Error(ERR_FATAL, "...GL_ARB_vertex_program not found\n");
|
|
}
|
|
|
|
// GL_ARB_vertex_buffer_object
|
|
if(GLEW_ARB_vertex_buffer_object)
|
|
{
|
|
ri.Printf(PRINT_ALL, "...using GL_ARB_vertex_buffer_object\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Error(ERR_FATAL, "...GL_ARB_vertex_buffer_object not found\n");
|
|
}
|
|
|
|
// GL_ARB_occlusion_query
|
|
glConfig2.occlusionQueryAvailable = qfalse;
|
|
glConfig2.occlusionQueryBits = 0;
|
|
if(GLEW_ARB_occlusion_query)
|
|
{
|
|
if(r_ext_occlusion_query->value)
|
|
{
|
|
glConfig2.occlusionQueryAvailable = qtrue;
|
|
glGetQueryivARB(GL_SAMPLES_PASSED, GL_QUERY_COUNTER_BITS, &glConfig2.occlusionQueryBits);
|
|
ri.Printf(PRINT_ALL, "...using GL_ARB_occlusion_query\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...ignoring GL_ARB_occlusion_query\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...GL_ARB_occlusion_query not found\n");
|
|
}
|
|
GL_CheckErrors();
|
|
|
|
// GL_ARB_shader_objects
|
|
if(GLEW_ARB_shader_objects)
|
|
{
|
|
ri.Printf(PRINT_ALL, "...using GL_ARB_shader_objects\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Error(ERR_FATAL, "...GL_ARB_shader_objects not found\n");
|
|
}
|
|
|
|
// GL_ARB_vertex_shader
|
|
if(GLEW_ARB_vertex_shader)
|
|
{
|
|
int reservedComponents;
|
|
|
|
GL_CheckErrors();
|
|
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &glConfig2.maxVertexUniforms); GL_CheckErrors();
|
|
//glGetIntegerv(GL_MAX_VARYING_FLOATS_ARB, &glConfig.maxVaryingFloats); GL_CheckErrors();
|
|
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &glConfig2.maxVertexAttribs); GL_CheckErrors();
|
|
|
|
reservedComponents = 16 * 10; // approximation how many uniforms we have besides the bone matrices
|
|
|
|
/*
|
|
if(glConfig.driverType == GLDRV_MESA)
|
|
{
|
|
// HACK
|
|
// restrict to number of vertex uniforms to 512 because of:
|
|
// xreal.x86_64: nv50_program.c:4181: nv50_program_validate_data: Assertion `p->param_nr <= 512' failed
|
|
|
|
glConfig2.maxVertexUniforms = Q_bound(0, glConfig2.maxVertexUniforms, 512);
|
|
}
|
|
*/
|
|
|
|
glConfig2.maxVertexSkinningBones = (int) Q_bound(0.0, (Q_max(glConfig2.maxVertexUniforms - reservedComponents, 0) / 16), MAX_BONES);
|
|
glConfig2.vboVertexSkinningAvailable = r_vboVertexSkinning->integer && ((glConfig2.maxVertexSkinningBones >= 12) ? qtrue : qfalse);
|
|
|
|
ri.Printf(PRINT_ALL, "...using GL_ARB_vertex_shader\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Error(ERR_FATAL, "...GL_ARB_vertex_shader not found\n");
|
|
}
|
|
GL_CheckErrors();
|
|
|
|
// GL_ARB_fragment_shader
|
|
if(GLEW_ARB_fragment_shader)
|
|
{
|
|
ri.Printf(PRINT_ALL, "...using GL_ARB_fragment_shader\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Error(ERR_FATAL, "...GL_ARB_fragment_shader not found\n");
|
|
}
|
|
|
|
// GL_ARB_shading_language_100
|
|
if(GLEW_ARB_shading_language_100)
|
|
{
|
|
Q_strncpyz(glConfig2.shadingLanguageVersion, (char*)glGetString(GL_SHADING_LANGUAGE_VERSION_ARB),
|
|
sizeof(glConfig2.shadingLanguageVersion));
|
|
ri.Printf(PRINT_ALL, "...using GL_ARB_shading_language_100\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(ERR_FATAL, "...GL_ARB_shading_language_100 not found\n");
|
|
}
|
|
GL_CheckErrors();
|
|
|
|
// GL_ARB_texture_non_power_of_two
|
|
glConfig2.textureNPOTAvailable = qfalse;
|
|
if(GLEW_ARB_texture_non_power_of_two)
|
|
{
|
|
if(r_ext_texture_non_power_of_two->integer)
|
|
{
|
|
glConfig2.textureNPOTAvailable = qtrue;
|
|
ri.Printf(PRINT_ALL, "...using GL_ARB_texture_non_power_of_two\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...ignoring GL_ARB_texture_non_power_of_two\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...GL_ARB_texture_non_power_of_two not found\n");
|
|
}
|
|
|
|
// GL_ARB_draw_buffers
|
|
glConfig2.drawBuffersAvailable = qfalse;
|
|
if(GLEW_ARB_draw_buffers)
|
|
{
|
|
glGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &glConfig2.maxDrawBuffers);
|
|
|
|
if(r_ext_draw_buffers->integer)
|
|
{
|
|
glConfig2.drawBuffersAvailable = qtrue;
|
|
ri.Printf(PRINT_ALL, "...using GL_ARB_draw_buffers\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...ignoring GL_ARB_draw_buffers\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...GL_ARB_draw_buffers not found\n");
|
|
}
|
|
|
|
// GL_ARB_half_float_pixel
|
|
glConfig2.textureHalfFloatAvailable = qfalse;
|
|
if(GLEW_ARB_half_float_pixel)
|
|
{
|
|
if(r_ext_half_float_pixel->integer)
|
|
{
|
|
glConfig2.textureHalfFloatAvailable = qtrue;
|
|
ri.Printf(PRINT_ALL, "...using GL_ARB_half_float_pixel\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...ignoring GL_ARB_half_float_pixel\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...GL_ARB_half_float_pixel not found\n");
|
|
}
|
|
|
|
// GL_ARB_texture_float
|
|
glConfig2.textureFloatAvailable = qfalse;
|
|
if(GLEW_ARB_texture_float)
|
|
{
|
|
if(r_ext_texture_float->integer)
|
|
{
|
|
glConfig2.textureFloatAvailable = qtrue;
|
|
ri.Printf(PRINT_ALL, "...using GL_ARB_texture_float\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...ignoring GL_ARB_texture_float\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...GL_ARB_texture_float not found\n");
|
|
}
|
|
|
|
// GL_ARB_texture_compression
|
|
glConfig.textureCompression = TC_NONE;
|
|
if(GLEW_ARB_texture_compression)
|
|
{
|
|
if(r_ext_compressed_textures->integer)
|
|
{
|
|
glConfig2.ARBTextureCompressionAvailable = qtrue;
|
|
ri.Printf(PRINT_ALL, "...using GL_ARB_texture_compression\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...ignoring GL_ARB_texture_compression\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...GL_ARB_texture_compression not found\n");
|
|
}
|
|
|
|
// GL_ARB_vertex_array_object
|
|
glConfig2.vertexArrayObjectAvailable = qfalse;
|
|
if(GLEW_ARB_vertex_array_object)
|
|
{
|
|
if(r_ext_vertex_array_object->integer)
|
|
{
|
|
glConfig2.vertexArrayObjectAvailable = qtrue;
|
|
ri.Printf(PRINT_ALL, "...using GL_ARB_vertex_array_object\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...ignoring GL_ARB_vertex_array_object\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...GL_ARB_vertex_array_object not found\n");
|
|
}
|
|
|
|
// GL_EXT_texture_compression_s3tc
|
|
if(GLEW_EXT_texture_compression_s3tc)
|
|
{
|
|
if(r_ext_compressed_textures->integer)
|
|
{
|
|
glConfig.textureCompression = TC_S3TC;
|
|
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_EXT_texture3D
|
|
glConfig2.texture3DAvailable = qfalse;
|
|
if(GLEW_EXT_texture3D)
|
|
{
|
|
//if(r_ext_texture3d->value)
|
|
{
|
|
glConfig2.texture3DAvailable = qtrue;
|
|
ri.Printf(PRINT_ALL, "...using GL_EXT_texture3D\n");
|
|
}
|
|
/*
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...ignoring GL_EXT_texture3D\n");
|
|
}
|
|
*/
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...GL_EXT_texture3D not found\n");
|
|
}
|
|
|
|
// GL_EXT_stencil_wrap
|
|
glConfig2.stencilWrapAvailable = qfalse;
|
|
if(GLEW_EXT_stencil_wrap)
|
|
{
|
|
if(r_ext_stencil_wrap->value)
|
|
{
|
|
glConfig2.stencilWrapAvailable = qtrue;
|
|
ri.Printf(PRINT_ALL, "...using GL_EXT_stencil_wrap\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...ignoring GL_EXT_stencil_wrap\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...GL_EXT_stencil_wrap not found\n");
|
|
}
|
|
|
|
// GL_EXT_texture_filter_anisotropic
|
|
glConfig2.textureAnisotropyAvailable = qfalse;
|
|
if(GLEW_EXT_texture_filter_anisotropic)
|
|
{
|
|
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glConfig2.maxTextureAnisotropy);
|
|
|
|
if(r_ext_texture_filter_anisotropic->value)
|
|
{
|
|
glConfig2.textureAnisotropyAvailable = qtrue;
|
|
ri.Printf(PRINT_ALL, "...using GL_EXT_texture_filter_anisotropic\n");
|
|
}
|
|
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");
|
|
}
|
|
GL_CheckErrors();
|
|
|
|
// GL_EXT_stencil_two_side
|
|
if(GLEW_EXT_stencil_two_side)
|
|
{
|
|
if(r_ext_stencil_two_side->value)
|
|
{
|
|
ri.Printf(PRINT_ALL, "...using GL_EXT_stencil_two_side\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...ignoring GL_EXT_stencil_two_side\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...GL_EXT_stencil_two_side not found\n");
|
|
}
|
|
|
|
// GL_EXT_depth_bounds_test
|
|
if(GLEW_EXT_depth_bounds_test)
|
|
{
|
|
if(r_ext_depth_bounds_test->value)
|
|
{
|
|
ri.Printf(PRINT_ALL, "...using GL_EXT_depth_bounds_test\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...ignoring GL_EXT_depth_bounds_test\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...GL_EXT_depth_bounds_test not found\n");
|
|
}
|
|
|
|
// GL_EXT_framebuffer_object
|
|
glConfig2.framebufferObjectAvailable = qfalse;
|
|
if(GLEW_EXT_framebuffer_object)
|
|
{
|
|
glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE_EXT, &glConfig2.maxRenderbufferSize);
|
|
glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &glConfig2.maxColorAttachments);
|
|
|
|
if(r_ext_framebuffer_object->value)
|
|
{
|
|
glConfig2.framebufferObjectAvailable = qtrue;
|
|
ri.Printf(PRINT_ALL, "...using GL_EXT_framebuffer_object\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...ignoring GL_EXT_framebuffer_object\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...GL_EXT_framebuffer_object not found\n");
|
|
}
|
|
GL_CheckErrors();
|
|
|
|
// GL_EXT_packed_depth_stencil
|
|
glConfig2.framebufferPackedDepthStencilAvailable = qfalse;
|
|
if(GLEW_EXT_packed_depth_stencil && glConfig.driverType != GLDRV_MESA)
|
|
{
|
|
if(r_ext_packed_depth_stencil->integer)
|
|
{
|
|
glConfig2.framebufferPackedDepthStencilAvailable = qtrue;
|
|
ri.Printf(PRINT_ALL, "...using GL_EXT_packed_depth_stencil\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...ignoring GL_EXT_packed_depth_stencil\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...GL_EXT_packed_depth_stencil not found\n");
|
|
}
|
|
|
|
// GL_EXT_framebuffer_blit
|
|
glConfig2.framebufferBlitAvailable = qfalse;
|
|
if(GLEW_EXT_framebuffer_blit)
|
|
{
|
|
if(r_ext_framebuffer_blit->integer)
|
|
{
|
|
glConfig2.framebufferBlitAvailable = qtrue;
|
|
ri.Printf(PRINT_ALL, "...using GL_EXT_framebuffer_blit\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...ignoring GL_EXT_framebuffer_blit\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...GL_EXT_framebuffer_blit not found\n");
|
|
}
|
|
|
|
// GL_EXTX_framebuffer_mixed_formats
|
|
/*
|
|
glConfig.framebufferMixedFormatsAvailable = qfalse;
|
|
if(GLEW_EXTX_framebuffer_mixed_formats)
|
|
{
|
|
if(r_extx_framebuffer_mixed_formats->integer)
|
|
{
|
|
glConfig.framebufferMixedFormatsAvailable = qtrue;
|
|
ri.Printf(PRINT_ALL, "...using GL_EXTX_framebuffer_mixed_formats\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...ignoring GL_EXTX_framebuffer_mixed_formats\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...GL_EXTX_framebuffer_mixed_formats not found\n");
|
|
}
|
|
*/
|
|
|
|
// GL_ATI_separate_stencil
|
|
if(GLEW_ATI_separate_stencil)
|
|
{
|
|
if(r_ext_separate_stencil->value)
|
|
{
|
|
ri.Printf(PRINT_ALL, "...using GL_ATI_separate_stencil\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...ignoring GL_ATI_separate_stencil\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...GL_ATI_separate_stencil not found\n");
|
|
}
|
|
|
|
// GL_SGIS_generate_mipmap
|
|
glConfig2.generateMipmapAvailable = qfalse;
|
|
if(GLEW_SGIS_generate_mipmap)
|
|
{
|
|
if(r_ext_generate_mipmap->value)
|
|
{
|
|
glConfig2.generateMipmapAvailable = qtrue;
|
|
ri.Printf(PRINT_ALL, "...using GL_SGIS_generate_mipmap\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...ignoring GL_SGIS_generate_mipmap\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...GL_SGIS_generate_mipmap not found\n");
|
|
}
|
|
|
|
// GL_GREMEDY_string_marker
|
|
if(GLEW_GREMEDY_string_marker)
|
|
{
|
|
ri.Printf(PRINT_ALL, "...using GL_GREMEDY_string_marker\n");
|
|
}
|
|
else
|
|
{
|
|
ri.Printf(PRINT_ALL, "...GL_GREMEDY_string_marker 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)
|
|
{
|
|
qboolean success = qtrue;
|
|
|
|
glConfig.driverType = GLDRV_DEFAULT;
|
|
|
|
r_sdlDriver = ri.Cvar_Get("r_sdlDriver", "", CVAR_ROM);
|
|
r_allowResize = ri.Cvar_Get("r_allowResize", "0", CVAR_ARCHIVE);
|
|
r_centerWindow = ri.Cvar_Get("r_centerWindow", "0", CVAR_ARCHIVE);
|
|
|
|
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");
|
|
}
|
|
|
|
//Sys_SetEnv("SDL_VIDEO_CENTERED", r_centerWindow->integer ? "1" : "");
|
|
|
|
//Sys_GLimpInit();
|
|
#if 0 //defined(WIN32)
|
|
if(!SDL_VIDEODRIVER_externallySet)
|
|
{
|
|
// It's a little bit weird having in_mouse control the
|
|
// video driver, but from ioq3's point of view they're
|
|
// virtually the same except for the mouse input anyway
|
|
if(ri.Cvar_VariableIntegerValue("in_mouse") == -1)
|
|
{
|
|
// Use the windib SDL backend, which is closest to
|
|
// the behaviour of idq3 with in_mouse set to -1
|
|
_putenv("SDL_VIDEODRIVER=windib");
|
|
}
|
|
else
|
|
{
|
|
// Use the DirectX SDL backend
|
|
_putenv("SDL_VIDEODRIVER=directx");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Create the window and set up the context
|
|
if(GLimp_StartDriverAndSetMode(r_mode->integer, r_fullscreen->integer, qfalse))
|
|
goto success;
|
|
|
|
// Try again, this time in a platform specific "safe mode"
|
|
//Sys_GLimpSafeInit();
|
|
#if 0 //defined(WIN32)
|
|
if(!SDL_VIDEODRIVER_externallySet)
|
|
{
|
|
// Here, we want to let SDL decide what do to unless
|
|
// explicitly requested otherwise
|
|
_putenv("SDL_VIDEODRIVER=");
|
|
}
|
|
#endif
|
|
|
|
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\n");
|
|
|
|
success:
|
|
// This values force the UI to disable driver selection
|
|
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;
|
|
|
|
// get our config strings
|
|
Q_strncpyz(glConfig.vendor_string, (char *)glGetString(GL_VENDOR), sizeof(glConfig.vendor_string));
|
|
Q_strncpyz(glConfig.renderer_string, (char *)glGetString(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 *)glGetString(GL_VERSION), sizeof(glConfig.version_string));
|
|
|
|
if(glConfig.driverType != GLDRV_OPENGL3)
|
|
{
|
|
Q_strncpyz(glConfig.extensions_string, (char *)glGetString(GL_EXTENSIONS), sizeof(glConfig.extensions_string));
|
|
}
|
|
|
|
if( Q_stristr(glConfig.renderer_string, "mesa") ||
|
|
Q_stristr(glConfig.renderer_string, "gallium") ||
|
|
Q_stristr(glConfig.vendor_string, "nouveau") ||
|
|
Q_stristr(glConfig.vendor_string, "mesa"))
|
|
{
|
|
// suckage
|
|
glConfig.driverType = GLDRV_MESA;
|
|
}
|
|
|
|
if(Q_stristr(glConfig.renderer_string, "geforce"))
|
|
{
|
|
if(Q_stristr(glConfig.renderer_string, "8400") ||
|
|
Q_stristr(glConfig.renderer_string, "8500") ||
|
|
Q_stristr(glConfig.renderer_string, "8600") ||
|
|
Q_stristr(glConfig.renderer_string, "8800") ||
|
|
Q_stristr(glConfig.renderer_string, "9500") ||
|
|
Q_stristr(glConfig.renderer_string, "9600") ||
|
|
Q_stristr(glConfig.renderer_string, "9800") ||
|
|
Q_stristr(glConfig.renderer_string, "gts 240") ||
|
|
Q_stristr(glConfig.renderer_string, "gts 250") ||
|
|
Q_stristr(glConfig.renderer_string, "gtx 260") ||
|
|
Q_stristr(glConfig.renderer_string, "gtx 275") ||
|
|
Q_stristr(glConfig.renderer_string, "gtx 280") ||
|
|
Q_stristr(glConfig.renderer_string, "gtx 285") ||
|
|
Q_stristr(glConfig.renderer_string, "gtx 295") ||
|
|
Q_stristr(glConfig.renderer_string, "gt 320") ||
|
|
Q_stristr(glConfig.renderer_string, "gt 330") ||
|
|
Q_stristr(glConfig.renderer_string, "gt 340") ||
|
|
Q_stristr(glConfig.renderer_string, "gt 415") ||
|
|
Q_stristr(glConfig.renderer_string, "gt 420") ||
|
|
Q_stristr(glConfig.renderer_string, "gt 425") ||
|
|
Q_stristr(glConfig.renderer_string, "gt 430") ||
|
|
Q_stristr(glConfig.renderer_string, "gt 435") ||
|
|
Q_stristr(glConfig.renderer_string, "gt 440") ||
|
|
Q_stristr(glConfig.renderer_string, "gt 520") ||
|
|
Q_stristr(glConfig.renderer_string, "gt 525") ||
|
|
Q_stristr(glConfig.renderer_string, "gt 540") ||
|
|
Q_stristr(glConfig.renderer_string, "gt 550") ||
|
|
Q_stristr(glConfig.renderer_string, "gt 555") ||
|
|
Q_stristr(glConfig.renderer_string, "gts 450") ||
|
|
Q_stristr(glConfig.renderer_string, "gtx 460") ||
|
|
Q_stristr(glConfig.renderer_string, "gtx 470") ||
|
|
Q_stristr(glConfig.renderer_string, "gtx 480") ||
|
|
Q_stristr(glConfig.renderer_string, "gtx 485") ||
|
|
Q_stristr(glConfig.renderer_string, "gtx 560") ||
|
|
Q_stristr(glConfig.renderer_string, "gtx 570") ||
|
|
Q_stristr(glConfig.renderer_string, "gtx 580") ||
|
|
Q_stristr(glConfig.renderer_string, "gtx 590"))
|
|
glConfig.hardwareType = GLHW_NV_DX10;
|
|
}
|
|
else if(Q_stristr(glConfig.renderer_string, "quadro fx"))
|
|
{
|
|
if(Q_stristr(glConfig.renderer_string, "3600"))
|
|
glConfig.hardwareType = GLHW_NV_DX10;
|
|
}
|
|
else if(Q_stristr(glConfig.renderer_string, "rv770"))
|
|
{
|
|
glConfig.hardwareType = GLHW_ATI_DX10;
|
|
}
|
|
else if(Q_stristr(glConfig.renderer_string, "radeon hd"))
|
|
{
|
|
glConfig.hardwareType = GLHW_ATI_DX10;
|
|
}
|
|
else if(Q_stristr(glConfig.renderer_string, "eah4850") || Q_stristr(glConfig.renderer_string, "eah4870"))
|
|
{
|
|
glConfig.hardwareType = GLHW_ATI_DX10;
|
|
}
|
|
else if(Q_stristr(glConfig.renderer_string, "radeon"))
|
|
{
|
|
glConfig.hardwareType = GLHW_ATI;
|
|
}
|
|
|
|
|
|
// 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");
|
|
|
|
ri.IN_Restart();
|
|
}
|
|
|
|
r_fullscreen->modified = qfalse;
|
|
}
|
|
}
|
|
|
|
|
|
void GLimp_LogComment(char *comment)
|
|
{
|
|
static char buf[4096];
|
|
|
|
if(r_logFile->integer && GLEW_GREMEDY_string_marker)
|
|
{
|
|
// copy string and ensure it has a trailing '\0'
|
|
Q_strncpyz(buf, comment, sizeof(buf));
|
|
|
|
glStringMarkerGREMEDY(strlen(buf), buf);
|
|
}
|
|
}
|