This commit is contained in:
nephacks
2025-06-04 03:22:50 +02:00
parent f234f23848
commit f12416cffd
14243 changed files with 6446499 additions and 26 deletions

View File

@@ -0,0 +1,52 @@
// ----------------------------------------- //
// File generated by VPC //
// ----------------------------------------- //
Source file: F:\csgo_64\cstrike15_src\common\debug_lib_check.cpp
Debug output file: F:\csgo_64\cstrike15_src\common\debug_lib_check.cpp
Release output file: F:\csgo_64\cstrike15_src\common\debug_lib_check.cpp
Containing unity file:
PCH file:
Source file: F:\csgo_64\cstrike15_src\fow\fow.cpp
Debug output file: F:\csgo_64\cstrike15_src\fow\fow.cpp
Release output file: F:\csgo_64\cstrike15_src\fow\fow.cpp
Containing unity file:
PCH file:
Source file: F:\csgo_64\cstrike15_src\fow\fow_2dplane.cpp
Debug output file: F:\csgo_64\cstrike15_src\fow\fow_2dplane.cpp
Release output file: F:\csgo_64\cstrike15_src\fow\fow_2dplane.cpp
Containing unity file:
PCH file:
Source file: F:\csgo_64\cstrike15_src\fow\fow_horizontalslice.cpp
Debug output file: F:\csgo_64\cstrike15_src\fow\fow_horizontalslice.cpp
Release output file: F:\csgo_64\cstrike15_src\fow\fow_horizontalslice.cpp
Containing unity file:
PCH file:
Source file: F:\csgo_64\cstrike15_src\fow\fow_lineoccluder.cpp
Debug output file: F:\csgo_64\cstrike15_src\fow\fow_lineoccluder.cpp
Release output file: F:\csgo_64\cstrike15_src\fow\fow_lineoccluder.cpp
Containing unity file:
PCH file:
Source file: F:\csgo_64\cstrike15_src\fow\fow_radiusoccluder.cpp
Debug output file: F:\csgo_64\cstrike15_src\fow\fow_radiusoccluder.cpp
Release output file: F:\csgo_64\cstrike15_src\fow\fow_radiusoccluder.cpp
Containing unity file:
PCH file:
Source file: F:\csgo_64\cstrike15_src\fow\fow_trisoup.cpp
Debug output file: F:\csgo_64\cstrike15_src\fow\fow_trisoup.cpp
Release output file: F:\csgo_64\cstrike15_src\fow\fow_trisoup.cpp
Containing unity file:
PCH file:
Source file: F:\csgo_64\cstrike15_src\fow\fow_viewer.cpp
Debug output file: F:\csgo_64\cstrike15_src\fow\fow_viewer.cpp
Release output file: F:\csgo_64\cstrike15_src\fow\fow_viewer.cpp
Containing unity file:
PCH file:

1773
fow/fow.cpp Normal file

File diff suppressed because it is too large Load Diff

43
fow/fow.vpc Normal file
View File

@@ -0,0 +1,43 @@
//-----------------------------------------------------------------------------
// FOW.VPC
//
// Project Script
//-----------------------------------------------------------------------------
$Macro SRCDIR ".."
$Macro OUTLIBDIR "$SRCDIR\lib\public"
$Include "$SRCDIR\vpc_scripts\source_lib_base.vpc"
$Configuration
{
$Compiler
{
$AdditionalIncludeDirectories "$BASE,$SRCDIR\utils\common,$SRCDIR\public\fow"
}
}
$Project "FoWLib"
{
$Folder "Source Files"
{
$File "fow.cpp"
$File "fow_2dplane.cpp"
$File "fow_horizontalslice.cpp"
$File "fow_lineoccluder.cpp"
$File "fow_radiusoccluder.cpp"
$File "fow_trisoup.cpp"
$File "fow_viewer.cpp"
}
$Folder "Header Files"
{
$File "..\public\fow\fow.h"
$File "fow_2dplane.h"
$File "fow_horizontalslice.h"
$File "fow_lineoccluder.h"
$File "fow_radiusoccluder.h"
$File "fow_trisoup.h"
$File "fow_viewer.h"
}
}

13
fow/fow.vpc.vpc_cache Normal file
View File

@@ -0,0 +1,13 @@
"vpc_cache"
{
"CacheVersion" "1"
"win32"
{
"CRCFile" "fow.vcxproj.vpc_crc"
"OutputFiles"
{
"0" "fow.vcxproj"
"1" "fow.vcxproj.filters"
}
}
}

156
fow/fow_2dplane.cpp Normal file
View File

@@ -0,0 +1,156 @@
#include "fow_2dplane.h"
#include "mathlib/vector.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
//-----------------------------------------------------------------------------
// Purpose: construct the plane from the given line segment
// Input : bx - starting x coord
// by - starting y coord
// ex - ending x coord
// ey - ending y coord
//-----------------------------------------------------------------------------
CFOW_2DPlane::CFOW_2DPlane( float bx, float by, float ex, float ey )
{
Init( bx, by, ex, ey );
}
//-----------------------------------------------------------------------------
// Purpose: construct the plane from the given point and normal
// Input : x - point on plane
// y - point on plane
// vNormal - normal of the plane
//-----------------------------------------------------------------------------
CFOW_2DPlane::CFOW_2DPlane( float x, float y, Vector2D &vNormal )
{
Init( x, y, vNormal );
}
//-----------------------------------------------------------------------------
// Purpose: construct the plane from the given distance and normal
// Input : flDistance - distance for the plane
// vNormal - normal of the plane
//-----------------------------------------------------------------------------
CFOW_2DPlane::CFOW_2DPlane( float flDistance, Vector2D &vNormal )
{
m_flDistance = flDistance;
m_vNormal = vNormal;
}
//-----------------------------------------------------------------------------
// Purpose: init routine to generate the plane from the given line segment
// Input : bx - starting x coord
// by - starting y coord
// ex - ending x coord
// ey - ending y coord
//-----------------------------------------------------------------------------
void CFOW_2DPlane::Init( float bx, float by, float ex, float ey )
{
float nx = ( ex - bx );
float ny = ( ey - by );
float flLen = ( float )sqrt( nx * nx + ny * ny );
Vector2D vNormal;
nx /= flLen;
ny /= flLen;
vNormal.x = ny;
vNormal.y = -nx;
Init( bx, by, vNormal );
}
//-----------------------------------------------------------------------------
// Purpose: init routine to generate the plane from the given point and normal
// Input : x - point on plane
// y - point on plane
// vNormal - normal of the plane
//-----------------------------------------------------------------------------
void CFOW_2DPlane::Init( float x, float y, Vector2D &vNormal )
{
m_vNormal = vNormal;
m_flDistance = ( x * m_vNormal.x + y * m_vNormal.y );
}
//-----------------------------------------------------------------------------
// Purpose: returns true if the point is in front of the plane
// Input : px - point to check
// py - point to check
// Output : returns true if the point is in front of the plane
//-----------------------------------------------------------------------------
bool CFOW_2DPlane::PointInFront( float px, float py )
{
return ( DistanceFrom( px, py ) >= 0.0f );
}
//-----------------------------------------------------------------------------
// Purpose: returns the distance the point is from the plane
// Input : px - point to check
// py - point to check
// Output : returns the distance the point is from the plane
//-----------------------------------------------------------------------------
float CFOW_2DPlane::DistanceFrom( float px, float py )
{
float d = ( px * m_vNormal.x + py * m_vNormal.y );
return d - m_flDistance;
}
//-----------------------------------------------------------------------------
// Purpose: finds the fraction from the starting point towards the normal along the line formed with ending point
// Input : bx - starting x coord of the line segment
// by - starting y coord of the line segment
// ex - ending x coord of the line segment
// ey - ending y coord of the line segment
// Output : returns the distance along the line segment the plane from the starting coord
//-----------------------------------------------------------------------------
float CFOW_2DPlane::DistanceFromLineStart( float bx, float by, float ex, float ey )
{
Vector2D vPointA( bx, by );
Vector2D vPointB( ex, ey );
Vector2D vDiff( vPointB - vPointA );
Vector2D vNormal = vDiff;
float flLen = ( float )sqrt( vDiff.x * vDiff.x + vDiff.y * vDiff.y );
vNormal /= flLen;
float t = -( m_vNormal.Dot( vPointA ) - m_flDistance ) / m_vNormal.Dot( vNormal );
return t;
}
//-----------------------------------------------------------------------------
// Purpose: finds the fraction from the starting point towards the normal along the line formed with ending point
// Input : bx - starting x coord of the line segment
// by - starting y coord of the line segment
// ex - ending x coord of the line segment
// ey - ending y coord of the line segment
// Output : returns the distance along the line segment the plane from the starting coord
//-----------------------------------------------------------------------------
float CFOW_2DPlane::DistanceFromRay( float bx, float by, float dx, float dy )
{
Vector2D vPointA( bx, by );
Vector2D vNormal( dx, dy );
float flNormalDiff = m_vNormal.Dot( vNormal );
if ( flNormalDiff == 0.0f )
{
return 0.0f;
}
float t = -( m_vNormal.Dot( vPointA ) - m_flDistance ) / flNormalDiff;
return t;
}
#include <tier0/memdbgoff.h>

