diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /hammer/camera.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'hammer/camera.cpp')
| -rw-r--r-- | hammer/camera.cpp | 714 |
1 files changed, 714 insertions, 0 deletions
diff --git a/hammer/camera.cpp b/hammer/camera.cpp new file mode 100644 index 0000000..9225aa8 --- /dev/null +++ b/hammer/camera.cpp @@ -0,0 +1,714 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Implements a camera for the 3D view. +// +// $NoKeywords: $ +//=============================================================================// + +#include <windows.h> +#include <math.h> +#include <stdlib.h> +#include <stdio.h> +#include "Camera.h" +#include "hammer_mathlib.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// +// Indices of camera axes. +// +#define CAMERA_RIGHT 0 +#define CAMERA_UP 1 +#define CAMERA_FORWARD 2 +#define CAMERA_ORIGIN 3 + +#define MIN_PITCH -90.0f +#define MAX_PITCH 90.0f + + +static void DBG(PRINTF_FORMAT_STRING const char *fmt, ...) +{ + char ach[128]; + va_list va; + + va_start(va, fmt); + vsprintf(ach, fmt, va); + va_end(va); + OutputDebugString(ach); +} + + +//----------------------------------------------------------------------------- +// Purpose: Constructor. +//----------------------------------------------------------------------------- +CCamera::CCamera(void) +{ + m_ViewPoint.Init(); + + m_fPitch = 0.0; + m_fRoll = 0.0; + m_fYaw = 0.0; + + m_fHorizontalFOV = 90; + m_fNearClip = 1.0; + m_fFarClip = 5000; + + m_fZoom = 1.0f; + m_bIsOrthographic = false; + + m_fScaleHorz = m_fScaleVert = 1; + m_nViewWidth = m_nViewHeight = 100; + + BuildViewMatrix(); + BuildProjMatrix(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Destructor. +//----------------------------------------------------------------------------- +CCamera::~CCamera(void) +{ +} + +void CCamera::SetViewPort( int width, int height ) +{ + if ( m_nViewWidth != width || m_nViewHeight != height ) + { + m_nViewWidth = width; + m_nViewHeight = height; + BuildProjMatrix(); + } +} + +void CCamera::GetViewPort( int &width, int &height ) +{ + width = m_nViewWidth; + height = m_nViewHeight; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the current value of the camera's pitch. +//----------------------------------------------------------------------------- +float CCamera::GetPitch(void) +{ + return(m_fPitch); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the current value of the camera's roll. +//----------------------------------------------------------------------------- +float CCamera::GetRoll(void) +{ + return(m_fRoll); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the current value of the camera's yaw. +//----------------------------------------------------------------------------- +float CCamera::GetYaw(void) +{ + return(m_fYaw); +} + + +//----------------------------------------------------------------------------- +// Purpose: returns the camera angles +// Output : returns the camera angles +//----------------------------------------------------------------------------- +QAngle CCamera::GetAngles() +{ + return QAngle( m_fPitch, m_fYaw, m_fRoll ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Moves the camera along the camera's right axis. +// Input : fUnits - World units to move the camera. +//----------------------------------------------------------------------------- +void CCamera::MoveRight(float fUnits) +{ + if (fUnits != 0) + { + m_ViewPoint[0] += m_ViewMatrix[CAMERA_RIGHT][0] * fUnits; + m_ViewPoint[1] += m_ViewMatrix[CAMERA_RIGHT][1] * fUnits; + m_ViewPoint[2] += m_ViewMatrix[CAMERA_RIGHT][2] * fUnits; + BuildViewMatrix(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Moves the camera along the camera's up axis. +// Input : fUnits - World units to move the camera. +//----------------------------------------------------------------------------- +void CCamera::MoveUp(float fUnits) +{ + if (fUnits != 0) + { + m_ViewPoint[0] += m_ViewMatrix[CAMERA_UP][0] * fUnits; + m_ViewPoint[1] += m_ViewMatrix[CAMERA_UP][1] * fUnits; + m_ViewPoint[2] += m_ViewMatrix[CAMERA_UP][2] * fUnits; + BuildViewMatrix(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Moves the camera along the camera's forward axis. +// Input : fUnits - World units to move the camera. +//----------------------------------------------------------------------------- +void CCamera::MoveForward(float fUnits) +{ + if (fUnits != 0) + { + m_ViewPoint[0] -= m_ViewMatrix[CAMERA_FORWARD][0] * fUnits; + m_ViewPoint[1] -= m_ViewMatrix[CAMERA_FORWARD][1] * fUnits; + m_ViewPoint[2] -= m_ViewMatrix[CAMERA_FORWARD][2] * fUnits; + BuildViewMatrix(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the camera's viewpoint. +//----------------------------------------------------------------------------- +void CCamera::GetViewPoint(Vector& ViewPoint) const +{ + ViewPoint = m_ViewPoint; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns a vector indicating the camera's forward axis. +//----------------------------------------------------------------------------- +void CCamera::GetViewForward(Vector& ViewForward) const +{ + ViewForward[0] = -m_ViewMatrix[CAMERA_FORWARD][0]; + ViewForward[1] = -m_ViewMatrix[CAMERA_FORWARD][1]; + ViewForward[2] = -m_ViewMatrix[CAMERA_FORWARD][2]; +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns a vector indicating the camera's up axis. +//----------------------------------------------------------------------------- +void CCamera::GetViewUp(Vector& ViewUp) const +{ + ViewUp[0] = m_ViewMatrix[CAMERA_UP][0]; + ViewUp[1] = m_ViewMatrix[CAMERA_UP][1]; + ViewUp[2] = m_ViewMatrix[CAMERA_UP][2]; +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns a vector indicating the camera's right axis. +//----------------------------------------------------------------------------- +void CCamera::GetViewRight(Vector& ViewRight) const +{ + ViewRight[0] = m_ViewMatrix[CAMERA_RIGHT][0]; + ViewRight[1] = m_ViewMatrix[CAMERA_RIGHT][1]; + ViewRight[2] = m_ViewMatrix[CAMERA_RIGHT][2]; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the horizontal field of view in degrees. +//----------------------------------------------------------------------------- +float CCamera::GetFOV(void) +{ + return(m_fHorizontalFOV); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the distance from the camera to the near clipping plane in world units. +//----------------------------------------------------------------------------- +float CCamera::GetNearClip(void) +{ + return(m_fNearClip); +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the distance from the camera to the far clipping plane in world units. +//----------------------------------------------------------------------------- +float CCamera::GetFarClip(void) +{ + return(m_fFarClip); +} + +//----------------------------------------------------------------------------- +// Purpose: Sets up fields of view & clip plane distances for the view frustum. +// Input : fHorizontalFOV - +// fVerticalFOV - +// fNearClip - +// fFarClip - +//----------------------------------------------------------------------------- +void CCamera::SetPerspective(float fHorizontalFOV, float fNearClip, float fFarClip) +{ + m_bIsOrthographic = false; + m_fHorizontalFOV = fHorizontalFOV; + m_fNearClip = fNearClip; + m_fFarClip = fFarClip; + BuildProjMatrix(); +} + +void CCamera::SetOrthographic(float fZoom, float fNearClip, float fFarClip) +{ + m_fZoom = fZoom; + m_fNearClip = fNearClip; + m_fFarClip = fFarClip; + m_bIsOrthographic = true; + BuildProjMatrix(); +} + +void CCamera::GetFrustumPlanes( Vector4D Planes[6] ) +{ + // TODO check for FrustumPlanesFromMatrix, maybe we can use that + + Vector ViewForward; + GetViewForward(ViewForward); + + VMatrix CameraMatrix = m_ProjMatrix * m_ViewMatrix; + + // + // Now the plane coefficients can be pulled directly out of the the camera + // matrix as follows: + // + // Right : first_column - fourth_column + // Left : -first_column - fourth_column + // Top : second_column - fourth_column + // Bottom: -second_column - fourth_column + // Front : -third_column - fourth_column + // Back : third_column + fourth_column + // + // dvs: My plane constants should be coming directly from the matrices, + // but they aren't (for some reason). Instead I calculate the plane + // constants myself. Sigh. + // + Planes[0][0] = CameraMatrix[0][0] - CameraMatrix[3][0]; + Planes[0][1] = CameraMatrix[0][1] - CameraMatrix[3][1]; + Planes[0][2] = CameraMatrix[0][2] - CameraMatrix[3][2]; + VectorNormalize(Planes[0].AsVector3D()); + Planes[0][3] = DotProduct(m_ViewPoint, Planes[0].AsVector3D()); + + Planes[1][0] = -CameraMatrix[0][0] - CameraMatrix[3][0]; + Planes[1][1] = -CameraMatrix[0][1] - CameraMatrix[3][1]; + Planes[1][2] = -CameraMatrix[0][2] - CameraMatrix[3][2]; + VectorNormalize(Planes[1].AsVector3D()); + Planes[1][3] = DotProduct(m_ViewPoint, Planes[1].AsVector3D()); + + Planes[2][0] = CameraMatrix[1][0] - CameraMatrix[3][0]; + Planes[2][1] = CameraMatrix[1][1] - CameraMatrix[3][1]; + Planes[2][2] = CameraMatrix[1][2] - CameraMatrix[3][2]; + VectorNormalize(Planes[2].AsVector3D()); + Planes[2][3] = DotProduct(m_ViewPoint, Planes[2].AsVector3D()); + + Planes[3][0] = -CameraMatrix[1][0] - CameraMatrix[3][0]; + Planes[3][1] = -CameraMatrix[1][1] - CameraMatrix[3][1]; + Planes[3][2] = -CameraMatrix[1][2] - CameraMatrix[3][2]; + VectorNormalize(Planes[3].AsVector3D()); + Planes[3][3] = DotProduct(m_ViewPoint, Planes[3].AsVector3D()); + + Planes[4][0] = -CameraMatrix[2][0] - CameraMatrix[3][0]; + Planes[4][1] = -CameraMatrix[2][1] - CameraMatrix[3][1]; + Planes[4][2] = -CameraMatrix[2][2] - CameraMatrix[3][2]; + VectorNormalize(Planes[4].AsVector3D()); + Planes[4][3] = DotProduct(m_ViewPoint + ViewForward * m_fNearClip, Planes[4].AsVector3D()); + + Planes[5][0] = CameraMatrix[2][0] + CameraMatrix[3][0]; + Planes[5][1] = CameraMatrix[2][1] + CameraMatrix[3][1]; + Planes[5][2] = CameraMatrix[2][2] + CameraMatrix[3][2]; + VectorNormalize(Planes[5].AsVector3D()); + Planes[5][3] = DotProduct(m_ViewPoint + ViewForward * m_fFarClip, Planes[5].AsVector3D()); +} + +bool CCamera::IsOrthographic() +{ + return m_bIsOrthographic; +} + +void CCamera::BuildProjMatrix() +{ + memset( &m_ProjMatrix,0,sizeof(m_ProjMatrix) ); + VMatrix &m = m_ProjMatrix; + + if ( m_bIsOrthographic ) + { + // same as D3DXMatrixOrthoRH + float w = (float)m_nViewWidth / m_fZoom; + float h = (float)m_nViewHeight / m_fZoom; + + m[0][0] = 2/w; + m[1][1] = 2/h; + + m[2][2] = 1/(m_fNearClip-m_fFarClip); + m[2][3] = m_fNearClip/(m_fNearClip-m_fFarClip); + + m[3][3] = 1; + } + else + { + // same as D3DXMatrixPerspectiveRH + float w = 2 * m_fNearClip * tan( m_fHorizontalFOV * M_PI / 360.0 ); + float h = ( w * float(m_nViewHeight) ) / float(m_nViewWidth); + + m[0][0] = 2*m_fNearClip/w; + m[1][1] = 2*m_fNearClip/h; + + m[2][2] = m_fFarClip/(m_fNearClip-m_fFarClip); + m[2][3] = (m_fNearClip*m_fFarClip)/(m_fNearClip-m_fFarClip); + + m[3][2] = -1; + } + + m_ViewProjMatrix = m_ProjMatrix * m_ViewMatrix; + m_ViewProjMatrix.InverseGeneral( m_InvViewProjMatrix ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets the distance from the camera to the near clipping plane in world units. +//----------------------------------------------------------------------------- +void CCamera::SetNearClip(float fNearClip) +{ + if ( m_fNearClip != fNearClip ) + { + m_fNearClip = fNearClip; + BuildProjMatrix(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets the distance from the camera to the far clipping plane in world units. +//----------------------------------------------------------------------------- +void CCamera::SetFarClip(float fFarClip) +{ + if ( m_fFarClip != fFarClip ) + { + m_fFarClip = fFarClip; + BuildProjMatrix(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets the pitch in degrees, from [MIN_PITCH..MAX_PITCH] +//----------------------------------------------------------------------------- +void CCamera::SetPitch(float fDegrees) +{ + if (m_fPitch != fDegrees) + { + m_fPitch = fDegrees; + + if (m_fPitch > MAX_PITCH) + { + m_fPitch = MAX_PITCH; + } + else if (m_fPitch < MIN_PITCH) + { + m_fPitch = MIN_PITCH; + } + BuildViewMatrix(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets the roll in degrees, from [0..360) +//----------------------------------------------------------------------------- +void CCamera::SetRoll(float fDegrees) +{ + while (fDegrees >= 360) + { + fDegrees -= 360; + } + + while (fDegrees < 0) + { + fDegrees += 360; + } + + if (m_fRoll != fDegrees) + { + m_fRoll = fDegrees; + BuildViewMatrix(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets the yaw in degrees, from [0..360) +//----------------------------------------------------------------------------- +void CCamera::SetYaw(float fDegrees) +{ + while (fDegrees >= 360) + { + fDegrees -= 360; + } + + while (fDegrees < 0) + { + fDegrees += 360; + } + + if (m_fYaw != fDegrees) + { + m_fYaw = fDegrees; + BuildViewMatrix(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets the view point. +//----------------------------------------------------------------------------- +void CCamera::SetViewPoint(const Vector &ViewPoint) +{ + if ( m_ViewPoint != ViewPoint ) + { + m_ViewPoint = ViewPoint; + BuildViewMatrix(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets the camera target, rebuilding the view matrix. +// Input : ViewTarget - the point in world space that the camera should look at. +//----------------------------------------------------------------------------- +void CCamera::SetViewTarget(const Vector &ViewTarget) +{ + Vector ViewOrigin; + Vector ViewForward; + + GetViewPoint( ViewOrigin ); + + VectorSubtract(ViewTarget, ViewOrigin, ViewForward); + VectorNormalize(ViewForward); + + // + // Ideally we could replace the math below with standard VectorAngles stuff, but Hammer + // camera matrices use a different convention from QAngle (sadly). + // + float fYaw = RAD2DEG(atan2(ViewForward[0], ViewForward[1])); + SetYaw(fYaw); + + float fPitch = -RAD2DEG(asin(ViewForward[2])); + SetPitch(fPitch); +} + + +//----------------------------------------------------------------------------- +// Purpose: Pitches the camera forward axis toward the camera's down axis a +// given number of degrees. +//----------------------------------------------------------------------------- +void CCamera::Pitch(float fDegrees) +{ + if (fDegrees != 0) + { + float fPitch = GetPitch(); + fPitch += fDegrees; + SetPitch(fPitch); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Rolls the camera's right axis toward the camera's up axis a given +// number of degrees. +//----------------------------------------------------------------------------- +void CCamera::Roll(float fDegrees) +{ + if (fDegrees != 0) + { + float fRoll = GetRoll(); + fRoll += fDegrees; + SetRoll(fRoll); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Yaws the camera's forward axis toward the camera's right axis a +// given number of degrees. +//----------------------------------------------------------------------------- +void CCamera::Yaw(float fDegrees) +{ + if (fDegrees != 0) + { + float fYaw = GetYaw(); + fYaw += fDegrees; + SetYaw(fYaw); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Loads the given matrix with an identity matrix. +// Input : Matrix - 4 x 4 matrix to be loaded with the identity matrix. +//----------------------------------------------------------------------------- +void CCamera::CameraIdentityMatrix(VMatrix& Matrix) +{ + // This function produces a transform which transforms from + // material system camera space to quake camera space + + // Camera right axis lies along the world X axis. + Matrix[CAMERA_RIGHT][0] = 1; + Matrix[CAMERA_RIGHT][1] = 0; + Matrix[CAMERA_RIGHT][2] = 0; + Matrix[CAMERA_RIGHT][3] = 0; + + // Camera up axis lies along the world Z axis. + Matrix[CAMERA_UP][0] = 0; + Matrix[CAMERA_UP][1] = 0; + Matrix[CAMERA_UP][2] = 1; + Matrix[CAMERA_UP][3] = 0; + + // Camera forward axis lies along the negative world Y axis. + Matrix[CAMERA_FORWARD][0] = 0; + Matrix[CAMERA_FORWARD][1] = -1; + Matrix[CAMERA_FORWARD][2] = 0; + Matrix[CAMERA_FORWARD][3] = 0; + + Matrix[CAMERA_ORIGIN][0] = 0; + Matrix[CAMERA_ORIGIN][1] = 0; + Matrix[CAMERA_ORIGIN][2] = 0; + Matrix[CAMERA_ORIGIN][3] = 1; +} + +//----------------------------------------------------------------------------- +// Purpose: Generates a view matrix based on our current yaw, pitch, and roll. +// The view matrix does not consider FOV or clip plane distances. +//----------------------------------------------------------------------------- +void CCamera::BuildViewMatrix() +{ + // The camera transformation is produced by multiplying roll * yaw * pitch. + // This will transform a point from world space into quake camera space, + // which is exactly what we want for our view matrix. However, quake + // camera space isn't the same as material system camera space, so + // we're going to have to apply a transformation that goes from quake + // camera space to material system camera space. + + CameraIdentityMatrix( m_ViewMatrix ); + + RotateAroundAxis(m_ViewMatrix, m_fPitch, 0 ); + RotateAroundAxis(m_ViewMatrix, m_fRoll, 1); + RotateAroundAxis(m_ViewMatrix, m_fYaw, 2); + + // Translate the viewpoint to the world origin. + VMatrix TempMatrix; + TempMatrix.Identity(); + TempMatrix.SetTranslation( -m_ViewPoint ); + + m_ViewMatrix = m_ViewMatrix * TempMatrix; + + m_ViewProjMatrix = m_ProjMatrix * m_ViewMatrix; + m_ViewProjMatrix.InverseGeneral( m_InvViewProjMatrix ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : Matrix - +//----------------------------------------------------------------------------- +void CCamera::GetViewMatrix(VMatrix& Matrix) +{ + Matrix = m_ViewMatrix; + +} + +void CCamera::GetProjMatrix(VMatrix& Matrix) +{ + Matrix = m_ProjMatrix; +} + + +//----------------------------------------------------------------------------- +// Purpose: Sets the view matrix of the current projection +// Output : Matrix - the matrix to store the current projection matrix +//----------------------------------------------------------------------------- +void CCamera::GetViewProjMatrix( VMatrix &Matrix ) +{ + Matrix = m_ViewProjMatrix; +} + + +//----------------------------------------------------------------------------- +// Purpose: to set the zoom in the orthographic gl view +// Input: fScale - the zoom scale +//----------------------------------------------------------------------------- +void CCamera::SetZoom( float fScale ) +{ + if ( m_fZoom != fScale ) + { + m_fZoom = fScale; + BuildProjMatrix(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: to accumulate the zoom in the orthographic gl view +// Input: fScale - the zoom scale +//----------------------------------------------------------------------------- +void CCamera::Zoom( float fScale ) +{ + m_fZoom += fScale; + + // don't zoom negative + if( m_fZoom < 0.00001f ) + m_fZoom = 0.00001f; +} + + +//----------------------------------------------------------------------------- +// Purpose: to get the zoom in the orthographic gl view +// Output: return the zoom scale +//----------------------------------------------------------------------------- +float CCamera::GetZoom( void ) +{ + return m_fZoom; +} + +void CCamera::WorldToView( const Vector& vWorld, Vector2D &vView ) +{ + Vector vView3D; + + Vector3DMultiplyPositionProjective( m_ViewProjMatrix, vWorld, vView3D ); + + // NOTE: The negative sign on y is because wc wants to think about screen + // coordinates in a different way than the material system + vView.x = 0.5 * (vView3D.x + 1.0) * m_nViewWidth; + vView.y = 0.5 * (-vView3D.y + 1.0) * m_nViewHeight; +} + +void CCamera::ViewToWorld( const Vector2D &vView, Vector& vWorld) +{ + Vector vView3D; + + vView3D.x = 2.0 * vView.x / m_nViewWidth - 1; + vView3D.y = -2.0 * vView.y / m_nViewHeight + 1; + vView3D.z = 0; + + Vector3DMultiplyPositionProjective( m_InvViewProjMatrix, vView3D, vWorld ); +} + +void CCamera::BuildRay( const Vector2D &vView, Vector& vStart, Vector& vEnd ) +{ + // Find the point they clicked on in world coordinates. It lies on the near + // clipping plane. + Vector vClickPoint; + ViewToWorld(vView, vClickPoint ); + + // Build a ray from the viewpoint through the point on the near clipping plane. + Vector vRay = vClickPoint - m_ViewPoint; + VectorNormalize( vRay ); + + vStart = m_ViewPoint; + vEnd = vStart + vRay * 99999; +} + + |