From 12cccf0e39516b1817f937aa5ba4870d8f03a923 Mon Sep 17 00:00:00 2001 From: Spoike Date: Sun, 19 Jul 2009 18:13:03 +0000 Subject: [PATCH] ffov implemented in GL. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@3320 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/gl/gl_rmain.c | 692 ++++++++++++++++++++++++++++++------------- 1 file changed, 494 insertions(+), 198 deletions(-) diff --git a/engine/gl/gl_rmain.c b/engine/gl/gl_rmain.c index c57e00b3d..d47d59bac 100644 --- a/engine/gl/gl_rmain.c +++ b/engine/gl/gl_rmain.c @@ -70,6 +70,7 @@ qboolean mirror; mplane_t *mirror_plane; msurface_t *r_mirror_chain; qboolean r_inmirror; //or out-of-body +extern msurface_t *r_alpha_surfaces; // // view origin @@ -121,6 +122,8 @@ cvar_t gl_maxdist = SCVAR("gl_maxdist", "8192"); extern cvar_t gl_contrast; extern cvar_t gl_mindist; +extern cvar_t ffov; + extern cvar_t gl_motionblur; extern cvar_t gl_motionblurscale; @@ -154,6 +157,12 @@ int scenepp_mt_parm_texture0i; int scenepp_mt_parm_colorf; int scenepp_mt_parm_inverti; +int scenepp_fisheye_texture; +int scenepp_fisheye_program; +int scenepp_fisheye_parm_fov; +int scenepp_panorama_program; +int scenepp_panorama_parm_fov; + // KrimZon - init post processing - called in GL_CheckExtensions, when they're called // I put it here so that only this file need be changed when messing with the post // processing shaders @@ -223,6 +232,67 @@ void GL_InitSceneProcessingShaders_WaterWarp (void) Con_Printf(CON_ERROR "GL Error initing shader object\n"); } +void GL_InitFisheyeFov(void) +{ + char *vshader = "\ + varying vec2 texcoord;\ + void main(void)\ + {\ + texcoord = gl_MultiTexCoord0.xy;\ + gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\ + }"; + char *fisheyefshader = "\ + uniform samplerCube source;\ + varying vec2 texcoord;\ + uniform float fov;\ + void main(void)\ + {\ + vec3 tc; \ + vec2 d; \ + vec2 ang; \ + d = texcoord; \ + ang.x = sqrt(d.x*d.x+d.y*d.y)*fov; \ + ang.y = -atan(d.y, d.x); \ + tc.x = sin(ang.x) * cos(ang.y); \ + tc.y = sin(ang.x) * sin(ang.y); \ + tc.z = cos(ang.x); \ + gl_FragColor = textureCube(source, tc);\ + }"; + + char *panoramafshader = "\ + uniform samplerCube source;\ + varying vec2 texcoord;\ + uniform float fov;\ + void main(void)\ + {\ + vec3 tc; \ + float ang; \ + ang = texcoord.x*fov; \ + tc.x = sin(ang); \ + tc.y = -texcoord.y; \ + tc.z = cos(ang); \ + gl_FragColor = textureCube(source, tc);\ + }"; + + scenepp_fisheye_program = GLSlang_CreateProgram(NULL, vshader, fisheyefshader); + if (scenepp_fisheye_program) + { + GLSlang_UseProgram(scenepp_fisheye_program); + GLSlang_SetUniform1i(GLSlang_GetUniformLocation(scenepp_fisheye_program, "source"), 0); + scenepp_fisheye_parm_fov = GLSlang_GetUniformLocation(scenepp_fisheye_program, "fov"); + GLSlang_UseProgram(0); + } + + scenepp_panorama_program = GLSlang_CreateProgram(NULL, vshader, panoramafshader); + if (scenepp_panorama_program) + { + GLSlang_UseProgram(scenepp_panorama_program); + GLSlang_SetUniform1i(GLSlang_GetUniformLocation(scenepp_panorama_program, "source"), 0); + scenepp_panorama_parm_fov = GLSlang_GetUniformLocation(scenepp_panorama_program, "fov"); + GLSlang_UseProgram(0); + } +} + void GL_InitSceneProcessingShaders_MenuTint(void) { char *vshader = "\ @@ -273,6 +343,7 @@ void GL_InitSceneProcessingShaders_MenuTint(void) void GL_InitSceneProcessingShaders (void) { GL_InitSceneProcessingShaders_WaterWarp(); + GL_InitFisheyeFov(); GL_InitSceneProcessingShaders_MenuTint(); } @@ -285,6 +356,8 @@ void GL_SetupSceneProcessingTextures (void) unsigned char pp_warp_tex[PP_WARP_TEX_SIZE*PP_WARP_TEX_SIZE*3]; unsigned char pp_edge_tex[PP_AMP_TEX_SIZE*PP_AMP_TEX_SIZE*3]; + scenepp_fisheye_texture = 0; + sceneblur_texture = GL_AllocNewTexture(); if (!gl_config.arb_shader_objects) @@ -1567,6 +1640,407 @@ void GLR_SetupFog (void) } #endif +static void R_RenderMotionBlur(void) +{ + int vwidth = 1, vheight = 1; + float vs, vt, cs, ct; + + if (gl_config.arb_texture_non_power_of_two) + { //we can use any size, supposedly + vwidth = glwidth; + vheight = glheight; + } + else + { //limit the texture size to square and use padding. + while (vwidth < glwidth) + vwidth *= 2; + while (vheight < glheight) + vheight *= 2; + } + + qglViewport (glx, gly, glwidth, glheight); + + GL_Bind(sceneblur_texture); + + // go 2d + qglMatrixMode(GL_PROJECTION); + qglPushMatrix(); + qglLoadIdentity (); + qglOrtho (0, glwidth, 0, glheight, -99999, 99999); + qglMatrixMode(GL_MODELVIEW); + qglPushMatrix(); + qglLoadIdentity (); + + //blend the last frame onto the scene + //the maths is because our texture is over-sized (must be power of two) + cs = vs = (float)glwidth / vwidth * 0.5; + ct = vt = (float)glheight / vheight * 0.5; + vs *= gl_motionblurscale.value; + vt *= gl_motionblurscale.value; + + qglDisable (GL_DEPTH_TEST); + qglDisable (GL_CULL_FACE); + qglDisable (GL_ALPHA_TEST); + qglEnable(GL_BLEND); + qglColor4f(1, 1, 1, gl_motionblur.value); + qglBegin(GL_QUADS); + qglTexCoord2f(cs-vs, ct-vt); + qglVertex2f(0, 0); + qglTexCoord2f(cs+vs, ct-vt); + qglVertex2f(glwidth, 0); + qglTexCoord2f(cs+vs, ct+vt); + qglVertex2f(glwidth, glheight); + qglTexCoord2f(cs-vs, ct+vt); + qglVertex2f(0, glheight); + qglEnd(); + + qglMatrixMode(GL_PROJECTION); + qglPopMatrix(); + qglMatrixMode(GL_MODELVIEW); + qglPopMatrix(); + + + //copy the image into the texture so that we can play with it next frame too! + qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, glx, gly, vwidth, vheight, 0); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +} + +static void R_RenderWaterWarp(void) +{ + float vwidth = 1, vheight = 1; + float vs, vt; + + // get the powers of 2 for the size of the texture that will hold the scene + + if (gl_config.arb_texture_non_power_of_two) + { + vwidth = glwidth; + vheight = glheight; + } + else + { + while (vwidth < glwidth) + { + vwidth *= 2; + } + while (vheight < glheight) + { + vheight *= 2; + } + } + + // get the maxtexcoords while we're at it + vs = glwidth / vwidth; + vt = glheight / vheight; + + // 2d mode, but upside down to quake's normal 2d drawing + // this makes grabbing the sreen a lot easier + qglViewport (glx, gly, glwidth, glheight); + + qglMatrixMode(GL_PROJECTION); + // Push the matrices to go into 2d mode, that matches opengl's mode + qglPushMatrix(); + qglLoadIdentity (); + // TODO: use actual window width and height + qglOrtho (0, glwidth, 0, glheight, -99999, 99999); + + qglMatrixMode(GL_MODELVIEW); + qglPushMatrix(); + qglLoadIdentity (); + + qglDisable (GL_DEPTH_TEST); + qglDisable (GL_CULL_FACE); + qglDisable (GL_BLEND); + qglEnable (GL_ALPHA_TEST); + + // copy the scene to texture + GL_Bind(scenepp_texture); + qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, glx, gly, vwidth, vheight, 0); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + if (qglGetError()) + Con_Printf(CON_ERROR "GL Error after qglCopyTexImage2D\n"); + + // Here we apply the shaders - currently just waterwarp + GLSlang_UseProgram(scenepp_ww_program); + //keep the amp proportional to the size of the scene in texture coords + // WARNING - waterwarp can change the amplitude, but if it's too big it'll exceed + // the size determined by the edge texture, after which black bits will be shown. + // Suggest clamping to a suitable range. + if (r_waterwarp.value<0) + { + GLSlang_SetUniform1f(scenepp_ww_parm_ampscalef, (0.005 / 0.625) * vs*(-r_waterwarp.value)); + } + else + { + GLSlang_SetUniform1f(scenepp_ww_parm_ampscalef, (0.005 / 0.625) * vs*r_waterwarp.value); + } + + if (qglGetError()) + Con_Printf("GL Error after GLSlang_UseProgram\n"); + + { + float xmin, xmax, ymin, ymax; + + xmin = cl.time * 0.25; + ymin = cl.time * 0.25; + xmax = xmin + 1; + ymax = ymin + 1/vt*vs; + + GL_EnableMultitexture(); + GL_Bind (scenepp_texture_warp); + + GL_SelectTexture(mtexid1+1); + qglEnable(GL_TEXTURE_2D); + GL_Bind(scenepp_texture_edge); + + qglBegin(GL_QUADS); + + qglMTexCoord2fSGIS (mtexid0, 0, 0); + qglMTexCoord2fSGIS (mtexid1, xmin, ymin); + qglMTexCoord2fSGIS (mtexid1+1, 0, 0); + qglVertex2f(0, 0); + + qglMTexCoord2fSGIS (mtexid0, vs, 0); + qglMTexCoord2fSGIS (mtexid1, xmax, ymin); + qglMTexCoord2fSGIS (mtexid1+1, 1, 0); + qglVertex2f(glwidth, 0); + + qglMTexCoord2fSGIS (mtexid0, vs, vt); + qglMTexCoord2fSGIS (mtexid1, xmax, ymax); + qglMTexCoord2fSGIS (mtexid1+1, 1, 1); + qglVertex2f(glwidth, glheight); + + qglMTexCoord2fSGIS (mtexid0, 0, vt); + qglMTexCoord2fSGIS (mtexid1, xmin, ymax); + qglMTexCoord2fSGIS (mtexid1+1, 0, 1); + qglVertex2f(0, glheight); + + qglEnd(); + + qglDisable(GL_TEXTURE_2D); + GL_SelectTexture(mtexid1); + + GL_DisableMultitexture(); + } + + // Disable shaders + GLSlang_UseProgram(0); + + // After all the post processing, pop the matrices + qglMatrixMode(GL_PROJECTION); + qglPopMatrix(); + qglMatrixMode(GL_MODELVIEW); + qglPopMatrix(); + + if (qglGetError()) + Con_Printf("GL Error after drawing with shaderobjects\n"); +} + +qboolean R_RenderScene_Fish(void) +{ + int cmapsize = 512; + int i; + static vec3_t ang[6] = + { {0, -90, 0}, {0, 90, 0}, + {90, 0, 0}, {-90, 0, 0}, + {0, 0, 0}, {0, -180, 0} }; + int order[6] = {4, 0, 1, 5, 3, 2}; + int numsides = 4; + vec3_t saveang; + int rot45 = 0; + + if (!scenepp_panorama_program) + return false; + + if (gl_config.arb_texture_non_power_of_two) + { + if (glwidth < glheight) + cmapsize = glwidth; + else + cmapsize = glheight; + } + else + { + while (cmapsize > glwidth || cmapsize > glheight) + { + cmapsize /= 2; + } + } + + VectorCopy(r_refdef.viewangles, saveang); + saveang[2] = 0; + + if (ffov.value < 0) + { + //panoramic view needs at most the four sides + if (ffov.value >= -90) + numsides = 1; +// else if (ffov.value >= -180) +// { +// numsides = 2; +// rot45 = 1; +// } + else if (ffov.value >= -270) + numsides = 3; + else + numsides = 4; + + order[0] = 4; + order[1] = 0; + order[2] = 1; + order[3] = 5; + } + else + { + //fisheye view sees a full sphere + // + if (ffov.value <= 77) + numsides = 1; +// else if (ffov.value <= 180) +// { +// numsides = 3; +// rot45 = 3; +// } + else if (ffov.value <= 270) + numsides = 5; + else + numsides = 6; + + order[0] = 4; + order[1] = 0; + order[2] = 3; + order[3] = 1; + order[4] = 2; + order[5] = 5; + } + + qglViewport (glx, gly+glheight - cmapsize, cmapsize, cmapsize); + + if (!scenepp_fisheye_texture) + { + scenepp_fisheye_texture = GL_AllocNewTexture(); + + qglDisable(GL_TEXTURE_2D); + qglEnable(GL_TEXTURE_CUBE_MAP_ARB); + + bindTexFunc(GL_TEXTURE_CUBE_MAP_ARB, scenepp_fisheye_texture); + for (i = 0; i < 6; i++) + qglCopyTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + i, 0, GL_RGB, 0, 0, cmapsize, cmapsize, 0); + qglTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + qglTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + qglTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + qglTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + qglEnable(GL_TEXTURE_2D); + qglDisable(GL_TEXTURE_CUBE_MAP_ARB); + } + + r_refdef.vrect.width = (cmapsize+0.99)*vid.width/glwidth; + r_refdef.vrect.height = (cmapsize+0.99)*vid.height/glheight; + r_refdef.vrect.x = 0; + r_refdef.vrect.y = vid.height - r_refdef.vrect.height; + + ang[0][0] = -saveang[0]; + ang[0][1] = -90; + ang[0][2] = -saveang[0]; + + ang[1][0] = -saveang[0]; + ang[1][1] = 90; + ang[1][2] = saveang[0]; + ang[5][0] = -saveang[0]*2; + for (i = 0; i < numsides; i++) + { + mirror = false; + + r_refdef.fov_x = 90; + r_refdef.fov_y = 90; + r_refdef.viewangles[0] = saveang[0]+ang[order[i]][0]; + r_refdef.viewangles[1] = saveang[1]+ang[order[i]][1]; + r_refdef.viewangles[2] = saveang[2]+ang[order[i]][2]; + + R_Clear (); + + // GLR_SetupFog (); + + r_alpha_surfaces = NULL; + + GL_SetShaderState2D(false); + + // render normal view + R_RenderScene (); + + GLR_DrawWaterSurfaces (); + GLR_DrawAlphaSurfaces (); + + // render mirror view + R_Mirror (); + + qglDisable(GL_TEXTURE_2D); + qglEnable(GL_TEXTURE_CUBE_MAP_ARB); + GL_BindType(GL_TEXTURE_CUBE_MAP_ARB, scenepp_fisheye_texture); + qglCopyTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + order[i], 0, 0, 0, 0, 0, cmapsize, cmapsize); + qglEnable(GL_TEXTURE_2D); + qglDisable(GL_TEXTURE_CUBE_MAP_ARB); + } + +//qglClear (GL_COLOR_BUFFER_BIT); + qglViewport (glx, gly, glwidth, glheight); + + qglDisable(GL_TEXTURE_2D); + GL_BindType(GL_TEXTURE_CUBE_MAP_ARB, scenepp_fisheye_texture); + qglEnable(GL_TEXTURE_CUBE_MAP_ARB); + + if (scenepp_panorama_program && ffov.value < 0) + { + GLSlang_UseProgram(scenepp_panorama_program); + GLSlang_SetUniform1f(scenepp_panorama_parm_fov, -ffov.value*3.1415926535897932384626433832795/180); + } + else + { + GLSlang_UseProgram(scenepp_fisheye_program); + GLSlang_SetUniform1f(scenepp_fisheye_parm_fov, ffov.value*3.1415926535897932384626433832795/180); + } + + + // go 2d + qglMatrixMode(GL_PROJECTION); + qglPushMatrix(); + qglLoadIdentity (); + qglOrtho (0, glwidth, 0, glheight, -99999, 99999); + qglMatrixMode(GL_MODELVIEW); + qglPushMatrix(); + qglLoadIdentity (); + + qglDisable (GL_DEPTH_TEST); + qglDisable (GL_CULL_FACE); + qglDisable (GL_ALPHA_TEST); + qglDisable(GL_BLEND); + qglBegin(GL_QUADS); + qglTexCoord2f(-0.5, -0.5); + qglVertex2f(0, 0); + qglTexCoord2f(0.5, -0.5); + qglVertex2f(glwidth, 0); + qglTexCoord2f(0.5, 0.5); + qglVertex2f(glwidth, glheight); + qglTexCoord2f(-0.5, 0.5); + qglVertex2f(0, glheight); + qglEnd(); + + qglMatrixMode(GL_PROJECTION); + qglPopMatrix(); + qglMatrixMode(GL_MODELVIEW); + qglPopMatrix(); + + qglDisable(GL_TEXTURE_CUBE_MAP_ARB); + qglEnable(GL_TEXTURE_2D); + + GLSlang_UseProgram(0); + + return true; +} /* ================ R_RenderView @@ -1576,7 +2050,6 @@ r_refdef must be set before the first call */ void GLR_RenderView (void) { - extern msurface_t *r_alpha_surfaces; double time1 = 0, time2; if (qglGetError()) @@ -1627,24 +2100,31 @@ void GLR_RenderView (void) c_alias_polys = 0; } - mirror = false; + if (ffov.value && cls.allow_fish && !(r_refdef.flags & Q2RDF_NOWORLDMODEL) && R_RenderScene_Fish()) + { + //fisheye does its own rendering. + } + else + { + mirror = false; - R_Clear (); + R_Clear (); -// GLR_SetupFog (); + // GLR_SetupFog (); - r_alpha_surfaces = NULL; + r_alpha_surfaces = NULL; - GL_SetShaderState2D(false); + GL_SetShaderState2D(false); - // render normal view - R_RenderScene (); + // render normal view + R_RenderScene (); - GLR_DrawWaterSurfaces (); - GLR_DrawAlphaSurfaces (); + GLR_DrawWaterSurfaces (); + GLR_DrawAlphaSurfaces (); - // render mirror view - R_Mirror (); + // render mirror view + R_Mirror (); + } R_BloomBlend(); @@ -1674,196 +2154,12 @@ void GLR_RenderView (void) // we check if we need to use any shaders - currently it's just waterwarp if (scenepp_ww_program) if ((r_waterwarp.value>0 && r_viewleaf && r_viewleaf->contents <= Q1CONTENTS_WATER)) - { - float vwidth = 1, vheight = 1; - float vs, vt; - - // get the powers of 2 for the size of the texture that will hold the scene - while (vwidth < glwidth) - { - vwidth *= 2; - } - while (vheight < glheight) - { - vheight *= 2; - } - - // get the maxtexcoords while we're at it - vs = glwidth / vwidth; - vt = glheight / vheight; - - // 2d mode, but upside down to quake's normal 2d drawing - // this makes grabbing the sreen a lot easier - qglViewport (glx, gly, glwidth, glheight); - - qglMatrixMode(GL_PROJECTION); - // Push the matrices to go into 2d mode, that matches opengl's mode - qglPushMatrix(); - qglLoadIdentity (); - // TODO: use actual window width and height - qglOrtho (0, glwidth, 0, glheight, -99999, 99999); - - qglMatrixMode(GL_MODELVIEW); - qglPushMatrix(); - qglLoadIdentity (); - - qglDisable (GL_DEPTH_TEST); - qglDisable (GL_CULL_FACE); - qglDisable (GL_BLEND); - qglEnable (GL_ALPHA_TEST); - - // copy the scene to texture - GL_Bind(scenepp_texture); - qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, glx, gly, vwidth, vheight, 0); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - if (qglGetError()) - Con_Printf(CON_ERROR "GL Error after qglCopyTexImage2D\n"); - - // Here we apply the shaders - currently just waterwarp - GLSlang_UseProgram(scenepp_ww_program); - //keep the amp proportional to the size of the scene in texture coords - // WARNING - waterwarp can change the amplitude, but if it's too big it'll exceed - // the size determined by the edge texture, after which black bits will be shown. - // Suggest clamping to a suitable range. - if (r_waterwarp.value<0) - { - GLSlang_SetUniform1f(scenepp_ww_parm_ampscalef, (0.005 / 0.625) * vs*(-r_waterwarp.value)); - } - else - { - GLSlang_SetUniform1f(scenepp_ww_parm_ampscalef, (0.005 / 0.625) * vs*r_waterwarp.value); - } - - if (qglGetError()) - Con_Printf("GL Error after GLSlang_UseProgram\n"); - - { - float xmin, xmax, ymin, ymax; - - xmin = cl.time * 0.25; - ymin = cl.time * 0.25; - xmax = xmin + 1; - ymax = ymin + 1/vt*vs; - - GL_EnableMultitexture(); - GL_Bind (scenepp_texture_warp); - - GL_SelectTexture(mtexid1+1); - qglEnable(GL_TEXTURE_2D); - GL_Bind(scenepp_texture_edge); - - qglBegin(GL_QUADS); - - qglMTexCoord2fSGIS (mtexid0, 0, 0); - qglMTexCoord2fSGIS (mtexid1, xmin, ymin); - qglMTexCoord2fSGIS (mtexid1+1, 0, 0); - qglVertex2f(0, 0); - - qglMTexCoord2fSGIS (mtexid0, vs, 0); - qglMTexCoord2fSGIS (mtexid1, xmax, ymin); - qglMTexCoord2fSGIS (mtexid1+1, 1, 0); - qglVertex2f(glwidth, 0); - - qglMTexCoord2fSGIS (mtexid0, vs, vt); - qglMTexCoord2fSGIS (mtexid1, xmax, ymax); - qglMTexCoord2fSGIS (mtexid1+1, 1, 1); - qglVertex2f(glwidth, glheight); - - qglMTexCoord2fSGIS (mtexid0, 0, vt); - qglMTexCoord2fSGIS (mtexid1, xmin, ymax); - qglMTexCoord2fSGIS (mtexid1+1, 0, 1); - qglVertex2f(0, glheight); - - qglEnd(); - - qglDisable(GL_TEXTURE_2D); - GL_SelectTexture(mtexid1); - - GL_DisableMultitexture(); - } - - // Disable shaders - GLSlang_UseProgram(0); - - // After all the post processing, pop the matrices - qglMatrixMode(GL_PROJECTION); - qglPopMatrix(); - qglMatrixMode(GL_MODELVIEW); - qglPopMatrix(); - - if (qglGetError()) - Con_Printf("GL Error after drawing with shaderobjects\n"); - } + R_RenderWaterWarp(); if (gl_motionblur.value>0 && gl_motionblur.value < 1 && qglCopyTexImage2D) - { - int vwidth = 1, vheight = 1; - float vs, vt, cs, ct; - - if (gl_config.arb_texture_non_power_of_two) - { //we can use any size, supposedly - vwidth = glwidth; - vheight = glheight; - } - else - { //limit the texture size to square and use padding. - while (vwidth < glwidth) - vwidth *= 2; - while (vheight < glheight) - vheight *= 2; - } - - qglViewport (glx, gly, glwidth, glheight); - - GL_Bind(sceneblur_texture); - - // go 2d - qglMatrixMode(GL_PROJECTION); - qglPushMatrix(); - qglLoadIdentity (); - qglOrtho (0, glwidth, 0, glheight, -99999, 99999); - qglMatrixMode(GL_MODELVIEW); - qglPushMatrix(); - qglLoadIdentity (); - - //blend the last frame onto the scene - //the maths is because our texture is over-sized (must be power of two) - cs = vs = (float)glwidth / vwidth * 0.5; - ct = vt = (float)glheight / vheight * 0.5; - vs *= gl_motionblurscale.value; - vt *= gl_motionblurscale.value; - - qglDisable (GL_DEPTH_TEST); - qglDisable (GL_CULL_FACE); - qglDisable (GL_ALPHA_TEST); - qglEnable(GL_BLEND); - qglColor4f(1, 1, 1, gl_motionblur.value); - qglBegin(GL_QUADS); - qglTexCoord2f(cs-vs, ct-vt); - qglVertex2f(0, 0); - qglTexCoord2f(cs+vs, ct-vt); - qglVertex2f(glwidth, 0); - qglTexCoord2f(cs+vs, ct+vt); - qglVertex2f(glwidth, glheight); - qglTexCoord2f(cs-vs, ct+vt); - qglVertex2f(0, glheight); - qglEnd(); - - qglMatrixMode(GL_PROJECTION); - qglPopMatrix(); - qglMatrixMode(GL_MODELVIEW); - qglPopMatrix(); - - - //copy the image into the texture so that we can play with it next frame too! - qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, glx, gly, vwidth, vheight, 0); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } + R_RenderMotionBlur(); } #endif