ffov implemented in GL.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@3320 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2009-07-19 18:13:03 +00:00
parent efb1d412a5
commit 12cccf0e39
1 changed files with 494 additions and 198 deletions

View File

@ -70,6 +70,7 @@ qboolean mirror;
mplane_t *mirror_plane; mplane_t *mirror_plane;
msurface_t *r_mirror_chain; msurface_t *r_mirror_chain;
qboolean r_inmirror; //or out-of-body qboolean r_inmirror; //or out-of-body
extern msurface_t *r_alpha_surfaces;
// //
// view origin // view origin
@ -121,6 +122,8 @@ cvar_t gl_maxdist = SCVAR("gl_maxdist", "8192");
extern cvar_t gl_contrast; extern cvar_t gl_contrast;
extern cvar_t gl_mindist; extern cvar_t gl_mindist;
extern cvar_t ffov;
extern cvar_t gl_motionblur; extern cvar_t gl_motionblur;
extern cvar_t gl_motionblurscale; extern cvar_t gl_motionblurscale;
@ -154,6 +157,12 @@ int scenepp_mt_parm_texture0i;
int scenepp_mt_parm_colorf; int scenepp_mt_parm_colorf;
int scenepp_mt_parm_inverti; 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 // 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 // I put it here so that only this file need be changed when messing with the post
// processing shaders // processing shaders
@ -223,6 +232,67 @@ void GL_InitSceneProcessingShaders_WaterWarp (void)
Con_Printf(CON_ERROR "GL Error initing shader object\n"); 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) void GL_InitSceneProcessingShaders_MenuTint(void)
{ {
char *vshader = "\ char *vshader = "\
@ -273,6 +343,7 @@ void GL_InitSceneProcessingShaders_MenuTint(void)
void GL_InitSceneProcessingShaders (void) void GL_InitSceneProcessingShaders (void)
{ {
GL_InitSceneProcessingShaders_WaterWarp(); GL_InitSceneProcessingShaders_WaterWarp();
GL_InitFisheyeFov();
GL_InitSceneProcessingShaders_MenuTint(); 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_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]; unsigned char pp_edge_tex[PP_AMP_TEX_SIZE*PP_AMP_TEX_SIZE*3];
scenepp_fisheye_texture = 0;
sceneblur_texture = GL_AllocNewTexture(); sceneblur_texture = GL_AllocNewTexture();
if (!gl_config.arb_shader_objects) if (!gl_config.arb_shader_objects)
@ -1567,118 +1640,86 @@ void GLR_SetupFog (void)
} }
#endif #endif
/* static void R_RenderMotionBlur(void)
================
R_RenderView
r_refdef must be set before the first call
================
*/
void GLR_RenderView (void)
{ {
extern msurface_t *r_alpha_surfaces; int vwidth = 1, vheight = 1;
double time1 = 0, time2; float vs, vt, cs, ct;
if (qglGetError()) if (gl_config.arb_texture_non_power_of_two)
Con_Printf("GL Error before drawing scene\n"); { //we can use any size, supposedly
vwidth = glwidth;
if (r_norefresh.value || !glwidth || !glheight) vheight = glheight;
{
GL_DoSwap();
return;
}
if (!(r_refdef.flags & Q2RDF_NOWORLDMODEL))
if (!r_worldentity.model || !cl.worldmodel)
{
GL_DoSwap();
return;
}
// Sys_Error ("R_RenderView: NULL worldmodel");
if (qglPNTrianglesiATI)
{
if (gl_ati_truform_type.value)
{ //linear
qglPNTrianglesiATI(GL_PN_TRIANGLES_NORMAL_MODE_ATI, GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI);
qglPNTrianglesiATI(GL_PN_TRIANGLES_POINT_MODE_ATI, GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI);
} }
else else
{ //quadric { //limit the texture size to square and use padding.
qglPNTrianglesiATI(GL_PN_TRIANGLES_NORMAL_MODE_ATI, GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI); while (vwidth < glwidth)
qglPNTrianglesiATI(GL_PN_TRIANGLES_POINT_MODE_ATI, GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI); vwidth *= 2;
} while (vheight < glheight)
qglPNTrianglesfATI(GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI, gl_ati_truform_tesselation.value); vheight *= 2;
} }
if (gl_finish.value) qglViewport (glx, gly, glwidth, glheight);
{
RSpeedMark();
qglFinish ();
RSpeedEnd(RSPEED_FINISH);
}
if (r_speeds.value) GL_Bind(sceneblur_texture);
{
time1 = Sys_DoubleTime ();
c_brush_polys = 0;
c_alias_polys = 0;
}
mirror = false; // go 2d
qglMatrixMode(GL_PROJECTION);
qglPushMatrix();
qglLoadIdentity ();
qglOrtho (0, glwidth, 0, glheight, -99999, 99999);
qglMatrixMode(GL_MODELVIEW);
qglPushMatrix();
qglLoadIdentity ();
R_Clear (); //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;
// GLR_SetupFog (); 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();
r_alpha_surfaces = NULL; qglMatrixMode(GL_PROJECTION);
qglPopMatrix();
qglMatrixMode(GL_MODELVIEW);
qglPopMatrix();
GL_SetShaderState2D(false);
// render normal view //copy the image into the texture so that we can play with it next frame too!
R_RenderScene (); 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);
}
GLR_DrawWaterSurfaces (); static void R_RenderWaterWarp(void)
GLR_DrawAlphaSurfaces (); {
// render mirror view
R_Mirror ();
R_BloomBlend();
R_PolyBlend ();
// qglDisable(GL_FOG);
if (r_speeds.value)
{
// glFinish ();
time2 = Sys_DoubleTime ();
RQuantAdd(RQUANT_MSECS, (int)((time2-time1)*1000000));
RQuantAdd(RQUANT_WPOLYS, c_brush_polys);
RQuantAdd(RQUANT_EPOLYS, c_alias_polys);
// Con_Printf ("%3i ms %4i wpoly %4i epoly\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys);
}
if (qglGetError())
Con_Printf("GL Error drawing scene\n");
if (r_refdef.flags & Q2RDF_NOWORLDMODEL)
return;
// SCENE POST PROCESSING
// 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 vwidth = 1, vheight = 1;
float vs, vt; float vs, vt;
// get the powers of 2 for the size of the texture that will hold the scene // 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) while (vwidth < glwidth)
{ {
vwidth *= 2; vwidth *= 2;
@ -1687,6 +1728,7 @@ void GLR_RenderView (void)
{ {
vheight *= 2; vheight *= 2;
} }
}
// get the maxtexcoords while we're at it // get the maxtexcoords while we're at it
vs = glwidth / vwidth; vs = glwidth / vwidth;
@ -1795,31 +1837,173 @@ void GLR_RenderView (void)
if (qglGetError()) if (qglGetError())
Con_Printf("GL Error after drawing with shaderobjects\n"); 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)
if (gl_motionblur.value>0 && gl_motionblur.value < 1 && qglCopyTexImage2D) return false;
{
int vwidth = 1, vheight = 1;
float vs, vt, cs, ct;
if (gl_config.arb_texture_non_power_of_two) if (gl_config.arb_texture_non_power_of_two)
{ //we can use any size, supposedly {
vwidth = glwidth; if (glwidth < glheight)
vheight = glheight; cmapsize = glwidth;
else
cmapsize = glheight;
} }
else else
{ //limit the texture size to square and use padding. {
while (vwidth < glwidth) while (cmapsize > glwidth || cmapsize > glheight)
vwidth *= 2; {
while (vheight < glheight) cmapsize /= 2;
vheight *= 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); qglViewport (glx, gly, glwidth, glheight);
GL_Bind(sceneblur_texture); 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 // go 2d
qglMatrixMode(GL_PROJECTION); qglMatrixMode(GL_PROJECTION);
@ -1830,26 +2014,18 @@ void GLR_RenderView (void)
qglPushMatrix(); qglPushMatrix();
qglLoadIdentity (); 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_DEPTH_TEST);
qglDisable (GL_CULL_FACE); qglDisable (GL_CULL_FACE);
qglDisable (GL_ALPHA_TEST); qglDisable (GL_ALPHA_TEST);
qglEnable(GL_BLEND); qglDisable(GL_BLEND);
qglColor4f(1, 1, 1, gl_motionblur.value);
qglBegin(GL_QUADS); qglBegin(GL_QUADS);
qglTexCoord2f(cs-vs, ct-vt); qglTexCoord2f(-0.5, -0.5);
qglVertex2f(0, 0); qglVertex2f(0, 0);
qglTexCoord2f(cs+vs, ct-vt); qglTexCoord2f(0.5, -0.5);
qglVertex2f(glwidth, 0); qglVertex2f(glwidth, 0);
qglTexCoord2f(cs+vs, ct+vt); qglTexCoord2f(0.5, 0.5);
qglVertex2f(glwidth, glheight); qglVertex2f(glwidth, glheight);
qglTexCoord2f(cs-vs, ct+vt); qglTexCoord2f(-0.5, 0.5);
qglVertex2f(0, glheight); qglVertex2f(0, glheight);
qglEnd(); qglEnd();
@ -1858,12 +2034,132 @@ void GLR_RenderView (void)
qglMatrixMode(GL_MODELVIEW); qglMatrixMode(GL_MODELVIEW);
qglPopMatrix(); qglPopMatrix();
qglDisable(GL_TEXTURE_CUBE_MAP_ARB);
qglEnable(GL_TEXTURE_2D);
//copy the image into the texture so that we can play with it next frame too! GLSlang_UseProgram(0);
qglCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, glx, gly, vwidth, vheight, 0);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); return true;
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); }
/*
================
R_RenderView
r_refdef must be set before the first call
================
*/
void GLR_RenderView (void)
{
double time1 = 0, time2;
if (qglGetError())
Con_Printf("GL Error before drawing scene\n");
if (r_norefresh.value || !glwidth || !glheight)
{
GL_DoSwap();
return;
} }
if (!(r_refdef.flags & Q2RDF_NOWORLDMODEL))
if (!r_worldentity.model || !cl.worldmodel)
{
GL_DoSwap();
return;
}
// Sys_Error ("R_RenderView: NULL worldmodel");
if (qglPNTrianglesiATI)
{
if (gl_ati_truform_type.value)
{ //linear
qglPNTrianglesiATI(GL_PN_TRIANGLES_NORMAL_MODE_ATI, GL_PN_TRIANGLES_NORMAL_MODE_LINEAR_ATI);
qglPNTrianglesiATI(GL_PN_TRIANGLES_POINT_MODE_ATI, GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI);
}
else
{ //quadric
qglPNTrianglesiATI(GL_PN_TRIANGLES_NORMAL_MODE_ATI, GL_PN_TRIANGLES_NORMAL_MODE_QUADRATIC_ATI);
qglPNTrianglesiATI(GL_PN_TRIANGLES_POINT_MODE_ATI, GL_PN_TRIANGLES_POINT_MODE_CUBIC_ATI);
}
qglPNTrianglesfATI(GL_PN_TRIANGLES_TESSELATION_LEVEL_ATI, gl_ati_truform_tesselation.value);
}
if (gl_finish.value)
{
RSpeedMark();
qglFinish ();
RSpeedEnd(RSPEED_FINISH);
}
if (r_speeds.value)
{
time1 = Sys_DoubleTime ();
c_brush_polys = 0;
c_alias_polys = 0;
}
if (ffov.value && cls.allow_fish && !(r_refdef.flags & Q2RDF_NOWORLDMODEL) && R_RenderScene_Fish())
{
//fisheye does its own rendering.
}
else
{
mirror = false;
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 ();
}
R_BloomBlend();
R_PolyBlend ();
// qglDisable(GL_FOG);
if (r_speeds.value)
{
// glFinish ();
time2 = Sys_DoubleTime ();
RQuantAdd(RQUANT_MSECS, (int)((time2-time1)*1000000));
RQuantAdd(RQUANT_WPOLYS, c_brush_polys);
RQuantAdd(RQUANT_EPOLYS, c_alias_polys);
// Con_Printf ("%3i ms %4i wpoly %4i epoly\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys);
}
if (qglGetError())
Con_Printf("GL Error drawing scene\n");
if (r_refdef.flags & Q2RDF_NOWORLDMODEL)
return;
// SCENE POST PROCESSING
// 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))
R_RenderWaterWarp();
if (gl_motionblur.value>0 && gl_motionblur.value < 1 && qglCopyTexImage2D)
R_RenderMotionBlur();
} }
#endif #endif