53
fow/fow_2dplane.h Normal file
View File

@@ -0,0 +1,53 @@
//========= Copyright © 1996-2009, Valve Corporation, All rights reserved. ============//
//
// Purpose: 2d plane routines for Fog of War
//
// $NoKeywords: $
//=====================================================================================//
#ifndef FOW_2DPLANE_H
#define FOW_2DPLANE_H
#if defined( COMPILER_MSVC )
#pragma once
#endif
#include "mathlib/vector.h"
class CFOW_2DPlane
{
public:
CFOW_2DPlane( void ) { }
// construct the plane from the given line segment
CFOW_2DPlane( float bx, float by, float ex, float ey );
// construct the plane from the given point and normal
CFOW_2DPlane( float x, float y, Vector2D &vNormal );
CFOW_2DPlane( float flDistance, Vector2D &vNormal );
// init routine to generate the plane from the given line segment
void Init( float bx, float by, float ex, float ey );
// init routine to generate the plane from the given point and normal
void Init( float x, float y, Vector2D &vNormal );
// returns the normal of the plane
inline Vector2D &GetNormal( void ) { return m_vNormal; }
//
inline float GetDistance( ) { return m_flDistance; }
// returns true if the point is in front of the plane
bool PointInFront( float px, float py );
// returns the distance the point is from the plane
float DistanceFrom( float px, float py );
// finds the fraction from the starting point towards the normal along the line formed with ending point
float DistanceFromLineStart( float bx, float by, float ex, float ey );
// finds the fraction from the starting point towards the normal along the line formed with ending point
float DistanceFromRay( float bx, float by, float dx, float dy );
private:
Vector2D m_vNormal; // the normal of the plane
float m_flDistance; // the plane distance
};
#endif // FOW_2DPLANE_H

107
fow/fow_horizontalslice.cpp Normal file
View File

