303 lines
10 KiB
C++
303 lines
10 KiB
C++
//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======//
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $NoKeywords: $
|
|
//
|
|
//=============================================================================//
|
|
|
|
#ifndef CAMERA_H
|
|
#define CAMERA_H
|
|
|
|
#ifdef _WIN32
|
|
#pragma once
|
|
#endif
|
|
|
|
#include <math.h>
|
|
#include <float.h>
|
|
|
|
// For vec_t, put this somewhere else?
|
|
#include "tier0/basetypes.h"
|
|
#include "mathlib/vector.h"
|
|
|
|
#include "tier0/dbg.h"
|
|
#include "mathlib/vector2d.h"
|
|
#include "mathlib/math_pfns.h"
|
|
#include "mathlib/vmatrix.h"
|
|
#include "mathlib/ssemath.h"
|
|
#include "datamap.h"
|
|
|
|
#include "tier0/memalloc.h"
|
|
// declarations for camera and frustum
|
|
|
|
struct Camera_t
|
|
{
|
|
Vector m_origin;
|
|
QAngle m_angles;
|
|
float m_flFOVX; // FOV for X/width
|
|
float m_flZNear;
|
|
float m_flZFar;
|
|
};
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// accessors for generated matrices
|
|
//-----------------------------------------------------------------------------
|
|
void ComputeViewMatrix( VMatrix *pWorldToView, const Camera_t& camera );
|
|
void ComputeViewMatrix( matrix3x4_t *pWorldToView, const Camera_t& camera );
|
|
void ComputeViewMatrix( matrix3x4_t *pWorldToView, matrix3x4_t *pWorldToCamera, const Camera_t &camera );
|
|
void ComputeProjectionMatrix( VMatrix *pCameraToProjection, const Camera_t& camera, int width, int height );
|
|
void ComputeProjectionMatrix( VMatrix *pCameraToProjection, float flZNear, float flZFar, float flFOVX, float flAspectRatio );
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Computes the screen space position given a screen size
|
|
//-----------------------------------------------------------------------------
|
|
void ComputeScreenSpacePosition( Vector2D *pScreenPosition, const Vector &vecWorldPosition,
|
|
const Camera_t &camera, int width, int height );
|
|
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// AABB
|
|
//--------------------------------------------------------------------------------------
|
|
struct AABB_t
|
|
{
|
|
DECLARE_BYTESWAP_DATADESC();
|
|
|
|
Vector m_vMinBounds;
|
|
Vector m_vMaxBounds;
|
|
|
|
Vector GetCenter() const { return ( m_vMaxBounds + m_vMinBounds ) / 2.0f; }
|
|
|
|
float GetMinDistToPoint( const Vector &vPoint ) const
|
|
{
|
|
return CalcDistanceToAABB( m_vMinBounds, m_vMaxBounds, vPoint );
|
|
}
|
|
|
|
void CreatePlanesFrom( Vector4D *pPlanes ) const
|
|
{
|
|
// X
|
|
pPlanes[0] = Vector4D( 1, 0, 0, -m_vMaxBounds.x );
|
|
pPlanes[1] = Vector4D( -1, 0, 0, m_vMinBounds.x );
|
|
|
|
// Y
|
|
pPlanes[2] = Vector4D( 0, 1, 0, -m_vMaxBounds.y );
|
|
pPlanes[3] = Vector4D( 0, -1, 0, m_vMinBounds.y );
|
|
|
|
// Z
|
|
pPlanes[4] = Vector4D( 0, 0, 1, -m_vMaxBounds.z );
|
|
pPlanes[5] = Vector4D( 0, 0, -1, m_vMinBounds.z );
|
|
}
|
|
|
|
// set the aabb to be invalid (max < min )
|
|
void MakeInvalid( void )
|
|
{
|
|
m_vMinBounds.Init( FLT_MAX, FLT_MAX, FLT_MAX );
|
|
m_vMaxBounds.Init( -FLT_MAX, -FLT_MAX, -FLT_MAX );
|
|
}
|
|
|
|
};
|
|
|
|
class CFrustum
|
|
{
|
|
public:
|
|
CFrustum()
|
|
{
|
|
}
|
|
|
|
~CFrustum()
|
|
{
|
|
}
|
|
|
|
bool BoundingVolumeIntersectsFrustum( AABB_t const &box ) const
|
|
{
|
|
Vector vMins = box.m_vMinBounds - m_camera.m_origin;
|
|
Vector vMaxs = box.m_vMaxBounds - m_camera.m_origin;
|
|
return !m_frustum.CullBox( vMins, vMaxs );
|
|
}
|
|
|
|
bool BoundingVolumeIntersectsFrustum( Vector const &mins, Vector const &maxes ) const
|
|
{
|
|
Vector vMins = mins - m_camera.m_origin;
|
|
Vector vMaxs = maxes - m_camera.m_origin;
|
|
return !m_frustum.CullBox( vMins, vMaxs );
|
|
}
|
|
|
|
bool BoundingVolumeIntersectsFrustum( AABB_t const &box, Vector &vOriginShift ) const
|
|
{
|
|
Vector vMins = box.m_vMinBounds - m_camera.m_origin - vOriginShift;
|
|
Vector vMaxs = box.m_vMaxBounds - m_camera.m_origin - vOriginShift;
|
|
return !m_frustum.CullBox( vMins, vMaxs );
|
|
}
|
|
|
|
FORCEINLINE bool CheckBoxInline( const VectorAligned &mins, const VectorAligned &maxs )
|
|
{
|
|
fltx4 fl4Origin = LoadAlignedSIMD( &m_camera.m_origin );
|
|
fltx4 mins4 = SubSIMD( LoadAlignedSIMD( &mins.x ), fl4Origin );
|
|
fltx4 maxs4 = SubSIMD( LoadAlignedSIMD( &maxs.x ), fl4Origin );
|
|
|
|
fltx4 minx = SplatXSIMD(mins4);
|
|
fltx4 miny = SplatYSIMD(mins4);
|
|
fltx4 minz = SplatZSIMD(mins4);
|
|
fltx4 maxx = SplatXSIMD(maxs4);
|
|
fltx4 maxy = SplatYSIMD(maxs4);
|
|
fltx4 maxz = SplatZSIMD(maxs4);
|
|
|
|
// compute the dot product of the normal and the farthest corner
|
|
// dotBack0 = DotProduct( normal, normals.x < 0 ? mins.x : maxs.x );
|
|
for ( int i = 0; i < 2; i++ )
|
|
{
|
|
fltx4 xTotalBack = MulSIMD( m_frustum.planes[i].nX, MaskedAssign( m_frustum.planes[i].xSign, minx, maxx ) );
|
|
fltx4 yTotalBack = MulSIMD( m_frustum.planes[i].nY, MaskedAssign( m_frustum.planes[i].ySign, miny, maxy ) );
|
|
fltx4 zTotalBack = MulSIMD( m_frustum.planes[i].nZ, MaskedAssign( m_frustum.planes[i].zSign, minz, maxz ) );
|
|
fltx4 dotBack = AddSIMD( xTotalBack, AddSIMD(yTotalBack, zTotalBack) );
|
|
// if plane of the farthest corner is behind the plane, then the box is completely outside this plane
|
|
#if _X360
|
|
if ( !XMVector3GreaterOrEqual( dotBack, m_frustum.planes[i].dist ) )
|
|
return false;
|
|
#else
|
|
fltx4 isOut = CmpLtSIMD( dotBack, m_frustum.planes[i].dist );
|
|
if ( IsAnyNegative(isOut) )
|
|
return false;
|
|
#endif
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void GetNearAndFarPlanesAroundBox( float *pNear, float *pFar, AABB_t const &inBox, Vector &vOriginShift ) const
|
|
{
|
|
AABB_t box = inBox;
|
|
box.m_vMinBounds -= vOriginShift;
|
|
box.m_vMaxBounds -= vOriginShift;
|
|
|
|
Vector vCorners[8];
|
|
vCorners[0] = box.m_vMinBounds;
|
|
vCorners[1] = Vector( box.m_vMinBounds.x, box.m_vMinBounds.y, box.m_vMaxBounds.z );
|
|
vCorners[2] = Vector( box.m_vMinBounds.x, box.m_vMaxBounds.y, box.m_vMinBounds.z );
|
|
vCorners[3] = Vector( box.m_vMinBounds.x, box.m_vMaxBounds.y, box.m_vMaxBounds.z );
|
|
|
|
vCorners[4] = Vector( box.m_vMaxBounds.x, box.m_vMinBounds.y, box.m_vMinBounds.z );
|
|
vCorners[5] = Vector( box.m_vMaxBounds.x, box.m_vMinBounds.y, box.m_vMaxBounds.z );
|
|
vCorners[6] = Vector( box.m_vMaxBounds.x, box.m_vMaxBounds.y, box.m_vMinBounds.z );
|
|
vCorners[7] = box.m_vMaxBounds;
|
|
|
|
float flNear = FLT_MAX;//m_camera.m_flZNear;
|
|
float flFar = -FLT_MAX;//m_camera.m_flZFar;
|
|
for ( int i=0; i<8; ++i )
|
|
{
|
|
Vector vDelta = vCorners[i] - m_camera.m_origin;
|
|
float flDist = DotProduct( m_forward, vDelta );
|
|
flNear = MIN( flNear, flDist );
|
|
flFar = MAX( flFar, flDist );
|
|
}
|
|
|
|
*pNear = flNear;
|
|
*pFar = flFar;
|
|
}
|
|
|
|
void UpdateFrustumFromCamera()
|
|
{
|
|
ComputeViewMatrix( &m_worldToView, &m_cameraToWorld, m_camera );
|
|
ComputeProjectionMatrix( &m_projection, m_camera.m_flZNear, m_camera.m_flZFar, m_camera.m_flFOVX, m_flAspect );
|
|
|
|
m_viewProj = (m_projection * VMatrix(m_worldToView)).Transpose();
|
|
MatrixGetColumn( m_cameraToWorld, 0, m_forward );
|
|
MatrixGetColumn( m_cameraToWorld, 1, m_left );
|
|
MatrixGetColumn( m_cameraToWorld, 2, m_up );
|
|
|
|
// NOTE: Don't pass camera origin here. Compute it locally so that voxels can be translated here
|
|
// and the plane constants retain precision over large world coordinate spaces
|
|
// Also the voxel renderer needs the camera information anyway to compute LOD so this is
|
|
// convenient
|
|
GeneratePerspectiveFrustum( vec3_origin, m_camera.m_angles, m_camera.m_flZNear, m_camera.m_flZFar, m_camera.m_flFOVX, m_flAspect, m_frustum );
|
|
}
|
|
|
|
|
|
|
|
// Just cram this here since until I figure out how to convert from direction to angles
|
|
static VMatrix ViewMatrixRH( Vector &vEye, Vector &vAt, Vector &vUp )
|
|
{
|
|
Vector xAxis, yAxis;
|
|
Vector zAxis = vEye - vAt;
|
|
xAxis = CrossProduct( vUp, zAxis );
|
|
yAxis = CrossProduct( zAxis, xAxis );
|
|
xAxis.NormalizeInPlace();
|
|
yAxis.NormalizeInPlace();
|
|
zAxis.NormalizeInPlace();
|
|
float flDotX = -DotProduct( xAxis, vEye );
|
|
float flDotY = -DotProduct( yAxis, vEye );
|
|
float flDotZ = -DotProduct( zAxis, vEye );
|
|
VMatrix mRet(
|
|
xAxis.x, yAxis.x, zAxis.x, 0,
|
|
xAxis.y, yAxis.y, zAxis.y, 0,
|
|
xAxis.z, yAxis.z, zAxis.z, 0,
|
|
flDotX, flDotY, flDotZ, 1 );
|
|
return mRet.Transpose();
|
|
}
|
|
|
|
VMatrix OrthoMatrixRH( float flWidth, float flHeight, float flNear, float flFar )
|
|
{
|
|
float flDelta = flNear - flFar;
|
|
|
|
VMatrix mRet(
|
|
2.0f / flWidth, 0, 0, 0,
|
|
0, 2.0f / flHeight, 0, 0,
|
|
0, 0, 1.0f / flDelta, 0,
|
|
0, 0, flNear / flDelta, 1 );
|
|
return mRet.Transpose();
|
|
}
|
|
|
|
|
|
const Vector &Forward() const { return m_forward; }
|
|
const Vector &Left() const { return m_left; }
|
|
const Vector &Up() const { return m_up; }
|
|
|
|
void SetView( VMatrix &mView ) { m_worldToView = mView.As3x4(); }
|
|
void SetProj( VMatrix &mProj ) { m_projection = mProj; }
|
|
void CalcViewProj( ) { m_viewProj = (m_projection * VMatrix(m_worldToView)).Transpose(); }
|
|
void SetFrustum( const Frustum_t &frustum ) { m_frustum = frustum; }
|
|
void SetForward( Vector &forward ) { m_forward = forward; }
|
|
void SetNearFarPlanes( float flNear, float flFar ) { m_camera.m_flZNear = flNear; m_camera.m_flZFar = flFar; }
|
|
void SetCameraPosition( const Vector &origin ) { m_camera.m_origin = origin; }
|
|
void SetCameraAngles( const QAngle &angles ) { m_camera.m_angles = angles; }
|
|
void SetAspect( float flAspect ) { m_flAspect = flAspect; }
|
|
void SetFOV( float flFOV ) { m_camera.m_flFOVX = flFOV; }
|
|
|
|
const Vector &GetCameraPosition() const { return m_camera.m_origin; }
|
|
const QAngle &GetCameraAngles() const { return m_camera.m_angles; }
|
|
const matrix3x4_t &GetView() const { return m_worldToView; }
|
|
const VMatrix &GetProj() const { return m_projection; }
|
|
const VMatrix &GetViewProj() const { return m_viewProj; }
|
|
float GetAspect() const { return m_flAspect; }
|
|
float GetNearPlane() const { return m_camera.m_flZNear; }
|
|
float GetFarPlane() const { return m_camera.m_flZFar; }
|
|
float GetFOV() const { return m_camera.m_flFOVX; }
|
|
|
|
void InitCamera( const Vector &origin, const QAngle &angles, float flNear, float flFar, float flFOV, float flAspect )
|
|
{
|
|
m_camera.m_origin = origin;
|
|
m_camera.m_angles = angles;
|
|
m_camera.m_flZNear = flNear;
|
|
m_camera.m_flZFar = flFar;
|
|
m_camera.m_flFOVX = flFOV;
|
|
m_flAspect = flAspect;
|
|
}
|
|
|
|
protected:
|
|
ALIGN16 Frustum_t m_frustum;
|
|
ALIGN16 Camera_t m_camera;
|
|
float m_flAspect;
|
|
Vector m_forward;
|
|
Vector m_left;
|
|
Vector m_up;
|
|
|
|
matrix3x4_t m_cameraToWorld;
|
|
matrix3x4_t m_worldToView;
|
|
VMatrix m_viewToWorld;
|
|
VMatrix m_projection;
|
|
VMatrix m_viewProj;
|
|
};
|
|
|
|
#endif // CAMERA_H
|
|
|