This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/engine/client/gl_rmain.c

1566 lines
36 KiB
C
Raw Normal View History

2011-05-09 22:00:00 +02:00
/*
gl_rmain.c - renderer main loop
Copyright (C) 2010 Uncle Mike
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 3 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.
*/
2010-11-28 22:00:00 +01:00
#include "common.h"
#include "client.h"
#include "gl_local.h"
2010-12-22 22:00:00 +01:00
#include "mathlib.h"
2011-12-04 21:00:00 +01:00
#include "library.h"
#include "beamdef.h"
#include "particledef.h"
2013-02-19 21:00:00 +01:00
#include "entity_types.h"
2010-11-28 22:00:00 +01:00
2011-09-03 22:00:00 +02:00
#define IsLiquidContents( cnt ) ( cnt == CONTENTS_WATER || cnt == CONTENTS_SLIME || cnt == CONTENTS_LAVA )
2010-12-06 22:00:00 +01:00
float gldepthmin, gldepthmax;
2017-02-15 22:00:00 +01:00
ref_instance_t RI;
2010-11-29 22:00:00 +01:00
2018-02-20 22:00:00 +01:00
static int R_RankForRenderMode( int rendermode )
2010-12-02 22:00:00 +01:00
{
2018-02-20 22:00:00 +01:00
switch( rendermode )
2010-12-13 22:00:00 +01:00
{
case kRenderTransTexture:
return 1; // draw second
case kRenderTransAdd:
return 2; // draw third
case kRenderGlow:
return 3; // must be last!
}
return 0;
}
2010-12-06 22:00:00 +01:00
2017-08-15 23:00:00 +02:00
void R_AllowFog( int allowed )
{
if( allowed )
{
2019-02-21 22:00:00 +01:00
if( glState.isFogEnabled )
2017-08-15 23:00:00 +02:00
pglEnable( GL_FOG );
}
else
{
2019-02-21 22:00:00 +01:00
if( glState.isFogEnabled )
2017-08-15 23:00:00 +02:00
pglDisable( GL_FOG );
}
}
2010-12-15 22:00:00 +01:00
/*
===============
R_OpaqueEntity
Opaque entity can be brush or studio model but sprite
===============
*/
static qboolean R_OpaqueEntity( cl_entity_t *ent )
{
2018-02-20 22:00:00 +01:00
if( R_GetEntityRenderMode( ent ) == kRenderNormal )
2010-12-15 22:00:00 +01:00
return true;
2010-12-14 22:00:00 +01:00
return false;
}
/*
===============
R_TransEntityCompare
Sorting translucent entities by rendermode then by distance
===============
*/
static int R_TransEntityCompare( const cl_entity_t **a, const cl_entity_t **b )
2010-12-13 22:00:00 +01:00
{
cl_entity_t *ent1, *ent2;
vec3_t vecLen, org;
2017-08-21 23:00:00 +02:00
float dist1, dist2;
2018-02-20 22:00:00 +01:00
int rendermode1;
int rendermode2;
2010-12-06 22:00:00 +01:00
2010-12-13 22:00:00 +01:00
ent1 = (cl_entity_t *)*a;
ent2 = (cl_entity_t *)*b;
2018-02-20 22:00:00 +01:00
rendermode1 = R_GetEntityRenderMode( ent1 );
rendermode2 = R_GetEntityRenderMode( ent2 );
2010-12-13 22:00:00 +01:00
2017-08-21 23:00:00 +02:00
// sort by distance
2018-02-20 22:00:00 +01:00
if( ent1->model->type != mod_brush || rendermode1 != kRenderTransAlpha )
2010-12-06 22:00:00 +01:00
{
2010-12-13 22:00:00 +01:00
VectorAverage( ent1->model->mins, ent1->model->maxs, org );
VectorAdd( ent1->origin, org, org );
2011-12-09 21:00:00 +01:00
VectorSubtract( RI.vieworg, org, vecLen );
2017-08-21 23:00:00 +02:00
dist1 = DotProduct( vecLen, vecLen );
2010-12-13 22:00:00 +01:00
}
2017-08-21 23:00:00 +02:00
else dist1 = 1000000000;
2010-12-06 22:00:00 +01:00
2018-02-20 22:00:00 +01:00
if( ent2->model->type != mod_brush || rendermode2 != kRenderTransAlpha )
2010-12-13 22:00:00 +01:00
{
VectorAverage( ent2->model->mins, ent2->model->maxs, org );
VectorAdd( ent2->origin, org, org );
2011-12-09 21:00:00 +01:00
VectorSubtract( RI.vieworg, org, vecLen );
2017-08-21 23:00:00 +02:00
dist2 = DotProduct( vecLen, vecLen );
2010-12-06 22:00:00 +01:00
}
2017-08-21 23:00:00 +02:00
else dist2 = 1000000000;
2010-12-13 22:00:00 +01:00
2017-08-21 23:00:00 +02:00
if( dist1 > dist2 )
2010-12-13 22:00:00 +01:00
return -1;
2017-08-21 23:00:00 +02:00
if( dist1 < dist2 )
2010-12-13 22:00:00 +01:00
return 1;
2017-08-21 23:00:00 +02:00
// then sort by rendermode
2018-02-20 22:00:00 +01:00
if( R_RankForRenderMode( rendermode1 ) > R_RankForRenderMode( rendermode2 ))
2017-08-17 23:00:00 +02:00
return 1;
2018-02-20 22:00:00 +01:00
if( R_RankForRenderMode( rendermode1 ) < R_RankForRenderMode( rendermode2 ))
2017-08-17 23:00:00 +02:00
return -1;
2010-12-13 22:00:00 +01:00
return 0;
2010-12-02 22:00:00 +01:00
}
2012-03-19 21:00:00 +01:00
/*
===============
R_WorldToScreen
Convert a given point from world into screen space
2017-02-21 22:00:00 +01:00
Returns true if we behind to screen
2012-03-19 21:00:00 +01:00
===============
*/
2010-12-02 22:00:00 +01:00
qboolean R_WorldToScreen( const vec3_t point, vec3_t screen )
{
2010-12-12 22:00:00 +01:00
matrix4x4 worldToScreen;
2011-08-14 22:00:00 +02:00
qboolean behind;
float w;
if( !point || !screen )
2017-02-21 22:00:00 +01:00
return true;
2010-12-12 22:00:00 +01:00
Matrix4x4_Copy( worldToScreen, RI.worldviewProjectionMatrix );
screen[0] = worldToScreen[0][0] * point[0] + worldToScreen[0][1] * point[1] + worldToScreen[0][2] * point[2] + worldToScreen[0][3];
screen[1] = worldToScreen[1][0] * point[0] + worldToScreen[1][1] * point[1] + worldToScreen[1][2] * point[2] + worldToScreen[1][3];
w = worldToScreen[3][0] * point[0] + worldToScreen[3][1] * point[1] + worldToScreen[3][2] * point[2] + worldToScreen[3][3];
2011-10-06 22:00:00 +02:00
screen[2] = 0.0f; // just so we have something valid here
2010-12-12 22:00:00 +01:00
if( w < 0.001f )
{
screen[0] *= 100000;
screen[1] *= 100000;
2017-02-21 22:00:00 +01:00
behind = true;
2010-12-12 22:00:00 +01:00
}
else
{
float invw = 1.0f / w;
screen[0] *= invw;
screen[1] *= invw;
2017-02-21 22:00:00 +01:00
behind = false;
2010-12-12 22:00:00 +01:00
}
2017-02-21 22:00:00 +01:00
2010-12-12 22:00:00 +01:00
return behind;
2010-12-02 22:00:00 +01:00
}
2012-03-19 21:00:00 +01:00
/*
===============
R_ScreenToWorld
Convert a given point from screen into world space
===============
*/
2010-12-02 22:00:00 +01:00
void R_ScreenToWorld( const vec3_t screen, vec3_t point )
{
2011-10-06 22:00:00 +02:00
matrix4x4 screenToWorld;
float w;
if( !point || !screen )
return;
2012-03-19 21:00:00 +01:00
Matrix4x4_Invert_Full( screenToWorld, RI.worldviewProjectionMatrix );
point[0] = screen[0] * screenToWorld[0][0] + screen[1] * screenToWorld[0][1] + screen[2] * screenToWorld[0][2] + screenToWorld[0][3];
point[1] = screen[0] * screenToWorld[1][0] + screen[1] * screenToWorld[1][1] + screen[2] * screenToWorld[1][2] + screenToWorld[1][3];
point[2] = screen[0] * screenToWorld[2][0] + screen[1] * screenToWorld[2][1] + screen[2] * screenToWorld[2][2] + screenToWorld[2][3];
w = screen[0] * screenToWorld[3][0] + screen[1] * screenToWorld[3][1] + screen[2] * screenToWorld[3][2] + screenToWorld[3][3];
if( w != 0.0f ) VectorScale( point, ( 1.0f / w ), point );
2010-12-02 22:00:00 +01:00
}
2018-03-20 22:00:00 +01:00
/*
===============
R_PushScene
===============
*/
void R_PushScene( void )
{
if( ++tr.draw_stack_pos >= MAX_DRAW_STACK )
Host_Error( "draw stack overflow\n" );
tr.draw_list = &tr.draw_stack[tr.draw_stack_pos];
}
/*
===============
R_PushScene
===============
*/
void R_PopScene( void )
{
if( --tr.draw_stack_pos < 0 )
Host_Error( "draw stack underflow\n" );
tr.draw_list = &tr.draw_stack[tr.draw_stack_pos];
}
2010-11-29 22:00:00 +01:00
/*
===============
R_ClearScene
===============
*/
2010-11-28 22:00:00 +01:00
void R_ClearScene( void )
{
2018-03-20 22:00:00 +01:00
tr.draw_list->num_solid_entities = 0;
tr.draw_list->num_trans_entities = 0;
tr.draw_list->num_beam_entities = 0;
2010-11-29 22:00:00 +01:00
}
2010-12-02 22:00:00 +01:00
/*
===============
R_AddEntity
===============
*/
2017-02-21 22:00:00 +01:00
qboolean R_AddEntity( struct cl_entity_s *clent, int type )
2010-12-02 22:00:00 +01:00
{
2017-02-12 22:00:00 +01:00
if( !r_drawentities->value )
2010-12-14 22:00:00 +01:00
return false; // not allow to drawing
2010-12-13 22:00:00 +01:00
if( !clent || !clent->model )
2010-12-12 22:00:00 +01:00
return false; // if set to invisible, skip
2018-05-08 23:00:00 +02:00
if( FBitSet( clent->curstate.effects, EF_NODRAW ))
2011-03-15 22:00:00 +01:00
return false; // done
2018-05-08 23:00:00 +02:00
if( !R_ModelOpaque( clent->curstate.rendermode ) && CL_FxBlend( clent ) <= 0 )
2013-03-01 21:00:00 +01:00
return true; // invisible
2010-12-12 22:00:00 +01:00
2017-02-21 22:00:00 +01:00
if( type == ET_FRAGMENTED )
2013-02-19 21:00:00 +01:00
r_stats.c_client_ents++;
2010-12-15 22:00:00 +01:00
if( R_OpaqueEntity( clent ))
2010-12-13 22:00:00 +01:00
{
2018-02-02 22:00:00 +01:00
// opaque
2018-03-20 22:00:00 +01:00
if( tr.draw_list->num_solid_entities >= MAX_VISIBLE_PACKET )
2018-02-02 22:00:00 +01:00
return false;
2010-12-11 22:00:00 +01:00
2018-03-20 22:00:00 +01:00
tr.draw_list->solid_entities[tr.draw_list->num_solid_entities] = clent;
tr.draw_list->num_solid_entities++;
2010-12-13 22:00:00 +01:00
}
else
{
// translucent
2018-03-20 22:00:00 +01:00
if( tr.draw_list->num_trans_entities >= MAX_VISIBLE_PACKET )
2010-12-13 22:00:00 +01:00
return false;
2010-12-11 22:00:00 +01:00
2018-03-20 22:00:00 +01:00
tr.draw_list->trans_entities[tr.draw_list->num_trans_entities] = clent;
tr.draw_list->num_trans_entities++;
2010-12-13 22:00:00 +01:00
}
2017-03-11 22:00:00 +01:00
2010-12-06 22:00:00 +01:00
return true;
}
/*
=============
R_Clear
=============
*/
static void R_Clear( int bitMask )
{
2011-07-07 22:00:00 +02:00
int bits;
2017-02-21 22:00:00 +01:00
if( CL_IsDevOverviewMode( ))
2011-08-21 22:00:00 +02:00
pglClearColor( 0.0f, 1.0f, 0.0f, 1.0f ); // green background (Valve rules)
else pglClearColor( 0.5f, 0.5f, 0.5f, 1.0f );
2010-12-06 22:00:00 +01:00
bits = GL_DEPTH_BUFFER_BIT;
2011-04-19 22:00:00 +02:00
if( glState.stencilEnabled )
2010-12-06 22:00:00 +01:00
bits |= GL_STENCIL_BUFFER_BIT;
bits &= bitMask;
pglClear( bits );
2011-08-21 22:00:00 +02:00
// change ordering for overview
if( RI.drawOrtho )
{
gldepthmin = 1.0f;
gldepthmax = 0.0f;
}
else
{
gldepthmin = 0.0f;
gldepthmax = 1.0f;
}
2011-09-28 22:00:00 +02:00
pglDepthFunc( GL_LEQUAL );
2010-12-06 22:00:00 +01:00
pglDepthRange( gldepthmin, gldepthmax );
2010-12-02 22:00:00 +01:00
}
2010-12-06 22:00:00 +01:00
//=============================================================================
2010-11-29 22:00:00 +01:00
/*
===============
2010-12-06 22:00:00 +01:00
R_GetFarClip
2010-11-29 22:00:00 +01:00
===============
*/
2010-12-06 22:00:00 +01:00
static float R_GetFarClip( void )
2010-11-29 22:00:00 +01:00
{
2010-12-06 22:00:00 +01:00
if( cl.worldmodel && RI.drawWorld )
2017-02-15 22:00:00 +01:00
return clgame.movevars.zmax * 1.73f;
2010-12-06 22:00:00 +01:00
return 2048.0f;
}
/*
===============
R_SetupFrustum
===============
*/
2011-10-06 22:00:00 +02:00
void R_SetupFrustum( void )
2010-12-06 22:00:00 +01:00
{
2017-03-13 22:00:00 +01:00
ref_overview_t *ov = &clgame.overView;
2010-12-06 22:00:00 +01:00
2017-08-12 23:00:00 +02:00
if( RP_NORMALPASS() && ( cl.local.waterlevel >= 3 ))
{
RI.fov_x = atan( tan( DEG2RAD( RI.fov_x ) / 2 ) * ( 0.97 + sin( cl.time * 1.5 ) * 0.03 )) * 2 / (M_PI / 180.0);
RI.fov_y = atan( tan( DEG2RAD( RI.fov_y ) / 2 ) * ( 1.03 - sin( cl.time * 1.5 ) * 0.03 )) * 2 / (M_PI / 180.0);
}
2017-02-15 22:00:00 +01:00
// build the transformation matrix for the given view angles
AngleVectors( RI.viewangles, RI.vforward, RI.vright, RI.vup );
2017-03-06 22:00:00 +01:00
if( !r_lockfrustum->value )
2017-02-15 22:00:00 +01:00
{
VectorCopy( RI.vieworg, RI.cullorigin );
VectorCopy( RI.vforward, RI.cull_vforward );
VectorCopy( RI.vright, RI.cull_vright );
VectorCopy( RI.vup, RI.cull_vup );
}
2011-08-21 22:00:00 +02:00
if( RI.drawOrtho )
2017-03-13 22:00:00 +01:00
GL_FrustumInitOrtho( &RI.frustum, ov->xLeft, ov->xRight, ov->yTop, ov->yBottom, ov->zNear, ov->zFar );
else GL_FrustumInitProj( &RI.frustum, 0.0f, R_GetFarClip(), RI.fov_x, RI.fov_y ); // NOTE: we ignore nearplane here (mirrors only)
2010-12-06 22:00:00 +01:00
}
/*
=============
R_SetupProjectionMatrix
=============
*/
2017-02-15 22:00:00 +01:00
static void R_SetupProjectionMatrix( matrix4x4 m )
2010-12-06 22:00:00 +01:00
{
GLdouble xMin, xMax, yMin, yMax, zNear, zFar;
2011-08-21 22:00:00 +02:00
if( RI.drawOrtho )
{
2011-09-28 22:00:00 +02:00
ref_overview_t *ov = &clgame.overView;
2017-03-13 22:00:00 +01:00
Matrix4x4_CreateOrtho( m, ov->xLeft, ov->xRight, ov->yTop, ov->yBottom, ov->zNear, ov->zFar );
2011-08-21 22:00:00 +02:00
return;
}
2010-12-06 22:00:00 +01:00
RI.farClip = R_GetFarClip();
zNear = 4.0f;
2010-12-07 22:00:00 +01:00
zFar = max( 256.0f, RI.farClip );
2010-12-06 22:00:00 +01:00
2017-02-15 22:00:00 +01:00
yMax = zNear * tan( RI.fov_y * M_PI / 360.0 );
2010-12-06 22:00:00 +01:00
yMin = -yMax;
2017-02-15 22:00:00 +01:00
xMax = zNear * tan( RI.fov_x * M_PI / 360.0 );
2010-12-06 22:00:00 +01:00
xMin = -xMax;
Matrix4x4_CreateProjection( m, xMax, xMin, yMax, yMin, zNear, zFar );
}
/*
=============
R_SetupModelviewMatrix
=============
*/
2017-02-15 22:00:00 +01:00
static void R_SetupModelviewMatrix( matrix4x4 m )
2010-12-06 22:00:00 +01:00
{
Matrix4x4_CreateModelview( m );
2017-02-15 22:00:00 +01:00
Matrix4x4_ConcatRotate( m, -RI.viewangles[2], 1, 0, 0 );
Matrix4x4_ConcatRotate( m, -RI.viewangles[0], 0, 1, 0 );
Matrix4x4_ConcatRotate( m, -RI.viewangles[1], 0, 0, 1 );
Matrix4x4_ConcatTranslate( m, -RI.vieworg[0], -RI.vieworg[1], -RI.vieworg[2] );
2010-12-06 22:00:00 +01:00
}
2010-12-11 22:00:00 +01:00
/*
=============
R_LoadIdentity
=============
*/
void R_LoadIdentity( void )
{
if( tr.modelviewIdentity ) return;
Matrix4x4_LoadIdentity( RI.objectMatrix );
Matrix4x4_Copy( RI.modelviewMatrix, RI.worldviewMatrix );
2011-10-06 22:00:00 +02:00
pglMatrixMode( GL_MODELVIEW );
2010-12-11 22:00:00 +01:00
GL_LoadMatrix( RI.modelviewMatrix );
tr.modelviewIdentity = true;
}
/*
=============
R_RotateForEntity
=============
*/
void R_RotateForEntity( cl_entity_t *e )
{
float scale = 1.0f;
2018-02-02 22:00:00 +01:00
if( e == clgame.entities )
2010-12-11 22:00:00 +01:00
{
R_LoadIdentity();
return;
}
if( e->model->type != mod_brush && e->curstate.scale > 0.0f )
scale = e->curstate.scale;
2010-12-22 22:00:00 +01:00
Matrix4x4_CreateFromEntity( RI.objectMatrix, e->angles, e->origin, scale );
2010-12-11 22:00:00 +01:00
Matrix4x4_ConcatTransforms( RI.modelviewMatrix, RI.worldviewMatrix, RI.objectMatrix );
2011-10-06 22:00:00 +02:00
pglMatrixMode( GL_MODELVIEW );
2010-12-11 22:00:00 +01:00
GL_LoadMatrix( RI.modelviewMatrix );
tr.modelviewIdentity = false;
}
/*
=============
R_TranslateForEntity
=============
*/
void R_TranslateForEntity( cl_entity_t *e )
{
float scale = 1.0f;
2018-02-02 22:00:00 +01:00
if( e == clgame.entities )
2010-12-11 22:00:00 +01:00
{
R_LoadIdentity();
return;
}
if( e->model->type != mod_brush && e->curstate.scale > 0.0f )
scale = e->curstate.scale;
2010-12-22 22:00:00 +01:00
Matrix4x4_CreateFromEntity( RI.objectMatrix, vec3_origin, e->origin, scale );
2010-12-11 22:00:00 +01:00
Matrix4x4_ConcatTransforms( RI.modelviewMatrix, RI.worldviewMatrix, RI.objectMatrix );
2011-10-06 22:00:00 +02:00
pglMatrixMode( GL_MODELVIEW );
2010-12-11 22:00:00 +01:00
GL_LoadMatrix( RI.modelviewMatrix );
tr.modelviewIdentity = false;
}
2011-10-06 22:00:00 +02:00
/*
===============
R_FindViewLeaf
===============
*/
void R_FindViewLeaf( void )
{
2017-03-16 22:00:00 +01:00
RI.oldviewleaf = RI.viewleaf;
2016-11-21 22:00:00 +01:00
RI.viewleaf = Mod_PointInLeaf( RI.pvsorigin, cl.worldmodel->nodes );
2011-10-06 22:00:00 +02:00
}
2010-12-06 22:00:00 +01:00
/*
===============
R_SetupFrame
===============
*/
static void R_SetupFrame( void )
{
2012-11-20 21:00:00 +01:00
// setup viewplane dist
2013-02-28 21:00:00 +01:00
RI.viewplanedist = DotProduct( RI.vieworg, RI.vforward );
2012-11-20 21:00:00 +01:00
2019-02-21 22:00:00 +01:00
// NOTE: this request is the fps-killer on some NVidia drivers
glState.isFogEnabled = pglIsEnabled( GL_FOG );
2017-02-12 22:00:00 +01:00
if( !gl_nosort->value )
2012-12-28 21:00:00 +01:00
{
// sort translucents entities by rendermode and distance
2018-03-20 22:00:00 +01:00
qsort( tr.draw_list->trans_entities, tr.draw_list->num_trans_entities, sizeof( cl_entity_t* ), R_TransEntityCompare );
2012-12-28 21:00:00 +01:00
}
2010-12-13 22:00:00 +01:00
2010-12-06 22:00:00 +01:00
// current viewleaf
if( RI.drawWorld )
{
2011-03-03 22:00:00 +01:00
RI.isSkyVisible = false; // unknown at this moment
2016-11-21 22:00:00 +01:00
R_FindViewLeaf();
2010-11-29 22:00:00 +01:00
}
2010-12-06 22:00:00 +01:00
}
/*
=============
R_SetupGL
=============
*/
2017-03-13 22:00:00 +01:00
void R_SetupGL( qboolean set_gl_state )
2010-12-06 22:00:00 +01:00
{
2017-02-15 22:00:00 +01:00
R_SetupModelviewMatrix( RI.worldviewMatrix );
R_SetupProjectionMatrix( RI.projectionMatrix );
2010-12-06 22:00:00 +01:00
Matrix4x4_Concat( RI.worldviewProjectionMatrix, RI.projectionMatrix, RI.worldviewMatrix );
2017-03-13 22:00:00 +01:00
if( !set_gl_state ) return;
2014-05-09 22:00:00 +02:00
if( RP_NORMALPASS( ))
{
int x, x2, y, y2;
// set up viewport (main, playersetup)
x = floor( RI.viewport[0] * glState.width / glState.width );
x2 = ceil(( RI.viewport[0] + RI.viewport[2] ) * glState.width / glState.width );
y = floor( glState.height - RI.viewport[1] * glState.height / glState.height );
y2 = ceil( glState.height - ( RI.viewport[1] + RI.viewport[3] ) * glState.height / glState.height );
pglViewport( x, y2, x2 - x, y - y2 );
}
else
{
// envpass, mirrorpass
pglViewport( RI.viewport[0], RI.viewport[1], RI.viewport[2], RI.viewport[3] );
}
2010-11-29 22:00:00 +01:00
2010-12-06 22:00:00 +01:00
pglMatrixMode( GL_PROJECTION );
GL_LoadMatrix( RI.projectionMatrix );
pglMatrixMode( GL_MODELVIEW );
GL_LoadMatrix( RI.worldviewMatrix );
2018-05-08 23:00:00 +02:00
if( FBitSet( RI.params, RP_CLIPPLANE ))
2010-11-29 22:00:00 +01:00
{
2010-12-06 22:00:00 +01:00
GLdouble clip[4];
mplane_t *p = &RI.clipPlane;
clip[0] = p->normal[0];
clip[1] = p->normal[1];
clip[2] = p->normal[2];
clip[3] = -p->dist;
pglClipPlane( GL_CLIP_PLANE0, clip );
pglEnable( GL_CLIP_PLANE0 );
2010-11-29 22:00:00 +01:00
}
2010-12-06 22:00:00 +01:00
GL_Cull( GL_FRONT );
2011-02-25 22:00:00 +01:00
pglDisable( GL_BLEND );
pglDisable( GL_ALPHA_TEST );
pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
2010-12-06 22:00:00 +01:00
}
/*
=============
R_EndGL
=============
*/
static void R_EndGL( void )
{
if( RI.params & RP_CLIPPLANE )
pglDisable( GL_CLIP_PLANE0 );
}
2012-10-03 22:00:00 +02:00
/*
=============
R_RecursiveFindWaterTexture
using to find source waterleaf with
watertexture to grab fog values from it
=============
*/
2018-08-23 23:00:00 +02:00
static gl_texture_t *R_RecursiveFindWaterTexture( const mnode_t *node, const mnode_t *ignore, qboolean down )
2012-10-03 22:00:00 +02:00
{
2018-08-23 23:00:00 +02:00
gl_texture_t *tex = NULL;
2012-10-03 22:00:00 +02:00
// assure the initial node is not null
// we could check it here, but we would rather check it
// outside the call to get rid of one additional recursion level
2018-02-12 22:00:00 +01:00
Assert( node != NULL );
2012-10-03 22:00:00 +02:00
// ignore solid nodes
if( node->contents == CONTENTS_SOLID )
return NULL;
if( node->contents < 0 )
{
mleaf_t *pleaf;
msurface_t **mark;
int i, c;
// ignore non-liquid leaves
if( node->contents != CONTENTS_WATER && node->contents != CONTENTS_LAVA && node->contents != CONTENTS_SLIME )
return NULL;
// find texture
pleaf = (mleaf_t *)node;
mark = pleaf->firstmarksurface;
c = pleaf->nummarksurfaces;
for( i = 0; i < c; i++, mark++ )
{
if( (*mark)->flags & SURF_DRAWTURB && (*mark)->texinfo && (*mark)->texinfo->texture )
return R_GetTexture( (*mark)->texinfo->texture->gl_texturenum );
}
// texture not found
return NULL;
}
// this is a regular node
// traverse children
if( node->children[0] && ( node->children[0] != ignore ))
{
tex = R_RecursiveFindWaterTexture( node->children[0], node, true );
if( tex ) return tex;
}
if( node->children[1] && ( node->children[1] != ignore ))
{
tex = R_RecursiveFindWaterTexture( node->children[1], node, true );
if( tex ) return tex;
}
// for down recursion, return immediately
if( down ) return NULL;
// texture not found, step up if any
if( node->parent )
return R_RecursiveFindWaterTexture( node->parent, node, false );
// top-level node, bail out
return NULL;
}
2011-02-15 22:00:00 +01:00
/*
=============
R_CheckFog
check for underwater fog
2012-10-03 22:00:00 +02:00
Using backward recursion to find waterline leaf
from underwater leaf (idea: XaeroX)
2011-02-15 22:00:00 +01:00
=============
*/
static void R_CheckFog( void )
{
2011-09-03 22:00:00 +02:00
cl_entity_t *ent;
2018-08-23 23:00:00 +02:00
gl_texture_t *tex;
2011-09-03 22:00:00 +02:00
int i, cnt, count;
2011-02-15 22:00:00 +01:00
2017-07-20 23:00:00 +02:00
// quake global fog
2018-11-01 22:00:00 +01:00
if( CL_IsQuakeCompatible( ))
2017-07-20 23:00:00 +02:00
{
2018-11-01 22:00:00 +01:00
if( !clgame.movevars.fog_settings )
{
if( pglIsEnabled( GL_FOG ))
pglDisable( GL_FOG );
RI.fogEnabled = false;
return;
}
2017-07-20 23:00:00 +02:00
// quake-style global fog
RI.fogColor[0] = ((clgame.movevars.fog_settings & 0xFF000000) >> 24) / 255.0f;
RI.fogColor[1] = ((clgame.movevars.fog_settings & 0xFF0000) >> 16) / 255.0f;
RI.fogColor[2] = ((clgame.movevars.fog_settings & 0xFF00) >> 8) / 255.0f;
2018-11-01 22:00:00 +01:00
RI.fogDensity = ((clgame.movevars.fog_settings & 0xFF) / 255.0f) * 0.01f;
2017-07-20 23:00:00 +02:00
RI.fogStart = RI.fogEnd = 0.0f;
2017-08-15 23:00:00 +02:00
RI.fogColor[3] = 1.0f;
2017-07-20 23:00:00 +02:00
RI.fogCustom = false;
RI.fogEnabled = true;
2017-08-15 23:00:00 +02:00
RI.fogSkybox = true;
2017-07-20 23:00:00 +02:00
return;
}
2011-03-20 22:00:00 +01:00
RI.fogEnabled = false;
2011-02-15 22:00:00 +01:00
2017-09-20 23:00:00 +02:00
if( RI.onlyClientDraw || cl.local.waterlevel < 3 || !RI.drawWorld || !RI.viewleaf )
2017-09-02 23:00:00 +02:00
{
2017-09-20 23:00:00 +02:00
if( RI.cached_waterlevel == 3 )
2017-09-02 23:00:00 +02:00
{
// in some cases waterlevel jumps from 3 to 1. Catch it
RI.cached_waterlevel = cl.local.waterlevel;
RI.cached_contents = CONTENTS_EMPTY;
2019-02-21 22:00:00 +01:00
if( !RI.fogCustom )
{
glState.isFogEnabled = false;
pglDisable( GL_FOG );
}
2017-09-02 23:00:00 +02:00
}
2011-02-15 22:00:00 +01:00
return;
2017-09-02 23:00:00 +02:00
}
2011-02-15 22:00:00 +01:00
2011-10-06 22:00:00 +02:00
ent = CL_GetWaterEntity( RI.vieworg );
2011-09-03 22:00:00 +02:00
if( ent && ent->model && ent->model->type == mod_brush && ent->curstate.skin < 0 )
cnt = ent->curstate.skin;
2016-11-21 22:00:00 +01:00
else cnt = RI.viewleaf->contents;
2011-02-15 22:00:00 +01:00
2017-09-02 23:00:00 +02:00
RI.cached_waterlevel = cl.local.waterlevel;
2011-09-03 22:00:00 +02:00
if( !IsLiquidContents( RI.cached_contents ) && IsLiquidContents( cnt ))
{
tex = NULL;
// check for water texture
if( ent && ent->model && ent->model->type == mod_brush )
2011-02-15 22:00:00 +01:00
{
2011-09-03 22:00:00 +02:00
msurface_t *surf;
count = ent->model->nummodelsurfaces;
for( i = 0, surf = &ent->model->surfaces[ent->model->firstmodelsurface]; i < count; i++, surf++ )
2011-02-15 22:00:00 +01:00
{
2011-09-03 22:00:00 +02:00
if( surf->flags & SURF_DRAWTURB && surf->texinfo && surf->texinfo->texture )
{
tex = R_GetTexture( surf->texinfo->texture->gl_texturenum );
RI.cached_contents = ent->curstate.skin;
break;
}
2011-02-15 22:00:00 +01:00
}
}
2011-09-03 22:00:00 +02:00
else
{
2016-11-21 22:00:00 +01:00
tex = R_RecursiveFindWaterTexture( RI.viewleaf->parent, NULL, false );
if( tex ) RI.cached_contents = RI.viewleaf->contents;
2011-02-15 22:00:00 +01:00
}
2012-10-03 22:00:00 +02:00
if( !tex ) return; // no valid fogs
2011-09-03 22:00:00 +02:00
// copy fog params
RI.fogColor[0] = tex->fogParams[0] / 255.0f;
RI.fogColor[1] = tex->fogParams[1] / 255.0f;
RI.fogColor[2] = tex->fogParams[2] / 255.0f;
RI.fogDensity = tex->fogParams[3] * 0.000025f;
RI.fogStart = RI.fogEnd = 0.0f;
2017-08-15 23:00:00 +02:00
RI.fogColor[3] = 1.0f;
2011-09-03 22:00:00 +02:00
RI.fogCustom = false;
RI.fogEnabled = true;
2017-09-02 23:00:00 +02:00
RI.fogSkybox = true;
2011-09-03 22:00:00 +02:00
}
else
{
RI.fogCustom = false;
RI.fogEnabled = true;
2017-09-02 23:00:00 +02:00
RI.fogSkybox = true;
2011-09-03 22:00:00 +02:00
}
2011-02-15 22:00:00 +01:00
}
2018-09-08 23:00:00 +02:00
/*
=============
R_CheckGLFog
special condition for Spirit 1.9
that used direct calls of glFog-functions
=============
*/
static void R_CheckGLFog( void )
{
#ifdef HACKS_RELATED_HLMODS
if(( !RI.fogEnabled && !RI.fogCustom ) && pglIsEnabled( GL_FOG ) && VectorIsNull( RI.fogColor ))
{
// fill the fog color from GL-state machine
pglGetFloatv( GL_FOG_COLOR, RI.fogColor );
RI.fogSkybox = true;
}
#endif
}
2011-02-15 22:00:00 +01:00
/*
=============
R_DrawFog
=============
*/
void R_DrawFog( void )
{
2017-08-15 23:00:00 +02:00
if( !RI.fogEnabled ) return;
2011-02-15 22:00:00 +01:00
pglEnable( GL_FOG );
2018-11-01 22:00:00 +01:00
if( CL_IsQuakeCompatible( ))
pglFogi( GL_FOG_MODE, GL_EXP2 );
else pglFogi( GL_FOG_MODE, GL_EXP );
2011-03-20 22:00:00 +01:00
pglFogf( GL_FOG_DENSITY, RI.fogDensity );
pglFogfv( GL_FOG_COLOR, RI.fogColor );
2011-02-15 22:00:00 +01:00
pglHint( GL_FOG_HINT, GL_NICEST );
}
2010-12-11 22:00:00 +01:00
/*
=============
R_DrawEntitiesOnList
=============
*/
void R_DrawEntitiesOnList( void )
{
2011-03-07 22:00:00 +01:00
int i;
2010-12-11 22:00:00 +01:00
2017-03-06 22:00:00 +01:00
tr.blend = 1.0f;
2017-08-21 23:00:00 +02:00
GL_CheckForErrors();
2011-02-26 22:00:00 +01:00
2010-12-13 22:00:00 +01:00
// first draw solid entities
2018-03-20 22:00:00 +01:00
for( i = 0; i < tr.draw_list->num_solid_entities && !RI.onlyClientDraw; i++ )
2010-12-11 22:00:00 +01:00
{
2018-03-20 22:00:00 +01:00
RI.currententity = tr.draw_list->solid_entities[i];
2010-12-14 22:00:00 +01:00
RI.currentmodel = RI.currententity->model;
2017-08-15 23:00:00 +02:00
2018-02-12 22:00:00 +01:00
Assert( RI.currententity != NULL );
Assert( RI.currentmodel != NULL );
2010-12-11 22:00:00 +01:00
2010-12-14 22:00:00 +01:00
switch( RI.currentmodel->type )
2010-12-11 22:00:00 +01:00
{
case mod_brush:
R_DrawBrushModel( RI.currententity );
break;
2017-06-23 23:00:00 +02:00
case mod_alias:
R_DrawAliasModel( RI.currententity );
break;
2010-12-16 22:00:00 +01:00
case mod_studio:
R_DrawStudioModel( RI.currententity );
break;
2010-12-11 22:00:00 +01:00
default:
break;
}
}
2010-12-12 22:00:00 +01:00
2017-08-21 23:00:00 +02:00
GL_CheckForErrors();
2017-08-15 23:00:00 +02:00
// quake-specific feature
2017-08-12 23:00:00 +02:00
R_DrawAlphaTextureChains();
2017-08-21 23:00:00 +02:00
GL_CheckForErrors();
2017-08-15 23:00:00 +02:00
// draw sprites seperately, because of alpha blending
2018-03-20 22:00:00 +01:00
for( i = 0; i < tr.draw_list->num_solid_entities && !RI.onlyClientDraw; i++ )
2017-08-15 23:00:00 +02:00
{
2018-03-20 22:00:00 +01:00
RI.currententity = tr.draw_list->solid_entities[i];
2017-08-15 23:00:00 +02:00
RI.currentmodel = RI.currententity->model;
2018-02-12 22:00:00 +01:00
Assert( RI.currententity != NULL );
Assert( RI.currentmodel != NULL );
2017-08-15 23:00:00 +02:00
switch( RI.currentmodel->type )
{
case mod_sprite:
R_DrawSpriteModel( RI.currententity );
break;
}
}
2017-08-21 23:00:00 +02:00
GL_CheckForErrors();
2017-02-15 22:00:00 +01:00
if( !RI.onlyClientDraw )
2011-12-04 21:00:00 +01:00
{
CL_DrawBeams( false );
}
2011-03-23 22:00:00 +01:00
2017-08-21 23:00:00 +02:00
GL_CheckForErrors();
2011-03-23 22:00:00 +01:00
if( RI.drawWorld )
clgame.dllFuncs.pfnDrawNormalTriangles();
2010-12-12 22:00:00 +01:00
2017-08-21 23:00:00 +02:00
GL_CheckForErrors();
2010-12-12 22:00:00 +01:00
2011-07-07 22:00:00 +02:00
// then draw translucent entities
2018-03-20 22:00:00 +01:00
for( i = 0; i < tr.draw_list->num_trans_entities && !RI.onlyClientDraw; i++ )
2010-12-13 22:00:00 +01:00
{
2018-03-20 22:00:00 +01:00
RI.currententity = tr.draw_list->trans_entities[i];
2010-12-14 22:00:00 +01:00
RI.currentmodel = RI.currententity->model;
2018-03-01 22:00:00 +01:00
// handle studiomodels with custom rendermodes on texture
if( RI.currententity->curstate.rendermode != kRenderNormal )
tr.blend = CL_FxBlend( RI.currententity ) / 255.0f;
else tr.blend = 1.0f; // draw as solid but sorted by distance
2017-03-06 22:00:00 +01:00
if( tr.blend <= 0.0f ) continue;
2010-12-14 22:00:00 +01:00
2018-02-12 22:00:00 +01:00
Assert( RI.currententity != NULL );
Assert( RI.currentmodel != NULL );
2010-12-12 22:00:00 +01:00
2010-12-14 22:00:00 +01:00
switch( RI.currentmodel->type )
2010-12-12 22:00:00 +01:00
{
case mod_brush:
R_DrawBrushModel( RI.currententity );
break;
2017-06-23 23:00:00 +02:00
case mod_alias:
R_DrawAliasModel( RI.currententity );
break;
2010-12-16 22:00:00 +01:00
case mod_studio:
R_DrawStudioModel( RI.currententity );
break;
2010-12-15 22:00:00 +01:00
case mod_sprite:
R_DrawSpriteModel( RI.currententity );
break;
2010-12-12 22:00:00 +01:00
default:
break;
}
}
2010-12-13 22:00:00 +01:00
2017-08-21 23:00:00 +02:00
GL_CheckForErrors();
2011-03-23 22:00:00 +01:00
if( RI.drawWorld )
2016-10-26 23:00:00 +02:00
{
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
2011-03-23 22:00:00 +01:00
clgame.dllFuncs.pfnDrawTransparentTriangles ();
2016-10-26 23:00:00 +02:00
}
2010-12-27 22:00:00 +01:00
2017-08-21 23:00:00 +02:00
GL_CheckForErrors();
2017-02-15 22:00:00 +01:00
if( !RI.onlyClientDraw )
2011-12-04 21:00:00 +01:00
{
2017-08-15 23:00:00 +02:00
R_AllowFog( false );
2011-12-04 21:00:00 +01:00
CL_DrawBeams( true );
2017-02-21 22:00:00 +01:00
CL_DrawParticles( tr.frametime );
CL_DrawTracers( tr.frametime );
2017-08-15 23:00:00 +02:00
R_AllowFog( true );
2011-12-04 21:00:00 +01:00
}
2011-03-20 22:00:00 +01:00
2017-08-21 23:00:00 +02:00
GL_CheckForErrors();
2011-09-28 22:00:00 +02:00
pglDisable( GL_BLEND ); // Trinity Render issues
2017-08-20 23:00:00 +02:00
if( !RI.onlyClientDraw )
R_DrawViewModel();
2017-02-13 22:00:00 +01:00
CL_ExtraUpdate();
2017-08-21 23:00:00 +02:00
GL_CheckForErrors();
2010-12-11 22:00:00 +01:00
}
2010-12-06 22:00:00 +01:00
/*
================
R_RenderScene
2017-02-15 22:00:00 +01:00
R_SetupRefParams must be called right before
2010-12-06 22:00:00 +01:00
================
*/
2017-02-15 22:00:00 +01:00
void R_RenderScene( void )
2010-12-06 22:00:00 +01:00
{
if( !cl.worldmodel && RI.drawWorld )
Host_Error( "R_RenderView: NULL worldmodel\n" );
2017-02-21 22:00:00 +01:00
// frametime is valid only for normal pass
if( RP_NORMALPASS( ))
tr.frametime = cl.time - cl.oldtime;
else tr.frametime = 0.0;
2017-02-26 22:00:00 +01:00
// begin a new frame
tr.framecount++;
2010-12-06 22:00:00 +01:00
R_PushDlights();
R_SetupFrustum();
2017-02-15 22:00:00 +01:00
R_SetupFrame();
2017-03-13 22:00:00 +01:00
R_SetupGL( true );
2010-12-06 22:00:00 +01:00
R_Clear( ~0 );
R_MarkLeaves();
2017-08-15 23:00:00 +02:00
R_DrawFog ();
2018-09-08 23:00:00 +02:00
R_CheckGLFog();
2010-12-06 22:00:00 +01:00
R_DrawWorld();
2017-09-20 23:00:00 +02:00
R_CheckFog();
2010-12-06 22:00:00 +01:00
2017-02-13 22:00:00 +01:00
CL_ExtraUpdate (); // don't let sound get messed up if going slow
2010-12-06 22:00:00 +01:00
2010-12-11 22:00:00 +01:00
R_DrawEntitiesOnList();
2010-12-06 22:00:00 +01:00
2010-12-11 22:00:00 +01:00
R_DrawWaterSurfaces();
2010-12-06 22:00:00 +01:00
R_EndGL();
}
2017-03-08 22:00:00 +01:00
/*
===============
R_DoResetGamma
gamma will be reset for
some type of screenshots
===============
*/
qboolean R_DoResetGamma( void )
{
switch( cls.scrshot_action )
{
case scrshot_envshot:
case scrshot_skyshot:
return true;
default:
return false;
}
}
2010-12-06 22:00:00 +01:00
/*
===============
2019-06-13 23:00:00 +02:00
R_CheckGamma
2010-12-06 22:00:00 +01:00
===============
*/
2019-06-13 23:00:00 +02:00
void R_CheckGamma( void )
2010-12-06 22:00:00 +01:00
{
2017-03-08 22:00:00 +01:00
if( R_DoResetGamma( ))
2010-11-29 22:00:00 +01:00
{
2019-06-13 23:00:00 +02:00
// paranoia cubemaps uses this
2017-03-08 22:00:00 +01:00
BuildGammaTable( 1.8f, 0.0f );
2019-06-13 23:00:00 +02:00
// paranoia cubemap rendering
if( clgame.drawFuncs.GL_BuildLightmaps )
clgame.drawFuncs.GL_BuildLightmaps( );
2017-03-08 22:00:00 +01:00
}
else if( FBitSet( vid_gamma->flags, FCVAR_CHANGED ) || FBitSet( vid_brightness->flags, FCVAR_CHANGED ))
{
BuildGammaTable( vid_gamma->value, vid_brightness->value );
glConfig.softwareGammaUpdate = true;
GL_RebuildLightmaps();
glConfig.softwareGammaUpdate = false;
2010-11-29 22:00:00 +01:00
}
2019-06-13 23:00:00 +02:00
}
/*
===============
R_BeginFrame
===============
*/
void R_BeginFrame( qboolean clearScene )
{
glConfig.softwareGammaUpdate = false; // in case of possible fails
if(( gl_clear->value || CL_IsDevOverviewMode( )) && clearScene && cls.state != ca_cinematic )
{
pglClear( GL_COLOR_BUFFER_BIT );
}
R_CheckGamma();
2010-11-29 22:00:00 +01:00
2011-09-29 22:00:00 +02:00
R_Set2DMode( true );
2010-11-29 22:00:00 +01:00
// draw buffer stuff
2010-12-06 22:00:00 +01:00
pglDrawBuffer( GL_BACK );
2010-11-29 22:00:00 +01:00
// update texture parameters
2017-09-20 23:00:00 +02:00
if( FBitSet( gl_texture_nearest->flags|gl_lightmap_nearest->flags|gl_texture_anisotropy->flags|gl_texture_lodbias->flags, FCVAR_CHANGED ))
2010-11-29 22:00:00 +01:00
R_SetTextureParameters();
// swapinterval stuff
GL_UpdateSwapInterval();
2011-02-23 22:00:00 +01:00
2017-02-13 22:00:00 +01:00
CL_ExtraUpdate ();
2010-11-29 22:00:00 +01:00
}
2017-02-15 22:00:00 +01:00
/*
===============
R_SetupRefParams
set initial params for renderer
===============
*/
2017-02-21 22:00:00 +01:00
void R_SetupRefParams( const ref_viewpass_t *rvp )
2017-02-15 22:00:00 +01:00
{
RI.params = RP_NONE;
2017-02-21 22:00:00 +01:00
RI.drawWorld = FBitSet( rvp->flags, RF_DRAW_WORLD );
RI.onlyClientDraw = FBitSet( rvp->flags, RF_ONLY_CLIENTDRAW );
2017-02-15 22:00:00 +01:00
RI.farClip = 0;
2017-02-21 22:00:00 +01:00
if( !FBitSet( rvp->flags, RF_DRAW_CUBEMAP ))
2019-06-13 23:00:00 +02:00
{
2017-02-21 22:00:00 +01:00
RI.drawOrtho = FBitSet( rvp->flags, RF_DRAW_OVERVIEW );
2019-06-13 23:00:00 +02:00
}
else
{
SetBits( RI.params, RP_ENVVIEW );
RI.drawOrtho = false;
}
2017-02-21 22:00:00 +01:00
2017-02-15 22:00:00 +01:00
// setup viewport
2017-02-21 22:00:00 +01:00
RI.viewport[0] = rvp->viewport[0];
RI.viewport[1] = rvp->viewport[1];
RI.viewport[2] = rvp->viewport[2];
RI.viewport[3] = rvp->viewport[3];
2017-02-15 22:00:00 +01:00
// calc FOV
2017-02-21 22:00:00 +01:00
RI.fov_x = rvp->fov_x;
RI.fov_y = rvp->fov_y;
2017-02-15 22:00:00 +01:00
2017-02-21 22:00:00 +01:00
VectorCopy( rvp->vieworigin, RI.vieworg );
VectorCopy( rvp->viewangles, RI.viewangles );
VectorCopy( rvp->vieworigin, RI.pvsorigin );
2017-02-15 22:00:00 +01:00
}
2010-11-29 22:00:00 +01:00
/*
===============
R_RenderFrame
===============
*/
2017-02-21 22:00:00 +01:00
void R_RenderFrame( const ref_viewpass_t *rvp )
2010-11-29 22:00:00 +01:00
{
2017-02-12 22:00:00 +01:00
if( r_norefresh->value )
2010-12-06 22:00:00 +01:00
return;
2017-02-21 22:00:00 +01:00
// setup the initial render params
R_SetupRefParams( rvp );
2012-02-08 21:00:00 +01:00
2017-02-21 22:00:00 +01:00
if( gl_finish->value && RI.drawWorld )
pglFinish();
2012-03-24 21:00:00 +01:00
2018-05-08 23:00:00 +02:00
if( glConfig.max_multisamples > 1 && FBitSet( gl_msaa->flags, FCVAR_CHANGED ))
{
if( CVAR_TO_BOOL( gl_msaa ))
pglEnable( GL_MULTISAMPLE_ARB );
2018-09-08 23:00:00 +02:00
else pglDisable( GL_MULTISAMPLE_ARB );
2018-05-08 23:00:00 +02:00
ClearBits( gl_msaa->flags, FCVAR_CHANGED );
}
2018-04-18 23:00:00 +02:00
2011-12-04 21:00:00 +01:00
// completely override rendering
if( clgame.drawFuncs.GL_RenderFrame != NULL )
{
2017-03-29 23:00:00 +02:00
tr.fCustomRendering = true;
2017-02-21 22:00:00 +01:00
if( clgame.drawFuncs.GL_RenderFrame( rvp ))
2012-01-27 21:00:00 +01:00
{
2018-05-08 23:00:00 +02:00
R_GatherPlayerLight();
2017-03-26 23:00:00 +02:00
tr.realframecount++;
tr.fResetVis = true;
2011-12-04 21:00:00 +01:00
return;
2012-01-27 21:00:00 +01:00
}
2011-12-04 21:00:00 +01:00
}
2017-03-29 23:00:00 +02:00
tr.fCustomRendering = false;
2017-08-20 23:00:00 +02:00
if( !RI.onlyClientDraw )
R_RunViewmodelEvents();
2011-10-06 22:00:00 +02:00
2018-02-06 22:00:00 +01:00
tr.realframecount++; // right called after viewmodel events
2017-02-15 22:00:00 +01:00
R_RenderScene();
2010-11-29 22:00:00 +01:00
}
/*
===============
R_EndFrame
===============
*/
void R_EndFrame( void )
{
// flush any remaining 2D bits
R_Set2DMode( false );
2010-12-06 22:00:00 +01:00
if( !pwglSwapBuffers( glw_state.hDC ))
2018-04-25 23:00:00 +02:00
Sys_Error( "failed to swap buffers\nCheck your video driver and as possible of reinstall it" );
2010-11-29 22:00:00 +01:00
}
/*
===============
R_DrawCubemapView
===============
*/
void R_DrawCubemapView( const vec3_t origin, const vec3_t angles, int size )
{
2017-02-21 22:00:00 +01:00
ref_viewpass_t rvp;
2013-02-24 21:00:00 +01:00
2017-02-15 22:00:00 +01:00
// basic params
2017-02-21 22:00:00 +01:00
rvp.flags = rvp.viewentity = 0;
SetBits( rvp.flags, RF_DRAW_WORLD );
SetBits( rvp.flags, RF_DRAW_CUBEMAP );
2017-02-15 22:00:00 +01:00
2017-02-21 22:00:00 +01:00
rvp.viewport[0] = rvp.viewport[1] = 0;
rvp.viewport[2] = rvp.viewport[3] = size;
rvp.fov_x = rvp.fov_y = 90.0f; // this is a final fov value
2017-02-15 22:00:00 +01:00
// setup origin & angles
2017-02-21 22:00:00 +01:00
VectorCopy( origin, rvp.vieworigin );
VectorCopy( angles, rvp.viewangles );
2011-04-08 22:00:00 +02:00
2017-02-21 22:00:00 +01:00
R_RenderFrame( &rvp );
2011-04-08 22:00:00 +02:00
2017-02-21 22:00:00 +01:00
RI.viewleaf = NULL; // force markleafs next frame
2011-12-04 21:00:00 +01:00
}
static int GL_RenderGetParm( int parm, int arg )
{
2018-08-23 23:00:00 +02:00
gl_texture_t *glt;
2011-12-04 21:00:00 +01:00
switch( parm )
{
case PARM_TEX_WIDTH:
glt = R_GetTexture( arg );
return glt->width;
case PARM_TEX_HEIGHT:
glt = R_GetTexture( arg );
return glt->height;
case PARM_TEX_SRC_WIDTH:
glt = R_GetTexture( arg );
return glt->srcWidth;
case PARM_TEX_SRC_HEIGHT:
glt = R_GetTexture( arg );
return glt->srcHeight;
2015-04-25 23:00:00 +02:00
case PARM_TEX_GLFORMAT:
glt = R_GetTexture( arg );
return glt->format;
2016-04-24 23:00:00 +02:00
case PARM_TEX_ENCODE:
glt = R_GetTexture( arg );
return glt->encode;
2016-09-06 23:00:00 +02:00
case PARM_TEX_MIPCOUNT:
glt = R_GetTexture( arg );
return glt->numMips;
2016-09-19 23:00:00 +02:00
case PARM_TEX_DEPTH:
glt = R_GetTexture( arg );
return glt->depth;
2018-02-02 22:00:00 +01:00
case PARM_BSP2_SUPPORTED:
#ifdef SUPPORT_BSP2_FORMAT
return 1;
#endif
return 0;
2011-12-04 21:00:00 +01:00
case PARM_TEX_SKYBOX:
2018-02-12 22:00:00 +01:00
Assert( arg >= 0 && arg < 6 );
2011-12-04 21:00:00 +01:00
return tr.skyboxTextures[arg];
case PARM_TEX_SKYTEXNUM:
return tr.skytexturenum;
case PARM_TEX_LIGHTMAP:
2017-03-26 23:00:00 +02:00
arg = bound( 0, arg, MAX_LIGHTMAPS - 1 );
2011-12-04 21:00:00 +01:00
return tr.lightmapTextures[arg];
case PARM_SKY_SPHERE:
2018-02-05 22:00:00 +01:00
return FBitSet( world.flags, FWORLD_SKYSPHERE ) && !FBitSet( world.flags, FWORLD_CUSTOM_SKYBOX );
2018-06-17 23:00:00 +02:00
case PARAM_GAMEPAUSED:
return cl.paused;
2011-12-04 21:00:00 +01:00
case PARM_WIDESCREEN:
return glState.wideScreen;
case PARM_FULLSCREEN:
return glState.fullScreen;
case PARM_SCREEN_WIDTH:
return glState.width;
case PARM_SCREEN_HEIGHT:
return glState.height;
case PARM_CLIENT_INGAME:
return CL_IsInGame();
2011-12-18 21:00:00 +01:00
case PARM_MAX_ENTITIES:
return clgame.maxEntities;
2012-01-27 21:00:00 +01:00
case PARM_TEX_TARGET:
glt = R_GetTexture( arg );
return glt->target;
case PARM_TEX_TEXNUM:
glt = R_GetTexture( arg );
return glt->texnum;
case PARM_TEX_FLAGS:
glt = R_GetTexture( arg );
return glt->flags;
2012-07-11 22:00:00 +02:00
case PARM_FEATURES:
return host.features;
2013-09-03 22:00:00 +02:00
case PARM_ACTIVE_TMU:
return glState.activeTMU;
2017-03-26 23:00:00 +02:00
case PARM_LIGHTSTYLEVALUE:
arg = bound( 0, arg, MAX_LIGHTSTYLES - 1 );
return tr.lightstylevalue[arg];
2013-12-19 21:00:00 +01:00
case PARM_MAP_HAS_DELUXE:
2018-02-05 22:00:00 +01:00
return FBitSet( world.flags, FWORLD_HAS_DELUXEMAP );
2014-05-08 22:00:00 +02:00
case PARM_MAX_IMAGE_UNITS:
return GL_MaxTextureUnits();
2014-12-12 22:00:00 +01:00
case PARM_CLIENT_ACTIVE:
return (cls.state == ca_active);
2015-10-15 23:00:00 +02:00
case PARM_REBUILD_GAMMA:
return glConfig.softwareGammaUpdate;
2016-08-12 23:00:00 +02:00
case PARM_DEDICATED_SERVER:
return (host.type == HOST_DEDICATED);
2016-11-28 22:00:00 +01:00
case PARM_SURF_SAMPLESIZE:
if( arg >= 0 && arg < cl.worldmodel->numsurfaces )
return Mod_SampleSizeForFace( &cl.worldmodel->surfaces[arg] );
return LM_SAMPLE_SIZE;
2016-12-10 22:00:00 +01:00
case PARM_GL_CONTEXT_TYPE:
return glConfig.context;
case PARM_GLES_WRAPPER:
return glConfig.wrapper;
2017-03-26 23:00:00 +02:00
case PARM_STENCIL_ACTIVE:
return glState.stencilEnabled;
2017-05-04 23:00:00 +02:00
case PARM_WATER_ALPHA:
2018-02-05 22:00:00 +01:00
return FBitSet( world.flags, FWORLD_WATERALPHA );
2019-05-11 23:00:00 +02:00
case PARM_TEX_MEMORY:
return GL_TexMemory();
2019-06-08 23:00:00 +02:00
case PARM_DELUXEDATA:
return *(int *)&world.deluxedata;
case PARM_SHADOWDATA:
return *(int *)&world.shadowdata;
2011-12-04 21:00:00 +01:00
}
return 0;
}
2012-01-27 21:00:00 +01:00
static void R_GetDetailScaleForTexture( int texture, float *xScale, float *yScale )
{
2018-08-23 23:00:00 +02:00
gl_texture_t *glt = R_GetTexture( texture );
2012-01-27 21:00:00 +01:00
if( xScale ) *xScale = glt->xscale;
if( yScale ) *yScale = glt->yscale;
}
static void R_GetExtraParmsForTexture( int texture, byte *red, byte *green, byte *blue, byte *density )
{
2018-08-23 23:00:00 +02:00
gl_texture_t *glt = R_GetTexture( texture );
2012-01-27 21:00:00 +01:00
if( red ) *red = glt->fogParams[0];
if( green ) *green = glt->fogParams[1];
if( blue ) *blue = glt->fogParams[2];
if( density ) *density = glt->fogParams[3];
}
2011-12-04 21:00:00 +01:00
/*
=================
R_EnvShot
=================
*/
2014-05-08 22:00:00 +02:00
static void R_EnvShot( const float *vieworg, const char *name, int skyshot, int shotsize )
2011-12-04 21:00:00 +01:00
{
static vec3_t viewPoint;
2018-09-28 23:00:00 +02:00
if( !COM_CheckString( name ))
2011-12-04 21:00:00 +01:00
return;
if( cls.scrshot_action != scrshot_inactive )
{
if( cls.scrshot_action != scrshot_skyshot && cls.scrshot_action != scrshot_envshot )
2018-09-28 23:00:00 +02:00
Con_Printf( S_ERROR "R_%sShot: subsystem is busy, try for next frame.\n", skyshot ? "Sky" : "Env" );
2011-12-04 21:00:00 +01:00
return;
}
cls.envshot_vieworg = NULL; // use client view
Q_strncpy( cls.shotname, name, sizeof( cls.shotname ));
if( vieworg )
{
// make sure what viewpoint don't temporare
VectorCopy( vieworg, viewPoint );
cls.envshot_vieworg = viewPoint;
2014-05-08 22:00:00 +02:00
cls.envshot_disable_vis = true;
2011-12-04 21:00:00 +01:00
}
// make request for envshot
if( skyshot ) cls.scrshot_action = scrshot_skyshot;
else cls.scrshot_action = scrshot_envshot;
2014-05-08 22:00:00 +02:00
// catch negative values
cls.envshot_viewsize = max( 0, shotsize );
2011-12-04 21:00:00 +01:00
}
static void R_SetCurrentEntity( cl_entity_t *ent )
{
RI.currententity = ent;
// set model also
if( RI.currententity != NULL )
{
RI.currentmodel = RI.currententity->model;
}
}
static void R_SetCurrentModel( model_t *mod )
{
RI.currentmodel = mod;
}
2017-03-26 23:00:00 +02:00
static int R_FatPVS( const vec3_t org, float radius, byte *visbuffer, qboolean merge, qboolean fullvis )
{
2017-03-29 23:00:00 +02:00
return Mod_FatPVS( org, radius, visbuffer, world.visbytes, merge, fullvis );
2017-03-26 23:00:00 +02:00
}
2011-12-04 21:00:00 +01:00
static lightstyle_t *CL_GetLightStyle( int number )
{
2018-02-12 22:00:00 +01:00
Assert( number >= 0 && number < MAX_LIGHTSTYLES );
2011-12-04 21:00:00 +01:00
return &cl.lightstyles[number];
}
static dlight_t *CL_GetDynamicLight( int number )
{
2018-02-12 22:00:00 +01:00
Assert( number >= 0 && number < MAX_DLIGHTS );
2011-12-04 21:00:00 +01:00
return &cl_dlights[number];
}
static dlight_t *CL_GetEntityLight( int number )
{
2018-02-12 22:00:00 +01:00
Assert( number >= 0 && number < MAX_ELIGHTS );
2011-12-04 21:00:00 +01:00
return &cl_elights[number];
}
2017-03-26 23:00:00 +02:00
static float R_GetFrameTime( void )
{
return tr.frametime;
}
2011-12-24 21:00:00 +01:00
static const char *GL_TextureName( unsigned int texnum )
{
return R_GetTexture( texnum )->name;
}
2015-01-24 22:00:00 +01:00
const byte *GL_TextureData( unsigned int texnum )
2014-01-01 21:00:00 +01:00
{
rgbdata_t *pic = R_GetTexture( texnum )->original;
if( pic != NULL )
return pic->buffer;
return NULL;
}
2013-09-14 22:00:00 +02:00
static const ref_overview_t *GL_GetOverviewParms( void )
{
return &clgame.overView;
}
2013-12-05 21:00:00 +01:00
static void *R_Mem_Alloc( size_t cb, const char *filename, const int fileline )
{
2018-05-26 23:00:00 +02:00
return _Mem_Alloc( cls.mempool, cb, true, filename, fileline );
2013-12-05 21:00:00 +01:00
}
static void R_Mem_Free( void *mem, const char *filename, const int fileline )
{
2016-12-10 22:00:00 +01:00
if( !mem ) return;
2013-12-05 21:00:00 +01:00
_Mem_Free( mem, filename, fileline );
}
/*
=========
pfnGetFilesList
=========
*/
static char **pfnGetFilesList( const char *pattern, int *numFiles, int gamedironly )
{
static search_t *t = NULL;
if( t ) Mem_Free( t ); // release prev search
t = FS_Search( pattern, true, gamedironly );
if( !t )
{
if( numFiles ) *numFiles = 0;
return NULL;
}
if( numFiles ) *numFiles = t->numfilenames;
return t->filenames;
}
2018-01-21 22:00:00 +01:00
static uint pfnFileBufferCRC32( const void *buffer, const int length )
{
uint modelCRC = 0;
if( !buffer || length <= 0 )
return modelCRC;
CRC32_Init( &modelCRC );
CRC32_ProcessBuffer( &modelCRC, buffer, length );
2018-03-20 22:00:00 +01:00
return CRC32_Final( modelCRC );
2018-01-21 22:00:00 +01:00
}
2018-03-09 22:00:00 +01:00
/*
=============
CL_GenericHandle
=============
*/
const char *CL_GenericHandle( int fileindex )
{
if( fileindex < 0 || fileindex >= MAX_CUSTOM )
return 0;
return cl.files_precache[fileindex];
}
2013-12-05 21:00:00 +01:00
2011-12-04 21:00:00 +01:00
static render_api_t gRenderAPI =
{
GL_RenderGetParm,
2012-01-27 21:00:00 +01:00
R_GetDetailScaleForTexture,
R_GetExtraParmsForTexture,
2011-12-04 21:00:00 +01:00
CL_GetLightStyle,
CL_GetDynamicLight,
CL_GetEntityLight,
2017-03-07 22:00:00 +01:00
LightToTexGamma,
2017-03-26 23:00:00 +02:00
R_GetFrameTime,
2012-01-27 21:00:00 +01:00
R_SetCurrentEntity,
R_SetCurrentModel,
2017-03-26 23:00:00 +02:00
R_FatPVS,
2013-10-23 22:00:00 +02:00
R_StoreEfrags,
2012-01-27 21:00:00 +01:00
GL_FindTexture,
GL_TextureName,
2014-01-01 21:00:00 +01:00
GL_TextureData,
2018-10-17 23:00:00 +02:00
GL_LoadTexture,
2012-01-27 21:00:00 +01:00
GL_CreateTexture,
2018-10-17 23:00:00 +02:00
GL_LoadTextureArray,
2016-09-26 23:00:00 +02:00
GL_CreateTextureArray,
2012-01-27 21:00:00 +01:00
GL_FreeTexture,
2017-03-23 22:00:00 +01:00
DrawSingleDecal,
2013-10-23 22:00:00 +02:00
R_DecalSetupVerts,
R_EntityRemoveDecals,
2018-10-01 23:00:00 +02:00
AVI_LoadVideo,
2011-12-04 21:00:00 +01:00
AVI_GetVideoInfo,
AVI_GetVideoFrameNumber,
AVI_GetVideoFrame,
R_UploadStretchRaw,
AVI_FreeVideo,
AVI_IsActive,
2018-10-01 23:00:00 +02:00
S_StreamAviSamples,
2018-02-07 22:00:00 +01:00
NULL,
NULL,
2012-01-27 21:00:00 +01:00
GL_Bind,
GL_SelectTexture,
GL_LoadTexMatrixExt,
GL_LoadIdentityTexMatrix,
GL_CleanUpTextureUnits,
GL_TexGen,
2013-09-03 22:00:00 +02:00
GL_TextureTarget,
2013-12-07 21:00:00 +01:00
GL_SetTexCoordArrayMode,
2016-12-10 22:00:00 +01:00
GL_GetProcAddress,
2018-08-23 23:00:00 +02:00
GL_UpdateTexSize,
2013-12-07 21:00:00 +01:00
NULL,
NULL,
2013-10-23 22:00:00 +02:00
CL_DrawParticlesExternal,
R_EnvShot,
pfnSPR_LoadExt,
2018-02-07 22:00:00 +01:00
R_LightVec,
2013-10-23 22:00:00 +02:00
R_StudioGetTexture,
2013-09-14 22:00:00 +02:00
GL_GetOverviewParms,
2018-03-09 22:00:00 +01:00
CL_GenericHandle,
2019-06-08 23:00:00 +02:00
COM_SaveFile,
2018-02-07 22:00:00 +01:00
NULL,
2013-12-05 21:00:00 +01:00
R_Mem_Alloc,
R_Mem_Free,
pfnGetFilesList,
2018-01-21 22:00:00 +01:00
pfnFileBufferCRC32,
2018-02-07 22:00:00 +01:00
COM_CompareFileTime,
Host_Error,
2018-02-25 22:00:00 +01:00
CL_ModelHandle,
2018-02-05 22:00:00 +01:00
pfnTime,
2018-02-07 22:00:00 +01:00
Cvar_Set,
S_FadeMusicVolume,
COM_SetRandomSeed,
2011-12-04 21:00:00 +01:00
};
/*
===============
R_InitRenderAPI
Initialize client external rendering
===============
*/
qboolean R_InitRenderAPI( void )
{
2013-02-28 21:00:00 +01:00
// make sure what render functions is cleared
2016-11-17 22:00:00 +01:00
memset( &clgame.drawFuncs, 0, sizeof( clgame.drawFuncs ));
2019-06-08 23:00:00 +02:00
glConfig.fCustomRenderer = false;
2013-02-28 21:00:00 +01:00
2011-12-04 21:00:00 +01:00
if( clgame.dllFuncs.pfnGetRenderInterface )
{
if( clgame.dllFuncs.pfnGetRenderInterface( CL_RENDER_INTERFACE_VERSION, &gRenderAPI, &clgame.drawFuncs ))
{
2018-09-28 23:00:00 +02:00
Con_Reportf( "CL_LoadProgs: ^2initailized extended RenderAPI ^7ver. %i\n", CL_RENDER_INTERFACE_VERSION );
2019-06-08 23:00:00 +02:00
glConfig.fCustomRenderer = true;
2011-12-04 21:00:00 +01:00
return true;
}
// make sure what render functions is cleared
2016-11-17 22:00:00 +01:00
memset( &clgame.drawFuncs, 0, sizeof( clgame.drawFuncs ));
2011-12-04 21:00:00 +01:00
return false; // just tell user about problems
}
// render interface is missed
return true;
2010-11-28 22:00:00 +01:00
}