GL_EXT_framebuffer_object support. God rays post-processing effect.

This commit is contained in:
Andrei Drexler 2011-03-14 12:27:43 +00:00
parent 2d8bbf6c53
commit 2fc2a4a947
11 changed files with 2141 additions and 1312 deletions

View file

@ -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

View 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

View file

@ -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);
}
/*
=============

View 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]);
}

View file

@ -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

View file

@ -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);
/*
============================================================

View 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();
}

View file

@ -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 );
}

View file

@ -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

View file

@ -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;
}