xash3d-fwgs/engine/client/cl_view.c
Gleb Mazovetskiy 5e0a0765ce Trim all trailing whitespace
The `.editorconfig` file in this repo is configured to trim all trailing
whitespace regardless of whether the line is modified.

Trims all trailing whitespace in the repository to make the codebase easier
to work with in editors that respect `.editorconfig`.

`git blame` becomes less useful on these lines but it already isn't very useful.

Commands:

```
find . -type f -name '*.h' -exec sed --in-place 's/[[:space:]]\+$//' {} \+
find . -type f -name '*.c' -exec sed --in-place 's/[[:space:]]\+$//' {} \+
```
2021-01-04 20:55:10 +03:00

498 lines
12 KiB
C

/*
cl_view.c - player rendering positioning
Copyright (C) 2009 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.
*/
#include "common.h"
#include "client.h"
#include "const.h"
#include "entity_types.h"
#include "vgui_draw.h"
#include "sound.h"
#include "input.h" // touch
#include "platform/platform.h" // GL_UpdateSwapInterval
/*
===============
V_CalcViewRect
calc frame rectangle (Quake1 style)
===============
*/
void V_CalcViewRect( void )
{
qboolean full = false;
int sb_lines;
float size;
// intermission is always full screen
if( cl.intermission ) size = 120.0f;
else size = scr_viewsize->value;
if( size >= 120.0f )
sb_lines = 0; // no status bar at all
else if( size >= 110.0f )
sb_lines = 24; // no inventory
else sb_lines = 48;
if( scr_viewsize->value >= 100.0f )
{
full = true;
size = 100.0f;
}
else size = scr_viewsize->value;
if( cl.intermission )
{
size = 100.0f;
sb_lines = 0;
full = true;
}
size /= 100.0f;
clgame.viewport[2] = refState.width * size;
clgame.viewport[3] = refState.height * size;
if( clgame.viewport[3] > refState.height - sb_lines )
clgame.viewport[3] = refState.height - sb_lines;
if( clgame.viewport[3] > refState.height )
clgame.viewport[3] = refState.height;
clgame.viewport[0] = ( refState.width - clgame.viewport[2] ) / 2;
if( full ) clgame.viewport[1] = 0;
else clgame.viewport[1] = ( refState.height - sb_lines - clgame.viewport[3] ) / 2;
}
/*
===============
V_SetupViewModel
===============
*/
void V_SetupViewModel( void )
{
cl_entity_t *view = &clgame.viewent;
player_info_t *info = &cl.players[cl.playernum];
if( !cl.local.weaponstarttime )
cl.local.weaponstarttime = cl.time;
// setup the viewent variables
view->curstate.colormap = (info->topcolor & 0xFFFF)|((info->bottomcolor << 8) & 0xFFFF);
view->curstate.number = cl.playernum + 1;
view->index = cl.playernum + 1;
view->model = CL_ModelHandle( cl.local.viewmodel );
view->curstate.modelindex = cl.local.viewmodel;
view->curstate.sequence = cl.local.weaponsequence;
view->curstate.rendermode = kRenderNormal;
// alias models has another animation methods
if( view->model && view->model->type == mod_studio )
{
view->curstate.animtime = cl.local.weaponstarttime;
view->curstate.frame = 0.0f;
}
}
/*
===============
V_SetRefParams
===============
*/
void V_SetRefParams( ref_params_t *fd )
{
memset( fd, 0, sizeof( ref_params_t ));
// probably this is not needs
VectorCopy( refState.vieworg, fd->vieworg );
VectorCopy( refState.viewangles, fd->viewangles );
fd->frametime = host.frametime;
fd->time = cl.time;
fd->intermission = cl.intermission;
fd->paused = (cl.paused != 0);
fd->spectator = (cls.spectator != 0);
fd->onground = (cl.local.onground != -1);
fd->waterlevel = cl.local.waterlevel;
VectorCopy( cl.simvel, fd->simvel );
VectorCopy( cl.simorg, fd->simorg );
VectorCopy( cl.viewheight, fd->viewheight );
fd->idealpitch = cl.local.idealpitch;
VectorCopy( cl.viewangles, fd->cl_viewangles );
fd->health = cl.local.health;
VectorCopy( cl.crosshairangle, fd->crosshairangle );
fd->viewsize = scr_viewsize->value;
VectorCopy( cl.punchangle, fd->punchangle );
fd->maxclients = cl.maxclients;
fd->viewentity = cl.viewentity;
fd->playernum = cl.playernum;
fd->max_entities = clgame.maxEntities;
fd->demoplayback = cls.demoplayback;
fd->hardware = 1; // OpenGL
if( cl.first_frame || cl.skip_interp )
{
cl.first_frame = false; // now can be unlocked
fd->smoothing = true; // NOTE: currently this used to prevent ugly un-duck effect while level is changed
}
else fd->smoothing = cl.local.pushmsec; // enable smoothing in multiplayer by server request (AMX uses)
// get pointers to movement vars and user cmd
fd->movevars = &clgame.movevars;
fd->cmd = cl.cmd;
// setup viewport
fd->viewport[0] = clgame.viewport[0];
fd->viewport[1] = clgame.viewport[1];
fd->viewport[2] = clgame.viewport[2];
fd->viewport[3] = clgame.viewport[3];
fd->onlyClientDraw = 0; // reset clientdraw
fd->nextView = 0; // reset nextview
}
/*
===============
V_MergeOverviewRefdef
merge refdef with overview settings
===============
*/
void V_RefApplyOverview( ref_viewpass_t *rvp )
{
ref_overview_t *ov = &clgame.overView;
float aspect;
float size_x, size_y;
vec2_t mins, maxs;
if( !CL_IsDevOverviewMode( ))
return;
// NOTE: Xash3D may use 16:9 or 16:10 aspects
aspect = (float)refState.width / (float)refState.height;
size_x = fabs( 8192.0f / ov->flZoom );
size_y = fabs( 8192.0f / (ov->flZoom * aspect ));
// compute rectangle
ov->xLeft = -(size_x / 2);
ov->xRight = (size_x / 2);
ov->yTop = -(size_y / 2);
ov->yBottom = (size_y / 2);
if( CL_IsDevOverviewMode() == 1 )
{
Con_NPrintf( 0, " Overview: Zoom %.2f, Map Origin (%.2f, %.2f, %.2f), Z Min %.2f, Z Max %.2f, Rotated %i\n",
ov->flZoom, ov->origin[0], ov->origin[1], ov->origin[2], ov->zNear, ov->zFar, ov->rotated );
}
VectorCopy( ov->origin, rvp->vieworigin );
rvp->vieworigin[2] = ov->zFar + ov->zNear;
Vector2Copy( rvp->vieworigin, mins );
Vector2Copy( rvp->vieworigin, maxs );
mins[!ov->rotated] += ov->xLeft;
maxs[!ov->rotated] += ov->xRight;
mins[ov->rotated] += ov->yTop;
maxs[ov->rotated] += ov->yBottom;
rvp->viewangles[0] = 90.0f;
rvp->viewangles[1] = 90.0f;
rvp->viewangles[2] = (ov->rotated) ? (ov->flZoom < 0.0f) ? 180.0f : 0.0f : (ov->flZoom < 0.0f) ? -90.0f : 90.0f;
SetBits( rvp->flags, RF_DRAW_OVERVIEW );
ref.dllFuncs.GL_OrthoBounds( mins, maxs );
}
/*
=============
V_GetRefParams
=============
*/
void V_GetRefParams( ref_params_t *fd, ref_viewpass_t *rvp )
{
// part1: deniable updates
VectorCopy( fd->simvel, cl.simvel );
VectorCopy( fd->simorg, cl.simorg );
VectorCopy( fd->punchangle, cl.punchangle );
VectorCopy( fd->viewheight, cl.viewheight );
// part2: really used updates
VectorCopy( fd->crosshairangle, cl.crosshairangle );
VectorCopy( fd->cl_viewangles, cl.viewangles );
// setup ref_viewpass
rvp->viewport[0] = fd->viewport[0];
rvp->viewport[1] = fd->viewport[1];
rvp->viewport[2] = fd->viewport[2];
rvp->viewport[3] = fd->viewport[3];
VectorCopy( fd->vieworg, rvp->vieworigin );
VectorCopy( fd->viewangles, rvp->viewangles );
rvp->viewentity = fd->viewentity;
// calc FOV
rvp->fov_x = bound( 10.0f, cl.local.scr_fov, 150.0f ); // this is a final fov value
// first we need to compute FOV and other things that needs for frustum properly work
rvp->fov_y = V_CalcFov( &rvp->fov_x, clgame.viewport[2], clgame.viewport[3] );
// adjust FOV for widescreen
if( refState.wideScreen && r_adjust_fov->value )
V_AdjustFov( &rvp->fov_x, &rvp->fov_y, clgame.viewport[2], clgame.viewport[3], false );
rvp->flags = 0;
if( fd->onlyClientDraw )
SetBits( rvp->flags, RF_ONLY_CLIENTDRAW );
SetBits( rvp->flags, RF_DRAW_WORLD );
}
/*
==================
V_PreRender
==================
*/
qboolean V_PreRender( void )
{
// too early
if( !ref.initialized )
return false;
if( host.status == HOST_NOFOCUS )
return false;
if( host.status == HOST_SLEEP )
return false;
// if the screen is disabled (loading plaque is up)
if( cls.disable_screen )
{
if(( host.realtime - cls.disable_screen ) > cl_timeout->value )
{
Con_Reportf( "V_PreRender: loading plaque timed out\n" );
cls.disable_screen = 0.0f;
}
return false;
}
ref.dllFuncs.R_BeginFrame( !cl.paused && ( cls.state == ca_active ));
GL_UpdateSwapInterval( );
return true;
}
//============================================================================
/*
==================
V_RenderView
==================
*/
void V_RenderView( void )
{
ref_params_t rp;
ref_viewpass_t rvp;
int viewnum = 0;
if( !cl.video_prepped || ( !ui_renderworld->value && UI_IsVisible() && !cl.background ))
return; // still loading
V_CalcViewRect (); // compute viewport rectangle
V_SetRefParams( &rp );
V_SetupViewModel ();
ref.dllFuncs.R_Set2DMode( false );
SCR_DirtyScreen();
ref.dllFuncs.GL_BackendStartFrame ();
do
{
clgame.dllFuncs.pfnCalcRefdef( &rp );
V_GetRefParams( &rp, &rvp );
V_RefApplyOverview( &rvp );
if( viewnum == 0 && FBitSet( rvp.flags, RF_ONLY_CLIENTDRAW ))
{
ref.dllFuncs.R_ClearScreen();
}
GL_RenderFrame( &rvp );
S_UpdateFrame( &rvp );
viewnum++;
} while( rp.nextView );
// draw debug triangles on a server
SV_DrawDebugTriangles ();
ref.dllFuncs.GL_BackendEndFrame ();
}
#define POINT_SIZE 16.0f
#define NODE_INTERVAL_X(x) (x * 16.0f)
#define NODE_INTERVAL_Y(x) (x * 16.0f)
void R_DrawLeafNode( float x, float y, float scale )
{
float downScale = scale * 0.25f;// * POINT_SIZE;
ref.dllFuncs.R_DrawStretchPic( x - downScale * 0.5f, y - downScale * 0.5f, downScale, downScale, 0, 0, 1, 1, R_GetBuiltinTexture( REF_PARTICLE_TEXTURE ) );
}
void R_DrawNodeConnection( float x, float y, float x2, float y2 )
{
ref.dllFuncs.Begin( TRI_LINES );
ref.dllFuncs.Vertex3f( x, y, 0 );
ref.dllFuncs.Vertex3f( x2, y2, 0 );
ref.dllFuncs.End( );
}
void R_ShowTree_r( mnode_t *node, float x, float y, float scale, int shownodes, mleaf_t *viewleaf )
{
float downScale = scale * 0.8f;
downScale = Q_max( downScale, 1.0f );
if( !node ) return;
world.recursion_level++;
if( node->contents < 0 )
{
mleaf_t *leaf = (mleaf_t *)node;
if( world.recursion_level > world.max_recursion )
world.max_recursion = world.recursion_level;
if( shownodes == 1 )
{
if( cl.worldmodel->leafs == leaf )
ref.dllFuncs.Color4f( 1.0f, 1.0f, 1.0f, 1.0f );
else if( viewleaf && viewleaf == leaf )
ref.dllFuncs.Color4f( 1.0f, 0.0f, 0.0f, 1.0f );
else ref.dllFuncs.Color4f( 0.0f, 1.0f, 0.0f, 1.0f );
R_DrawLeafNode( x, y, scale );
}
world.recursion_level--;
return;
}
if( shownodes == 1 )
{
ref.dllFuncs.Color4f( 0.0f, 0.0f, 1.0f, 1.0f );
R_DrawLeafNode( x, y, scale );
}
else if( shownodes == 2 )
{
R_DrawNodeConnection( x, y, x - scale, y + scale );
R_DrawNodeConnection( x, y, x + scale, y + scale );
}
R_ShowTree_r( node->children[1], x - scale, y + scale, downScale, shownodes, viewleaf );
R_ShowTree_r( node->children[0], x + scale, y + scale, downScale, shownodes, viewleaf );
world.recursion_level--;
}
void R_ShowTree( void )
{
float x = (float)((refState.width - (int)POINT_SIZE) >> 1);
float y = NODE_INTERVAL_Y(1.0f);
mleaf_t *viewleaf;
if( !cl.worldmodel || !CVAR_TO_BOOL( r_showtree ))
return;
world.recursion_level = 0;
viewleaf = Mod_PointInLeaf( refState.vieworg, cl.worldmodel->nodes );
//pglEnable( GL_BLEND );
//pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
//pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
//pglLineWidth( 2.0f );
ref.dllFuncs.Color4f( 1, 0.7f, 0, 1.0f );
//pglDisable( GL_TEXTURE_2D );
R_ShowTree_r( cl.worldmodel->nodes, x, y, world.max_recursion * 3.5f, 2, viewleaf );
//pglEnable( GL_TEXTURE_2D );
//pglLineWidth( 1.0f );
R_ShowTree_r( cl.worldmodel->nodes, x, y, world.max_recursion * 3.5f, 1, viewleaf );
Con_NPrintf( 0, "max recursion %d\n", world.max_recursion );
}
/*
==================
V_PostRender
==================
*/
void V_PostRender( void )
{
static double oldtime;
qboolean draw_2d = false;
ref.dllFuncs.R_AllowFog( false );
ref.dllFuncs.R_Set2DMode( true );
if( cls.state == ca_active && cls.signon == SIGNONS && cls.scrshot_action != scrshot_mapshot )
{
SCR_TileClear();
CL_DrawHUD( CL_ACTIVE );
VGui_Paint();
}
switch( cls.scrshot_action )
{
case scrshot_inactive:
case scrshot_normal:
case scrshot_snapshot:
draw_2d = true;
break;
}
if( draw_2d )
{
SCR_RSpeeds();
SCR_NetSpeeds();
SCR_DrawNetGraph();
SV_DrawOrthoTriangles();
CL_DrawDemoRecording();
CL_DrawHUD( CL_CHANGELEVEL );
ref.dllFuncs.R_ShowTextures();
R_ShowTree();
Con_DrawConsole();
UI_UpdateMenu( host.realtime );
Con_DrawVersion();
Con_DrawDebug(); // must be last
Touch_Draw();
OSK_Draw();
S_ExtraUpdate();
}
SCR_MakeScreenShot();
ref.dllFuncs.R_AllowFog( true );
ref.dllFuncs.R_EndFrame();
}