Files
xash3d-fwgs/ref/dx2/r_main.c
2026-07-25 16:30:23 +03:00

353 lines
8.0 KiB
C

/*
r_main.c -- dx2 renderer main loop
Copyright (C) 2010 Uncle Mike
Copyright (C) 2025-2026 lewa_j
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 "r_local.h"
#include "ref_params.h"
#include "xash3d_mathlib.h"
ref_instance_t RI;
static float R_GetFarClip( void )
{
if( tr.worldmodel && FBitSet( RI.rvp.flags, RF_DRAW_WORLD ) )
return gp_movevars->zmax * 1.73f;
return 2048.0f;
}
void R_SetupFrustum( void )
{
// build the transformation matrix for the given view angles
AngleVectors( RI.rvp.viewangles, RI.vforward, RI.vright, RI.vup );
if( !r_lockfrustum.value )
{
VectorCopy( RI.rvp.vieworigin, RI.cullorigin );
VectorCopy( RI.vforward, RI.cull_vforward );
VectorCopy( RI.vright, RI.cull_vright );
VectorCopy( RI.vup, RI.cull_vup );
}
if( FBitSet( RI.rvp.flags, RF_DRAW_OVERVIEW ))
{
const ref_overview_t *ov = gEngfuncs.GetOverviewParms();
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.rvp.fov_x, RI.rvp.fov_y ); // NOTE: we ignore nearplane here (mirrors only)
}
}
static void R_SetupProjectionMatrix( matrix4x4 m )
{
float xMin, xMax, yMin, yMax, zNear, zFar;
if( FBitSet( RI.rvp.flags, RF_DRAW_OVERVIEW ))
{
const ref_overview_t *ov = gEngfuncs.GetOverviewParms();
Matrix4x4_CreateOrtho( m, ov->xLeft, ov->xRight, ov->yTop, ov->yBottom, ov->zNear, ov->zFar );
return;
}
RI.farClip = R_GetFarClip();
zNear = 4.0f;
zFar = Q_max( 256.0f, RI.farClip );
yMax = zNear * tan( RI.rvp.fov_y * M_PI_F / 360.0f );
yMin = -yMax;
xMax = zNear * tan( RI.rvp.fov_x * M_PI_F / 360.0f );
xMin = -xMax;
if( tr.rotation & 1 )
{
Matrix4x4_CreateProjection( m, yMax, yMin, xMax, xMin, zNear, zFar );
}
else
{
Matrix4x4_CreateProjection( m, xMax, xMin, yMax, yMin, zNear, zFar );
}
}
/*
=============
R_SetupModelviewMatrix
=============
*/
static void R_SetupModelviewMatrix( matrix4x4 m )
{
Matrix4x4_CreateModelview( m );
if( tr.rotation & 1 )
{
Matrix4x4_ConcatRotate( m, anglemod( -RI.rvp.viewangles[2] + 90 ), 1, 0, 0 );
Matrix4x4_ConcatRotate( m, -RI.rvp.viewangles[0], 0, 1, 0 );
Matrix4x4_ConcatRotate( m, -RI.rvp.viewangles[1], 0, 0, 1 );
}
else
{
Matrix4x4_ConcatRotate( m, -RI.rvp.viewangles[2], 1, 0, 0 );
Matrix4x4_ConcatRotate( m, -RI.rvp.viewangles[0], 0, 1, 0 );
Matrix4x4_ConcatRotate( m, -RI.rvp.viewangles[1], 0, 0, 1 );
}
Matrix4x4_ConcatTranslate( m, -RI.rvp.vieworigin[0], -RI.rvp.vieworigin[1], -RI.rvp.vieworigin[2] );
}
void R_LoadIdentity( void )
{
if( tr.modelviewIdentity ) return;
Matrix4x4_LoadIdentity( RI.objectMatrix );
Matrix4x4_Copy( RI.modelviewMatrix, RI.worldviewMatrix );
//TODO GL_LoadMatrix( MODELVIEW, RI.modelviewMatrix );
tr.modelviewIdentity = true;
}
void R_GammaChanged( qboolean do_reset_gamma )
{
if( do_reset_gamma )
{
// paranoia cubemap rendering
if( gEngfuncs.drawFuncs->GL_BuildLightmaps )
gEngfuncs.drawFuncs->GL_BuildLightmaps( );
}
else
{
//GL_RebuildLightmaps();
}
}
void R_BeginFrame( qboolean clearScene )
{
gEngfuncs.CL_ExtraUpdate();
}
static void R_DrawEntitiesOnList( void )
{
}
void R_RenderScene( void )
{
if( !tr.worldmodel && FBitSet( RI.rvp.flags, RF_DRAW_WORLD ) )
gEngfuncs.Host_Error("%s: NULL worldmodel\n", __func__);
// frametime is valid only for normal pass
if( !FBitSet( RI.rvp.flags, RF_DRAW_CUBEMAP ))
tr.frametime = gp_cl->time - gp_cl->oldtime;
else tr.frametime = 0.0;
// begin a new frame
tr.framecount++;
tr.dlightframecount = R_PushDlights( tr.worldmodel, tr.framecount );
R_SetupFrustum();
#if 0
R_SetupFrame();
#endif
R_SetupD3D(true);
#if 0
R_Clear(~0);
#endif
R_MarkLeaves();
#if 0
R_DrawFog();
if( FBitSet( RI.rvp.flags, RF_DRAW_WORLD ))
R_AnimateRipples();
R_CheckGLFog();
#endif
R_DrawWorld();
// R_CheckFog();
gEngfuncs.CL_ExtraUpdate(); // don't let sound get messed up if going slow
R_DrawEntitiesOnList();
// R_DrawWaterSurfaces();
}
void R_EndFrame( void )
{
//swap
if (!dxc.window)
return;
if (dxc.pddsBack)
{
RECT dstRect = { 0 };
POINT point = { 0,0 };
ClientToScreen(dxc.window, &point);
GetClientRect(dxc.window, &dstRect);
OffsetRect(&dstRect, point.x, point.y);
RECT srcRect = { 0,0,dxc.windowWidth,dxc.windowHeight };
DXCheck(IDirectDrawSurface_Blt(dxc.pddsPrimary, &dstRect, dxc.pddsBack, &srcRect, DDBLT_WAIT, NULL));
}
//resize
RECT rect = { 0 };
GetClientRect(dxc.window, &rect);
int w = rect.right - rect.left;
int h = rect.bottom - rect.top;
if (w != dxc.windowWidth || h != dxc.windowHeight)
{
D3D_Resize(w, h);
}
}
void R_AllowFog( qboolean allowed )
{
}
static void R_SetupRefParams( const ref_viewpass_t *rvp )
{
RI.rvp = *rvp;
RI.farClip = 0;
}
void R_RenderFrame( const ref_viewpass_t *rvp )
{
if( r_norefresh->value )
return;
// setup the initial render params
R_SetupRefParams( rvp );
// completely override rendering
if( gEngfuncs.drawFuncs->GL_RenderFrame != NULL )
{
tr.fCustomRendering = true;
if( gEngfuncs.drawFuncs->GL_RenderFrame( rvp ))
{
R_GatherPlayerLight( tr.viewent );
tr.realframecount++;
tr.fResetVis = true;
return;
}
}
tr.fCustomRendering = false;
#if 0
if( !FBitSet( RI.rvp.flags, RF_ONLY_CLIENTDRAW ))
R_RunViewmodelEvents();
#endif
tr.realframecount++; // right called after viewmodel events
R_RenderScene();
}
qboolean R_AddEntity( struct cl_entity_s *clent, int type )
{
return true;
}
void R_ClearScene( void )
{
tr.draw_list->num_solid_entities = 0;
tr.draw_list->num_trans_entities = 0;
tr.draw_list->num_beam_entities = 0;
// clear the scene befor start new frame
if (gEngfuncs.drawFuncs->R_ClearScene != NULL)
gEngfuncs.drawFuncs->R_ClearScene();
}
int WorldToScreen( const vec3_t world, vec3_t screen )
{
VectorClear( screen );
return 0;
}
void R_SetupD3D( qboolean set_state )
{
R_SetupModelviewMatrix( RI.worldviewMatrix );
R_SetupProjectionMatrix( RI.projectionMatrix );
Matrix4x4_Concat( RI.worldviewProjectionMatrix, RI.projectionMatrix, RI.worldviewMatrix );
if( !set_state ) return;
D3DVIEWPORT viewport = { 0 };
viewport.dwSize = sizeof(viewport);
if( !FBitSet( RI.rvp.flags, RF_DRAW_CUBEMAP ))
{
int x, x2, y, y2;
// set up viewport (main, playersetup)
x = floor( RI.rvp.viewport[0] * gpGlobals->width / gpGlobals->width );
x2 = ceil( (RI.rvp.viewport[0] + RI.rvp.viewport[2]) * gpGlobals->width / gpGlobals->width );
y = floor( gpGlobals->height - RI.rvp.viewport[1] * gpGlobals->height / gpGlobals->height );
y2 = ceil( gpGlobals->height - (RI.rvp.viewport[1] + RI.rvp.viewport[3]) * gpGlobals->height / gpGlobals->height );
if( tr.rotation & 1 )
{
viewport.dwX = y2;
viewport.dwY = x;
viewport.dwWidth = y - y2;
viewport.dwHeight = x2 - x;
}
else
{
viewport.dwX = x;
viewport.dwY = y2;
viewport.dwWidth = x2 - x;
viewport.dwHeight = y - y2;
}
}
else
{
// envpass, mirrorpass
viewport.dwX = RI.rvp.viewport[0];
viewport.dwY = RI.rvp.viewport[1];
viewport.dwWidth = RI.rvp.viewport[2];
viewport.dwHeight = RI.rvp.viewport[3];
}
viewport.dvScaleX = 0.5f * viewport.dwWidth;
viewport.dvScaleY = 0.5f * viewport.dwHeight;
viewport.dvMaxX = 1;//calc for partial views
viewport.dvMaxY = 1;
viewport.dvMinZ = 0;
viewport.dvMaxZ = 1;
DXCheck(IDirect3DViewport_SetViewport(dxc.viewport, &viewport));
{
float dest[16];
Matrix4x4_ToArrayFloatGL(RI.projectionMatrix, dest);
DXCheck(IDirect3DDevice_SetMatrix(dxc.pd3dd, dxc.mtxProjection, (D3DMATRIX *)&dest));
Matrix4x4_ToArrayFloatGL(RI.worldviewMatrix, dest);
DXCheck(IDirect3DDevice_SetMatrix(dxc.pd3dd, dxc.mtxWorld, (D3DMATRIX *)&dest));
}
}