//===== 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 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( 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; iDraw(); 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( 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 : "" ); }