@@ -0,0 +1,107 @@
#include "fow.h"
#include "fow_horizontalslice.h"
#include "fow_viewer.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
//-----------------------------------------------------------------------------
// Purpose: empty constructor
//-----------------------------------------------------------------------------
CFoW_HorizontalSlice::CFoW_HorizontalSlice( void )
{
}
//-----------------------------------------------------------------------------
// Purpose: clears the sphere tree of all line occluders
//-----------------------------------------------------------------------------
void CFoW_HorizontalSlice::Clear( void )
{
m_SphereTree.Purge();
}
//-----------------------------------------------------------------------------
// Purpose: adds a line occluder to the sphere tree
// Input : pLineOccluder - the occluder to add
//-----------------------------------------------------------------------------
void CFoW_HorizontalSlice::AddHorizontalOccluder( CFoW_LineOccluder *pLineOccluder )
{
Vector2D start = pLineOccluder->GetStart();
Vector2D end = pLineOccluder->GetEnd();
Vector2D diff = ( end - start );
Sphere_t bounds;
bounds.x = ( start.x + end.x ) / 2.0f;
bounds.y = ( start.y + end.y ) / 2.0f;
bounds.z = 0.0f;
bounds.w = sqrt( ( diff.x * diff.x ) + ( diff.y * diff.y ) );
m_SphereTree.Insert( (void *)pLineOccluder, &bounds );
#if 0
Sphere_t TestSphere( -320, -1088, 0.0f, 592.77820 );
Vector vDiff = TestSphere.AsVector3D() - bounds.AsVector3D();
float flLen = vDiff.Length();
if ( flLen <= ( bounds.w + TestSphere.w ) )
{
Msg( "here" );
CFoW_LineOccluder *FixedPointerArray[ FOW_MAX_LINE_OCCLUDERS_TO_CHECK ];
CUtlVector< void * > FoundOccluders( ( void ** )FixedPointerArray, FOW_MAX_LINE_OCCLUDERS_TO_CHECK );
int RealCount = m_SphereTree.IntersectWithSphere( TestSphere, true, FoundOccluders, FOW_MAX_LINE_OCCLUDERS_TO_CHECK );
bool bFound = false;
for ( int i = 0; i < FoundOccluders.Count(); i++ )
{
if ( FixedPointerArray[ i ] == pLineOccluder )
{
bFound = true;
}
}
if ( bFound == true )
{
Msg( "We found it!\n" );
}
else
{
Msg( "WE LOST IT!!!?" );
}
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose: tests the viewer against all line occluders that are near the viewer
// Input : pFoW - the main FoW object
// pViewer - the viewer to obstruct
//-----------------------------------------------------------------------------
void CFoW_HorizontalSlice::ObstructViewer( CFoW *pFoW, CFoW_Viewer *pViewer )
{
Sphere_t TestSphere( pViewer->GetLocation().x, pViewer->GetLocation().y, 0.0f, pViewer->GetSize() );
CFoW_LineOccluder *FixedPointerArray[ FOW_MAX_LINE_OCCLUDERS_TO_CHECK ];
CUtlVector< void * > FoundOccluders( ( void ** )FixedPointerArray, FOW_MAX_LINE_OCCLUDERS_TO_CHECK );
int RealCount = m_SphereTree.IntersectWithSphere( TestSphere, true, FoundOccluders, FOW_MAX_LINE_OCCLUDERS_TO_CHECK );
if ( RealCount > FOW_MAX_LINE_OCCLUDERS_TO_CHECK )
{
// we overflowed, what should we do?
}
// Msg( "Slice Counts: %d / %d\n", FoundOccluders.Count(), RealCount );
for ( int i = 0; i < FoundOccluders.Count(); i++ )
{
FixedPointerArray[ i ]->ObstructViewer( pFoW, pViewer );
}
}
#include <tier0/memdbgoff.h>

39
fow/fow_horizontalslice.h Normal file
View File

@@ -0,0 +1,39 @@
//========= Copyright © 1996-2009, Valve Corporation, All rights reserved. ============//
//
// Purpose: used to cross section maps ( i.e. displacements ) to do fast occlusion against
//
// $NoKeywords: $
//=====================================================================================//
#ifndef FOW_HORIZONTALSLICE_H
#define FOW_HORIZONTALSLICE_H
#if defined( COMPILER_MSVC )
#pragma once
#endif
#include "utlvector.h"
#include "utlspheretree.h"
#include "mathlib/vector.h"
#include "fow_lineoccluder.h"
class CFoW;
class CFoW_Viewer;
class CFoW_HorizontalSlice
{
public:
CFoW_HorizontalSlice( void );
// clears the sphere tree of all line occluders
void Clear( void );
// adds a line occluder to the sphere tree
void AddHorizontalOccluder( CFoW_LineOccluder *pLineOccluder );
// tests the viewer against all line occluders that are near the viewer
void ObstructViewer( CFoW *pFoW, CFoW_Viewer *pViewer );
private:
CUtlSphereTree m_SphereTree; // spherical tree to quickly find line occulders near a given point
};
#endif // FOW_HORIZONTALSLICE_H

238
fow/fow_lineoccluder.cpp Normal file
View File

@@ -0,0 +1,238 @@
#include "fow.h"
#include "fow_lineoccluder.h"
#include "fow_viewer.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
//-----------------------------------------------------------------------------
// Purpose: construct a line accluder from the given points. the normal is supplied, though if it doesn't match up with the points, then the points are swapped.
// Input : bx - starting x coord
// by - starting y coord
// ex - ending x coord
// ey - ending y coord
// vNormal - the normal coming from a pre-existing plane from which the line was formed
// nSlinceNum - the slice this occluder belongs to
//-----------------------------------------------------------------------------
CFoW_LineOccluder::CFoW_LineOccluder( float bx, float by, float ex, float ey, Vector2D &vNormal, int nSliceNum )
{
m_vStart.Init( bx, by );
m_vEnd.Init( ex, ey );
m_Plane.Init( bx, by, ex, ey );
if ( fabs( m_Plane.GetNormal().x - vNormal.x ) < 0.1f && fabs( m_Plane.GetNormal().y - vNormal.y ) < 0.1f )
{
m_vStart.Init( ex, ey );
m_vEnd.Init( bx, by );
m_Plane.Init( ex, ey, bx, by );
}
m_nSliceNum = nSliceNum;
}
CFoW_LineOccluder::CFoW_LineOccluder( Vector2D &vStart, Vector2D &vEnd, CFOW_2DPlane &Plane, int nSliceNum )
{
m_vStart = vStart;
m_vEnd = vEnd;
m_Plane = Plane;
m_nSliceNum = nSliceNum;
}
// #define SLOW_PATH 1
//-----------------------------------------------------------------------------
// Purpose: determine the occlusion of this line for the viewer
// Input : pFoW - the main FoW object
// pViewer - the viewer to obstruct
//-----------------------------------------------------------------------------
void CFoW_LineOccluder::ObstructViewer( CFoW *pFoW, CFoW_Viewer *pViewer )
{
int nUnits = pViewer->GetRadiusUnits();
int *pVisibility = pViewer->GetVisibilityRadius();
Vector vCenterLocation = pViewer->GetRealLocation(); // we don't want to use the grid centered location, as the z is not centered
float distance = m_Plane.DistanceFrom( vCenterLocation.x, vCenterLocation.y );
if ( distance < 0.0f )
{
return;
}
#ifdef SLOW_PATH
float flDegreeAmount = 360.0 / pViewer->GetRadiusUnits();
CFOW_2DPlane Edge1, Edge2;
Edge1.Init( vCenterLocation.x, vCenterLocation.y, m_vStart.x, m_vStart.y );
Edge2.Init( m_vEnd.x, m_vEnd.y, vCenterLocation.x, vCenterLocation.y );
float flCurrentDegree = 0.0f;
for ( int i = 0; i < nUnits; i++, flCurrentDegree += flDegreeAmount )
{
Vector Location = pViewer->GetLocation();
Location.x += cos( DEG2RAD( flCurrentDegree ) ) * pViewer->GetSize();
Location.y += sin( DEG2RAD( flCurrentDegree ) ) * pViewer->GetSize();
float flDistance = m_Plane.DistanceFromLineStart( vCenterLocation.x, vCenterLocation.y, Location.x, Location.y );
// flDistance *= pViewer->GetSize();
if ( flDistance >= 0.0f )
{
// distance += Viewer->GetSize();
flDistance *= flDistance;
if ( flDistance >= 0.0f && flDistance < pVisibility[ i ] )
{
if ( Edge1.PointInFront( Location.x, Location.y ) && Edge2.PointInFront( Location.x, Location.y ) )
{
pVisibility[ i ] = flDistance;
}
}
}
}
#else
const Vector2D vStraight( 0.0f, 1.0f );
Vector2D P1( m_vStart.x - vCenterLocation.x, m_vStart.y - vCenterLocation.y );
P1.NormalizeInPlace();
Vector2D P2( m_vEnd.x - vCenterLocation.x, m_vEnd.y - vCenterLocation.y );
P2.NormalizeInPlace();
#if 0
float flCurrentDegree = 0.0f;
for ( int i = 0; i < nUnits; i++, flCurrentDegree += flDegreeAmount )
{
Vector Location = pViewer->GetLocation();
Location.x += cos( DEG2RAD( flCurrentDegree ) ) * pViewer->GetSize();
Location.y += sin( DEG2RAD( flCurrentDegree ) ) * pViewer->GetSize();
float flDistance = m_Plane.DistanceFromLineStart( vCenterLocation.x, vCenterLocation.y, Location.x, Location.y );
// flDistance *= pViewer->GetSize();
if ( flDistance >= 0.0f )
{
// distance += Viewer->GetSize();
flDistance *= flDistance;
if ( flDistance >= 0.0f && flDistance < pVisibility[ i ] )
{
if ( Edge1.PointInFront( Location.x, Location.y ) && Edge2.PointInFront( Location.x, Location.y ) )
{
pVisibility[ i ] = flDistance;
}
}
}
}
#endif
if ( fabs( P1.Dot( P2 ) ) > 0.99995f )
{
return;
}
float flDot1 = vStraight.Dot( P1 );
float flPos = acos( flDot1 );
if ( P1.x < 0.0f )
{
flPos = 2.0f * M_PI_F - flPos;
}
float flDot2 = vStraight.Dot( P2 );
float flNeg = acos( flDot2 );
if ( P2.x < 0.0f )
{
flNeg = 2.0f * M_PI_F - flNeg;
}
if ( fabs( flPos - flNeg ) > M_PI_F )
{
if ( flPos < flNeg )
{
flPos += M_PI_F * 2.0f;
}
else
{
flNeg += M_PI_F * 2.0f;
}
}
// float flAng1 = RAD2DEG( flPos );
// float flAng2 = RAD2DEG( flNeg );
float flCurrentDegree, flFinishDegree;
int nStartIndex;
if ( flPos < flNeg )
{
flCurrentDegree = flPos;
flFinishDegree = flNeg;
}
else
{
flCurrentDegree = flNeg;
flFinishDegree = flPos;
}
/* if ( ( flFinishDegree - flCurrentDegree ) > M_PI_F )
{
float flTemp = flCurrentDegree;
flCurrentDegree = flFinishDegree;
flFinishDegree = flTemp + ( 2.0f * M_PI_F );
}
*/
nUnits = pViewer->GetRadiusUnits();
float flDegreeAmount = 2.0f * M_PI_F / nUnits;
nStartIndex = ( int )( flCurrentDegree / flDegreeAmount ) % nUnits;
if ( nStartIndex < 0 )
{
nStartIndex += nUnits;
}
// Vector vViewerLoc = pViewer->GetLocation();
// float flViewerRadius = pViewer->GetSize();
// float flMaxDistance = ( m_vStart - m_vEnd ).LengthSqr() + ( 60.0f * 60.0f );
#if 1
for ( int i = nStartIndex; flCurrentDegree < flFinishDegree; i++, flCurrentDegree += flDegreeAmount )
{
Vector2D vDelta;
if ( i >= nUnits )
{
i = 0;
}
vDelta.x = TableSin( flCurrentDegree );
vDelta.y = TableCos( flCurrentDegree );
#if 0
float flDistance = m_Plane.DistanceFromRay( vCenterLocation.x, vCenterLocation.y, vDelta.x, vDelta.y );
Vector2D vFinal = vCenterLocation.AsVector2D() + ( vDelta * flDistance );
float flDist1 = ( vFinal - m_vStart ).LengthSqr();
float flDist2 = ( vFinal - m_vEnd ).LengthSqr();
if ( flDistance >= 0.0f && ( flDist1 + flDist2 ) < flMaxDistance )
#else
// vDelta = ( vDelta * pViewer->GetSize() ) + vCenterLocation.AsVector2D();
// float flDistance = m_Plane.DistanceFromLineStart( vCenterLocation.x, vCenterLocation.y, vDelta.x, vDelta.y );
float flDistance = m_Plane.DistanceFromRay( vCenterLocation.x, vCenterLocation.y, vDelta.x, vDelta.y );
if ( flDistance >= 0.0f )
#endif
{
flDistance *= flDistance;
if ( flDistance < pVisibility[ i ] )
{
pVisibility[ i ] = flDistance;
}
}
}
#else
int nStart = ( 0.0f / 4.0f ) * nUnits;
int nEnd = ( 1.0f / 4.0f ) * nUnits;
for( ; nStart < nEnd; nStart++ )
{
pVisibility[ nStart ] /= 5.0f;
}
#endif
#endif
}
#include <tier0/memdbgoff.h>

49
fow/fow_lineoccluder.h Normal file
View File

@@ -0,0 +1,49 @@
//========= Copyright © 1996-2009, Valve Corporation, All rights reserved. ============//
//
// Purpose: 2d line occlusion for Fog of War
//
// $NoKeywords: $
//=====================================================================================//
#ifndef FOW_LINEOCCLUDER_H
#define FOW_LINEOCCLUDER_H
#if defined( COMPILER_MSVC )
#pragma once
#endif
#include "mathlib/vector.h"
#include "fow_2dplane.h"
class CFoW;
class CFoW_Viewer;
class CFoW_LineOccluder
{
public:
// construct a line occluder from the given points. the normal is supplied, though if it doesn't match up with the points, then the points are swapped.
CFoW_LineOccluder( float bx, float by, float ex, float ey, Vector2D &vNormal, int nSliceNum );
CFoW_LineOccluder( Vector2D &vStart, Vector2D &vEnd, CFOW_2DPlane &Plane, int nSliceNum );
// get the starting point as determined by the normal
inline Vector2D &GetStart( void ) { return m_vStart; }
// get the ending point as determined by the normal
inline Vector2D &GetEnd( void ) { return m_vEnd; }
// get the plane normal
inline Vector2D GetPlaneNormal( void ) { return m_Plane.GetNormal(); }
// get the plane normal
inline float GetPlaneDistance( void ) { return m_Plane.GetDistance(); }
// get the slice index this occluder belongs to
inline int GetSliceNum( void ) { return m_nSliceNum; }
// determine the occlusion of this line for the viewer
void ObstructViewer( CFoW *pFoW, CFoW_Viewer *pViewer );
private:
Vector2D m_vStart; // the starting point as determined by the normal
Vector2D m_vEnd; // the ending point as determined by the normal
CFOW_2DPlane m_Plane; // the plane that is formed
int m_nSliceNum; // the slice index of this occluder
};
#endif // FOW_LINEOCCLUDER_H

462
fow/fow_radiusoccluder.cpp Normal file
View File

@@ -0,0 +1,462 @@
#include "fow.h"
#include "fow_radiusoccluder.h"
#include "fow_viewer.h"
#include "fow_2dplane.h"
#include "engine/IVDebugOverlay.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
extern IVDebugOverlay *debugoverlay;
//-----------------------------------------------------------------------------
// Purpose: constructor to init this occluder with the id
// Input : nID - the id of this occluder
//-----------------------------------------------------------------------------
CFoW_RadiusOccluder::CFoW_RadiusOccluder( int nID )
{
m_nID = nID;
m_flRadius = 0.0f;
m_vLocation.Zero();
m_nHeightGroup = 0;
m_bEnabled = true;
}
//-----------------------------------------------------------------------------
// Purpose: update the radius of this occluder
// Input : flRadius - the new radius size
//-----------------------------------------------------------------------------
void CFoW_RadiusOccluder::UpdateSize( float flRadius )
{
m_flRadius = flRadius;
}
//-----------------------------------------------------------------------------
// Purpose: update the location of this occluder
// Input : vLocation - the new location
//-----------------------------------------------------------------------------
void CFoW_RadiusOccluder::UpdateLocation( Vector &vLocation )
{
m_vLocation = vLocation;
}
//-----------------------------------------------------------------------------
// Purpose: update the height group of this occluder
// Input : nHeightGroup - the new height group
//-----------------------------------------------------------------------------
void CFoW_RadiusOccluder::UpdateHeightGroup( uint8 nHeightGroup )
{
m_nHeightGroup = nHeightGroup;
}
//-----------------------------------------------------------------------------
// Purpose: is the occluder within range of the viewer?
// Input : pViewer - the viewer to check against
// Output : returns true if the two circles intersect
//-----------------------------------------------------------------------------
bool CFoW_RadiusOccluder::IsInRange( CFoW_Viewer *pViewer )
{
if ( m_bEnabled == false )
{
return false;
}
Vector vDiff = pViewer->GetLocation() - m_vLocation;
float flLen = sqrt( ( vDiff.x * vDiff.x ) + ( vDiff.y * vDiff.y ) );
return ( flLen <= m_flRadius + pViewer->GetSize() );
}
//-----------------------------------------------------------------------------
// Purpose: obstruct the viewer by updating the local viewer grid
// Input : pFoW - the main FoW object
// pViewer - the viewer to obstruct
//-----------------------------------------------------------------------------
void CFoW_RadiusOccluder::ObstructViewerGrid( CFoW *pFoW, CFoW_Viewer *pViewer )
{
if ( m_bEnabled == false )
{
return;
}
Vector vViewerLoc = pViewer->GetLocation();
float flViewerRadius = pViewer->GetSize();
Vector vDelta = ( vViewerLoc - m_vLocation );
vDelta.z = 0.0f;
float flLength = vDelta.Length();
if ( flLength > ( flViewerRadius + m_flRadius ) )
{
return;
}
// if ( length <= m_flRadius || length > ViewerRadius )
if ( flLength <= m_flRadius )
{
return;
}
float flAngle = ( float )atan2( vDelta.y, vDelta.x );
float flTangentLen = sqrt( flLength * flLength - m_flRadius * m_flRadius );
float flTangentAngle = ( float )asin( m_flRadius / flLength );
// compute the two tangent angles
float flPos = flAngle + flTangentAngle;
float flNeg = flAngle - flTangentAngle;
float x[ 6 ], y[ 6 ];
// compute the two tangent points
x[ 0 ] = -( float )cos( flPos ) * flTangentLen + vViewerLoc.x;
y[ 0 ] = -( float )sin( flPos ) * flTangentLen + vViewerLoc.y;
x[ 5 ] = -( float )cos( flNeg ) * flTangentLen + vViewerLoc.x;
y[ 5 ] = -( float )sin( flNeg ) * flTangentLen + vViewerLoc.y;
// extend the tangent points to the viewer's edge
x[ 1 ] = -( float )cos( flPos ) * flViewerRadius + vViewerLoc.x;
y[ 1 ] = -( float )sin( flPos ) * flViewerRadius + vViewerLoc.y;
x[ 4 ] = -( float )cos( flNeg ) * flViewerRadius + vViewerLoc.x;
y[ 4 ] = -( float )sin( flNeg ) * flViewerRadius + vViewerLoc.y;
// compute the forward direction of the viewer's intersection through this blocker
float fx = -vDelta.x / flLength;
float fy = -vDelta.y / flLength;
// compute half the length between the viewer's tangent edges
float dx2 = x[ 4 ] - x[ 1 ];
float dy2 = y[ 4 ] - y[ 1 ];
float flHalflen = ( dx2 * dx2 + dy2 * dy2 ) / 4;
// compute the side of the triangle that forms from viewer's radius to half way across the viewer's tangent edges
float flLen2 = ( float )sqrt( flViewerRadius * flViewerRadius - flHalflen );
flLen2 = flViewerRadius - flLen2;
// compute the box extents to encompass the circle's bounds
x[ 2 ] = x[ 1 ] + ( fx * flLen2 );
y[ 2 ] = y[ 1 ] + ( fy * flLen2 );
x[ 3 ] = x[ 4 ] + ( fx * flLen2 );
y[ 3 ] = y[ 4 ] + ( fy * flLen2 );
CFOW_2DPlane Planes[ 6 ];
for (int i = 0; i < 6; i++)
{
Planes[ i ].Init( x[ i ], y[ i ], x[ ( i + 1 ) % 6 ], y[ ( i + 1 ) % 6 ] );
}
float flMinX = x[ 0 ], flMinY = y[ 0 ], flMaxX = x[ 0 ], flMaxY = y[ 0 ];
for ( int i = 1; i < 6; i++ )
{
if ( x[ i ] < flMinX )
{
flMinX = x[ i ];
}
if ( x[ i ] > flMaxX )
{
flMaxX = x[ i ];
}
if ( y[ i ] < flMinY )
{
flMinY = y[ i ];
}
if ( y[i] > flMaxY )
{
flMaxY = y[ i ];
}
}
float px, py, flStart_py, ex, ey;
int nGridX, nGridY, nStartGridY;
Vector2D vViewerStart, vViewerEnd;
int nGridSize = pFoW->GetHorizontalGridSize();
pViewer->GetStartPosition( vViewerStart );
pViewer->GetEndPosition( vViewerEnd );
if ( flMinX > vViewerStart.x )
{
nGridX = ( int )( flMinX - vViewerStart.x ) / nGridSize;
px = vViewerStart.x + ( int )( nGridSize * nGridX );
}
else
{
px = vViewerStart.x;
nGridX = 0;
}
if ( flMaxX < vViewerEnd.x )
{
ex = flMaxX;
}
else
{
ex = vViewerEnd.x;
}
if ( flMinY > vViewerStart.y )
{
nStartGridY = ( int )( flMinY - vViewerStart.y ) / nGridSize;
flStart_py = vViewerStart.y + ( int )( nGridSize * nStartGridY );
}
else
{
nStartGridY = 0;
flStart_py = vViewerStart.y;
}
if ( flMaxY < vViewerEnd.y )
{
ey = flMaxY;
}
else
{
ey = vViewerEnd.y;
}
byte *pLocalVisibility = pViewer->GetVisibility();
int nLocalGridUnits = pViewer->GetGridUnits();
// offset to center of grid
px += nGridSize / 2;
flStart_py += nGridSize / 2;
for ( ; px < ex; px += nGridSize, nGridX++)
{
for ( nGridY = nStartGridY, py = flStart_py; py < ey; py += nGridSize, nGridY++ )
{
byte *pPos = pLocalVisibility + ( nGridX * nLocalGridUnits ) + nGridY;
if ( ( ( *pPos ) & FOW_VG_IS_VISIBLE ) == 0 )
{
continue;
}
int i;
for ( i = 0; i < 6; i++ )
{
#if 0
// we don't need to check the bounding planes - these would be used to construct a stencil buffer though
if ( i == 1 || i == 2 || i == 3 )
{
continue;
}
#endif
if ( !Planes[ i ].PointInFront( px, py ) )
{
break;
}
}
if ( i == 6 )
{
( *pPos ) &= ~FOW_VG_IS_VISIBLE;
}
}
}
}
// #define SLOW_PATH 1
//-----------------------------------------------------------------------------
// Purpose: obstruct the viewer by updating the depth circle
// Input : pFoW - the main FoW object
// pViewer - the viewer to obstruct
//-----------------------------------------------------------------------------
void CFoW_RadiusOccluder::ObstructViewerRadius( CFoW *pFoW, CFoW_Viewer *pViewer )
{
if ( m_bEnabled == false )
{
return;
}
if ( m_flRadius <= 1.0f )
{
Warning( "FoW: Occluder %d has invalid radius\n", m_nID );
return;
}
int nViewerHeightGroup = pViewer->GetHeightGroup();
if ( nViewerHeightGroup >= 1 && m_nHeightGroup >= 1 && m_nHeightGroup < nViewerHeightGroup )
{ // both the viewer and the occluder have height groups and this occluder is under the viewer, then don't obstruct
return;
}
Vector vViewerLoc = pViewer->GetLocation();
float flViewerRadius = pViewer->GetSize();
Vector vDelta = ( vViewerLoc - m_vLocation );
vDelta.z = 0.0f;
float flLength = vDelta.Length();
if ( flLength > ( flViewerRadius + m_flRadius ) )
{
return;
}
// if ( length <= m_flRadius || length > ViewerRadius )
if ( flLength <= m_flRadius )
{
return;
}
float flAngle = ( float )atan2( vDelta.x, vDelta.y ) + DEG2RAD( 180.0f );
float flTangentLen = sqrt( flLength * flLength - m_flRadius * m_flRadius );
float flTangentAngle = ( float )asin( m_flRadius / flLength );
// compute the two tangent angles
float flPos = flAngle + flTangentAngle;
float flNeg = flAngle - flTangentAngle;
float x[ 6 ], y[ 6 ];
// compute the two tangent points
#ifdef SLOW_PATH
x[ 0 ] = ( float )sin( flPos ) * flTangentLen + vViewerLoc.x;
y[ 0 ] = ( float )cos( flPos ) * flTangentLen + vViewerLoc.y;
x[ 5 ] = ( float )sin( flNeg ) * flTangentLen + vViewerLoc.x;
y[ 5 ] = ( float )cos( flNeg ) * flTangentLen + vViewerLoc.y;
#else
x[ 0 ] = ( float )TableSin( flPos ) * flTangentLen + vViewerLoc.x;
y[ 0 ] = ( float )TableCos( flPos ) * flTangentLen + vViewerLoc.y;
x[ 5 ] = ( float )TableSin( flNeg ) * flTangentLen + vViewerLoc.x;
y[ 5 ] = ( float )TableCos( flNeg ) * flTangentLen + vViewerLoc.y;
#endif
// Msg( "%g, %g\n", RAD2DEG( flPos ), RAD2DEG( flNeg ) );
CFOW_2DPlane Plane;
Plane.Init( x[ 5 ], y[ 5 ], x[ 0 ], y[ 0 ] );
int nUnits = pViewer->GetRadiusUnits();
int *pVisibility = pViewer->GetVisibilityRadius();
Vector vCenterLocation = vViewerLoc;
float flDistance = Plane.DistanceFrom( vCenterLocation.x, vCenterLocation.y );
if ( flDistance < 0.0f )
{
return;
}
#ifdef SLOW_PATH
CFOW_2DPlane Edge1, Edge2;
Edge1.Init( vCenterLocation.x, vCenterLocation.y, x[ 0 ], y[ 0 ] );
Edge2.Init( x[ 5 ], y[ 5 ], vCenterLocation.x, vCenterLocation.y );
float flDegreeAmount = 360.0f / nUnits;
float flCurrentDegree = 0.0f;
for ( int i = 0; i < nUnits; i++, flCurrentDegree += flDegreeAmount )
{
Vector vLocation = vViewerLoc;
Vector vDelta;
vDelta.x = sin( DEG2RAD( flCurrentDegree ) );
vDelta.y = cos( DEG2RAD( flCurrentDegree ) );
vLocation += vDelta * flViewerRadius;
float flDistance = Plane.DistanceFromRay( vCenterLocation.x, vCenterLocation.y, vDelta.x, vDelta.y );
if ( flDistance >= 0.0f )
{
flDistance *= flDistance;
if ( flDistance >= 0.0f && flDistance < pVisibility[ i ] )
{
if ( Edge1.PointInFront( vLocation.x, vLocation.y ) && Edge2.PointInFront( vLocation.x, vLocation.y ) )
{
pVisibility[ i ] = flDistance;
}
}
}
}
#else
float flCurrentDegree, flFinishDegree;
int nStartIndex;
if ( flPos < flNeg )
{
flCurrentDegree = flPos;
flFinishDegree = flNeg;
}
else
{
flCurrentDegree = flNeg;
flFinishDegree = flPos;
}
float flDegreeAmount = 2.0f * M_PI_F / nUnits;
nStartIndex = ( int )( flCurrentDegree / flDegreeAmount ) % nUnits;
if ( nStartIndex < 0 )
{
nStartIndex += nUnits;
}
float flHorizontalGridSize = pFoW->GetHorizontalGridSize();
for ( int i = nStartIndex; flCurrentDegree < flFinishDegree; i++, flCurrentDegree += flDegreeAmount )
{
Vector vDelta;
if ( i >= nUnits )
{
i = 0;
}
vDelta.x = TableSin( flCurrentDegree );
vDelta.y = TableCos( flCurrentDegree );
float flDistance = Plane.DistanceFromRay( vCenterLocation.x, vCenterLocation.y, vDelta.x, vDelta.y );
if ( flDistance >= 0.0f )
{
flDistance += flHorizontalGridSize * 1.1f; // back off a bit
flDistance *= flDistance;
if ( flDistance < pVisibility[ i ] )
{
pVisibility[ i ] = flDistance;
}
}
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
//-----------------------------------------------------------------------------
void CFoW_RadiusOccluder::DrawDebugInfo( Vector &vLocation, float flViewRadius, unsigned nFlags )
{
if ( ( nFlags & FOW_DEBUG_SHOW_OCCLUDERS ) == 0 )
{
return;
}
Vector vDiff = vLocation - m_vLocation;
if ( vDiff.Length2D() > flViewRadius + m_flRadius )
{
return;
}
if ( ( nFlags & FOW_DEBUG_SHOW_OCCLUDERS ) != 0 )
{
debugoverlay->AddSphereOverlay( m_vLocation, m_flRadius, 10, 10, 255, 0, 0, 127, FOW_DEBUG_VIEW_TIME );
debugoverlay->AddBoxOverlay( m_vLocation, Vector( -16.0f, -16.0f, -16.0f ), Vector( 16.0f, 16.0f, 16.0f ), QAngle( 0, 0, 0 ), 255, 0, 0, 127, FOW_DEBUG_VIEW_TIME );
}
}
#include <tier0/memdbgoff.h>

63
fow/fow_radiusoccluder.h Normal file
View File

@@ -0,0 +1,63 @@
//========= Copyright © 1996-2009, Valve Corporation, All rights reserved. ============//
//
// Purpose: radius occlusion for Fog of War
//
// $NoKeywords: $
//=====================================================================================//
#ifndef FOW_RADIUSOCCLUDER_H
#define FOW_RADIUSOCCLUDER_H
#if defined( COMPILER_MSVC )
#pragma once
#endif
#include "mathlib/vector.h"
class CFoW;
class CFoW_Viewer;
class CFoW_RadiusOccluder
{
public:
// constructor to init this occluder with the id
CFoW_RadiusOccluder( int nID );
// update the radius of this occluder
void UpdateSize( float flRadius );
// update the location of this occluder
void UpdateLocation( Vector &vLocation );
// update the height group of this occluder
void UpdateHeightGroup( uint8 nHeightGroup );
// get the radius of this occluder
inline float GetSize( void ) { return m_flRadius; }
// get the location of this occluder
inline Vector &GetLocation( void ) { return m_vLocation; }
//
inline uint8 GetHeightGroup( void ) { return m_nHeightGroup; }
//
inline bool IsEnabled( ) { return m_bEnabled; }
//
inline void SetEnable( bool bEnable ) { m_bEnabled = bEnable; }
// is the occluder within range of the viewer?
bool IsInRange( CFoW_Viewer *pViewer );
// obstruct the viewer by updating the local viewer grid
void ObstructViewerGrid( CFoW *pFoW, CFoW_Viewer *pViewer );
// obstruct the viewer by updating the depth circle
void ObstructViewerRadius( CFoW *pFoW, CFoW_Viewer *pViewer );
//
void DrawDebugInfo( Vector &vLocation, float flViewRadius, unsigned nFlags );
private:
int m_nID; // the id of this occluder
float m_flRadius; // the radius of this occluder
Vector m_vLocation; // the location of this occluder
bool m_bEnabled;
uint8 m_nHeightGroup; // the height group this occluder belongs to
};
#endif // FOW_RADIUSOCCLUDER_H

206
fow/fow_trisoup.cpp Normal file
View File

@@ -0,0 +1,206 @@
#include "fow.h"
#include "fow_trisoup.h"
#include "fow_lineoccluder.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
//-----------------------------------------------------------------------------
// Purpose: constructor to init this collection with the id
// Input : nID - unused
//-----------------------------------------------------------------------------
CFoW_TriSoupCollection::CFoW_TriSoupCollection( unsigned nID )
{
}
//-----------------------------------------------------------------------------
// Purpose: destructor to dealloc the occluders
//-----------------------------------------------------------------------------
CFoW_TriSoupCollection::~CFoW_TriSoupCollection( void )
{
Clear();
}
//-----------------------------------------------------------------------------
// Purpose: clears all entries from the collection ( useful for hammer editing only )
//-----------------------------------------------------------------------------
void CFoW_TriSoupCollection::Clear( void )
{
m_Occluders.PurgeAndDeleteElements();
}
//-----------------------------------------------------------------------------
// Purpose: adds a tri to the collection. this is immediately split up into the horizontal slices. very slow!
// Input : pFoW - the main FoW object
// vPointA - a point on the tri
// vPointB - a point on the tri
// vPointC - a point on the tri
//-----------------------------------------------------------------------------
void CFoW_TriSoupCollection::AddTri( CFoW *pFoW, Vector &vPointA, Vector &vPointB, Vector &vPointC )
{
Vector vVerts[ 3 ], vOutVerts[ 8 ];
int nBottomZ;
int nGridSize;
int nGridUnits;
Vector vNormal, vTestNormal;
float flIntercept;
float *pflVerticalLevels;
vVerts[ 0 ] = vPointA;
vVerts[ 1 ] = vPointB;
vVerts[ 2 ] = vPointC;
pFoW->GetVerticalGridInfo( nBottomZ, nGridSize, nGridUnits, &pflVerticalLevels );
ComputeTrianglePlane( vPointA, vPointB, vPointC, vNormal, flIntercept );
vTestNormal = vNormal;
vTestNormal.z = 0.0f;
vTestNormal.NormalizeInPlace();
Vector2D vTestNormal2( vTestNormal.x, vTestNormal.y );
for ( int i = 0; i < nGridUnits; i++ )
{
nBottomZ = pflVerticalLevels[ i ] + 16.0f;
int nCount = HorizontalSplitTri( vVerts, 3, vOutVerts, nBottomZ, 0.0f );
if ( nCount == 2 )
{
CFoW_LineOccluder *pOccluder = new CFoW_LineOccluder( vOutVerts[ 0 ].x, vOutVerts[ 0 ].y, vOutVerts[ 1 ].x, vOutVerts[ 1 ].y, vTestNormal2, i );
m_Occluders.AddToTail( pOccluder );
pFoW->AddTriSoupOccluder( pOccluder, i );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: adds all occluders back into the visibility tree
// Input : pFoW - the main FoW object
//-----------------------------------------------------------------------------
void CFoW_TriSoupCollection::RepopulateOccluders( CFoW *pFoW )
{
for ( int i = 0; i < m_Occluders.Count(); i++ )
{
pFoW->AddTriSoupOccluder( m_Occluders[ i ], m_Occluders[ i ]->GetSliceNum() );
}
}
#if 0
void CFoW_TriSoupCollection::ObstructViewer( CFoW *FoW, CFoW_Viewer *Viewer )
{
for ( int i = 0; i < m_Occluders.Count(); i++ )
{
m_Occluders[ i ].ObstructViewer( FoW, Viewer );
}
}
#endif
//-----------------------------------------------------------------------------
// Purpose: clip a poly to the horizontal plane and return the poly on the front side of the plane
// Input : *pInVerts - input polygon
// nVertCount - # verts in input poly
// *pOutVerts - destination poly
// flDist - plane constant
// flOnPlaneEpsilon - the fudge factor for determining if a point is within the plane edge
// Output : int - # verts in output poly
//-----------------------------------------------------------------------------
int CFoW_TriSoupCollection::HorizontalSplitTri( Vector *pInVerts, int nVertCount, Vector *pOutVerts, float flDist, float flOnPlaneEpsilon )
{
vec_t *pDists = ( vec_t * )stackalloc( sizeof( vec_t ) * nVertCount * 4 ); //4x vertcount should cover all cases
int *pSides = ( int * )stackalloc( sizeof( vec_t ) * nVertCount * 4 );
int nCounts[ 3 ];
vec_t flDot;
int i, j;
Vector vMid = vec3_origin;
int nOutCount;
Vector vNormal( 0.0f, 0.0f, 1.0f );
nCounts[ 0 ] = nCounts[ 1 ] = nCounts[ 2 ] = 0;
// determine sides for each point
for ( i = 0; i < nVertCount; i++ )
{
flDot = DotProduct( pInVerts[ i ], vNormal ) - flDist;
pDists[ i ] = flDot;
if ( flDot > flOnPlaneEpsilon )
{
pSides[ i ] = SIDE_FRONT;
}
else if ( flDot < -flOnPlaneEpsilon )
{
pSides[ i ] = SIDE_BACK;
}
else
{
pSides[ i ] = SIDE_ON;
}
nCounts[ pSides[ i ] ]++;
}
pSides[ i ] = pSides[ 0 ];
pDists[ i ] = pDists[ 0 ];
if ( !nCounts[ SIDE_FRONT ] )
{ // if this has 2 sides that are side_on, then this should be a tri coming soon with the same two sides that are on, but with one on side_back
return 0;
}
nOutCount = 0;
for ( i = 0; i < nVertCount; i++ )
{
int nCurrent = ( i + 0 ) % nVertCount;
int nNext = ( i + 1 ) % nVertCount;
Vector &p1 = pInVerts[ nCurrent ];
if ( pSides[ nCurrent ] == SIDE_ON )
{
VectorCopy( p1, pOutVerts[ nOutCount ] );
nOutCount++;
continue;
}
if ( pSides[ nCurrent ] == SIDE_FRONT )
{
// VectorCopy( p1, outVerts[outCount]);
// outCount++;
}
if ( pSides[ nNext ] == SIDE_ON || pSides[ nNext ] == pSides[ nCurrent ] )
{
continue;
}
// generate a split point
Vector &p2 = pInVerts[ nNext ];
flDot = pDists[ nCurrent ] / ( pDists[ nCurrent ] - pDists[ nNext ] );
for ( j = 0; j < 3; j++ )
{ // avoid round off error when possible
if ( vNormal[ j ] == 1 )
{
vMid[ j ] = flDist;
}
else if ( vNormal[ j ] == -1 )
{
vMid[ j ] = -flDist;
}
else
{
vMid[ j ] = p1[ j ] + flDot * ( p2[ j ] - p1[ j ] );
}
}
VectorCopy ( vMid, pOutVerts[ nOutCount ] );
nOutCount++;
}
return nOutCount;
}
#include <tier0/memdbgoff.h>

52
fow/fow_trisoup.h Normal file
View File

@@ -0,0 +1,52 @@
//========= Copyright © 1996-2009, Valve Corporation, All rights reserved. ============//
//
// Purpose: stores all line occlusions ( horizontal slices ) for the tri soup for the Fog of War
//
// $NoKeywords: $
//=====================================================================================//
#ifndef FOW_TRISOUP_H
#define FOW_TRISOUP_H
#if defined( COMPILER_MSVC )
#pragma once
#endif
#include "utlvector.h"
#include "mathlib/vector.h"
class CFoW;
class CFoW_Viewer;
class CFoW_LineOccluder;
class CFoW_TriSoupCollection
{
public:
// constructor to init this collection with the id
CFoW_TriSoupCollection( unsigned nID );
// destructor to dealloc the occluders
~CFoW_TriSoupCollection( void );
// clears all entries from the collection ( useful for hammer editing only )
void Clear( void );
// adds a tri to the collection. this is immediately split up into the horizontal slices. very slow!
void AddTri( CFoW *pFoW, Vector &vPointA, Vector &vPointB, Vector &vPointC );
// adds all occluders back into the visibility tree
void RepopulateOccluders( CFoW *pFoW );
// void ObstructViewer( CFoW *FoW, CFoW_Viewer *Viewer );
//
int GetNumOccluders( ) { return m_Occluders.Count(); }
//
CFoW_LineOccluder *GetOccluder( int nIndex ) { return m_Occluders[ nIndex ]; }
private:
// attempt to split the tri horizontally given the distance / offset from z 0.0
int HorizontalSplitTri( Vector *pInVerts, int nVertCount, Vector *pOutVerts, float flDist, float flOnPlaneEpsilon );
CUtlVector< CFoW_LineOccluder * > m_Occluders;
};
#endif // FOW_TRISOUP_H

367
fow/fow_viewer.cpp Normal file
View File

@@ -0,0 +1,367 @@
#include "fow_viewer.h"
#include "fow_radiusoccluder.h"
#include "fow_lineoccluder.h"
#include "fow_horizontalslice.h"
#include "fow.h"
#include "engine/IVDebugOverlay.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
extern IVDebugOverlay *debugoverlay;
//-----------------------------------------------------------------------------
// Purpose: constructor to init this viewer with the id and temp
// Input : nID - the id of this viewer
// nViewerTeam - the team this viewer is on
//-----------------------------------------------------------------------------
CFoW_Viewer::CFoW_Viewer( int nID, unsigned nViewerTeam )
{
m_nID = nID;
m_nViewerTeam = nViewerTeam;
m_vLocation.Init();
m_flRadius = 0.0f;
m_pVisibility = NULL;
m_pVisibilityRadius = NULL;
m_nRadiusUnits = 0;
m_nHeightGroup = 0;
m_nAllocatedMemory = 0;
m_bDirty = true;
}
//-----------------------------------------------------------------------------
// Purpose: destructor to free up the local vis grids
//-----------------------------------------------------------------------------
CFoW_Viewer::~CFoW_Viewer( void )
{
if ( m_pVisibility )
{
free( m_pVisibility );
m_pVisibility = NULL;
}
if ( m_pVisibilityRadius )
{
free( m_pVisibilityRadius );
m_pVisibilityRadius = NULL;
}
}
//-----------------------------------------------------------------------------
// Purpose: update the radius of the viewer. this will realloc the local vis grids
// Input : pFoW - the main FoW object
// flRadius - the new radius
//-----------------------------------------------------------------------------
void CFoW_Viewer::UpdateSize( CFoW *pFoW, float flRadius )
{
m_flRadius = flRadius;
if ( m_pVisibility )
{
free( m_pVisibility );
}
if ( m_pVisibilityRadius )
{
free( m_pVisibilityRadius );
}
m_nAllocatedMemory = 0;
int nGridSize = pFoW->GetHorizontalGridSize();
m_nGridUnits = ( ( m_flRadius * 2 ) + nGridSize - 1 ) / nGridSize;
m_nGridUnits |= 1; // always make it odd, so that we have a true center
m_pVisibility = ( byte * )malloc( sizeof( m_pVisibility[ 0 ] ) * m_nGridUnits * m_nGridUnits );
m_nAllocatedMemory += sizeof( m_pVisibility[ 0 ] ) * m_nGridUnits * m_nGridUnits;
m_nRadiusUnits = ( ( 2 * M_PI * m_flRadius ) + nGridSize - 1 ) / nGridSize;
// m_nRadiusUnits = 360;
m_pVisibilityRadius = ( int * )malloc( sizeof( m_pVisibilityRadius[ 0 ] ) * m_nRadiusUnits );
m_nAllocatedMemory += sizeof( m_pVisibilityRadius[ 0 ] ) * m_nRadiusUnits;
m_pVisibilityTable = pFoW->FindRadiusTable( flRadius );
m_bDirty = true;
}
//-----------------------------------------------------------------------------
// Purpose: update the location of the viewer
// Input : vLocation - the new location
//-----------------------------------------------------------------------------
bool CFoW_Viewer::UpdateLocation( CFoW *pFoW, const Vector &vLocation, Vector *pvOldLocation )
{
Vector vNewLocation = vLocation;
m_vRealLocation = vLocation;
pFoW->CenterCoordToGrid( vNewLocation );
if ( vNewLocation.x != m_vLocation.x || vNewLocation.y != m_vLocation.y )
{ // we've moved to a new grid center
m_bDirty = true;
if ( pvOldLocation != NULL )
{
*pvOldLocation = m_vLocation;
}
m_vLocation = vNewLocation;
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: update the height group of this viewer
// Input : nHeightGroup - the new height group
//-----------------------------------------------------------------------------
void CFoW_Viewer::UpdateHeightGroup( uint8 nHeightGroup )
{
if ( m_nHeightGroup != nHeightGroup )
{
m_bDirty = true;
}
m_nHeightGroup = nHeightGroup;
}
//-----------------------------------------------------------------------------
// Purpose: get the upper left coords of this viewer
// Output : vResults - the upper left location of this viewer
//-----------------------------------------------------------------------------
void CFoW_Viewer::GetStartPosition( Vector2D &vResults )
{
vResults.x = m_vLocation.x - m_flRadius;
vResults.y = m_vLocation.y - m_flRadius;
}
//-----------------------------------------------------------------------------
// Purpose: get the lower right coords of this viewer
// Output : vResults - the lower right of this viewer
//-----------------------------------------------------------------------------
void CFoW_Viewer::GetEndPosition( Vector2D &vResults )
{
vResults.x = m_vLocation.x + m_flRadius;
vResults.y = m_vLocation.y + m_flRadius;
}
//-----------------------------------------------------------------------------
// Purpose: calculate the localized visibility against all occluders.
// Input : pFoW - the main FoW object
//-----------------------------------------------------------------------------
void CFoW_Viewer::CalcLocalizedVisibility( CFoW *pFoW )
{
if ( m_bDirty == false )
{
return;
}
// DefaultViewingArea( pFoW );
DefaultViewingRadius( pFoW );
pFoW->ObstructOccludersNearViewer( m_nID );
#if 0
int NumOccluders = FoW->GetNumOccluders();
for ( int i = 0; i < NumOccluders; i++ )
{
CFoW_RadiusOccluder *Occluder = FoW->GetOccluder( i );
if ( !Occluder )
{
continue;
}
if ( !Occluder->IsInRange( this ) )
{
continue;
}
Occluder->ObstructViewer( FoW, this );
}
#endif
int nSliceIndex = pFoW->GetHorizontalSlice( m_vLocation.z );
if ( nSliceIndex != -1 )
{
pFoW->GetSlice( nSliceIndex )->ObstructViewer( pFoW, this );
}
ResolveRadius( pFoW );
m_bDirty = false;
}
//-----------------------------------------------------------------------------
// Purpose: clear the localized visibility grid to just the raw radius
// Input : pFoW - the main FoW object
//-----------------------------------------------------------------------------
// use this FOW_VG_DEFAULT_VISIBLE
void CFoW_Viewer::DefaultViewingArea( CFoW *pFoW )
{
memset( m_pVisibility, 0, sizeof( m_pVisibility[ 0 ] ) * m_nGridUnits * m_nGridUnits );
int nGridSize = pFoW->GetHorizontalGridSize();
int nOffset = ( m_nGridUnits / 2 ) * nGridSize;
byte *pVisibility = m_pVisibility;
int nRadius2 = m_flRadius * m_flRadius;
for ( int x = 0, xPos = -nOffset; x < m_nGridUnits; x++, xPos += nGridSize )
{
for ( int y = 0, yPos = -nOffset; y < m_nGridUnits; y++, yPos += nGridSize, pVisibility++ )
{
if ( ( ( xPos * xPos ) + ( yPos * yPos ) ) <= nRadius2 )
{
*pVisibility = FOW_VG_IS_VISIBLE | FOW_VG_DEFAULT_VISIBLE;
}
else
{
*pVisibility = 0;
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: clear the localized radius grid to the maximum distance
// Input : pFoW - the main FoW object
//-----------------------------------------------------------------------------
void CFoW_Viewer::DefaultViewingRadius( CFoW *pFoW )
{
int nRadius2 = m_flRadius * m_flRadius;
for ( int i = 0; i < m_nRadiusUnits; i++ )
{
m_pVisibilityRadius[ i ] = nRadius2;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
//-----------------------------------------------------------------------------
void CFoW_Viewer::DrawDebugInfo( Vector &vLocation, float flViewRadius, unsigned nFlags )
{
if ( ( nFlags & ( FOW_DEBUG_SHOW_VIEWERS_TEAM_0 | FOW_DEBUG_SHOW_VIEWERS_TEAM_1 ) ) == 0 )
{
return;
}
Vector vDiff = vLocation - m_vLocation;
if ( vDiff.Length2D() > flViewRadius + m_flRadius )
{
return;
}
if ( ( nFlags & FOW_DEBUG_SHOW_VIEWERS_TEAM_0 ) != 0 )
{
debugoverlay->AddSphereOverlay( m_vLocation, m_flRadius, 10, 10, 0, 255, 0, 127, FOW_DEBUG_VIEW_TIME );
debugoverlay->AddBoxOverlay( m_vLocation, Vector( -16.0f, -16.0f, -16.0f ), Vector( 16.0f, 16.0f, 16.0f ), QAngle( 0, 0, 0 ), 0, 255, 0, 127, FOW_DEBUG_VIEW_TIME );
}
if ( ( nFlags & FOW_DEBUG_SHOW_VIEWERS_TEAM_1 ) != 0 )
{
debugoverlay->AddSphereOverlay( m_vLocation, m_flRadius, 10, 10, 0, 0, 255, 127, FOW_DEBUG_VIEW_TIME );
debugoverlay->AddBoxOverlay( m_vLocation, Vector( -16.0f, -16.0f, -16.0f ), Vector( 16.0f, 16.0f, 16.0f ), QAngle( 0, 0, 0 ), 0, 0, 255, 127, FOW_DEBUG_VIEW_TIME );
}
}
//-----------------------------------------------------------------------------
// Purpose: turn the radius grid into the localized visibility grid
// Input : pFoW - the main FoW object
//-----------------------------------------------------------------------------
void CFoW_Viewer::ResolveRadius( CFoW *pFoW )
{
#if 0
int nGridSize = pFoW->GetHorizontalGridSize();
int nHalfGridSize = nGridSize / 2;
byte *pVisibility = m_pVisibility;
// int Radius2 = m_flRadius * m_flRadius;
for ( int x = 0, xPos = -m_flRadius + nHalfGridSize; x < m_nGridUnits; x++, xPos += nGridSize )
{
for ( int y = 0, yPos = -m_flRadius + nHalfGridSize; y < m_nGridUnits; y++, yPos += nGridSize, pVisibility++ )
{
float flDist = sqrt( ( float )( ( xPos * xPos ) + ( yPos * yPos ) ) );
if ( flDist > m_flRadius )
{
*pVisibility = 0;
continue;
}
float nx = xPos / flDist;
float ny = yPos / flDist;
float flAngle = ( 0 * nx ) + ( 1 * ny );
float flRealAngle = RAD2DEG( acos( flAngle ) );
flAngle = -flAngle + 1;
if ( nx < 0.0f )
{
flAngle = 4 - flAngle;
flRealAngle = 360 - flRealAngle;
}
flAngle /= 4.0f;
flAngle *= m_nRadiusUnits;
flRealAngle = ( flRealAngle / 360.0f ) * m_nRadiusUnits;
if ( flDist <= m_pVisibilityRadius[ ( int )flRealAngle ] )
{
*pVisibility = FOW_VG_IS_VISIBLE;
}
else
{
*pVisibility = 0;
}
}
}
#else
int nGridSize = pFoW->GetHorizontalGridSize();
int nOffset = ( m_nGridUnits / 2 ) * nGridSize;
byte *pVisibility = m_pVisibility;
int *pVisibilityTable = m_pVisibilityTable;
for ( int x = 0, xPos = -nOffset; x < m_nGridUnits; x++, xPos += nGridSize )
{
for ( int y = 0, yPos = -nOffset; y < m_nGridUnits; y++, yPos += nGridSize, pVisibility++, pVisibilityTable++ )
{
if ( ( *pVisibilityTable ) == -1 )
{
*pVisibility = 0;
continue;
}
float flDist = ( ( xPos * xPos ) + ( yPos * yPos ) );
if ( flDist <= m_pVisibilityRadius[ *pVisibilityTable ] )
{
*pVisibility = FOW_VG_IS_VISIBLE;
}
else
{
*pVisibility = 0;
}
}
}
#endif
}
#include <tier0/memdbgoff.h>

91
fow/fow_viewer.h Normal file
View File

@@ -0,0 +1,91 @@
//========= Copyright © 1996-2009, Valve Corporation, All rights reserved. ============//
//
// Purpose: a localized viewer for the Fog of War
//
// $NoKeywords: $
//=====================================================================================//
#ifndef FOW_VIEWER_H
#define FOW_VIEWER_H
#if defined( COMPILER_MSVC )
#pragma once
#endif
#include "mathlib/vector.h"
class CFoW;
class CFoW_Viewer
{
public:
// constructor to init this viewer with the id and temp
CFoW_Viewer( int nID, unsigned nViewerTeam );
// destructor to free up the local vis grids
~CFoW_Viewer( void );
// update the radius of the viewer. this will realloc the local vis grids
void UpdateSize( CFoW *pFoW, float flRadius );
// update the location of the viewer
bool UpdateLocation( CFoW *pFoW, const Vector &vLocation, Vector *pvOldLocation );
// update the height group of this viewer
void UpdateHeightGroup( uint8 nHeightGroup );
//
inline void Dirty( ) { m_bDirty = true; }
//
inline bool IsDirty( ) { return m_bDirty; }
// get the team the viewer is on
inline unsigned GetTeam( void ) { return m_nViewerTeam; }
// get the radius of the viewer
inline float GetSize( void ) { return m_flRadius; }
// get the grid-centered location of the viewer
inline Vector &GetLocation( void ) { return m_vLocation; }
// get the real location of the viewer
inline Vector &GetRealLocation( void ) { return m_vRealLocation; }
// get the height group of the viewer
inline uint8 GetHeightGroup( void ) { return m_nHeightGroup; }
// get the grid units of the local vis. ( diameter / horizontal grid size ) rounded up
inline int GetGridUnits( void ) { return m_nGridUnits; }
// get the local visibility grid
inline byte *GetVisibility( void ) { return m_pVisibility; }
// get the visibility radius grid
inline int *GetVisibilityRadius( void ) { return m_pVisibilityRadius; }
// get the grid units of the radius grid ( circumference / horizontal grid size ) rounded up
inline int GetRadiusUnits( void ) { return m_nRadiusUnits; }
// get the upper left coords of this viewer
void GetStartPosition( Vector2D &vResults );
// get the lower right coords of this viewer
void GetEndPosition( Vector2D &vResults );
// calculate the localized visibility against all occluders.
void CalcLocalizedVisibility( CFoW *pFoW );
// clear the localized radius grid to the maximum distance
void DefaultViewingRadius( CFoW *pFoW );
//
void DrawDebugInfo( Vector &vLocation, float flViewRadius, unsigned nFlags );
//
size_t GetAllocatedMemory( ) { return m_nAllocatedMemory; }
private:
// clear the localized visibility grid to just the raw radius
void DefaultViewingArea( CFoW *pFoW );
// turn the radius grid into the localized visibility grid
void ResolveRadius( CFoW *pFoW );
int m_nID; // the id of this viewer
unsigned m_nViewerTeam; // the team this viewer belongs to
float m_flRadius; // the radius of this viewer
Vector m_vLocation; // the grid location of this viewer
Vector m_vRealLocation; // the real location of this viewer
byte *m_pVisibility; // the localized visibility grid
int m_nGridUnits; // the grid units ( diameter / horizontal grid size ) rounded up
int *m_pVisibilityRadius; // the localized visibility depth circle
int m_nRadiusUnits; // the grid units of the radius grid ( circumference / horizontal grid size ) rounded up
int *m_pVisibilityTable; // the visibility table to go from grid to radius
bool m_bDirty; //
uint8 m_nHeightGroup; // the height group this viewer belongs to
size_t m_nAllocatedMemory; //
};
#endif // FOW_VIEWER_H