csgo-2018-source/hammer/mapworldtext.cpp
2021-07-24 21:11:47 -07:00

437 lines
13 KiB
C++

//===== Copyright Valve Corporation, All rights reserved. ======//
#include "stdafx.h"
#include "hammer_mathlib.h"
#include "Box3D.h"
#include "BSPFile.h"
#include "const.h"
#include "MapDefs.h" // dvs: For COORD_NOTINIT
#include "MapDoc.h"
#include "MapEntity.h"
#include "mapworldtext.h"
#include "Render2D.h"
#include "Render3D.h"
#include "hammer.h"
#include "Texture.h"
#include "TextureSystem.h"
#include "materialsystem/IMesh.h"
#include "Material.h"
#include "Options.h"
#include "camera.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
IMPLEMENT_MAPCLASS(CWorldTextHelper)
//-----------------------------------------------------------------------------
// Purpose: Factory function. Used for creating a CWorldTextHelper from a set
// of string parameters from the FGD file.
// Input : *pInfo - Pointer to helper info class which gives us information
// about how to create the class.
// Output : Returns a pointer to the class, NULL if an error occurs.
//-----------------------------------------------------------------------------
CMapClass *CWorldTextHelper::CreateWorldText( CHelperInfo *pHelperInfo, CMapEntity *pParent )
{
const char* pMsg = pParent->GetKeyValue( "message" );
CWorldTextHelper *pWorldText = new CWorldTextHelper;
pWorldText->SetText( pMsg );
pWorldText->SetRenderMode( kRenderTransAlpha );
return pWorldText;
}
//-----------------------------------------------------------------------------
// Purpose: Constructor.
//-----------------------------------------------------------------------------
CWorldTextHelper::CWorldTextHelper()
: m_eRenderMode( kRenderTransAlpha ),
m_flTextSize( 10.f ),
m_pText( nullptr )
{
m_RenderColor.r = 255;
m_RenderColor.g = 255;
m_RenderColor.b = 255;
m_RenderColor.a = 255;
Initialize();
}
//-----------------------------------------------------------------------------
// Purpose: Destructor.
//-----------------------------------------------------------------------------
CWorldTextHelper::~CWorldTextHelper( void )
{
if ( m_pText )
{
free( m_pText );
}
}
//-----------------------------------------------------------------------------
// Sets the render mode
//-----------------------------------------------------------------------------
void CWorldTextHelper::SetRenderMode( int eRenderMode )
{
m_eRenderMode = eRenderMode;
}
void CWorldTextHelper::ComputeCornerVertices( Vector *pVerts, float flBloat ) const
{
Vector ViewForward( 1.0f, 0.0f, 0.0f );
Vector ViewUp( 0.0f, 1.0f, 0.0f );
Vector ViewRight( 0.0f, 0.0f, -1.0f );
AngleVectors( m_Angles, &ViewForward, &ViewRight, &ViewUp );
float flStrLength = V_strlen( m_pText );
flStrLength = Max( flStrLength, 1.0f );
pVerts[ 0 ] = m_Origin - flBloat * ( ViewRight + ViewUp );
pVerts[ 1 ] = pVerts[ 0 ] + ( m_flTextSize * ( 1.0f + ( flStrLength - 1.0f ) * 0.6f ) + 2.0f * flBloat ) * ViewRight;
pVerts[ 2 ] = pVerts[ 1 ] + ( m_flTextSize + 2.0f * flBloat )* ViewUp;
pVerts[ 3 ] = pVerts[ 0 ] + ( m_flTextSize + 2.0f * flBloat )* ViewUp;
}
//-----------------------------------------------------------------------------
// Purpose: Calculates our bounding box based on the sprite dimensions.
// Input : bFullUpdate - Whether we should recalculate our childrens' bounds.
//-----------------------------------------------------------------------------
void CWorldTextHelper::CalcBounds( BOOL bFullUpdate )
{
CMapClass::CalcBounds(bFullUpdate);
Vector cornerVerts[ 4 ];
ComputeCornerVertices( cornerVerts );
Vector vMin = VectorMin( VectorMin( cornerVerts[ 0 ], cornerVerts[ 1 ] ), VectorMin( cornerVerts[ 2 ], cornerVerts[ 3 ] ) );
Vector vMax = VectorMax( VectorMax( cornerVerts[ 0 ], cornerVerts[ 1 ] ), VectorMax( cornerVerts[ 2 ], cornerVerts[ 3 ] ) );
m_CullBox.UpdateBounds( vMin, vMax );
m_Render2DBox.UpdateBounds( vMin, vMax );
}
//-----------------------------------------------------------------------------
// Purpose: Returns a copy of this object.
// Output : Pointer to the new object.
//-----------------------------------------------------------------------------
CMapClass *CWorldTextHelper::Copy( bool bUpdateDependencies )
{
CWorldTextHelper *pCopy = new CWorldTextHelper;
if (pCopy != NULL)
{
pCopy->CopyFrom(this, bUpdateDependencies);
}
return pCopy;
}
//-----------------------------------------------------------------------------
// Purpose: Turns this into a duplicate of the given object.
// Input : pObject - Pointer to the object to copy from.
// Output : Returns a pointer to this object.
//-----------------------------------------------------------------------------
CMapClass *CWorldTextHelper::CopyFrom( CMapClass *pObject, bool bUpdateDependencies )
{
CWorldTextHelper *pFrom = dynamic_cast<CWorldTextHelper*>( pObject );
Assert( pFrom != NULL );
if ( pFrom != NULL )
{
CMapClass::CopyFrom(pObject, bUpdateDependencies);
m_Angles = pFrom->m_Angles;
SetText( pFrom->m_pText );
SetRenderMode( pFrom->m_eRenderMode );
m_RenderColor = pFrom->m_RenderColor;
}
return this;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : Angles -
//-----------------------------------------------------------------------------
void CWorldTextHelper::GetAngles( QAngle &Angles )
{
Angles = m_Angles;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWorldTextHelper::Initialize( void )
{
SetText( "" );
m_Angles.Init();
//m_eRenderMode = kRenderNormal;
m_RenderColor.r = 255;
m_RenderColor.g = 255;
m_RenderColor.b = 255;
}
#define CHAR_WIDTH 0.0625f // 1/16
#define CHAR_HEIGHT 0.0625f // 1/16
void CWorldTextHelper::Render3DText( CRender3D *pRender, const char* szText, const float flTextSize )
{
if ( !szText )
return;
int nNumChars = strlen( szText );
if ( !nNumChars )
return;
Vector ViewForward( 1.0f, 0.0f, 0.0f );
Vector ViewUp( 0.0f, 1.0f, 0.0f );
Vector ViewRight( 0.0f, 0.0f, -1.0f );
AngleVectors( m_Angles, &ViewForward, &ViewRight, &ViewUp );
Vector vecStartPos;
VectorCopy( m_Origin, vecStartPos );
IMaterial* pDebugText = g_pMaterialSystem->FindMaterial( "editor/worldtext", TEXTURE_GROUP_OTHER, true );
if ( !pDebugText )
return;
pRender->PushRenderMode( RENDER_MODE_EXTERN );
CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
pRenderContext->Bind( pDebugText );
IMesh* pMesh = pRenderContext->GetDynamicMesh();
CMeshBuilder meshBuilder;
float screenSize = flTextSize;
meshBuilder.Begin( pMesh, MATERIAL_QUADS, nNumChars );
for ( int i=0; i<nNumChars; i++ )
{
int nCharIdx = (int)((char)*szText) - 32;
int nRow = nCharIdx / 16;
int nCol = nCharIdx % 16;
float flU = (nCol * CHAR_WIDTH);
float flV = (nRow * CHAR_HEIGHT);
flV += CHAR_HEIGHT;
meshBuilder.Position3fv( vecStartPos.Base() );
meshBuilder.TexCoord2f( 0, flU, flV );
meshBuilder.Color4ub( m_RenderColor.r, m_RenderColor.g, m_RenderColor.b, 255 );
meshBuilder.AdvanceVertex();
vecStartPos += (ViewUp * screenSize);
flV -= CHAR_HEIGHT;
meshBuilder.Position3fv( vecStartPos.Base() );
meshBuilder.TexCoord2f( 0, flU, flV );
meshBuilder.Color4ub( m_RenderColor.r, m_RenderColor.g, m_RenderColor.b, 255 );
meshBuilder.AdvanceVertex();
vecStartPos += (ViewRight * screenSize);
flU += CHAR_WIDTH;
meshBuilder.Position3fv( vecStartPos.Base() );
meshBuilder.TexCoord2f( 0, flU, flV );
meshBuilder.Color4ub( m_RenderColor.r, m_RenderColor.g, m_RenderColor.b, 255 );
meshBuilder.AdvanceVertex();
vecStartPos -= (ViewUp * screenSize);
flV += CHAR_HEIGHT;
meshBuilder.Position3fv( vecStartPos.Base() );
meshBuilder.TexCoord2f( 0, flU, flV );
meshBuilder.Color4ub( m_RenderColor.r, m_RenderColor.g, m_RenderColor.b, 255 );
meshBuilder.AdvanceVertex();
vecStartPos -= (ViewRight * screenSize * 0.4f);
szText++;
}
meshBuilder.End();
pMesh->Draw();
pRender->PopRenderMode();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pRender -
//-----------------------------------------------------------------------------
void CWorldTextHelper::Render3D(CRender3D *pRender)
{
pRender->BeginRenderHitTarget( this );
Render3DText( pRender, m_pText, m_flTextSize );
pRender->EndRenderHitTarget();
if ( GetSelectionState() != SELECT_NONE )
{
// Selection box
pRender->PushRenderMode( RENDER_MODE_WIREFRAME );
Vector cornerVerts[ 4 ];
ComputeCornerVertices( cornerVerts, 0.2f );
pRender->SetDrawColor( 255, 255, 0 );
pRender->DrawLine( cornerVerts[ 0 ], cornerVerts[ 1 ] );
pRender->DrawLine( cornerVerts[ 1 ], cornerVerts[ 2 ] );
pRender->DrawLine( cornerVerts[ 2 ], cornerVerts[ 3 ] );
pRender->DrawLine( cornerVerts[ 3 ], cornerVerts[ 0 ] );
pRender->PopRenderMode();
}
//pRender->PushRenderMode(RENDER_MODE_NONE);
//pRender->BeginRenderHitTarget( this );
//VMatrix matXform;
//matXform.SetupMatrixOrgAngles( m_Origin, m_Angles );
//pRender->BeginLocalTransfrom( matXform );
//float flStrLength = V_strlen( m_pText );
//pRender->RenderBox( Vector( -1.0f, 0.0f, 0.0f ), Vector( 1.0f, -m_flTextSize * ( 1.0f + ( flStrLength - 1.0f ) * 0.6f ), m_flTextSize ), 0, 255, 0, GetSelectionState() );
//pRender->EndLocalTransfrom();
//pRender->EndRenderHitTarget();
//pRender->PopRenderMode();
}
//-----------------------------------------------------------------------------
int CWorldTextHelper::SerializeRMF(std::fstream &File, BOOL bRMF)
{
return(0);
}
//-----------------------------------------------------------------------------
int CWorldTextHelper::SerializeMAP(std::fstream &File, BOOL bRMF)
{
return(0);
}
//-----------------------------------------------------------------------------
void CWorldTextHelper::DoTransform(const VMatrix &matrix)
{
BaseClass::DoTransform(matrix);
matrix3x4_t fCurrentMatrix,fMatrixNew;
AngleMatrix(m_Angles, fCurrentMatrix);
ConcatTransforms(matrix.As3x4(), fCurrentMatrix, fMatrixNew);
MatrixAngles(fMatrixNew, m_Angles);
//
// Update the angles of our parent entity.
//
CMapEntity *pEntity = dynamic_cast<CMapEntity*>( m_pParent );
if ( pEntity )
{
char szValue[ 80 ];
sprintf( szValue, "%g %g %g", m_Angles[ 0 ], m_Angles[ 1 ], m_Angles[ 2 ] );
pEntity->NotifyChildKeyChanged( this, "angles", szValue );
}
}
//-----------------------------------------------------------------------------
// Purpose: Notifies that this object's parent entity has had a key value change.
// Input : szKey - The key that changed.
// szValue - The new value of the key.
//-----------------------------------------------------------------------------
void CWorldTextHelper::OnParentKeyChanged(const char* szKey, const char* szValue)
{
if (!stricmp(szKey, "message"))
{
SetText( szValue );
PostUpdate(Notify_Changed);
}
else if (!stricmp(szKey, "angles"))
{
sscanf(szValue, "%f %f %f", &m_Angles[PITCH], &m_Angles[YAW], &m_Angles[ROLL]);
PostUpdate(Notify_Changed);
}
else if ( !stricmp( szKey, "textsize" ) )
{
sscanf( szValue, "%f", &m_flTextSize );
PostUpdate( Notify_Changed );
}
else if ( !stricmp( szKey, "color" ) )
{
int r = 0, g = 0, b = 0;
sscanf( szValue, "%d %d %d", &r, &g, &b );
m_RenderColor.r = r;
m_RenderColor.g = g;
m_RenderColor.b = b;
PostUpdate( Notify_Changed );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CWorldTextHelper::ShouldRenderLast(void)
{
return false;
}
//-----------------------------------------------------------------------------
void CWorldTextHelper::Render2D(CRender2D *pRender)
{
Vector vecMins;
Vector vecMaxs;
GetRender2DBox(vecMins, vecMaxs);
Vector2D pt,pt2;
pRender->TransformPoint(pt, vecMins);
pRender->TransformPoint(pt2, vecMaxs);
if ( !IsSelected() )
{
pRender->SetDrawColor( r, g, b );
pRender->SetHandleColor( r, g, b );
}
else
{
pRender->SetDrawColor( GetRValue(Options.colors.clrSelection), GetGValue(Options.colors.clrSelection), GetBValue(Options.colors.clrSelection) );
pRender->SetHandleColor( GetRValue(Options.colors.clrSelection), GetGValue(Options.colors.clrSelection), GetBValue(Options.colors.clrSelection) );
}
// Draw the bounding box.
pRender->DrawBox( vecMins, vecMaxs );
//
// Draw center handle.
//
if ( pRender->IsActiveView() )
{
int sizex = abs(pt.x - pt2.x)+1;
int sizey = abs(pt.y - pt2.y)+1;
// dont draw handle if object is too small
if ( sizex > 6 && sizey > 6 )
{
pRender->SetHandleStyle( HANDLE_RADIUS, CRender::HANDLE_CROSS );
pRender->DrawHandle( (vecMins+vecMaxs)/2 );
}
}
}
void CWorldTextHelper::SetText( const char *pNewText )
{
if ( m_pText )
{
free( m_pText );
}
m_pText = strdup( pNewText ? pNewText : "" );
}