2022-02-08 19:06:54 +00:00
/*
Copyright ( C ) 1996 - 2001 Id Software , Inc .
Copyright ( C ) 2002 - 2009 John Fitzgibbons and others
Copyright ( C ) 2010 - 2014 QuakeSpasm developers
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
See the GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
// r_main.c
# include "quakedef.h"
qboolean r_cache_thrash ; // compatability
vec3_t modelorg , r_entorigin ;
entity_t * currententity ;
int r_visframecount ; // bumped when going to a new PVS
int r_framecount ; // used for dlight push checking
mplane_t frustum [ 4 ] ;
//johnfitz -- rendering statistics
int rs_brushpolys , rs_aliaspolys , rs_skypolys , rs_particles , rs_fogpolys ;
int rs_dynamiclightmaps , rs_brushpasses , rs_aliaspasses , rs_skypasses ;
float rs_megatexels ;
//
// view origin
//
vec3_t vup ;
vec3_t vpn ;
vec3_t vright ;
vec3_t r_origin ;
float r_fovx , r_fovy ; //johnfitz -- rendering fov may be different becuase of r_waterwarp and r_stereo
//
// screen size info
//
refdef_t r_refdef ;
mleaf_t * r_viewleaf , * r_oldviewleaf ;
int d_lightstylevalue [ 256 ] ; // 8.8 fraction of base light value
cvar_t r_norefresh = { " r_norefresh " , " 0 " , CVAR_NONE } ;
cvar_t r_drawentities = { " r_drawentities " , " 1 " , CVAR_NONE } ;
cvar_t r_drawviewmodel = { " r_drawviewmodel " , " 1 " , CVAR_NONE } ;
cvar_t r_speeds = { " r_speeds " , " 0 " , CVAR_NONE } ;
cvar_t r_pos = { " r_pos " , " 0 " , CVAR_NONE } ;
cvar_t r_fullbright = { " r_fullbright " , " 0 " , CVAR_NONE } ;
cvar_t r_lightmap = { " r_lightmap " , " 0 " , CVAR_NONE } ;
cvar_t r_shadows = { " r_shadows " , " 0 " , CVAR_ARCHIVE } ;
cvar_t r_wateralpha = { " r_wateralpha " , " 1 " , CVAR_ARCHIVE } ;
cvar_t r_dynamic = { " r_dynamic " , " 1 " , CVAR_ARCHIVE } ;
cvar_t r_novis = { " r_novis " , " 0 " , CVAR_ARCHIVE } ;
cvar_t gl_finish = { " gl_finish " , " 0 " , CVAR_NONE } ;
cvar_t gl_clear = { " gl_clear " , " 1 " , CVAR_NONE } ;
cvar_t gl_cull = { " gl_cull " , " 1 " , CVAR_NONE } ;
cvar_t gl_smoothmodels = { " gl_smoothmodels " , " 1 " , CVAR_NONE } ;
cvar_t gl_affinemodels = { " gl_affinemodels " , " 0 " , CVAR_NONE } ;
cvar_t gl_polyblend = { " gl_polyblend " , " 1 " , CVAR_NONE } ;
cvar_t gl_flashblend = { " gl_flashblend " , " 0 " , CVAR_ARCHIVE } ;
cvar_t gl_playermip = { " gl_playermip " , " 0 " , CVAR_NONE } ;
cvar_t gl_nocolors = { " gl_nocolors " , " 0 " , CVAR_NONE } ;
//johnfitz -- new cvars
cvar_t r_stereo = { " r_stereo " , " 0 " , CVAR_NONE } ;
cvar_t r_stereodepth = { " r_stereodepth " , " 128 " , CVAR_NONE } ;
cvar_t r_clearcolor = { " r_clearcolor " , " 2 " , CVAR_ARCHIVE } ;
cvar_t r_drawflat = { " r_drawflat " , " 0 " , CVAR_NONE } ;
cvar_t r_flatlightstyles = { " r_flatlightstyles " , " 0 " , CVAR_NONE } ;
cvar_t gl_fullbrights = { " gl_fullbrights " , " 1 " , CVAR_ARCHIVE } ;
cvar_t gl_farclip = { " gl_farclip " , " 16384 " , CVAR_ARCHIVE } ;
cvar_t gl_overbright = { " gl_overbright " , " 1 " , CVAR_ARCHIVE } ;
cvar_t gl_overbright_models = { " gl_overbright_models " , " 1 " , CVAR_ARCHIVE } ;
cvar_t r_oldskyleaf = { " r_oldskyleaf " , " 0 " , CVAR_NONE } ;
cvar_t r_drawworld = { " r_drawworld " , " 1 " , CVAR_NONE } ;
cvar_t r_showtris = { " r_showtris " , " 0 " , CVAR_NONE } ;
cvar_t r_showbboxes = { " r_showbboxes " , " 0 " , CVAR_NONE } ;
cvar_t r_lerpmodels = { " r_lerpmodels " , " 1 " , CVAR_NONE } ;
cvar_t r_lerpmove = { " r_lerpmove " , " 1 " , CVAR_NONE } ;
cvar_t r_nolerp_list = { " r_nolerp_list " , " progs/flame.mdl,progs/flame2.mdl,progs/braztall.mdl,progs/brazshrt.mdl,progs/longtrch.mdl,progs/flame_pyre.mdl,progs/v_saw.mdl,progs/v_xfist.mdl,progs/h2stuff/newfire.mdl " , CVAR_NONE } ;
2022-04-05 21:59:58 +00:00
cvar_t r_noshadow_list = { " r_noshadow_list " , " progs/flame2.mdl,progs/flame.mdl,progs/bolt1.mdl,models/misc/bolt2.mdl,progs/bolt3.mdl,progs/laser.mdl " , CVAR_NONE } ;
2022-02-08 19:06:54 +00:00
extern cvar_t r_vfog ;
//johnfitz
cvar_t gl_zfix = { " gl_zfix " , " 0 " , CVAR_NONE } ; // QuakeSpasm z-fighting fix
cvar_t r_lavaalpha = { " r_lavaalpha " , " 0 " , CVAR_NONE } ;
cvar_t r_telealpha = { " r_telealpha " , " 0 " , CVAR_NONE } ;
cvar_t r_slimealpha = { " r_slimealpha " , " 0 " , CVAR_NONE } ;
float map_wateralpha , map_lavaalpha , map_telealpha , map_slimealpha ;
qboolean r_drawflat_cheatsafe , r_fullbright_cheatsafe , r_lightmap_cheatsafe , r_drawworld_cheatsafe ; //johnfitz
cvar_t r_scale = { " r_scale " , " 1 " , CVAR_ARCHIVE } ;
//==============================================================================
//
// GLSL GAMMA CORRECTION
//
//==============================================================================
static GLuint r_gamma_texture ;
static GLuint r_gamma_program ;
static int r_gamma_texture_width , r_gamma_texture_height ;
// uniforms used in gamma shader
static GLuint gammaLoc ;
static GLuint contrastLoc ;
static GLuint textureLoc ;
/*
= = = = = = = = = = = = =
GLSLGamma_DeleteTexture
= = = = = = = = = = = = =
*/
void GLSLGamma_DeleteTexture ( void )
{
# ifndef VITA
glDeleteTextures ( 1 , & r_gamma_texture ) ;
r_gamma_texture = 0 ;
r_gamma_program = 0 ; // deleted in R_DeleteShaders
# endif
}
/*
= = = = = = = = = = = = =
GLSLGamma_CreateShaders
= = = = = = = = = = = = =
*/
static void GLSLGamma_CreateShaders ( void )
{
# ifndef VITA
const GLchar * vertSource = \
" #version 110 \n "
" \n "
" void main(void) { \n "
" gl_Position = vec4(gl_Vertex.xy, 0.0, 1.0); \n "
" gl_TexCoord[0] = gl_MultiTexCoord0; \n "
" } \n " ;
const GLchar * fragSource = \
" #version 110 \n "
" \n "
" uniform sampler2D GammaTexture; \n "
" uniform float GammaValue; \n "
" uniform float ContrastValue; \n "
" \n "
" void main(void) { \n "
" vec4 frag = texture2D(GammaTexture, gl_TexCoord[0].xy); \n "
" frag.rgb = frag.rgb * ContrastValue; \n "
" gl_FragColor = vec4(pow(frag.rgb, vec3(GammaValue)), 1.0); \n "
" } \n " ;
if ( ! gl_glsl_gamma_able )
return ;
r_gamma_program = GL_CreateProgram ( vertSource , fragSource , 0 , NULL ) ;
// get uniform locations
gammaLoc = GL_GetUniformLocation ( & r_gamma_program , " GammaValue " ) ;
contrastLoc = GL_GetUniformLocation ( & r_gamma_program , " ContrastValue " ) ;
textureLoc = GL_GetUniformLocation ( & r_gamma_program , " GammaTexture " ) ;
# endif
}
/*
= = = = = = = = = = = = =
GLSLGamma_GammaCorrect
= = = = = = = = = = = = =
*/
void GLSLGamma_GammaCorrect ( void )
{
# ifndef VITA
float smax , tmax ;
if ( ! gl_glsl_gamma_able )
return ;
if ( vid_gamma . value = = 1 & & vid_contrast . value = = 1 )
return ;
// create render-to-texture texture if needed
if ( ! r_gamma_texture )
{
glGenTextures ( 1 , & r_gamma_texture ) ;
glBindTexture ( GL_TEXTURE_2D , r_gamma_texture ) ;
r_gamma_texture_width = glwidth ;
r_gamma_texture_height = glheight ;
if ( ! gl_texture_NPOT )
{
r_gamma_texture_width = TexMgr_Pad ( r_gamma_texture_width ) ;
r_gamma_texture_height = TexMgr_Pad ( r_gamma_texture_height ) ;
}
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA8 , r_gamma_texture_width , r_gamma_texture_height , 0 , GL_BGRA , GL_UNSIGNED_INT_8_8_8_8_REV , NULL ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
}
// create shader if needed
if ( ! r_gamma_program )
{
GLSLGamma_CreateShaders ( ) ;
if ( ! r_gamma_program )
{
Sys_Error ( " GLSLGamma_CreateShaders failed " ) ;
}
}
// copy the framebuffer to the texture
GL_DisableMultitexture ( ) ;
glBindTexture ( GL_TEXTURE_2D , r_gamma_texture ) ;
glCopyTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , glx , gly , glwidth , glheight ) ;
// draw the texture back to the framebuffer with a fragment shader
GL_UseProgramFunc ( r_gamma_program ) ;
GL_Uniform1fFunc ( gammaLoc , vid_gamma . value ) ;
GL_Uniform1fFunc ( contrastLoc , q_min ( 2.0 , q_max ( 1.0 , vid_contrast . value ) ) ) ;
GL_Uniform1iFunc ( textureLoc , 0 ) ; // use texture unit 0
glDisable ( GL_ALPHA_TEST ) ;
glDisable ( GL_DEPTH_TEST ) ;
glViewport ( glx , gly , glwidth , glheight ) ;
smax = glwidth / ( float ) r_gamma_texture_width ;
tmax = glheight / ( float ) r_gamma_texture_height ;
glBegin ( GL_QUADS ) ;
glTexCoord2f ( 0 , 0 ) ;
glVertex2f ( - 1 , - 1 ) ;
glTexCoord2f ( smax , 0 ) ;
glVertex2f ( 1 , - 1 ) ;
glTexCoord2f ( smax , tmax ) ;
glVertex2f ( 1 , 1 ) ;
glTexCoord2f ( 0 , tmax ) ;
glVertex2f ( - 1 , 1 ) ;
glEnd ( ) ;
GL_UseProgramFunc ( 0 ) ;
// clear cached binding
GL_ClearBindings ( ) ;
# endif
}
/*
= = = = = = = = = = = = = = = = =
R_CullBox - - johnfitz - - replaced with new function from lordhavoc
Returns true if the box is completely outside the frustum
= = = = = = = = = = = = = = = = =
*/
qboolean R_CullBox ( vec3_t emins , vec3_t emaxs )
{
int i ;
mplane_t * p ;
for ( i = 0 ; i < 4 ; i + + )
{
p = frustum + i ;
switch ( p - > signbits )
{
default :
case 0 :
if ( p - > normal [ 0 ] * emaxs [ 0 ] + p - > normal [ 1 ] * emaxs [ 1 ] + p - > normal [ 2 ] * emaxs [ 2 ] < p - > dist )
return true ;
break ;
case 1 :
if ( p - > normal [ 0 ] * emins [ 0 ] + p - > normal [ 1 ] * emaxs [ 1 ] + p - > normal [ 2 ] * emaxs [ 2 ] < p - > dist )
return true ;
break ;
case 2 :
if ( p - > normal [ 0 ] * emaxs [ 0 ] + p - > normal [ 1 ] * emins [ 1 ] + p - > normal [ 2 ] * emaxs [ 2 ] < p - > dist )
return true ;
break ;
case 3 :
if ( p - > normal [ 0 ] * emins [ 0 ] + p - > normal [ 1 ] * emins [ 1 ] + p - > normal [ 2 ] * emaxs [ 2 ] < p - > dist )
return true ;
break ;
case 4 :
if ( p - > normal [ 0 ] * emaxs [ 0 ] + p - > normal [ 1 ] * emaxs [ 1 ] + p - > normal [ 2 ] * emins [ 2 ] < p - > dist )
return true ;
break ;
case 5 :
if ( p - > normal [ 0 ] * emins [ 0 ] + p - > normal [ 1 ] * emaxs [ 1 ] + p - > normal [ 2 ] * emins [ 2 ] < p - > dist )
return true ;
break ;
case 6 :
if ( p - > normal [ 0 ] * emaxs [ 0 ] + p - > normal [ 1 ] * emins [ 1 ] + p - > normal [ 2 ] * emins [ 2 ] < p - > dist )
return true ;
break ;
case 7 :
if ( p - > normal [ 0 ] * emins [ 0 ] + p - > normal [ 1 ] * emins [ 1 ] + p - > normal [ 2 ] * emins [ 2 ] < p - > dist )
return true ;
break ;
}
}
return false ;
}
/*
= = = = = = = = = = = = = = =
R_CullModelForEntity - - johnfitz - - uses correct bounds based on rotation
= = = = = = = = = = = = = = =
*/
qboolean R_CullModelForEntity ( entity_t * e )
{
vec3_t mins , maxs ;
if ( e - > angles [ 0 ] | | e - > angles [ 2 ] ) //pitch or roll
{
VectorAdd ( e - > origin , e - > model - > rmins , mins ) ;
VectorAdd ( e - > origin , e - > model - > rmaxs , maxs ) ;
}
else if ( e - > angles [ 1 ] ) //yaw
{
VectorAdd ( e - > origin , e - > model - > ymins , mins ) ;
VectorAdd ( e - > origin , e - > model - > ymaxs , maxs ) ;
}
else //no rotation
{
VectorAdd ( e - > origin , e - > model - > mins , mins ) ;
VectorAdd ( e - > origin , e - > model - > maxs , maxs ) ;
}
return R_CullBox ( mins , maxs ) ;
}
/*
= = = = = = = = = = = = = = =
R_RotateForEntity - - johnfitz - - modified to take origin and angles instead of pointer to entity
= = = = = = = = = = = = = = =
*/
2023-12-29 22:10:12 +00:00
void R_RotateForEntity ( vec3_t origin , vec3_t angles , unsigned char scale )
2022-02-08 19:06:54 +00:00
{
glTranslatef ( origin [ 0 ] , origin [ 1 ] , origin [ 2 ] ) ;
glRotatef ( angles [ 1 ] , 0 , 0 , 1 ) ;
glRotatef ( - angles [ 0 ] , 0 , 1 , 0 ) ;
glRotatef ( angles [ 2 ] , 1 , 0 , 0 ) ;
2023-12-29 22:10:12 +00:00
if ( scale ! = ENTSCALE_DEFAULT ) {
float scalefactor = ENTSCALE_DECODE ( scale ) ;
glScalef ( scalefactor , scalefactor , scalefactor ) ;
}
2022-02-08 19:06:54 +00:00
}
/*
= = = = = = = = = = = = =
GL_PolygonOffset - - johnfitz
negative offset moves polygon closer to camera
= = = = = = = = = = = = =
*/
void GL_PolygonOffset ( int offset )
{
if ( offset > 0 )
{
glEnable ( GL_POLYGON_OFFSET_FILL ) ;
glEnable ( GL_POLYGON_OFFSET_LINE ) ;
glPolygonOffset ( 1 , offset ) ;
}
else if ( offset < 0 )
{
glEnable ( GL_POLYGON_OFFSET_FILL ) ;
glEnable ( GL_POLYGON_OFFSET_LINE ) ;
glPolygonOffset ( - 1 , offset ) ;
}
else
{
glDisable ( GL_POLYGON_OFFSET_FILL ) ;
glDisable ( GL_POLYGON_OFFSET_LINE ) ;
}
}
//==============================================================================
//
// SETUP FRAME
//
//==============================================================================
int SignbitsForPlane ( mplane_t * out )
{
int bits , j ;
// for fast box on planeside test
bits = 0 ;
for ( j = 0 ; j < 3 ; j + + )
{
if ( out - > normal [ j ] < 0 )
bits | = 1 < < j ;
}
return bits ;
}
/*
= = = = = = = = = = = = = = =
TurnVector - - johnfitz
turn forward towards side on the plane defined by forward and side
if angle = 90 , the result will be equal to side
assumes side and forward are perpendicular , and normalized
to turn away from side , use a negative angle
= = = = = = = = = = = = = = =
*/
# define DEG2RAD( a ) ( (a) * M_PI_DIV_180 )
void TurnVector ( vec3_t out , const vec3_t forward , const vec3_t side , float angle )
{
float scale_forward , scale_side ;
scale_forward = cos ( DEG2RAD ( angle ) ) ;
scale_side = sin ( DEG2RAD ( angle ) ) ;
out [ 0 ] = scale_forward * forward [ 0 ] + scale_side * side [ 0 ] ;
out [ 1 ] = scale_forward * forward [ 1 ] + scale_side * side [ 1 ] ;
out [ 2 ] = scale_forward * forward [ 2 ] + scale_side * side [ 2 ] ;
}
/*
= = = = = = = = = = = = = = =
R_SetFrustum - - johnfitz - - rewritten
= = = = = = = = = = = = = = =
*/
void R_SetFrustum ( float fovx , float fovy )
{
int i ;
if ( r_stereo . value )
fovx + = 10 ; //silly hack so that polygons don't drop out becuase of stereo skew
TurnVector ( frustum [ 0 ] . normal , vpn , vright , fovx / 2 - 90 ) ; //left plane
TurnVector ( frustum [ 1 ] . normal , vpn , vright , 90 - fovx / 2 ) ; //right plane
TurnVector ( frustum [ 2 ] . normal , vpn , vup , 90 - fovy / 2 ) ; //bottom plane
TurnVector ( frustum [ 3 ] . normal , vpn , vup , fovy / 2 - 90 ) ; //top plane
for ( i = 0 ; i < 4 ; i + + )
{
frustum [ i ] . type = PLANE_ANYZ ;
frustum [ i ] . dist = DotProduct ( r_origin , frustum [ i ] . normal ) ; //FIXME: shouldn't this always be zero?
frustum [ i ] . signbits = SignbitsForPlane ( & frustum [ i ] ) ;
}
}
/*
= = = = = = = = = = = = =
GL_SetFrustum - - johnfitz - - written to replace MYgluPerspective
= = = = = = = = = = = = =
*/
# define NEARCLIP 4
float frustum_skew = 0.0 ; //used by r_stereo
void GL_SetFrustum ( float fovx , float fovy )
{
float xmax , ymax ;
xmax = NEARCLIP * tan ( fovx * M_PI / 360.0 ) ;
ymax = NEARCLIP * tan ( fovy * M_PI / 360.0 ) ;
glFrustum ( - xmax + frustum_skew , xmax + frustum_skew , - ymax , ymax , NEARCLIP , gl_farclip . value ) ;
}
/*
= = = = = = = = = = = = =
R_SetupGL
= = = = = = = = = = = = =
*/
void R_SetupGL ( void )
{
int scale ;
//johnfitz -- rewrote this section
glMatrixMode ( GL_PROJECTION ) ;
glLoadIdentity ( ) ;
scale = CLAMP ( 1 , ( int ) r_scale . value , 4 ) ; // ericw -- see R_ScaleView
glViewport ( glx + r_refdef . vrect . x ,
gly + glheight - r_refdef . vrect . y - r_refdef . vrect . height ,
r_refdef . vrect . width / scale ,
r_refdef . vrect . height / scale ) ;
//johnfitz
GL_SetFrustum ( r_fovx , r_fovy ) ; //johnfitz -- use r_fov* vars
// glCullFace(GL_BACK); //johnfitz -- glquake used CCW with backwards culling -- let's do it right
glMatrixMode ( GL_MODELVIEW ) ;
glLoadIdentity ( ) ;
glRotatef ( - 90 , 1 , 0 , 0 ) ; // put Z going up
glRotatef ( 90 , 0 , 0 , 1 ) ; // put Z going up
glRotatef ( - r_refdef . viewangles [ 2 ] , 1 , 0 , 0 ) ;
glRotatef ( - r_refdef . viewangles [ 0 ] , 0 , 1 , 0 ) ;
glRotatef ( - r_refdef . viewangles [ 1 ] , 0 , 0 , 1 ) ;
glTranslatef ( - r_refdef . vieworg [ 0 ] , - r_refdef . vieworg [ 1 ] , - r_refdef . vieworg [ 2 ] ) ;
//
// set drawing parms
//
if ( gl_cull . value )
glEnable ( GL_CULL_FACE ) ;
else
glDisable ( GL_CULL_FACE ) ;
glDisable ( GL_BLEND ) ;
glDisable ( GL_ALPHA_TEST ) ;
glEnable ( GL_DEPTH_TEST ) ;
}
/*
= = = = = = = = = = = = =
R_Clear - - johnfitz - - rewritten and gutted
= = = = = = = = = = = = =
*/
void R_Clear ( void )
{
unsigned int clearbits ;
clearbits = GL_DEPTH_BUFFER_BIT ;
// from mh -- if we get a stencil buffer, we should clear it, even though we don't use it
if ( gl_stencilbits )
clearbits | = GL_STENCIL_BUFFER_BIT ;
if ( gl_clear . value )
clearbits | = GL_COLOR_BUFFER_BIT ;
glClear ( clearbits ) ;
}
/*
= = = = = = = = = = = = = = =
R_SetupScene - - johnfitz - - this is the stuff that needs to be done once per eye in stereo mode
= = = = = = = = = = = = = = =
*/
void R_SetupScene ( void )
{
R_PushDlights ( ) ;
R_AnimateLight ( ) ;
r_framecount + + ;
R_SetupGL ( ) ;
}
/*
= = = = = = = = = = = = = = =
R_SetupView - - johnfitz - - this is the stuff that needs to be done once per frame , even in stereo mode
= = = = = = = = = = = = = = =
*/
void R_SetupView ( void )
{
Fog_SetupFrame ( ) ; //johnfitz
// build the transformation matrix for the given view angles
VectorCopy ( r_refdef . vieworg , r_origin ) ;
AngleVectors ( r_refdef . viewangles , vpn , vright , vup ) ;
// current viewleaf
r_oldviewleaf = r_viewleaf ;
r_viewleaf = Mod_PointInLeaf ( r_origin , cl . worldmodel ) ;
V_SetContentsColor ( r_viewleaf - > contents ) ;
V_CalcBlend ( ) ;
r_cache_thrash = false ;
//johnfitz -- calculate r_fovx and r_fovy here
r_fovx = r_refdef . fov_x ;
r_fovy = r_refdef . fov_y ;
if ( r_waterwarp . value )
{
int contents = Mod_PointInLeaf ( r_origin , cl . worldmodel ) - > contents ;
if ( contents = = CONTENTS_WATER | | contents = = CONTENTS_SLIME | | contents = = CONTENTS_LAVA )
{
//variance is a percentage of width, where width = 2 * tan(fov / 2) otherwise the effect is too dramatic at high FOV and too subtle at low FOV. what a mess!
r_fovx = atan ( tan ( DEG2RAD ( r_refdef . fov_x ) / 2 ) * ( 0.97 + sin ( cl . time * 1.5 ) * 0.03 ) ) * 2 / M_PI_DIV_180 ;
r_fovy = atan ( tan ( DEG2RAD ( r_refdef . fov_y ) / 2 ) * ( 1.03 - sin ( cl . time * 1.5 ) * 0.03 ) ) * 2 / M_PI_DIV_180 ;
}
}
//johnfitz
R_SetFrustum ( r_fovx , r_fovy ) ; //johnfitz -- use r_fov* vars
R_MarkSurfaces ( ) ; //johnfitz -- create texture chains from PVS
R_CullSurfaces ( ) ; //johnfitz -- do after R_SetFrustum and R_MarkSurfaces
R_UpdateWarpTextures ( ) ; //johnfitz -- do this before R_Clear
R_Clear ( ) ;
//johnfitz -- cheat-protect some draw modes
r_drawflat_cheatsafe = r_fullbright_cheatsafe = r_lightmap_cheatsafe = false ;
r_drawworld_cheatsafe = true ;
if ( cl . maxclients = = 1 )
{
if ( ! r_drawworld . value ) r_drawworld_cheatsafe = false ;
if ( r_drawflat . value ) r_drawflat_cheatsafe = true ;
else if ( r_fullbright . value | | ! cl . worldmodel - > lightdata ) r_fullbright_cheatsafe = true ;
else if ( r_lightmap . value ) r_lightmap_cheatsafe = true ;
}
//johnfitz
}
//==============================================================================
//
// RENDER VIEW
//
//==============================================================================
/*
= = = = = = = = = = = = =
R_DrawEntitiesOnList
= = = = = = = = = = = = =
*/
2023-01-01 23:38:27 +00:00
//int doZHack;
2022-02-08 19:06:54 +00:00
void R_DrawEntitiesOnList ( qboolean alphapass ) //johnfitz -- added parameter
{
int i ;
2023-01-01 23:38:27 +00:00
//char specChar; //nzp
2022-02-08 19:06:54 +00:00
if ( ! r_drawentities . value )
return ;
2023-01-01 23:38:27 +00:00
//int zHackCount = 0;
//doZHack = 0;
2022-02-08 19:06:54 +00:00
char specChar ;
//johnfitz -- sprites are not a special case
for ( i = 0 ; i < cl_numvisedicts ; i + + )
{
currententity = cl_visedicts [ i ] ;
//johnfitz -- if alphapass is true, draw only alpha entites this time
//if alphapass is false, draw only nonalpha entities this time
if ( ( ENTALPHA_DECODE ( currententity - > alpha ) < 1 & & ! alphapass ) | |
( ENTALPHA_DECODE ( currententity - > alpha ) = = 1 & & alphapass ) )
continue ;
//johnfitz -- chasecam
if ( currententity = = & cl_entities [ cl . viewentity ] )
currententity - > angles [ 0 ] * = 0.3 ;
//johnfitz
if ( ! ( currententity - > model ) )
{
// Naiveil -- fixme
//R_DrawNullModel();
Con_Printf ( " Model is null! %s \n " , currententity - > model - > name ) ;
continue ;
}
specChar = currententity - > model - > name [ strlen ( currententity - > model - > name ) - 5 ] ;
// naievil -- skip this and hack in through qc
//if(specChar == '(' || specChar == '^')//skip heads and arms: it's faster to do this than a strcmp...
//{
// continue;
//}
2023-01-01 23:38:27 +00:00
/*doZHack = 0; sB needs to fix updateLimb in Quakespasm l8er
2022-02-08 19:06:54 +00:00
if ( specChar = = ' # ' )
{
if ( zHackCount > 5 | | ( ( currententity - > z_head ! = 0 ) & & ( currententity - > z_larm ! = 0 ) & & ( currententity - > z_rarm ! = 0 ) ) )
{
doZHack = 1 ;
}
else
{
zHackCount + + ; //drawing zombie piece by piece.
}
}
2023-01-01 23:38:27 +00:00
specChar = currententity - > model - > name [ strlen ( currententity - > model - > name ) - 5 ] ;
2022-02-08 19:06:54 +00:00
2023-01-01 23:38:27 +00:00
if ( specChar = = ' ( ' | | specChar = = ' ^ ' ) //skip heads and arms: it's faster to do this than a strcmp...
{
continue ;
}
doZHack = 0 ;
if ( specChar = = ' # ' )
{
if ( zHackCount > 5 | | ( ( currententity - > z_head ! = 0 ) & & ( currententity - > z_larm ! = 0 ) & & ( currententity - > z_rarm ! = 0 ) ) )
{
doZHack = 1 ;
}
else
{
zHackCount + + ; //drawing zombie piece by piece.
}
} */
2022-02-08 19:06:54 +00:00
switch ( currententity - > model - > type )
{
case mod_alias :
// Naievil -- fixme
// if (qmb_initialized && SetFlameModelState() == -1)
// continue;
if ( currententity - > model - > aliastype = = ALIASTYPE_MD2 ) {
Sys_Error ( " R_DrawMD2Model not yet implemented!!! " ) ;
// Naievil -- fixme
//R_DrawMD2Model (currententity);
} else {
if ( specChar = = ' $ ' ) //This is for smooth alpha, draw in the following loop, not this one
{
continue ;
}
R_DrawAliasModel ( currententity ) ;
}
break ;
case mod_md3 :
Sys_Error ( " R_DrawQ3Model not yet implemented!!! " ) ;
// Naievil -- fixme
//R_DrawQ3Model (currententity);
break ;
case mod_halflife :
Sys_Error ( " R_DrawHLModel not yet implemented!!! \n " ) ;
// Naievil -- fixme
//R_DrawHLModel (currententity);
break ;
case mod_brush :
R_DrawBrushModel ( currententity ) ;
break ;
default :
break ;
}
2023-01-01 23:38:27 +00:00
//doZHack = 0;
2022-02-08 19:06:54 +00:00
}
for ( i = 0 ; i < cl_numvisedicts ; i + + )
{
currententity = cl_visedicts [ i ] ;
if ( ! ( currententity - > model ) )
{
continue ;
}
specChar = currententity - > model - > name [ strlen ( currententity - > model - > name ) - 5 ] ;
switch ( currententity - > model - > type )
{
case mod_sprite :
{
2023-09-03 02:01:12 +00:00
Fog_DisableGFog ( ) ;
2022-02-08 19:06:54 +00:00
R_DrawSpriteModel ( currententity ) ;
2023-09-03 02:01:12 +00:00
Fog_EnableGFog ( ) ;
2022-02-08 19:06:54 +00:00
break ;
}
case mod_alias :
if ( currententity - > model - > aliastype ! = ALIASTYPE_MD2 )
{
if ( specChar = = ' $ ' ) //mdl model with blended alpha
{
R_DrawTransparentAliasModel ( currententity ) ;
}
}
break ;
default : break ;
}
}
}
/*
= = = = = = = = = = = = =
R_DrawViewModel - - johnfitz - - gutted
= = = = = = = = = = = = =
*/
void R_DrawViewModel ( void )
{
if ( ! r_drawviewmodel . value | | ! r_drawentities . value | | chase_active . value )
return ;
if ( cl . items & IT_INVISIBILITY | | cl . stats [ STAT_HEALTH ] < = 0 )
return ;
currententity = & cl . viewent ;
if ( ! currententity - > model )
return ;
//johnfitz -- this fixes a crash
if ( currententity - > model - > type ! = mod_alias )
return ;
//johnfitz
// hack the depth range to prevent view model from poking into walls
glDepthRange ( 0 , 0.3 ) ;
R_DrawAliasModel ( currententity ) ;
glDepthRange ( 0 , 1 ) ;
}
/*
= = = = = = = = = = = = =
R_DrawView2Model - - johnfitz - - gutted
= = = = = = = = = = = = =
*/
void R_DrawView2Model ( void )
{
if ( ! r_drawviewmodel . value | | ! r_drawentities . value | | chase_active . value )
return ;
if ( cl . items & IT_INVISIBILITY | | cl . stats [ STAT_HEALTH ] < = 0 )
return ;
currententity = & cl . viewent2 ;
if ( ! currententity - > model )
return ;
//johnfitz -- this fixes a crash
if ( currententity - > model - > type ! = mod_alias )
return ;
//johnfitz
// hack the depth range to prevent view model from poking into walls
glDepthRange ( 0 , 0.3 ) ;
R_DrawAliasModel ( currententity ) ;
glDepthRange ( 0 , 1 ) ;
}
/*
= = = = = = = = = = = = = = = =
R_EmitWirePoint - - johnfitz - - draws a wireframe cross shape for point entities
= = = = = = = = = = = = = = = =
*/
void R_EmitWirePoint ( vec3_t origin )
{
int size = 8 ;
glBegin ( GL_LINES ) ;
glVertex3f ( origin [ 0 ] - size , origin [ 1 ] , origin [ 2 ] ) ;
glVertex3f ( origin [ 0 ] + size , origin [ 1 ] , origin [ 2 ] ) ;
glVertex3f ( origin [ 0 ] , origin [ 1 ] - size , origin [ 2 ] ) ;
glVertex3f ( origin [ 0 ] , origin [ 1 ] + size , origin [ 2 ] ) ;
glVertex3f ( origin [ 0 ] , origin [ 1 ] , origin [ 2 ] - size ) ;
glVertex3f ( origin [ 0 ] , origin [ 1 ] , origin [ 2 ] + size ) ;
glEnd ( ) ;
}
/*
= = = = = = = = = = = = = = = =
R_EmitWireBox - - johnfitz - - draws one axis aligned bounding box
= = = = = = = = = = = = = = = =
*/
void R_EmitWireBox ( vec3_t mins , vec3_t maxs )
{
# ifdef VITA
glBegin ( GL_QUADS ) ;
glVertex3f ( mins [ 0 ] , mins [ 1 ] , mins [ 2 ] ) ;
glVertex3f ( mins [ 0 ] , mins [ 1 ] , maxs [ 2 ] ) ;
glVertex3f ( maxs [ 0 ] , mins [ 1 ] , mins [ 2 ] ) ;
glVertex3f ( maxs [ 0 ] , mins [ 1 ] , maxs [ 2 ] ) ;
glVertex3f ( maxs [ 0 ] , mins [ 1 ] , mins [ 2 ] ) ;
glVertex3f ( maxs [ 0 ] , mins [ 1 ] , maxs [ 2 ] ) ;
glVertex3f ( maxs [ 0 ] , maxs [ 1 ] , mins [ 2 ] ) ;
glVertex3f ( maxs [ 0 ] , maxs [ 1 ] , maxs [ 2 ] ) ;
glVertex3f ( maxs [ 0 ] , maxs [ 1 ] , mins [ 2 ] ) ;
glVertex3f ( maxs [ 0 ] , maxs [ 1 ] , maxs [ 2 ] ) ;
glVertex3f ( mins [ 0 ] , maxs [ 1 ] , mins [ 2 ] ) ;
glVertex3f ( mins [ 0 ] , maxs [ 1 ] , maxs [ 2 ] ) ;
glVertex3f ( mins [ 0 ] , maxs [ 1 ] , mins [ 2 ] ) ;
glVertex3f ( mins [ 0 ] , maxs [ 1 ] , maxs [ 2 ] ) ;
glVertex3f ( mins [ 0 ] , mins [ 1 ] , mins [ 2 ] ) ;
glVertex3f ( mins [ 0 ] , mins [ 1 ] , maxs [ 2 ] ) ;
# else
glBegin ( GL_QUAD_STRIP ) ;
glVertex3f ( mins [ 0 ] , mins [ 1 ] , mins [ 2 ] ) ;
glVertex3f ( mins [ 0 ] , mins [ 1 ] , maxs [ 2 ] ) ;
glVertex3f ( maxs [ 0 ] , mins [ 1 ] , mins [ 2 ] ) ;
glVertex3f ( maxs [ 0 ] , mins [ 1 ] , maxs [ 2 ] ) ;
glVertex3f ( maxs [ 0 ] , maxs [ 1 ] , mins [ 2 ] ) ;
glVertex3f ( maxs [ 0 ] , maxs [ 1 ] , maxs [ 2 ] ) ;
glVertex3f ( mins [ 0 ] , maxs [ 1 ] , mins [ 2 ] ) ;
glVertex3f ( mins [ 0 ] , maxs [ 1 ] , maxs [ 2 ] ) ;
glVertex3f ( mins [ 0 ] , mins [ 1 ] , mins [ 2 ] ) ;
glVertex3f ( mins [ 0 ] , mins [ 1 ] , maxs [ 2 ] ) ;
# endif
glEnd ( ) ;
}
/*
= = = = = = = = = = = = = = = =
R_ShowBoundingBoxes - - johnfitz
draw bounding boxes - - the server - side boxes , not the renderer cullboxes
= = = = = = = = = = = = = = = =
*/
void R_ShowBoundingBoxes ( void )
{
extern edict_t * sv_player ;
vec3_t mins , maxs ;
edict_t * ed ;
int i ;
if ( ! r_showbboxes . value | | cl . maxclients > 1 | | ! r_drawentities . value | | ! sv . active )
return ;
glDisable ( GL_DEPTH_TEST ) ;
glPolygonMode ( GL_FRONT_AND_BACK , GL_LINE ) ;
GL_PolygonOffset ( OFFSET_SHOWTRIS ) ;
glDisable ( GL_TEXTURE_2D ) ;
glDisable ( GL_CULL_FACE ) ;
glColor3f ( 1 , 1 , 1 ) ;
for ( i = 0 , ed = NEXT_EDICT ( sv . edicts ) ; i < sv . num_edicts ; i + + , ed = NEXT_EDICT ( ed ) )
{
if ( ed = = sv_player )
continue ; //don't draw player's own bbox
// if (r_showbboxes.value != 2)
// if (!SV_VisibleToClient (sv_player, ed, sv.worldmodel))
// continue; //don't draw if not in pvs
if ( ed - > v . mins [ 0 ] = = ed - > v . maxs [ 0 ] & & ed - > v . mins [ 1 ] = = ed - > v . maxs [ 1 ] & & ed - > v . mins [ 2 ] = = ed - > v . maxs [ 2 ] )
{
//point entity
R_EmitWirePoint ( ed - > v . origin ) ;
}
else
{
//box entity
VectorAdd ( ed - > v . mins , ed - > v . origin , mins ) ;
VectorAdd ( ed - > v . maxs , ed - > v . origin , maxs ) ;
R_EmitWireBox ( mins , maxs ) ;
}
}
glColor3f ( 1 , 1 , 1 ) ;
glEnable ( GL_TEXTURE_2D ) ;
glEnable ( GL_CULL_FACE ) ;
glPolygonMode ( GL_FRONT_AND_BACK , GL_FILL ) ;
GL_PolygonOffset ( OFFSET_NONE ) ;
glEnable ( GL_DEPTH_TEST ) ;
Sbar_Changed ( ) ; //so we don't get dots collecting on the statusbar
}
/*
= = = = = = = = = = = = = = = =
R_ShowTris - - johnfitz
= = = = = = = = = = = = = = = =
*/
void R_ShowTris ( void )
{
extern cvar_t r_particles ;
int i ;
if ( r_showtris . value < 1 | | r_showtris . value > 2 | | cl . maxclients > 1 )
return ;
if ( r_showtris . value = = 1 )
glDisable ( GL_DEPTH_TEST ) ;
glPolygonMode ( GL_FRONT_AND_BACK , GL_LINE ) ;
GL_PolygonOffset ( OFFSET_SHOWTRIS ) ;
glDisable ( GL_TEXTURE_2D ) ;
glColor3f ( 1 , 1 , 1 ) ;
// glEnable (GL_BLEND);
// glBlendFunc (GL_ONE, GL_ONE);
if ( r_drawworld . value )
{
R_DrawWorld_ShowTris ( ) ;
}
if ( r_drawentities . value )
{
for ( i = 0 ; i < cl_numvisedicts ; i + + )
{
currententity = cl_visedicts [ i ] ;
if ( currententity = = & cl_entities [ cl . viewentity ] ) // chasecam
currententity - > angles [ 0 ] * = 0.3 ;
switch ( currententity - > model - > type )
{
case mod_brush :
R_DrawBrushModel_ShowTris ( currententity ) ;
break ;
case mod_alias :
R_DrawAliasModel_ShowTris ( currententity ) ;
break ;
case mod_sprite :
R_DrawSpriteModel ( currententity ) ;
break ;
default :
break ;
}
}
// viewmodel
currententity = & cl . viewent ;
if ( r_drawviewmodel . value
& & ! chase_active . value
& & cl . stats [ STAT_HEALTH ] > 0
& & ! ( cl . items & IT_INVISIBILITY )
& & currententity - > model
& & currententity - > model - > type = = mod_alias )
{
glDepthRange ( 0 , 0.3 ) ;
R_DrawAliasModel_ShowTris ( currententity ) ;
glDepthRange ( 0 , 1 ) ;
}
}
if ( r_particles . value )
{
R_DrawParticles_ShowTris ( ) ;
}
// glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// glDisable (GL_BLEND);
glColor3f ( 1 , 1 , 1 ) ;
glEnable ( GL_TEXTURE_2D ) ;
glPolygonMode ( GL_FRONT_AND_BACK , GL_FILL ) ;
GL_PolygonOffset ( OFFSET_NONE ) ;
if ( r_showtris . value = = 1 )
glEnable ( GL_DEPTH_TEST ) ;
Sbar_Changed ( ) ; //so we don't get dots collecting on the statusbar
}
//==================================================================================
/*
int SetFlameModelState ( void )
{
if ( ! r_part_flames . value & & ! strcmp ( currententity - > model - > name , " progs/flame0.mdl " ) )
{
currententity - > model = cl . model_precache [ cl_modelindex [ mi_flame1 ] ] ;
}
else if ( r_part_flames . value )
{
vec3_t liteorg ;
VectorCopy ( currententity - > origin , liteorg ) ;
if ( currententity - > baseline . modelindex = = cl_modelindex [ mi_flame0 ] )
{
if ( r_part_flames . value = = 2 )
{
liteorg [ 2 ] + = 14 ;
QMB_Q3TorchFlame ( liteorg , 15 ) ;
}
else
{
liteorg [ 2 ] + = 5.5 ;
if ( r_flametype . value = = 2 )
QMB_FlameGt ( liteorg , 7 , 0.8 ) ;
else
QMB_TorchFlame ( liteorg ) ;
}
}
else if ( currententity - > baseline . modelindex = = cl_modelindex [ mi_flame1 ] )
{
if ( r_part_flames . value = = 2 )
{
liteorg [ 2 ] + = 14 ;
QMB_Q3TorchFlame ( liteorg , 15 ) ;
}
else
{
liteorg [ 2 ] + = 5.5 ;
if ( r_flametype . value > 1 )
QMB_FlameGt ( liteorg , 7 , 0.8 ) ;
else
QMB_TorchFlame ( liteorg ) ;
}
currententity - > model = cl . model_precache [ cl_modelindex [ mi_flame0 ] ] ;
}
else if ( currententity - > baseline . modelindex = = cl_modelindex [ mi_flame2 ] )
{
if ( r_part_flames . value = = 2 )
{
liteorg [ 2 ] + = 14 ;
QMB_Q3TorchFlame ( liteorg , 32 ) ;
}
else
{
liteorg [ 2 ] - = 1 ;
if ( r_flametype . value > 1 )
QMB_FlameGt ( liteorg , 12 , 1 ) ;
else
QMB_BigTorchFlame ( liteorg ) ;
}
return - 1 ; //continue;
}
else if ( ! strcmp ( currententity - > model - > name , " progs/wyvflame.mdl " ) )
{
liteorg [ 2 ] - = 1 ;
if ( r_flametype . value > 1 )
QMB_FlameGt ( liteorg , 12 , 1 ) ;
else
QMB_BigTorchFlame ( liteorg ) ;
return - 1 ; //continue;
}
}
return 0 ;
}
*/
/*
= = = = = = = = = = = = = = = =
R_DrawShadows
= = = = = = = = = = = = = = = =
*/
void R_DrawShadows ( void )
{
int i ;
if ( ! r_shadows . value | | ! r_drawentities . value | | r_drawflat_cheatsafe | | r_lightmap_cheatsafe )
return ;
// Use stencil buffer to prevent self-intersecting shadows, from Baker (MarkV)
if ( gl_stencilbits )
{
glClear ( GL_STENCIL_BUFFER_BIT ) ;
glStencilFunc ( GL_EQUAL , 0 , ~ 0 ) ;
glStencilOp ( GL_KEEP , GL_KEEP , GL_INCR ) ;
glEnable ( GL_STENCIL_TEST ) ;
}
for ( i = 0 ; i < cl_numvisedicts ; i + + )
{
currententity = cl_visedicts [ i ] ;
if ( currententity - > model - > type ! = mod_alias )
continue ;
if ( currententity = = & cl . viewent )
return ;
GL_DrawAliasShadow ( currententity ) ;
}
if ( gl_stencilbits )
{
glDisable ( GL_STENCIL_TEST ) ;
}
}
/*
= = = = = = = = = = = = = = = =
R_RenderScene
= = = = = = = = = = = = = = = =
*/
void R_RenderScene ( void )
{
R_SetupScene ( ) ; //johnfitz -- this does everything that should be done once per call to RenderScene
2023-09-03 02:01:12 +00:00
2022-02-08 19:06:54 +00:00
Fog_EnableGFog ( ) ; //johnfitz
2023-09-03 02:01:12 +00:00
2022-02-08 19:06:54 +00:00
Sky_DrawSky ( ) ; //johnfitz
R_DrawWorld ( ) ;
S_ExtraUpdate ( ) ; // don't let sound get messed up if going slow
2023-01-01 23:38:27 +00:00
2022-02-08 19:06:54 +00:00
R_DrawShadows ( ) ; //johnfitz -- render entity shadows
R_DrawEntitiesOnList ( false ) ; //johnfitz -- false means this is the pass for nonalpha entities
R_DrawWorld_Water ( ) ; //johnfitz -- drawn here since they might have transparency
R_DrawEntitiesOnList ( true ) ; //johnfitz -- true means this is the pass for alpha entities
R_RenderDlights ( ) ; //triangle fan dlights -- johnfitz -- moved after water
2023-09-03 02:01:12 +00:00
Fog_DisableGFog ( ) ; //johnfitz
2022-02-08 19:06:54 +00:00
R_DrawParticles ( ) ;
QMB_DrawParticles ( ) ;
2023-09-03 02:01:12 +00:00
2022-02-08 19:06:54 +00:00
R_DrawViewModel ( ) ; //johnfitz -- moved here from R_RenderView
R_DrawView2Model ( ) ;
R_ShowTris ( ) ; //johnfitz
R_ShowBoundingBoxes ( ) ; //johnfitz
}
static GLuint r_scaleview_texture ;
static int r_scaleview_texture_width , r_scaleview_texture_height ;
/*
= = = = = = = = = = = = =
R_ScaleView_DeleteTexture
= = = = = = = = = = = = =
*/
void R_ScaleView_DeleteTexture ( void )
{
glDeleteTextures ( 1 , & r_scaleview_texture ) ;
r_scaleview_texture = 0 ;
}
/*
= = = = = = = = = = = = = = = =
R_ScaleView
The r_scale cvar allows rendering the 3 D view at 1 / 2 , 1 / 3 , or 1 / 4 resolution .
This function scales the reduced resolution 3 D view back up to fill
r_refdef . vrect . This is for emulating a low - resolution pixellated look ,
or possibly as a perforance boost on slow graphics cards .
= = = = = = = = = = = = = = = =
*/
void R_ScaleView ( void )
{
# ifndef VITA
float smax , tmax ;
int scale ;
int srcx , srcy , srcw , srch ;
// copied from R_SetupGL()
scale = CLAMP ( 1 , ( int ) r_scale . value , 4 ) ;
srcx = glx + r_refdef . vrect . x ;
srcy = gly + glheight - r_refdef . vrect . y - r_refdef . vrect . height ;
srcw = r_refdef . vrect . width / scale ;
srch = r_refdef . vrect . height / scale ;
if ( scale = = 1 )
return ;
// make sure texture unit 0 is selected
GL_DisableMultitexture ( ) ;
// create (if needed) and bind the render-to-texture texture
if ( ! r_scaleview_texture )
{
glGenTextures ( 1 , & r_scaleview_texture ) ;
r_scaleview_texture_width = 0 ;
r_scaleview_texture_height = 0 ;
}
glBindTexture ( GL_TEXTURE_2D , r_scaleview_texture ) ;
// resize render-to-texture texture if needed
if ( r_scaleview_texture_width < srcw
| | r_scaleview_texture_height < srch )
{
r_scaleview_texture_width = srcw ;
r_scaleview_texture_height = srch ;
if ( ! gl_texture_NPOT )
{
r_scaleview_texture_width = TexMgr_Pad ( r_scaleview_texture_width ) ;
r_scaleview_texture_height = TexMgr_Pad ( r_scaleview_texture_height ) ;
}
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , r_scaleview_texture_width , r_scaleview_texture_height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , NULL ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
}
// copy the framebuffer to the texture
glBindTexture ( GL_TEXTURE_2D , r_scaleview_texture ) ;
glCopyTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , srcx , srcy , srcw , srch ) ;
// draw the texture back to the framebuffer
glDisable ( GL_ALPHA_TEST ) ;
glDisable ( GL_DEPTH_TEST ) ;
glDisable ( GL_CULL_FACE ) ;
glDisable ( GL_BLEND ) ;
glViewport ( srcx , srcy , r_refdef . vrect . width , r_refdef . vrect . height ) ;
glMatrixMode ( GL_PROJECTION ) ;
glLoadIdentity ( ) ;
glMatrixMode ( GL_MODELVIEW ) ;
glLoadIdentity ( ) ;
// correction factor if we lack NPOT textures, normally these are 1.0f
smax = srcw / ( float ) r_scaleview_texture_width ;
tmax = srch / ( float ) r_scaleview_texture_height ;
glBegin ( GL_QUADS ) ;
glTexCoord2f ( 0 , 0 ) ;
glVertex2f ( - 1 , - 1 ) ;
glTexCoord2f ( smax , 0 ) ;
glVertex2f ( 1 , - 1 ) ;
glTexCoord2f ( smax , tmax ) ;
glVertex2f ( 1 , 1 ) ;
glTexCoord2f ( 0 , tmax ) ;
glVertex2f ( - 1 , 1 ) ;
glEnd ( ) ;
// clear cached binding
GL_ClearBindings ( ) ;
# endif
}
/*
= = = = = = = = = = = = = = = =
R_RenderView
= = = = = = = = = = = = = = = =
*/
void R_RenderView ( void )
{
double time1 , time2 ;
if ( r_norefresh . value )
return ;
if ( ! cl . worldmodel )
Sys_Error ( " R_RenderView: NULL worldmodel " ) ;
time1 = 0 ; /* avoid compiler warning */
if ( r_speeds . value )
{
glFinish ( ) ;
time1 = Sys_DoubleTime ( ) ;
//johnfitz -- rendering statistics
rs_brushpolys = rs_aliaspolys = rs_skypolys = rs_particles = rs_fogpolys = rs_megatexels =
rs_dynamiclightmaps = rs_aliaspasses = rs_skypasses = rs_brushpasses = 0 ;
}
else if ( gl_finish . value )
glFinish ( ) ;
R_SetupView ( ) ; //johnfitz -- this does everything that should be done once per frame
//johnfitz -- stereo rendering -- full of hacky goodness
if ( r_stereo . value )
{
float eyesep = CLAMP ( - 8.0f , r_stereo . value , 8.0f ) ;
float fdepth = CLAMP ( 32.0f , r_stereodepth . value , 1024.0f ) ;
AngleVectors ( r_refdef . viewangles , vpn , vright , vup ) ;
//render left eye (red)
glColorMask ( 1 , 0 , 0 , 1 ) ;
VectorMA ( r_refdef . vieworg , - 0.5f * eyesep , vright , r_refdef . vieworg ) ;
frustum_skew = 0.5 * eyesep * NEARCLIP / fdepth ;
srand ( ( int ) ( cl . time * 1000 ) ) ; //sync random stuff between eyes
R_RenderScene ( ) ;
//render right eye (cyan)
glClear ( GL_DEPTH_BUFFER_BIT ) ;
glColorMask ( 0 , 1 , 1 , 1 ) ;
VectorMA ( r_refdef . vieworg , 1.0f * eyesep , vright , r_refdef . vieworg ) ;
frustum_skew = - frustum_skew ;
srand ( ( int ) ( cl . time * 1000 ) ) ; //sync random stuff between eyes
R_RenderScene ( ) ;
//restore
glColorMask ( 1 , 1 , 1 , 1 ) ;
VectorMA ( r_refdef . vieworg , - 0.5f * eyesep , vright , r_refdef . vieworg ) ;
frustum_skew = 0.0f ;
}
else
{
R_RenderScene ( ) ;
}
//johnfitz
R_ScaleView ( ) ;
//johnfitz -- modified r_speeds output
time2 = Sys_DoubleTime ( ) ;
if ( r_pos . value )
Con_Printf ( " x %i y %i z %i (pitch %i yaw %i roll %i) \n " ,
( int ) cl_entities [ cl . viewentity ] . origin [ 0 ] ,
( int ) cl_entities [ cl . viewentity ] . origin [ 1 ] ,
( int ) cl_entities [ cl . viewentity ] . origin [ 2 ] ,
( int ) cl . viewangles [ PITCH ] ,
( int ) cl . viewangles [ YAW ] ,
( int ) cl . viewangles [ ROLL ] ) ;
else if ( r_speeds . value = = 2 )
Con_Printf ( " %3i ms %4i/%4i wpoly %4i/%4i epoly %3i lmap %4i/%4i sky %1.1f mtex \n " ,
( int ) ( ( time2 - time1 ) * 1000 ) ,
rs_brushpolys ,
rs_brushpasses ,
rs_aliaspolys ,
rs_aliaspasses ,
rs_dynamiclightmaps ,
rs_skypolys ,
rs_skypasses ,
TexMgr_FrameUsage ( ) ) ;
else if ( r_speeds . value )
Con_Printf ( " %3i ms %4i wpoly %4i epoly %3i lmap \n " ,
( int ) ( ( time2 - time1 ) * 1000 ) ,
rs_brushpolys ,
rs_aliaspolys ,
rs_dynamiclightmaps ) ;
//johnfitz
}