mirror of
https://github.com/ReactionQuake3/reaction.git
synced 2024-11-10 15:21:44 +00:00
GL_EXT_framebuffer_object support. God rays post-processing effect.
This commit is contained in:
parent
2d8bbf6c53
commit
2fc2a4a947
11 changed files with 2141 additions and 1312 deletions
|
@ -32,6 +32,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
# include <SDL_opengl.h>
|
||||
#endif
|
||||
|
||||
#include "qglextensions.h"
|
||||
|
||||
extern void (APIENTRYP qglActiveTextureARB) (GLenum texture);
|
||||
extern void (APIENTRYP qglClientActiveTextureARB) (GLenum texture);
|
||||
extern void (APIENTRYP qglMultiTexCoord2fARB) (GLenum target, GLfloat s, GLfloat t);
|
||||
|
@ -110,6 +112,13 @@ extern void (APIENTRY * qglGetActiveAttribARB) (GLhandleARB programObj, GLui
|
|||
GLint * size, GLenum * type, GLcharARB * name);
|
||||
extern GLint(APIENTRY * qglGetAttribLocationARB) (GLhandleARB programObj, const GLcharARB * name);
|
||||
|
||||
#define HANDLE_EXT_FUNC(t, n) extern t q##n
|
||||
|
||||
ADD_ALL_EXTENSION_FUNCTIONS;
|
||||
|
||||
#undef HANDLE_EXT_FUNC
|
||||
|
||||
|
||||
#if defined(WIN32)
|
||||
// WGL_ARB_create_context
|
||||
#ifndef WGL_ARB_create_context
|
||||
|
|
32
reaction/code/renderer/qglextensions.h
Normal file
32
reaction/code/renderer/qglextensions.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef __QGLEXTENSIONS_H__
|
||||
#define __QGLEXTENSIONS_H__
|
||||
|
||||
#define GL_EXT_framebuffer_object_functions \
|
||||
HANDLE_EXT_FUNC(PFNGLGENFRAMEBUFFERSEXTPROC, glGenFramebuffersEXT); \
|
||||
HANDLE_EXT_FUNC(PFNGLBINDFRAMEBUFFEREXTPROC, glBindFramebufferEXT); \
|
||||
HANDLE_EXT_FUNC(PFNGLFRAMEBUFFERTEXTURE2DEXTPROC, glFramebufferTexture2DEXT); \
|
||||
HANDLE_EXT_FUNC(PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC, glFramebufferRenderbufferEXT); \
|
||||
HANDLE_EXT_FUNC(PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC, glCheckFramebufferStatusEXT); \
|
||||
HANDLE_EXT_FUNC(PFNGLDELETEFRAMEBUFFERSEXTPROC, glDeleteFramebuffersEXT); \
|
||||
HANDLE_EXT_FUNC(PFNGLGENERATEMIPMAPEXTPROC, glGenerateMipmapEXT); \
|
||||
HANDLE_EXT_FUNC(PFNGLDELETERENDERBUFFERSEXTPROC, glDeleteRenderbuffersEXT); \
|
||||
HANDLE_EXT_FUNC(PFNGLGENRENDERBUFFERSEXTPROC, glGenRenderbuffersEXT); \
|
||||
HANDLE_EXT_FUNC(PFNGLRENDERBUFFERSTORAGEEXTPROC, glRenderbufferStorageEXT); \
|
||||
HANDLE_EXT_FUNC(PFNGLBINDRENDERBUFFEREXTPROC, glBindRenderbufferEXT) \
|
||||
|
||||
|
||||
#define GL_EXT_framebuffer_multisample_functions \
|
||||
HANDLE_EXT_FUNC(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC, glRenderbufferStorageMultisampleEXT) \
|
||||
|
||||
|
||||
#define GL_EXT_framebuffer_blit_functions \
|
||||
HANDLE_EXT_FUNC(PFNGLBLITFRAMEBUFFEREXTPROC, glBlitFramebufferEXT) \
|
||||
|
||||
|
||||
#define ADD_ALL_EXTENSION_FUNCTIONS \
|
||||
GL_EXT_framebuffer_object_functions; \
|
||||
GL_EXT_framebuffer_multisample_functions; \
|
||||
GL_EXT_framebuffer_blit_functions \
|
||||
|
||||
|
||||
#endif
|
|
@ -500,11 +500,28 @@ void RB_BeginDrawingView (void) {
|
|||
// 2D images again
|
||||
backEnd.projection2D = qfalse;
|
||||
|
||||
if (backEnd.refdef.width == glConfig.vidWidth && backEnd.refdef.height == glConfig.vidHeight && 0 == (backEnd.refdef.rdflags & RDF_NOWORLDMODEL))
|
||||
{
|
||||
R_FBO_Bind(tr.fbo.full[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
R_FBO_Bind(NULL);
|
||||
}
|
||||
|
||||
//
|
||||
// set the modelview matrix for the viewer
|
||||
//
|
||||
SetViewportAndScissor();
|
||||
|
||||
if (glState.currentFBO)
|
||||
{
|
||||
fbo_t* old = R_FBO_Bind(tr.fbo.full[1]);
|
||||
qglClearColor(0.f, 0.f, 0.f, 1.f);
|
||||
qglClear(GL_COLOR_BUFFER_BIT);
|
||||
R_FBO_Bind(old);
|
||||
}
|
||||
|
||||
// ensures that depth writes are enabled for the depth clear
|
||||
GL_State( GLS_DEFAULT );
|
||||
// clear relevant buffers
|
||||
|
@ -540,6 +557,8 @@ void RB_BeginDrawingView (void) {
|
|||
// we will only draw a sun if there was sky rendered in this view
|
||||
backEnd.skyRenderedThisView = qfalse;
|
||||
|
||||
backEnd.hasSunFlare = qfalse;
|
||||
|
||||
// clip to the plane of the portal
|
||||
if ( backEnd.viewParms.isPortal ) {
|
||||
float plane[4];
|
||||
|
@ -572,10 +591,8 @@ void RB_BeginDrawingView (void) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#define MAC_EVENT_PUMP_MSEC 5
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
RB_RenderDrawSurfList
|
||||
|
@ -591,6 +608,10 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
|
|||
drawSurf_t *drawSurf;
|
||||
int oldSort;
|
||||
float originalTime;
|
||||
float depth[2];
|
||||
|
||||
depth[0] = 0.f;
|
||||
depth[1] = 1.f;
|
||||
|
||||
// save original time for entity shader offsets
|
||||
originalTime = backEnd.refdef.floatTime;
|
||||
|
@ -640,8 +661,15 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
|
|||
// change the modelview matrix if needed
|
||||
//
|
||||
if ( entityNum != oldEntityNum ) {
|
||||
qboolean sunflare = qfalse;
|
||||
depthRange = isCrosshair = qfalse;
|
||||
|
||||
if (oldEntityNum != -1 && 0 == (backEnd.refdef.entities[oldEntityNum].e.renderfx & RF_SUNFLARE) && glState.currentFBO)
|
||||
{
|
||||
R_FBO_Bind(tr.fbo.fbos[0]);
|
||||
qglDepthRange(depth[0], depth[1]);
|
||||
}
|
||||
|
||||
if ( entityNum != ENTITYNUM_WORLD ) {
|
||||
backEnd.currentEntity = &backEnd.refdef.entities[entityNum];
|
||||
backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime;
|
||||
|
@ -656,6 +684,18 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
|
|||
if ( backEnd.currentEntity->needDlights ) {
|
||||
R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or );
|
||||
}
|
||||
|
||||
if(backEnd.currentEntity->e.renderfx & RF_SUNFLARE) {
|
||||
if (glState.currentFBO) {
|
||||
VectorCopy(backEnd.currentEntity->e.origin, backEnd.sunFlarePos);
|
||||
backEnd.hasSunFlare = qtrue;
|
||||
sunflare = qtrue;
|
||||
R_FBO_Bind(tr.fbo.fbos[1]);
|
||||
qglDepthRange(1.f, 1.f);
|
||||
} else {
|
||||
depthRange = qtrue;
|
||||
}
|
||||
}
|
||||
|
||||
if(backEnd.currentEntity->e.renderfx & RF_DEPTHHACK)
|
||||
{
|
||||
|
@ -681,6 +721,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
|
|||
// change depthrange. Also change projection matrix so first person weapon does not look like coming
|
||||
// out of the screen.
|
||||
//
|
||||
|
||||
if (oldDepthRange != depthRange || wasCrosshair != isCrosshair)
|
||||
{
|
||||
if (depthRange)
|
||||
|
@ -706,7 +747,11 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
|
|||
}
|
||||
|
||||
if(!oldDepthRange)
|
||||
{
|
||||
depth[0] = 0;
|
||||
depth[1] = 0.3f;
|
||||
qglDepthRange (0, 0.3);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -715,7 +760,10 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
|
|||
GL_SetProjectionMatrix( backEnd.viewParms.projectionMatrix );
|
||||
}
|
||||
|
||||
qglDepthRange (0, 1);
|
||||
if (!sunflare)
|
||||
qglDepthRange (0, 1);
|
||||
depth[0] = 0;
|
||||
depth[1] = 1;
|
||||
}
|
||||
|
||||
oldDepthRange = depthRange;
|
||||
|
@ -739,9 +787,9 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
|
|||
// go back to the world modelview matrix
|
||||
|
||||
GL_SetModelviewMatrix( backEnd.viewParms.world.modelMatrix );
|
||||
if ( depthRange ) {
|
||||
//if ( depthRange ) {
|
||||
qglDepthRange (0, 1);
|
||||
}
|
||||
//}
|
||||
|
||||
#if 0
|
||||
RB_DrawSun();
|
||||
|
@ -751,6 +799,9 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
|
|||
|
||||
// add light flares on lights that aren't obscured
|
||||
RB_RenderFlares();
|
||||
|
||||
RB_PostProcess();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -764,20 +815,24 @@ RENDER BACK END THREAD FUNCTIONS
|
|||
|
||||
/*
|
||||
================
|
||||
RB_SetGL2D
|
||||
RB_SetGL2D_Level
|
||||
|
||||
================
|
||||
*/
|
||||
void RB_SetGL2D (void) {
|
||||
|
||||
void RB_SetGL2D_Level(int level)
|
||||
{
|
||||
matrix_t matrix;
|
||||
int width = glConfig.vidWidth >> level;
|
||||
int height = glConfig.vidHeight >> level;
|
||||
|
||||
backEnd.projection2D = qtrue;
|
||||
|
||||
// set 2D virtual screen size
|
||||
qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight );
|
||||
qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight );
|
||||
qglViewport( 0, 0, width, height );
|
||||
qglScissor( 0, 0, width, height );
|
||||
|
||||
Matrix16Ortho(0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1, matrix);
|
||||
Matrix16Ortho(0, width, height, 0, 0, 1, matrix);
|
||||
GL_SetProjectionMatrix(matrix);
|
||||
Matrix16Identity(matrix);
|
||||
GL_SetModelviewMatrix(matrix);
|
||||
|
@ -794,6 +849,16 @@ void RB_SetGL2D (void) {
|
|||
backEnd.refdef.floatTime = backEnd.refdef.time * 0.001f;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
RB_SetGL2D
|
||||
|
||||
================
|
||||
*/
|
||||
|
||||
void RB_SetGL2D (void) {
|
||||
RB_SetGL2D_Level(0);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
|
|
278
reaction/code/renderer/tr_fbo.c
Normal file
278
reaction/code/renderer/tr_fbo.c
Normal file
|
@ -0,0 +1,278 @@
|
|||
#include "tr_local.h"
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
|
||||
#endif
|
||||
|
||||
typedef struct fboRenderBuffer_s {
|
||||
GLuint id;
|
||||
int internalFormat;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
} fboRenderBuffer_t;
|
||||
|
||||
#define MAX_FBO_COLOR_BUFFERS 8
|
||||
|
||||
typedef struct fbo_s {
|
||||
GLuint id;
|
||||
|
||||
int numColorBufs;
|
||||
|
||||
image_t* color[MAX_FBO_COLOR_BUFFERS];
|
||||
fboZBuffer_t* depth;
|
||||
fboStencilBuffer_t* stencil;
|
||||
|
||||
char name[MAX_QPATH];
|
||||
} fbo_t;
|
||||
|
||||
|
||||
void R_FBO_InitRenderBuffer(fboRenderBuffer_t* buf)
|
||||
{
|
||||
buf->id = 0;
|
||||
qglGenRenderbuffersEXT(1, &buf->id);
|
||||
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, buf->id);
|
||||
qglRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, buf->internalFormat, buf->width, buf->height);
|
||||
qglBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
|
||||
}
|
||||
|
||||
void R_FBO_ReleaseRenderBuffer(fboRenderBuffer_t* buf)
|
||||
{
|
||||
if (buf->id == 0)
|
||||
return;
|
||||
|
||||
qglDeleteRenderbuffersEXT(1, &buf->id);
|
||||
buf->id = 0;
|
||||
}
|
||||
|
||||
fboRenderBuffer_t* R_FBO_CreateRenderBuffer(int width, int height, int pixelformat)
|
||||
{
|
||||
fboRenderBuffer_t* ret = NULL;
|
||||
if (tr.fbo.numRenderBuffers >= ARRAY_SIZE(tr.fbo.renderBuffers))
|
||||
{
|
||||
ri.Error(ERR_FATAL, "Too many FBO render buffers\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = ri.Hunk_Alloc(sizeof(*ret), h_low);
|
||||
memset(ret, 0, sizeof(*ret));
|
||||
|
||||
ret->width = width;
|
||||
ret->height = height;
|
||||
ret->internalFormat = pixelformat;
|
||||
|
||||
R_FBO_InitRenderBuffer(ret);
|
||||
|
||||
tr.fbo.renderBuffers[tr.fbo.numRenderBuffers++] = ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
fboZBuffer_t* R_FBO_CreateZBuffer(int width, int height)
|
||||
{
|
||||
return R_FBO_CreateRenderBuffer(width, height, GL_DEPTH_COMPONENT24);
|
||||
}
|
||||
|
||||
void R_FBO_Init(fbo_t* fbo)
|
||||
{
|
||||
memset(fbo, 0, sizeof(*fbo));
|
||||
qglGenFramebuffersEXT(1, &fbo->id);
|
||||
}
|
||||
|
||||
void R_FBO_Release(fbo_t* fbo)
|
||||
{
|
||||
if (fbo->id == 0)
|
||||
return;
|
||||
|
||||
qglDeleteFramebuffersEXT(1, &fbo->id);
|
||||
fbo->id = 0;
|
||||
}
|
||||
|
||||
void R_FBO_AddColorBuffer(fbo_t* fbo, image_t* image)
|
||||
{
|
||||
if (fbo->numColorBufs >= ARRAY_SIZE(fbo->color))
|
||||
{
|
||||
ri.Error(ERR_FATAL, "Max FBO color buffers exceeded.\n");
|
||||
return;
|
||||
}
|
||||
fbo->color[fbo->numColorBufs++] = image;
|
||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->id);
|
||||
qglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, (GLenum)(GL_COLOR_ATTACHMENT0_EXT + fbo->numColorBufs - 1), GL_TEXTURE_2D, image->texnum, 0);
|
||||
}
|
||||
|
||||
qboolean R_FBO_Check()
|
||||
{
|
||||
GLenum status = qglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
|
||||
const char* msg = "unknown error";
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case GL_FRAMEBUFFER_COMPLETE_EXT:
|
||||
return qtrue;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
|
||||
msg = "incomplete attachment";
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
|
||||
msg = "missing attachment";
|
||||
break;
|
||||
|
||||
//case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT:
|
||||
// msg = "duplicate attachment";
|
||||
// break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
|
||||
msg = "mismatched dimensions";
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
|
||||
msg = "mismatched formats";
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
|
||||
msg = "incomplete draw buffer";
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
|
||||
msg = "incomplete read buffer";
|
||||
break;
|
||||
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
|
||||
msg = "unsupported";
|
||||
break;
|
||||
|
||||
default:
|
||||
msg = va("unknown error (0x%x)", status);
|
||||
break;
|
||||
}
|
||||
|
||||
ri.Error(ERR_FATAL, "Bad framebuffer setup for '%s': %s\n", glState.currentFBO->name, msg);
|
||||
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
fbo_t* R_FBO_Bind(fbo_t* fbo)
|
||||
{
|
||||
fbo_t* old = glState.currentFBO;
|
||||
GLuint id = 0;
|
||||
if (!glRefConfig.framebufferObject)
|
||||
return NULL;
|
||||
|
||||
if (glState.currentFBO == fbo)
|
||||
return old;
|
||||
|
||||
glState.currentFBO = fbo;
|
||||
if (fbo)
|
||||
id = fbo->id;
|
||||
|
||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, id);
|
||||
|
||||
if (fbo)
|
||||
{
|
||||
if (1)
|
||||
R_FBO_Check();
|
||||
}
|
||||
|
||||
return old;
|
||||
}
|
||||
|
||||
void R_FBO_BindColorBuffer(fbo_t* fbo, int index)
|
||||
{
|
||||
GL_Bind(fbo->color[index]);
|
||||
}
|
||||
|
||||
fbo_t* R_FBO_CreateEx(const char* name, int numColorBuffers, image_t** colorBuffers, fboZBuffer_t* depth, fboStencilBuffer_t* stencil)
|
||||
{
|
||||
fbo_t* fbo = NULL;
|
||||
|
||||
if (tr.fbo.numFBOs >= ARRAY_SIZE(tr.fbo.fbos))
|
||||
{
|
||||
ri.Error(ERR_FATAL, "Too many FBO's\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ri.Printf(PRINT_DEVELOPER, "Creating FBO %s: %d color/%d depth/%d stencil\n", name, numColorBuffers, depth != NULL, stencil != NULL);
|
||||
|
||||
fbo = ri.Hunk_Alloc(sizeof(*fbo), h_low);
|
||||
|
||||
R_FBO_Init(fbo);
|
||||
|
||||
Q_strncpyz(fbo->name, name, ARRAY_SIZE(fbo->name));
|
||||
|
||||
while (numColorBuffers-- > 0)
|
||||
R_FBO_AddColorBuffer(fbo, *colorBuffers++);
|
||||
|
||||
fbo->depth = depth;
|
||||
fbo->stencil = stencil;
|
||||
|
||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo->id);
|
||||
|
||||
if (fbo->depth)
|
||||
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->depth->id);
|
||||
|
||||
if (fbo->stencil)
|
||||
qglFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, fbo->stencil->id);
|
||||
|
||||
qglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
|
||||
tr.fbo.fbos[tr.fbo.numFBOs++] = fbo;
|
||||
|
||||
return fbo;
|
||||
}
|
||||
|
||||
fbo_t* R_FBO_CreateSimple(const char* name, image_t* color, fboZBuffer_t* depth, fboStencilBuffer_t* stencil)
|
||||
{
|
||||
return R_FBO_CreateEx(name, color != NULL, &color, depth, stencil);
|
||||
}
|
||||
|
||||
void R_InitFBOs(void)
|
||||
{
|
||||
if (!glRefConfig.framebufferObject)
|
||||
return;
|
||||
|
||||
ri.Printf(PRINT_ALL, "------- R_InitFBOs -------\n");
|
||||
|
||||
tr.fbo.full[0] = R_FBO_CreateSimple(
|
||||
"main",
|
||||
R_CreateImage("*framebuffer", NULL, glConfig.vidWidth, glConfig.vidHeight, qfalse, qfalse, GL_CLAMP_TO_EDGE),
|
||||
R_FBO_CreateZBuffer(glConfig.vidWidth, glConfig.vidHeight),
|
||||
NULL);
|
||||
|
||||
tr.fbo.full[1] = R_FBO_CreateSimple(
|
||||
"postprocess",
|
||||
R_CreateImage("*framebuffer", NULL, glConfig.vidWidth, glConfig.vidHeight, qfalse, qfalse, GL_CLAMP_TO_EDGE),
|
||||
tr.fbo.full[0]->depth,
|
||||
NULL);
|
||||
|
||||
tr.fbo.quarter[0] = R_FBO_CreateSimple(
|
||||
"quarter0",
|
||||
R_CreateImage("*quarterBuffer0", NULL, glConfig.vidWidth/2, glConfig.vidHeight/2, qfalse, qfalse, GL_CLAMP_TO_EDGE),
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
tr.fbo.quarter[1] = R_FBO_CreateSimple(
|
||||
"quarter1",
|
||||
R_CreateImage("*quarterBuffer1", NULL, glConfig.vidWidth/2, glConfig.vidHeight/2, qfalse, qfalse, GL_CLAMP_TO_EDGE),
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
ri.Printf(PRINT_DEVELOPER, "Created %d FBOs\n", tr.fbo.numFBOs);
|
||||
}
|
||||
|
||||
void R_ShutDownFBOs(void)
|
||||
{
|
||||
if (!glRefConfig.framebufferObject)
|
||||
return;
|
||||
|
||||
ri.Printf(PRINT_ALL, "------- R_ShutdownFBOs -------\n");
|
||||
|
||||
R_FBO_Bind(NULL);
|
||||
|
||||
while (tr.fbo.numRenderBuffers>0)
|
||||
R_FBO_ReleaseRenderBuffer(tr.fbo.renderBuffers[--tr.fbo.numRenderBuffers]);
|
||||
|
||||
while (tr.fbo.numFBOs>0)
|
||||
R_FBO_Release(tr.fbo.fbos[--tr.fbo.numFBOs]);
|
||||
}
|
||||
|
|
@ -501,6 +501,18 @@ static void Upload32( unsigned *data,
|
|||
GLenum internalFormat = GL_RGB;
|
||||
float rMax = 0, gMax = 0, bMax = 0;
|
||||
|
||||
// Makro - render target
|
||||
if (!data)
|
||||
{
|
||||
internalFormat = GL_RGBA8;
|
||||
qglTexImage2D (GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
||||
GL_CheckErrors();
|
||||
*format = internalFormat;
|
||||
*pUploadWidth = width;
|
||||
*pUploadHeight = height;
|
||||
goto done;
|
||||
}
|
||||
|
||||
//
|
||||
// convert to exact power of 2 sizes
|
||||
//
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -152,6 +152,14 @@ typedef struct IBO_s
|
|||
// uint32_t ofsIndexes;
|
||||
} IBO_t;
|
||||
|
||||
typedef struct fboRenderBuffer_s fboRenderBuffer_t;
|
||||
typedef fboRenderBuffer_t fboZBuffer_t;
|
||||
typedef fboRenderBuffer_t fboStencilBuffer_t;
|
||||
typedef struct fbo_s fbo_t;
|
||||
|
||||
fbo_t *R_FBO_Bind(fbo_t* fbo);
|
||||
void R_FBO_BindColorBuffer(fbo_t* fbo, int index);
|
||||
|
||||
//===============================================================================
|
||||
|
||||
typedef enum {
|
||||
|
@ -2141,6 +2149,7 @@ typedef struct {
|
|||
shaderProgram_t *currentProgram;
|
||||
VBO_t *currentVBO;
|
||||
IBO_t *currentIBO;
|
||||
fbo_t *currentFBO;
|
||||
matrix_t modelview;
|
||||
matrix_t projection;
|
||||
matrix_t modelviewProjection;
|
||||
|
@ -2153,6 +2162,10 @@ typedef struct {
|
|||
int maxAnisotropy;
|
||||
qboolean multiDrawArrays;
|
||||
qboolean vertexBufferObject;
|
||||
|
||||
qboolean framebufferObject;
|
||||
qboolean framebufferBlit;
|
||||
qboolean framebufferMultisample;
|
||||
|
||||
// These next three are all required for one chunk of code, so glsl is
|
||||
// set if they are all true.
|
||||
|
@ -2200,6 +2213,9 @@ typedef struct {
|
|||
qboolean isHyperspace;
|
||||
trRefEntity_t *currentEntity;
|
||||
qboolean skyRenderedThisView; // flag for drawing sun
|
||||
|
||||
vec3_t sunFlarePos;
|
||||
qboolean hasSunFlare;
|
||||
|
||||
qboolean projection2D; // if qtrue, drawstretchpic doesn't need to change modes
|
||||
byte color2D[4];
|
||||
|
@ -2207,6 +2223,17 @@ typedef struct {
|
|||
trRefEntity_t entity2D; // currentEntity will point at this when doing 2D rendering
|
||||
} backEndState_t;
|
||||
|
||||
typedef struct {
|
||||
fbo_t *full[2]; // full resolution, shared zbuffer
|
||||
fbo_t *quarter[2]; // quarter resolution, no zbuffer
|
||||
|
||||
int numFBOs;
|
||||
fbo_t *fbos[1024];
|
||||
|
||||
int numRenderBuffers;
|
||||
fboRenderBuffer_t *renderBuffers[1024];
|
||||
} fboState_t;
|
||||
|
||||
/*
|
||||
** trGlobals_t
|
||||
**
|
||||
|
@ -2307,6 +2334,8 @@ typedef struct {
|
|||
int numIBOs;
|
||||
IBO_t *ibos[MAX_IBOS];
|
||||
|
||||
fboState_t fbo;
|
||||
|
||||
// shader indexes from other modules will be looked up in tr.shaders[]
|
||||
// shader indexes from drawsurfs will be looked up in sortedShaders[]
|
||||
// lower indexed sortedShaders must be rendered first (opaque surfaces before translucent)
|
||||
|
@ -2414,6 +2443,8 @@ extern cvar_t *r_arb_vertex_buffer_object;
|
|||
extern cvar_t *r_arb_shader_objects;
|
||||
extern cvar_t *r_ext_multi_draw_arrays;
|
||||
|
||||
extern cvar_t *r_ext_framebuffer_object;
|
||||
|
||||
extern cvar_t *r_nobind; // turns off binding to appropriate textures
|
||||
extern cvar_t *r_singleShader; // make most world faces use default shader
|
||||
extern cvar_t *r_roundImagesDown;
|
||||
|
@ -2722,6 +2753,10 @@ void RB_AddQuadStampExt( vec3_t origin, vec3_t left, vec3_t up, byte *color, flo
|
|||
|
||||
void RB_ShowImages( void );
|
||||
|
||||
void RB_SetGL2D(void);
|
||||
void RB_SetGL2D_Level(int level);
|
||||
void RB_PostProcess( void );
|
||||
|
||||
|
||||
/*
|
||||
============================================================
|
||||
|
@ -2843,6 +2878,16 @@ void R_VBOList_f(void);
|
|||
|
||||
void RB_UpdateVBOs(unsigned int attribBits);
|
||||
|
||||
/*
|
||||
============================================================
|
||||
|
||||
FRAME BUFFER OBJECTS
|
||||
|
||||
============================================================
|
||||
*/
|
||||
|
||||
void R_InitFBOs(void);
|
||||
void R_ShutDownFBOs(void);
|
||||
|
||||
/*
|
||||
============================================================
|
||||
|
|
317
reaction/code/renderer/tr_postprocess.c
Normal file
317
reaction/code/renderer/tr_postprocess.c
Normal file
|
@ -0,0 +1,317 @@
|
|||
#include "tr_local.h"
|
||||
|
||||
/* Color functions */
|
||||
|
||||
static void GLSL_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
|
||||
{
|
||||
vec4_t clr;
|
||||
MAKERGBA(clr, r, g, b, a);
|
||||
GLSL_SetUniform_Color(glState.currentProgram, clr);
|
||||
}
|
||||
|
||||
static void qglDefColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
|
||||
{
|
||||
qglColor4f(r, g, b, a);
|
||||
}
|
||||
|
||||
/* Quad-drawing functions */
|
||||
|
||||
static void tessTexCoord2f(float s, float t)
|
||||
{
|
||||
tess.texCoords[tess.numVertexes][0][0] = s;
|
||||
tess.texCoords[tess.numVertexes][0][1] = t;
|
||||
tess.texCoords[tess.numVertexes][0][2] = 0;
|
||||
tess.texCoords[tess.numVertexes][0][3] = 1;
|
||||
}
|
||||
|
||||
static void tessVertex2f(float x, float y)
|
||||
{
|
||||
tess.xyz[tess.numVertexes][0] = x;
|
||||
tess.xyz[tess.numVertexes][1] = y;
|
||||
tess.xyz[tess.numVertexes][2] = 0.f;
|
||||
tess.xyz[tess.numVertexes][3] = 1.f;
|
||||
++tess.numVertexes;
|
||||
}
|
||||
|
||||
static void tessBeginQuads(void)
|
||||
{
|
||||
tess.numIndexes = 0;
|
||||
tess.numVertexes = 0;
|
||||
tess.firstIndex = 0;
|
||||
}
|
||||
|
||||
static void tessEndQuads(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<tess.numVertexes; i+=4)
|
||||
{
|
||||
tess.indexes[tess.numIndexes++] = i+0;
|
||||
tess.indexes[tess.numIndexes++] = i+1;
|
||||
tess.indexes[tess.numIndexes++] = i+2;
|
||||
tess.indexes[tess.numIndexes++] = i+0;
|
||||
tess.indexes[tess.numIndexes++] = i+2;
|
||||
tess.indexes[tess.numIndexes++] = i+3;
|
||||
}
|
||||
|
||||
// FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function
|
||||
RB_UpdateVBOs(ATTR_POSITION | ATTR_TEXCOORD);
|
||||
|
||||
if (glRefConfig.glsl && r_arb_shader_objects->integer)
|
||||
{
|
||||
GLSL_VertexAttribsState(ATTR_POSITION | ATTR_TEXCOORD);
|
||||
GLSL_SetUniform_ModelViewProjectionMatrix(glState.currentProgram, glState.modelviewProjection);
|
||||
}
|
||||
else
|
||||
{
|
||||
qglEnableClientState( GL_VERTEX_ARRAY );
|
||||
qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||
qglVertexPointer(3, GL_FLOAT, glState.currentVBO->stride_xyz, BUFFER_OFFSET(glState.currentVBO->ofs_xyz));
|
||||
qglTexCoordPointer( 2, GL_FLOAT, glState.currentVBO->stride_st, BUFFER_OFFSET(glState.currentVBO->ofs_st) );
|
||||
}
|
||||
|
||||
qglDrawElements(GL_TRIANGLES, tess.numIndexes, GL_INDEX_TYPE, BUFFER_OFFSET(0));
|
||||
|
||||
//R_BindNullVBO();
|
||||
//R_BindNullIBO();
|
||||
|
||||
tess.numIndexes = 0;
|
||||
tess.numVertexes = 0;
|
||||
tess.firstIndex = 0;
|
||||
}
|
||||
|
||||
static void RB_DrawQuad_Imm(float x, float y, float w, float h, float s0, float t0, float s1, float t1)
|
||||
{
|
||||
qglBegin (GL_QUADS);
|
||||
{
|
||||
qglTexCoord2f( s0, t1 );
|
||||
qglVertex2f( x, y );
|
||||
|
||||
qglTexCoord2f( s1, t1 );
|
||||
qglVertex2f( x + w, y );
|
||||
|
||||
qglTexCoord2f( s1, t0 );
|
||||
qglVertex2f( x + w, y + h );
|
||||
|
||||
qglTexCoord2f( s0, t0 );
|
||||
qglVertex2f( x, y + h );
|
||||
}
|
||||
qglEnd();
|
||||
}
|
||||
|
||||
static void RB_DrawQuad_Tess(float x, float y, float w, float h, float s0, float t0, float s1, float t1)
|
||||
{
|
||||
tessBeginQuads();
|
||||
{
|
||||
tessTexCoord2f( s0, t1 );
|
||||
tessVertex2f( x, y );
|
||||
|
||||
tessTexCoord2f( s1, t1 );
|
||||
tessVertex2f( x + w, y );
|
||||
|
||||
tessTexCoord2f( s1, t0 );
|
||||
tessVertex2f( x + w, y + h );
|
||||
|
||||
tessTexCoord2f( s0, t0 );
|
||||
tessVertex2f( x, y + h );
|
||||
}
|
||||
tessEndQuads();
|
||||
}
|
||||
|
||||
static void (*RB_DrawQuad) (float x, float y, float w, float h, float s0, float t0, float s1, float t1) = NULL;
|
||||
static void (*RB_Color4f) (GLfloat r, GLfloat g, GLfloat b, GLfloat a) = NULL;
|
||||
|
||||
static void RB_DrawScaledQuad(float x, float y, float w, float h, float xcenter, float ycenter, float scale)
|
||||
{
|
||||
float iscale = 1.f / scale;
|
||||
float s0 = xcenter * (1.f - iscale);
|
||||
float t0 = ycenter * (1.f - iscale);
|
||||
float s1 = iscale + s0;
|
||||
float t1 = iscale + t0;
|
||||
|
||||
RB_DrawQuad(x, y, w, h, s0, t0, s1, t1);
|
||||
}
|
||||
|
||||
static void RB_RadialBlur(int passes, float stretch, float x, float y, float w, float h, float xcenter, float ycenter, float alpha)
|
||||
{
|
||||
const float inc = 1.f / (passes + 1.f);
|
||||
float scale;
|
||||
stretch -= 1.f;
|
||||
alpha *= inc;
|
||||
RB_Color4f(alpha, alpha, alpha, 1.f);
|
||||
for (scale=inc; scale<1.f; scale+=inc)
|
||||
{
|
||||
RB_DrawScaledQuad(x, y, w, h, xcenter, ycenter, 1.f + scale * stretch);
|
||||
}
|
||||
RB_Color4f(1.f, 1.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
RB_GodRays
|
||||
|
||||
================
|
||||
*/
|
||||
|
||||
static void RB_GodRays(void)
|
||||
{
|
||||
vec3_t dir;
|
||||
float dot;
|
||||
const float cutoff = 0.25f;
|
||||
|
||||
float x, y, w, h, w2, h2;
|
||||
matrix_t mvp;
|
||||
vec4_t pos, hpos;
|
||||
float mul;
|
||||
|
||||
if (!backEnd.hasSunFlare)
|
||||
return;
|
||||
|
||||
VectorSubtract(backEnd.sunFlarePos, backEnd.viewParms.or.origin, dir);
|
||||
VectorNormalize(dir);
|
||||
|
||||
dot = DotProduct(dir, backEnd.viewParms.or.axis[0]);
|
||||
if (dot < cutoff)
|
||||
return;
|
||||
|
||||
VectorCopy(backEnd.sunFlarePos, pos);
|
||||
pos[3] = 1.f;
|
||||
|
||||
// project sun point
|
||||
Matrix16Multiply(backEnd.viewParms.projectionMatrix, backEnd.viewParms.world.modelMatrix, mvp);
|
||||
Matrix16Transform(mvp, pos, hpos);
|
||||
|
||||
// transform to UV coords
|
||||
hpos[3] = 0.5f / hpos[3];
|
||||
|
||||
pos[0] = 0.5f + hpos[0] * hpos[3];
|
||||
pos[1] = 0.5f + hpos[1] * hpos[3];
|
||||
|
||||
// viewport dimensions
|
||||
x = 0.f;
|
||||
y = 0.f;
|
||||
w = glConfig.vidWidth;
|
||||
h = glConfig.vidHeight;
|
||||
w2 = w * 0.5f;
|
||||
h2 = h * 0.5f;
|
||||
|
||||
// downsample full-screen buffer to first quarter buffer
|
||||
R_FBO_Bind(tr.fbo.quarter[0]);
|
||||
|
||||
RB_SetGL2D_Level(1);
|
||||
|
||||
R_FBO_BindColorBuffer(tr.fbo.full[1], 0);
|
||||
GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
|
||||
|
||||
mul = 0.25f;
|
||||
RB_Color4f(mul, mul, mul, 1.f);
|
||||
RB_DrawQuad(x, y, w2, h2, 0.f, 0.f, 1.f, 1.f);
|
||||
|
||||
// copy to second quarter buffer
|
||||
R_FBO_Bind(tr.fbo.quarter[1]);
|
||||
R_FBO_BindColorBuffer(tr.fbo.quarter[0], 0);
|
||||
|
||||
mul = 0.5f;
|
||||
RB_Color4f(mul, mul, mul, 1.f);
|
||||
|
||||
RB_DrawScaledQuad(x, y, w2, h2, pos[0], pos[1], 1.f);
|
||||
|
||||
// several additive passes
|
||||
GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
|
||||
|
||||
RB_DrawScaledQuad(x, y, w2, h2, pos[0], pos[1], 1.f + 1.f/16.f);
|
||||
RB_DrawScaledQuad(x, y, w2, h2, pos[0], pos[1], 1.f + 2.f/16.f);
|
||||
RB_DrawScaledQuad(x, y, w2, h2, pos[0], pos[1], 1.f + 3.f/16.f);
|
||||
|
||||
// switch back to the first buffer and do some more passes
|
||||
R_FBO_Bind(tr.fbo.quarter[0]);
|
||||
R_FBO_BindColorBuffer(tr.fbo.quarter[1], 0);
|
||||
|
||||
RB_RadialBlur(5, 4.f, x, y, w2, h2, pos[0], pos[1], 1.f);
|
||||
|
||||
RB_Color4f(1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
// add back on top of the main buffer
|
||||
R_FBO_Bind(tr.fbo.full[0]);
|
||||
|
||||
RB_SetGL2D_Level(0);
|
||||
R_FBO_BindColorBuffer(tr.fbo.quarter[0], 0);
|
||||
GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
|
||||
|
||||
RB_DrawQuad(x, y, w, h, 0.f, 0.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
static void RB_BlitFBO(void)
|
||||
{
|
||||
R_FBO_Bind(NULL);
|
||||
|
||||
RB_Color4f(1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
R_FBO_BindColorBuffer(tr.fbo.full[0], 0);
|
||||
GL_State(GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
|
||||
|
||||
RB_DrawQuad(0.f, 0.f, glConfig.vidWidth, glConfig.vidHeight, 0.f, 0.f, 1.f, 1.f);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
RB_PostProcess
|
||||
|
||||
================
|
||||
*/
|
||||
|
||||
void RB_PostProcess(void)
|
||||
{
|
||||
if (!glState.currentFBO)
|
||||
return;
|
||||
|
||||
|
||||
RB_DrawQuad = NULL;
|
||||
RB_Color4f = NULL;
|
||||
|
||||
// initialize our function pointers and perform any necessary setup
|
||||
if (glRefConfig.vertexBufferObject && r_arb_vertex_buffer_object->integer)
|
||||
{
|
||||
RB_DrawQuad = &RB_DrawQuad_Tess;
|
||||
if (glRefConfig.glsl && r_arb_shader_objects->integer)
|
||||
{
|
||||
matrix_t matrix;
|
||||
shaderProgram_t *sp = &tr.genericShader[0];
|
||||
|
||||
GLSL_BindProgram(sp);
|
||||
|
||||
GLSL_SetUniform_ModelViewProjectionMatrix(sp, glState.modelviewProjection);
|
||||
|
||||
GLSL_SetUniform_FogAdjustColors(sp, 0);
|
||||
GLSL_SetUniform_DeformGen(sp, DGEN_NONE);
|
||||
GLSL_SetUniform_TCGen0(sp, TCGEN_TEXTURE);
|
||||
Matrix16Identity(matrix);
|
||||
GLSL_SetUniform_Texture0Matrix(sp, matrix);
|
||||
GLSL_SetUniform_Texture1Env(sp, 0);
|
||||
GLSL_SetUniform_ColorGen(sp, CGEN_CONST);
|
||||
GLSL_SetUniform_AlphaGen(sp, AGEN_IDENTITY);
|
||||
|
||||
RB_Color4f = &GLSL_Color4f;
|
||||
}
|
||||
else
|
||||
{
|
||||
RB_Color4f = &qglDefColor4f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RB_DrawQuad = &RB_DrawQuad_Imm;
|
||||
RB_Color4f = &qglDefColor4f;
|
||||
}
|
||||
|
||||
RB_SetGL2D();
|
||||
|
||||
GL_SelectTexture(1);
|
||||
GL_Bind(tr.whiteImage);
|
||||
GL_SelectTexture(0);
|
||||
|
||||
RB_Color4f(1.f, 1.f, 1.f, 1.f);
|
||||
|
||||
RB_GodRays();
|
||||
RB_BlitFBO();
|
||||
}
|
|
@ -260,8 +260,10 @@ RB_SurfaceSprite
|
|||
==============
|
||||
*/
|
||||
static void RB_SurfaceSprite( void ) {
|
||||
vec3_t left, up;
|
||||
float radius;
|
||||
vec3_t left, up;
|
||||
float radius;
|
||||
byte colors[4];
|
||||
trRefEntity_t *ent = backEnd.currentEntity;
|
||||
|
||||
// calculate the xyz locations for the four corners
|
||||
radius = backEnd.currentEntity->e.radius;
|
||||
|
@ -285,8 +287,16 @@ static void RB_SurfaceSprite( void ) {
|
|||
if ( backEnd.viewParms.isMirror ) {
|
||||
VectorSubtract( vec3_origin, left, left );
|
||||
}
|
||||
|
||||
if (ent->e.renderfx & RF_SUNFLARE) {
|
||||
colors[0] = colors[1] = colors[2] = colors[3] = ent->e.shaderRGBA[glRefConfig.framebufferObject];
|
||||
if (colors[0] == 0)
|
||||
return;
|
||||
} else {
|
||||
Vector4Copy(ent->e.shaderRGBA, colors);
|
||||
}
|
||||
|
||||
RB_AddQuadStamp( backEnd.currentEntity->e.origin, left, up, backEnd.currentEntity->e.shaderRGBA );
|
||||
RB_AddQuadStamp( backEnd.currentEntity->e.origin, left, up, colors );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -47,6 +47,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
||||
#define RF_SHADOW_PLANE 0x0100 // use refEntity->shadowPlane
|
||||
#define RF_WRAP_FRAMES 0x0200 // mod the model frames by the maxframes to allow continuous
|
||||
#define RF_DEPTHHACK 0x0008 // for view weapon Z crunching
|
||||
|
||||
#define RF_SUNFLARE 0x0400
|
||||
|
||||
// refdef flags
|
||||
#define RDF_NOWORLDMODEL 0x0001 // used for player configuration screen
|
||||
|
|
|
@ -40,6 +40,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#include <math.h>
|
||||
|
||||
#include "../renderer/tr_local.h"
|
||||
#include "../renderer/qglextensions.h"
|
||||
#include "../client/client.h"
|
||||
#include "../sys/sys_local.h"
|
||||
#include "sdl_icon.h"
|
||||
|
@ -200,6 +201,13 @@ void (APIENTRY * qglGetUniformfvARB) (GLhandleARB programObj, GLint l
|
|||
void (APIENTRY * qglGetUniformivARB) (GLhandleARB programObj, GLint location, GLint * params);
|
||||
void (APIENTRY * qglGetShaderSourceARB) (GLhandleARB obj, GLsizei maxLength, GLsizei * length, GLcharARB * source);
|
||||
|
||||
#define HANDLE_EXT_FUNC(t, n) t q##n
|
||||
|
||||
ADD_ALL_EXTENSION_FUNCTIONS;
|
||||
|
||||
#undef HANDLE_EXT_FUNC
|
||||
|
||||
|
||||
#if defined(WIN32)
|
||||
// WGL_ARB_create_context
|
||||
HGLRC(APIENTRY * qwglCreateContextAttribsARB) (HDC hdC, HGLRC hShareContext, const int *attribList);
|
||||
|
@ -1079,6 +1087,50 @@ static void GLimp_InitExtensions( void )
|
|||
ri.Printf(PRINT_ALL, "...GL_ARB_vertex_shader not found\n");
|
||||
}
|
||||
|
||||
// Makro - copy/paste vs macros - choosing the lesser evil
|
||||
# define HANDLE_EXT_FUNC(type, name) q##name = (type) SDL_GL_GetProcAddress(#name)
|
||||
|
||||
// GL_EXT_framebuffer_object
|
||||
if (GLimp_HaveExtension("GL_EXT_framebuffer_object"))
|
||||
{
|
||||
const char* action[2] = { "ignoring", "using" };
|
||||
GL_EXT_framebuffer_object_functions;
|
||||
glRefConfig.framebufferObject = (r_ext_framebuffer_object->integer != 0);
|
||||
ri.Printf(PRINT_ALL, "...%s GL_EXT_framebuffer_object\n", action[glRefConfig.framebufferObject]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf(PRINT_ALL, "...GL_EXT_framebuffer_object not found\n");
|
||||
}
|
||||
|
||||
// GL_EXT_framebuffer_blit
|
||||
if (GLimp_HaveExtension("GL_EXT_framebuffer_blit"))
|
||||
{
|
||||
const char* action[2] = { "ignoring", "using" };
|
||||
GL_EXT_framebuffer_blit_functions;
|
||||
glRefConfig.framebufferBlit = (r_ext_framebuffer_object->integer != 0);
|
||||
ri.Printf(PRINT_ALL, "...%s GL_EXT_framebuffer_blit\n", action[glRefConfig.framebufferBlit]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf(PRINT_ALL, "...GL_EXT_framebuffer_blit not found\n");
|
||||
}
|
||||
|
||||
// GL_EXT_framebuffer_multisample
|
||||
if (GLimp_HaveExtension("GL_EXT_framebuffer_multisample"))
|
||||
{
|
||||
const char* action[2] = { "ignoring", "using" };
|
||||
GL_EXT_framebuffer_multisample_functions;
|
||||
glRefConfig.framebufferMultisample = (r_ext_framebuffer_object->integer != 0);
|
||||
ri.Printf(PRINT_ALL, "...%s GL_EXT_framebuffer_multisample\n", action[glRefConfig.framebufferMultisample]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ri.Printf(PRINT_ALL, "...GL_EXT_framebuffer_multisample not found\n");
|
||||
}
|
||||
|
||||
# undef HANDLE_EXT_FUNC
|
||||
|
||||
glRefConfig.glsl = glRefConfig.vertexProgram && glRefConfig.shaderObjects && glRefConfig.vertexShader;
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue