summaryrefslogtreecommitdiff
path: root/tools/vcdblock
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /tools/vcdblock
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'tools/vcdblock')
-rw-r--r--tools/vcdblock/dmevmfentity.cpp664
-rw-r--r--tools/vcdblock/dmevmfentity.h131
-rw-r--r--tools/vcdblock/infotargetbrowserpanel.cpp297
-rw-r--r--tools/vcdblock/infotargetbrowserpanel.h68
-rw-r--r--tools/vcdblock/infotargetpropertiespanel.cpp225
-rw-r--r--tools/vcdblock/infotargetpropertiespanel.h76
-rw-r--r--tools/vcdblock/vcdblock.vpc64
-rw-r--r--tools/vcdblock/vcdblockdoc.cpp630
-rw-r--r--tools/vcdblock/vcdblockdoc.h108
-rw-r--r--tools/vcdblock/vcdblocktool.cpp1300
-rw-r--r--tools/vcdblock/vcdblocktool.h239
11 files changed, 3802 insertions, 0 deletions
diff --git a/tools/vcdblock/dmevmfentity.cpp b/tools/vcdblock/dmevmfentity.cpp
new file mode 100644
index 0000000..0432634
--- /dev/null
+++ b/tools/vcdblock/dmevmfentity.cpp
@@ -0,0 +1,664 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "DmeVMFEntity.h"
+#include "datamodel/dmelementfactoryhelper.h"
+#include "toolframework/itoolentity.h"
+#include "materialsystem/imesh.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imaterialsystem.h"
+#include "engine/iclientleafsystem.h"
+#include "toolutils/enginetools_int.h"
+#include "vcdblocktool.h"
+#include "tier1/KeyValues.h"
+
+// for tracing
+#include "cmodel.h"
+#include "engine/ienginetrace.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+#define SPHERE_RADIUS 16
+
+//-----------------------------------------------------------------------------
+// Expose this class to the scene database
+//-----------------------------------------------------------------------------
+IMPLEMENT_ELEMENT_FACTORY( DmeVMFEntity, CDmeVMFEntity );
+
+
+//-----------------------------------------------------------------------------
+// Used to store the next unique entity id;
+//-----------------------------------------------------------------------------
+int CDmeVMFEntity::s_nNextEntityId;
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDmeVMFEntity::OnConstruction()
+{
+ m_ClassName.Init( this, "classname", FATTRIB_HAS_CALLBACK );
+ m_TargetName.Init( this, "targetname" );
+ m_bIsPlaceholder.InitAndSet( this, "_placeholder", false, FATTRIB_DONTSAVE );
+ m_vecLocalOrigin.Init( this, "origin" );
+ m_vecLocalAngles.Init( this, "angles" );
+ m_bIsDeleted.Init( this, "deleted" );
+
+ if ( m_Name.Length() == 0 )
+ {
+ // Assign a unique ID to the name
+ char pNameString[128];
+ Q_snprintf( pNameString, sizeof(pNameString), "%d", GetNextEntityId() );
+ m_Name = pNameString;
+ }
+
+ // See if we need to bump the unique id up
+ int nEntityId = GetEntityId();
+ if ( s_nNextEntityId <= nEntityId )
+ {
+ s_nNextEntityId = nEntityId + 1;
+ }
+
+ // Get called back when the name changes
+ m_Name.GetAttribute()->AddFlag( FATTRIB_HAS_CALLBACK );
+
+ // Used to make sure these aren't saved if they aren't changed
+ //m_TargetName.GetAttribute()->AddFlag( FATTRIB_DONTSAVE | FATTRIB_HAS_CALLBACK );
+ //m_vecLocalAngles.GetAttribute()->AddFlag( FATTRIB_DONTSAVE | FATTRIB_HAS_CALLBACK );
+
+ m_bIsDirty = false;
+ m_bInfoTarget = false;
+ m_hEngineEntity = HTOOLHANDLE_INVALID;
+
+ m_Wireframe.Init( "debug/debugwireframevertexcolor", "editor" );
+
+ // FIXME: Need to abstract out rendering into a separate class
+ // based on information parsed from the FGD
+ KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
+ pVMTKeyValues->SetString( "$basetexture", "editor/info_target" );
+ pVMTKeyValues->SetInt( "$nocull", 1 );
+ pVMTKeyValues->SetInt( "$vertexcolor", 1 );
+ pVMTKeyValues->SetInt( "$vertexalpha", 1 );
+ pVMTKeyValues->SetInt( "$no_fullbright", 1 );
+ pVMTKeyValues->SetInt( "$translucent", 1 );
+ m_InfoTargetSprite.Init( "__vcdblock_info_target", pVMTKeyValues );
+
+ pVMTKeyValues = new KeyValues( "UnlitGeneric" );
+ pVMTKeyValues->SetInt( "$nocull", 1 );
+ pVMTKeyValues->SetString( "$color", "{64 64 64}" );
+ pVMTKeyValues->SetInt( "$vertexalpha", 1 );
+ pVMTKeyValues->SetInt( "$no_fullbright", 1 );
+ pVMTKeyValues->SetInt( "$additive", 1 );
+ m_SelectedInfoTarget.Init( "__selected_vcdblock_info_target", pVMTKeyValues );
+}
+
+void CDmeVMFEntity::OnDestruction()
+{
+ // Unhook it from the engine
+ AttachToEngineEntity( false );
+ m_Wireframe.Shutdown();
+ m_SelectedInfoTarget.Shutdown();
+ m_InfoTargetSprite.Shutdown();
+}
+
+
+//-----------------------------------------------------------------------------
+// Called whem attributes change
+//-----------------------------------------------------------------------------
+void CDmeVMFEntity::OnAttributeChanged( CDmAttribute *pAttribute )
+{
+ BaseClass::OnAttributeChanged( pAttribute );
+
+ // Once these have changed, then save them out, and don't bother calling back
+ if ( pAttribute == m_TargetName.GetAttribute() ||
+ pAttribute == m_vecLocalAngles.GetAttribute() )
+ {
+ pAttribute->RemoveFlag( FATTRIB_DONTSAVE | FATTRIB_HAS_CALLBACK );
+ return;
+ }
+
+ if ( pAttribute == m_ClassName.GetAttribute() )
+ {
+ m_bInfoTarget = !Q_strncmp( m_ClassName, "info_target", 11 );
+
+ // FIXME: Change the model based on the current class
+ SetModelName( NULL );
+ return;
+ }
+
+ // Make sure we have unique ids for all entities
+ if ( pAttribute == m_Name.GetAttribute() )
+ {
+ int nEntityId = GetEntityId();
+ if ( s_nNextEntityId <= nEntityId )
+ {
+ s_nNextEntityId = nEntityId + 1;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the entity ID
+//-----------------------------------------------------------------------------
+int CDmeVMFEntity::GetEntityId() const
+{
+ return atoi( GetName() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the next available entity id
+//-----------------------------------------------------------------------------
+int CDmeVMFEntity::GetNextEntityId()
+{
+ return s_nNextEntityId;
+}
+
+void CDmeVMFEntity::SetNextEntityId( int nEntityId )
+{
+ s_nNextEntityId = nEntityId;
+}
+
+
+//-----------------------------------------------------------------------------
+// Mark the entity as being dirty
+//-----------------------------------------------------------------------------
+void CDmeVMFEntity::MarkDirty( bool bDirty )
+{
+ m_bIsDirty = bDirty;
+
+ // FIXME: this is doing two operations!!
+ CopyToServer();
+}
+
+
+//-----------------------------------------------------------------------------
+// Is the renderable transparent?
+//-----------------------------------------------------------------------------
+bool CDmeVMFEntity::IsTransparent( void )
+{
+ return m_bIsDirty || m_bInfoTarget || BaseClass::IsTransparent();
+}
+
+
+//-----------------------------------------------------------------------------
+// Entity Key iteration
+//-----------------------------------------------------------------------------
+bool CDmeVMFEntity::IsEntityKey( CDmAttribute *pEntityKey )
+{
+ return pEntityKey->IsFlagSet( FATTRIB_USERDEFINED );
+}
+
+CDmAttribute *CDmeVMFEntity::FirstEntityKey()
+{
+ for ( CDmAttribute *pAttribute = FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
+ {
+ if ( IsEntityKey( pAttribute ) )
+ return pAttribute;
+ }
+ return NULL;
+}
+
+CDmAttribute *CDmeVMFEntity::NextEntityKey( CDmAttribute *pEntityKey )
+{
+ if ( !pEntityKey )
+ return NULL;
+
+ for ( CDmAttribute *pAttribute = pEntityKey->NextAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
+ {
+ if ( IsEntityKey( pAttribute ) )
+ return pAttribute;
+ }
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Attach/detach from an engine entity with the same editor index
+//-----------------------------------------------------------------------------
+void CDmeVMFEntity::AttachToEngineEntity( HTOOLHANDLE hToolHandle )
+{
+ if ( m_hEngineEntity != HTOOLHANDLE_INVALID )
+ {
+ clienttools->SetEnabled( m_hEngineEntity, true );
+ }
+ m_hEngineEntity = hToolHandle;
+ if ( m_hEngineEntity != HTOOLHANDLE_INVALID )
+ {
+ clienttools->SetEnabled( m_hEngineEntity, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Position and bounds for the model
+//-----------------------------------------------------------------------------
+const Vector &CDmeVMFEntity::GetRenderOrigin( void )
+{
+ return m_vecLocalOrigin;
+}
+
+const QAngle &CDmeVMFEntity::GetRenderAngles( void )
+{
+ return *(QAngle *)(&m_vecLocalAngles);
+}
+
+void CDmeVMFEntity::GetRenderBounds( Vector& mins, Vector& maxs )
+{
+ if ( !m_bInfoTarget )
+ {
+ BaseClass::GetRenderBounds( mins, maxs );
+ return;
+ }
+
+ mins.Init( -SPHERE_RADIUS, -SPHERE_RADIUS, -SPHERE_RADIUS );
+ maxs.Init( SPHERE_RADIUS, SPHERE_RADIUS, SPHERE_RADIUS );
+}
+
+
+//-----------------------------------------------------------------------------
+// Update renderable position
+//-----------------------------------------------------------------------------
+void CDmeVMFEntity::SetRenderOrigin( const Vector &vecOrigin )
+{
+ m_vecLocalOrigin = vecOrigin;
+ clienttools->MarkClientRenderableDirty( this );
+}
+
+void CDmeVMFEntity::SetRenderAngles( const QAngle &angles )
+{
+ m_vecLocalAngles.Set( Vector( angles.x, angles.y, angles.z ) ); // FIXME: angles is a vector due to the vmf "angles" having a problem parsing...
+ clienttools->MarkClientRenderableDirty( this );
+}
+
+
+//-----------------------------------------------------------------------------
+// Draws the helper for the entity
+//-----------------------------------------------------------------------------
+void CDmeVMFEntity::DrawSprite( IMaterial *pMaterial )
+{
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+
+ float t = 0.5f * sin( Plat_FloatTime() * M_PI / 1.0f ) + 0.5f;
+
+ pRenderContext->Bind( pMaterial );
+ IMesh* pMesh = pRenderContext->GetDynamicMesh();
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, 4, 4 );
+
+ unsigned char nBaseR = 255;
+ unsigned char nBaseG = 255;
+ unsigned char nBaseB = 255;
+ unsigned char nAlpha = m_bIsDirty ? (unsigned char)(255 * t) : 255;
+
+ meshBuilder.Position3f( -SPHERE_RADIUS, -SPHERE_RADIUS, 0.0f );
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
+ meshBuilder.BoneWeight( 0, 1.0f );
+ meshBuilder.BoneMatrix( 0, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( SPHERE_RADIUS, -SPHERE_RADIUS, 0.0f );
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
+ meshBuilder.BoneWeight( 0, 1.0f );
+ meshBuilder.BoneMatrix( 0, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( SPHERE_RADIUS, SPHERE_RADIUS, 0.0f );
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
+ meshBuilder.BoneWeight( 0, 1.0f );
+ meshBuilder.BoneMatrix( 0, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( -SPHERE_RADIUS, SPHERE_RADIUS, 0.0f );
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
+ meshBuilder.BoneWeight( 0, 1.0f );
+ meshBuilder.BoneMatrix( 0, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.FastIndex( 0 );
+ meshBuilder.FastIndex( 1 );
+ meshBuilder.FastIndex( 3 );
+ meshBuilder.FastIndex( 2 );
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Draws the helper for the entity
+//-----------------------------------------------------------------------------
+void CDmeVMFEntity::DrawDragHelpers( IMaterial *pMaterial )
+{
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+
+ float t = 0.5f * sin( Plat_FloatTime() * M_PI / 1.0f ) + 0.5f;
+
+ VMatrix worldToCamera;
+ // pRenderContext->GetMatrix( MATERIAL_VIEW, &worldToCamera );
+ worldToCamera.Identity();
+ worldToCamera.SetTranslation( m_vecLocalOrigin );
+
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadMatrix( worldToCamera );
+
+ pRenderContext->FogMode( MATERIAL_FOG_NONE );
+ pRenderContext->SetNumBoneWeights( 0 );
+ pRenderContext->CullMode( MATERIAL_CULLMODE_CW );
+
+ pRenderContext->Bind( pMaterial );
+ IMesh* pMesh = pRenderContext->GetDynamicMesh();
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_LINES, 3 );
+
+ unsigned char nBaseR = 255;
+ unsigned char nBaseG = 255;
+ unsigned char nBaseB = 255;
+ unsigned char nAlpha = m_bIsDirty ? (unsigned char)(255 * t) : 255;
+
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( 0, 0, 0 );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( SPHERE_RADIUS * 10, 0, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( 0, 0, 0 );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( 0, SPHERE_RADIUS * 10, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( 0, 0, 0 );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( 0, 0, SPHERE_RADIUS * 10 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+
+ pRenderContext->CullMode( MATERIAL_CULLMODE_CCW );
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PopMatrix();
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Draws the helper for the entity
+//-----------------------------------------------------------------------------
+void CDmeVMFEntity::DrawFloorTarget( IMaterial *pMaterial )
+{
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+
+ float t = 0.5f * sin( Plat_FloatTime() * M_PI / 1.0f ) + 0.5f;
+
+ // test movement
+ Ray_t ray;
+ CTraceFilterWorldAndPropsOnly traceFilter;
+ CBaseTrace tr;
+ ray.Init( m_vecLocalOrigin.Get()+ Vector( 0, 0, 10 ), m_vecLocalOrigin.Get() + Vector( 0,0, -128 ), Vector( -13, -13, 0 ), Vector( 13, 13, 10 ) );
+ enginetools->TraceRayServer( ray, MASK_OPAQUE, &traceFilter, &tr );
+
+
+ VMatrix worldToCamera;
+ // pRenderContext->GetMatrix( MATERIAL_VIEW, &worldToCamera );
+ worldToCamera.Identity();
+ worldToCamera.SetTranslation( tr.endpos );
+
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadMatrix( worldToCamera );
+
+ pRenderContext->FogMode( MATERIAL_FOG_NONE );
+ pRenderContext->SetNumBoneWeights( 0 );
+ pRenderContext->CullMode( MATERIAL_CULLMODE_CW );
+
+ pRenderContext->Bind( pMaterial );
+ IMesh* pMesh = pRenderContext->GetDynamicMesh();
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_LINES, 3 );
+
+ unsigned char nBaseR = 255;
+ unsigned char nBaseG = 255;
+ unsigned char nBaseB = 0;
+ unsigned char nAlpha = m_bIsDirty ? (unsigned char)(255 * t) : 255;
+
+ float block[4][2][3] = {
+ { { -13, -13, 0 }, { -13, -13, 10 } },
+ { { 13, -13, 0 }, { 13, -13, 10 } },
+ { { 13, 13, 0 }, { 13, 13, 10 } },
+ { { -13, 13, 0 }, { -13, 13, 10 } } };
+
+ for (int i = 0; i < 4; i++)
+ {
+ int j = (i + 1) % 4;
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( block[i][0][0], block[i][0][1], block[i][0][2] );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( block[i][1][0], block[i][1][1], block[i][1][2] );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( block[i][0][0], block[i][0][1], block[i][0][2] );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( block[j][0][0], block[j][0][1], block[j][0][2] );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( block[i][1][0], block[i][1][1], block[i][1][2] );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.Color4ub( nBaseR, nBaseG, nBaseB, nAlpha );
+ meshBuilder.Position3f( block[j][1][0], block[j][1][1], block[j][1][2] );
+ meshBuilder.AdvanceVertex();
+ }
+
+ // positive X
+ meshBuilder.Color4ub( 255, 0, 0, nAlpha );
+ meshBuilder.Position3f( 0, 0, 10 );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.Color4ub( 255, 0, 0, nAlpha );
+ meshBuilder.Position3f( 10, 0, 10 );
+ meshBuilder.AdvanceVertex();
+
+ // positive Y
+ meshBuilder.Color4ub( 0, 255, 0, nAlpha );
+ meshBuilder.Position3f( 0, 0, 10 );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.Color4ub( 0, 255, 0, nAlpha );
+ meshBuilder.Position3f( 0, 10, 10 );
+ meshBuilder.AdvanceVertex();
+
+ // just Z
+ meshBuilder.Color4ub( 255, 255, 255, nAlpha );
+ meshBuilder.Position3f( 0, 0, 10 );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.Color4ub( 255, 255, 255, nAlpha );
+ meshBuilder.Position3f( 0, 0, 0 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+
+ pRenderContext->CullMode( MATERIAL_CULLMODE_CCW );
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PopMatrix();
+}
+
+
+//-----------------------------------------------------------------------------
+// Draws the helper for the entity
+//-----------------------------------------------------------------------------
+int CDmeVMFEntity::DrawModel( int flags )
+{
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+
+ bool bSelected = ( g_pVcdBlockTool->GetCurrentEntity().Get() == this );
+ if ( !m_bInfoTarget )
+ {
+ // If we have a visible engine entity, we don't need to draw it here
+ // info targets always draw though, because they have no visible model.
+ CDisableUndoScopeGuard guard;
+ float t = 0.5f * sin( Plat_FloatTime() * M_PI / 1.0f ) + 0.5f;
+ unsigned char nAlpha = m_bIsDirty ? (unsigned char)(255 * t) : 255;
+ if ( bSelected )
+ {
+ GetMDL()->m_Color.SetColor( 255, 64, 64, nAlpha );
+ }
+ else
+ {
+ GetMDL()->m_Color.SetColor( 255, 255, 255, nAlpha );
+ }
+ return BaseClass::DrawModel( flags );
+ }
+
+ Assert( IsDrawingInEngine() );
+
+ matrix3x4_t mat;
+ VMatrix worldToCamera, cameraToWorld;
+ pRenderContext->GetMatrix( MATERIAL_VIEW, &worldToCamera );
+ MatrixInverseTR( worldToCamera, cameraToWorld );
+ MatrixCopy( cameraToWorld.As3x4(), mat );
+ MatrixSetColumn( m_vecLocalOrigin, 3, mat );
+
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadMatrix( mat );
+
+ pRenderContext->FogMode( MATERIAL_FOG_NONE );
+ pRenderContext->SetNumBoneWeights( 0 );
+ pRenderContext->CullMode( MATERIAL_CULLMODE_CW );
+
+ DrawSprite( m_InfoTargetSprite );
+ if ( bSelected )
+ {
+ DrawSprite( m_SelectedInfoTarget );
+
+ DrawFloorTarget( m_Wireframe );
+
+ if (g_pVcdBlockTool->IsInNodeDrag())
+ {
+ DrawDragHelpers( m_Wireframe );
+ }
+ // DrawLine( Vector( 0, 0, 0 ), Vector( 10, 0, 0 ), 0, 255, 255, 255 );
+ }
+
+ pRenderContext->CullMode( MATERIAL_CULLMODE_CCW );
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PopMatrix();
+
+ return 1;
+}
+
+
+bool CDmeVMFEntity::CopyFromServer( CBaseEntity *pServerEnt )
+{
+ CopyFromServer( pServerEnt, "targetname" );
+ CopyFromServer( pServerEnt, "classname" );
+ CopyFromServer( pServerEnt, "origin" );
+ CopyFromServer( pServerEnt, "angles" );
+
+ return true;
+}
+
+bool CDmeVMFEntity::CopyFromServer( CBaseEntity *pServerEnt, const char *szField )
+{
+ return CopyFromServer( pServerEnt, szField, szField );
+}
+
+bool CDmeVMFEntity::CopyFromServer( CBaseEntity *pServerEnt, const char *szSrcField, const char *szDstField )
+{
+ char text[256];
+ if ( servertools->GetKeyValue( pServerEnt, szSrcField, text, sizeof( text ) ) )
+ {
+ SetValueFromString( szDstField, text );
+ return true;
+ }
+ return false;
+}
+
+bool CDmeVMFEntity::CopyToServer( void )
+{
+ if (GetEntityId() != 0)
+ {
+ CBaseEntity *pServerEntity = servertools->FindEntityByHammerID( GetEntityId() );
+ if (pServerEntity != NULL)
+ {
+ servertools->SetKeyValue( pServerEntity, "origin", m_vecLocalOrigin.Get() );
+ // FIXME: isn't there a string to vector conversion?
+ Vector tmp( m_vecLocalAngles.Get().x, m_vecLocalAngles.Get().y, m_vecLocalAngles.Get().z );
+ servertools->SetKeyValue( pServerEntity, "angles", tmp );
+ return true;
+ }
+ else
+ {
+ // FIXME: does one need to be spawned?
+ }
+ }
+ return false;
+}
+
+bool CDmeVMFEntity::IsSameOnServer( CBaseEntity *pServerEntity )
+{
+ char text[256];
+
+ if (!pServerEntity)
+ {
+ return false;
+ }
+
+ // FIXME: check targetname? Can it be edited?
+ Vector mapOrigin;
+ servertools->GetKeyValue( pServerEntity, "origin", text, sizeof( text ) );
+ sscanf( text, "%f %f %f", &mapOrigin.x, &mapOrigin.y, &mapOrigin.z );
+ Vector mapAngles;
+ servertools->GetKeyValue( pServerEntity, "angles", text, sizeof( text ) );
+ sscanf( text, "%f %f %f", &mapAngles.x, &mapAngles.y, &mapAngles.z );
+
+ return ( mapOrigin == m_vecLocalOrigin.Get() && mapAngles == m_vecLocalAngles.Get() );
+}
+
+bool CDmeVMFEntity::CreateOnServer( void )
+{
+ CBaseEntity *pServerEntity = servertools->CreateEntityByName( m_ClassName.Get() );
+
+ if (pServerEntity)
+ {
+ // test movement
+ Ray_t ray;
+ CTraceFilterWorldAndPropsOnly traceFilter;
+ CBaseTrace tr;
+ ray.Init( m_vecLocalOrigin.Get()+ Vector( 0, 0, 10 ), m_vecLocalOrigin.Get() + Vector( 0,0, -1000 ) );
+ enginetools->TraceRayServer( ray, MASK_OPAQUE, &traceFilter, &tr );
+ m_vecLocalOrigin.Set( tr.endpos );
+
+ servertools->SetKeyValue( pServerEntity, "hammerid", GetEntityId() );
+ servertools->SetKeyValue( pServerEntity, "targetname", m_TargetName.Get() );
+ servertools->SetKeyValue( pServerEntity, "origin", m_vecLocalOrigin.Get() );
+ servertools->SetKeyValue( pServerEntity, "angles", m_vecLocalAngles.Get() );
+ servertools->DispatchSpawn( pServerEntity );
+
+ return true;
+ }
+ return false;
+}
diff --git a/tools/vcdblock/dmevmfentity.h b/tools/vcdblock/dmevmfentity.h
new file mode 100644
index 0000000..5400610
--- /dev/null
+++ b/tools/vcdblock/dmevmfentity.h
@@ -0,0 +1,131 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Represents an entity in a VMF
+//
+//=============================================================================
+
+#ifndef DMEVMFENTITY_H
+#define DMEVMFENTITY_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "toolutils/dmemdlrenderable.h"
+#include "datamodel/dmelement.h"
+#include "toolframework/itoolentity.h"
+#include "materialsystem/MaterialSystemUtil.h"
+
+
+//-----------------------------------------------------------------------------
+// Represents an editable entity; draws its helpers
+//-----------------------------------------------------------------------------
+class CDmeVMFEntity : public CDmeMdlRenderable<CDmElement>
+{
+ DEFINE_ELEMENT( CDmeVMFEntity, CDmeMdlRenderable<CDmElement> );
+
+public:
+ // Inherited from CDmElement
+ virtual void OnAttributeChanged( CDmAttribute *pAttribute );
+
+public:
+ // Inherited from DmeRenderable
+ virtual const Vector &GetRenderOrigin( void );
+ virtual const QAngle &GetRenderAngles( void );
+ virtual int DrawModel( int flags );
+ virtual bool IsTransparent( void );
+ virtual void GetRenderBounds( Vector& mins, Vector& maxs );
+
+public:
+ int GetEntityId() const;
+
+ // Returns the next available entity id
+ static int GetNextEntityId();
+ static void SetNextEntityId( int nEntityId );
+
+ const char *GetClassName() const;
+ const char *GetTargetName() const;
+
+ bool IsPlaceholder() const;
+
+ // Entity Key iteration
+ CDmAttribute *FirstEntityKey();
+ CDmAttribute *NextEntityKey( CDmAttribute *pEntityKey );
+
+ // Attach/detach from an engine entity with the same editor index
+ void AttachToEngineEntity( HTOOLHANDLE hToolHandle );
+
+ void SetRenderOrigin( const Vector &vecOrigin );
+ void SetRenderAngles( const QAngle &angles );
+
+ void MarkDirty( bool bDirty = true );
+ bool IsDirty( void ) { return m_bIsDirty; };
+
+ void MarkDeleted( bool bDeleted = true );
+ bool IsDeleted( void ) { return m_bIsDeleted; };
+
+ bool CopyFromServer( CBaseEntity *pServerEnt );
+ bool CopyFromServer( CBaseEntity *pServerEnt, const char *szField );
+ bool CopyFromServer( CBaseEntity *pServerEnt, const char *szSrcField, const char *szDstField );
+ bool CopyToServer( void );
+
+ bool IsSameOnServer( CBaseEntity *pServerEntity );
+ bool CreateOnServer( void );
+
+private:
+ bool IsEntityKey( CDmAttribute *pEntityKey );
+
+ // Draws the helper for the entity
+ void DrawSprite( IMaterial *pMaterial );
+ void DrawDragHelpers( IMaterial *pMaterial );
+ void DrawFloorTarget( IMaterial *pMaterial );
+
+ CDmaVar<Vector> m_vecLocalOrigin;
+ // CDmAttributeVar<QAngle> m_vecLocalAngles;
+ CDmaVar<Vector> m_vecLocalAngles; // something funky with the vmf importer, it asserts when it's a QAngle
+
+ CDmaString m_ClassName;
+ CDmaString m_TargetName;
+ CDmaVar<bool> m_bIsPlaceholder;
+
+ // The entity it's connected to in the engine
+ HTOOLHANDLE m_hEngineEntity;
+
+ CMaterialReference m_Wireframe;
+
+ CMaterialReference m_SelectedInfoTarget;
+ CMaterialReference m_InfoTargetSprite;
+
+ // pretty sure this entity is edited
+ bool m_bIsDirty;
+
+ // entity needs to be deleted
+ CDmaVar<bool> m_bIsDeleted;
+
+ // FIXME: This is a hack for info targets
+ bool m_bInfoTarget;
+
+ // Used to store the next unique entity id;
+ static int s_nNextEntityId;
+};
+
+
+//-----------------------------------------------------------------------------
+// Inline methods
+//-----------------------------------------------------------------------------
+inline const char *CDmeVMFEntity::GetClassName() const
+{
+ return m_ClassName;
+}
+
+inline const char *CDmeVMFEntity::GetTargetName() const
+{
+ return m_TargetName;
+}
+
+inline bool CDmeVMFEntity::IsPlaceholder() const
+{
+ return m_bIsPlaceholder;
+}
+
+
+#endif // DMEVMFENTITY_H
diff --git a/tools/vcdblock/infotargetbrowserpanel.cpp b/tools/vcdblock/infotargetbrowserpanel.cpp
new file mode 100644
index 0000000..50e5729
--- /dev/null
+++ b/tools/vcdblock/infotargetbrowserpanel.cpp
@@ -0,0 +1,297 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Singleton dialog that generates and presents the entity report.
+//
+//===========================================================================//
+
+#include "InfoTargetBrowserPanel.h"
+#include "tier1/KeyValues.h"
+#include "tier1/utlbuffer.h"
+#include "iregistry.h"
+#include "vgui/ivgui.h"
+#include "vgui_controls/listpanel.h"
+#include "vgui_controls/textentry.h"
+#include "vgui_controls/checkbutton.h"
+#include "vgui_controls/combobox.h"
+#include "vgui_controls/radiobutton.h"
+#include "vgui_controls/messagebox.h"
+#include "vcdblockdoc.h"
+#include "vcdblocktool.h"
+#include "datamodel/dmelement.h"
+#include "vgui/keycode.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+
+//-----------------------------------------------------------------------------
+// Sort by target name
+//-----------------------------------------------------------------------------
+static int __cdecl TargetNameSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
+{
+ const char *string1 = item1.kv->GetString("targetname");
+ const char *string2 = item2.kv->GetString("targetname");
+ int nRetVal = Q_stricmp( string1, string2 );
+ if ( nRetVal != 0 )
+ return nRetVal;
+
+ string1 = item1.kv->GetString("classname");
+ string2 = item2.kv->GetString("classname");
+ return Q_stricmp( string1, string2 );
+}
+
+//-----------------------------------------------------------------------------
+// Sort by class name
+//-----------------------------------------------------------------------------
+static int __cdecl ClassNameSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
+{
+ const char *string1 = item1.kv->GetString("classname");
+ const char *string2 = item2.kv->GetString("classname");
+ int nRetVal = Q_stricmp( string1, string2 );
+ if ( nRetVal != 0 )
+ return nRetVal;
+
+ string1 = item1.kv->GetString("targetname");
+ string2 = item2.kv->GetString("targetname");
+ return Q_stricmp( string1, string2 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CInfoTargetBrowserPanel::CInfoTargetBrowserPanel( CVcdBlockDoc *pDoc, vgui::Panel* pParent, const char *pName )
+ : BaseClass( pParent, pName ), m_pDoc( pDoc )
+{
+ SetPaintBackgroundEnabled( true );
+
+ m_pEntities = new vgui::ListPanel( this, "Entities" );
+ m_pEntities->AddColumnHeader( 0, "targetname", "Name", 52, ListPanel::COLUMN_RESIZEWITHWINDOW );
+ m_pEntities->AddColumnHeader( 1, "classname", "Class Name", 52, ListPanel::COLUMN_RESIZEWITHWINDOW );
+ m_pEntities->SetColumnSortable( 0, true );
+ m_pEntities->SetColumnSortable( 1, true );
+ m_pEntities->SetEmptyListText( "No info_targets" );
+ // m_pEntities->SetDragEnabled( true );
+ m_pEntities->AddActionSignalTarget( this );
+ m_pEntities->SetSortFunc( 0, TargetNameSortFunc );
+ m_pEntities->SetSortFunc( 1, ClassNameSortFunc );
+ m_pEntities->SetSortColumn( 0 );
+
+ LoadControlSettingsAndUserConfig( "resource/infotargetbrowserpanel.res" );
+
+ UpdateEntityList();
+}
+
+CInfoTargetBrowserPanel::~CInfoTargetBrowserPanel()
+{
+ SaveUserConfig();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Shows the most recent selected object in properties window
+//-----------------------------------------------------------------------------
+void CInfoTargetBrowserPanel::OnProperties(void)
+{
+ int iSel = m_pEntities->GetSelectedItem( 0 );
+ KeyValues *kv = m_pEntities->GetItem( iSel );
+ CDmeVMFEntity *pEntity = CastElement< CDmeVMFEntity >( (CDmElement *)kv->GetPtr( "entity" ) );
+ g_pVcdBlockTool->ShowEntityInEntityProperties( pEntity );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Deletes the marked objects.
+//-----------------------------------------------------------------------------
+void CInfoTargetBrowserPanel::OnDeleteEntities(void)
+{
+ int iSel = m_pEntities->GetSelectedItem( 0 );
+
+ {
+ // This is undoable
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Delete Entities", "Delete Entities" );
+
+ //
+ // Build a list of objects to delete.
+ //
+ int nCount = m_pEntities->GetSelectedItemsCount();
+ for (int i = 0; i < nCount; i++)
+ {
+ int nItemID = m_pEntities->GetSelectedItem(i);
+ KeyValues *kv = m_pEntities->GetItem( nItemID );
+ CDmeVMFEntity *pEntity = (CDmeVMFEntity *)kv->GetPtr( "entity" );
+ if ( pEntity )
+ {
+ m_pDoc->DeleteInfoTarget( pEntity );
+ }
+ }
+ }
+
+ // Update the list box selection.
+ if (iSel >= m_pEntities->GetItemCount())
+ {
+ iSel = m_pEntities->GetItemCount() - 1;
+ }
+ m_pEntities->SetSingleSelectedItem( iSel );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CInfoTargetBrowserPanel::OnKeyCodeTyped( vgui::KeyCode code )
+{
+ if ( code == KEY_DELETE )
+ {
+ OnDeleteEntities();
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped( code );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CInfoTargetBrowserPanel::OnItemSelected( void )
+{
+ OnProperties();
+}
+
+
+//-----------------------------------------------------------------------------
+// Select a particular node
+//-----------------------------------------------------------------------------
+void CInfoTargetBrowserPanel::SelectNode( CDmeVMFEntity *pNode )
+{
+ m_pEntities->ClearSelectedItems();
+ for ( int nItemID = m_pEntities->FirstItem(); nItemID != m_pEntities->InvalidItemID(); nItemID = m_pEntities->NextItem( nItemID ) )
+ {
+ KeyValues *kv = m_pEntities->GetItem( nItemID );
+ CDmElement *pEntity = (CDmElement *)kv->GetPtr( "entity" );
+ if ( pEntity == pNode )
+ {
+ m_pEntities->AddSelectedItem( nItemID );
+ break;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when buttons are clicked
+//-----------------------------------------------------------------------------
+void CInfoTargetBrowserPanel::OnCommand( const char *pCommand )
+{
+ if ( !Q_stricmp( pCommand, "delete" ) )
+ {
+ // Confirm we want to do it
+ MessageBox *pConfirm = new MessageBox( "#VcdBlockDeleteObjects", "#VcdBlockDeleteObjectsMsg", g_pVcdBlockTool->GetRootPanel() );
+ pConfirm->AddActionSignalTarget( this );
+ pConfirm->SetOKButtonText( "Yes" );
+ pConfirm->SetCommand( new KeyValues( "DeleteEntities" ) );
+ pConfirm->SetCancelButtonVisible( true );
+ pConfirm->SetCancelButtonText( "No" );
+ pConfirm->DoModal();
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "Save" ) )
+ {
+ g_pVcdBlockTool->Save();
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "RestartMap" ) )
+ {
+ g_pVcdBlockTool->RestartMap();
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "DropInfoTargets" ) )
+ {
+ g_pVcdBlockTool->EnterTargetDropMode();
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "quicksave" ) )
+ {
+ g_pVcdBlockTool->QuickSave();
+ return;
+ }
+
+ if ( !Q_stricmp( pCommand, "quickload" ) )
+ {
+ g_pVcdBlockTool->QuickLoad();
+ return;
+ }
+
+ BaseClass::OnCommand( pCommand );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CInfoTargetBrowserPanel::UpdateEntityList(void)
+{
+ m_pEntities->RemoveAll();
+
+ const CDmrElementArray<CDmElement> entityList( m_pDoc->GetEntityList() );
+ if ( !entityList.IsValid() )
+ return;
+
+ int nCount = entityList.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmElement *pEntity = entityList[i];
+
+ const char *pClassName = pEntity->GetValueString( "classname" );
+ if ( !pClassName || !pClassName[0] )
+ {
+ pClassName = "<no class>";
+ }
+
+ KeyValues *kv = new KeyValues( "node" );
+ kv->SetString( "classname", pClassName );
+ kv->SetPtr( "entity", pEntity );
+
+ const char *pTargetname = pEntity->GetValueString( "targetname" );
+ if ( !pTargetname || !pTargetname[0] )
+ {
+ pTargetname = "<no targetname>";
+ }
+ kv->SetString( "targetname", pTargetname );
+
+ int nItemID = m_pEntities->AddItem( kv, 0, false, false );
+
+ // Hide everything that isn't an info_target
+ m_pEntities->SetItemVisible( nItemID, !Q_stricmp( pClassName, "info_target" ) );
+ }
+ m_pEntities->SortList();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CInfoTargetBrowserPanel::Refresh(void)
+{
+ for ( int nItemID = m_pEntities->FirstItem(); nItemID != m_pEntities->InvalidItemID(); nItemID = m_pEntities->NextItem( nItemID ) )
+ {
+ KeyValues *kv = m_pEntities->GetItem( nItemID );
+ CDmElement *pEntity = (CDmElement *)kv->GetPtr( "entity" );
+
+ const char *pTargetname = pEntity->GetValueString( "targetname" );
+ if ( !pTargetname || !pTargetname[0] )
+ {
+ pTargetname = "<no targetname>";
+ }
+ kv->SetString( "targetname", pTargetname );
+ }
+}
+
diff --git a/tools/vcdblock/infotargetbrowserpanel.h b/tools/vcdblock/infotargetbrowserpanel.h
new file mode 100644
index 0000000..3a8ecc4
--- /dev/null
+++ b/tools/vcdblock/infotargetbrowserpanel.h
@@ -0,0 +1,68 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#ifndef INFOTARGETBROWSERPANEL_H
+#define INFOTARGETBROWSERPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/editablepanel.h"
+#include "tier1/utlstring.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CVcdBlockDoc;
+class CDmeVMFEntity;
+namespace vgui
+{
+ class ComboBox;
+ class Button;
+ class TextEntry;
+ class ListPanel;
+ class CheckButton;
+ class RadioButton;
+}
+
+
+//-----------------------------------------------------------------------------
+// Panel that shows all entities in the level
+//-----------------------------------------------------------------------------
+class CInfoTargetBrowserPanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CInfoTargetBrowserPanel, vgui::EditablePanel );
+
+public:
+ CInfoTargetBrowserPanel( CVcdBlockDoc *pDoc, vgui::Panel* pParent, const char *pName ); // standard constructor
+ virtual ~CInfoTargetBrowserPanel();
+
+ // Inherited from Panel
+ virtual void OnCommand( const char *pCommand );
+ virtual void OnKeyCodeTyped( vgui::KeyCode code );
+
+ // Methods related to updating the listpanel
+ void UpdateEntityList();
+ void Refresh();
+
+ // Select a particular node
+ void SelectNode( CDmeVMFEntity *pNode );
+
+private:
+ // Messages handled
+ MESSAGE_FUNC( OnDeleteEntities, "DeleteEntities" );
+ MESSAGE_FUNC( OnItemSelected, "ItemSelected" );
+
+ // Shows the most recent selected object in properties window
+ void OnProperties();
+
+ CVcdBlockDoc *m_pDoc;
+ vgui::ListPanel *m_pEntities;
+};
+
+
+#endif // INFOTARGETBROWSERPANEL_H
diff --git a/tools/vcdblock/infotargetpropertiespanel.cpp b/tools/vcdblock/infotargetpropertiespanel.cpp
new file mode 100644
index 0000000..1ba56f4
--- /dev/null
+++ b/tools/vcdblock/infotargetpropertiespanel.cpp
@@ -0,0 +1,225 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Singleton dialog that generates and presents the entity report.
+//
+//===========================================================================//
+
+#include "InfoTargetPropertiesPanel.h"
+#include "tier1/KeyValues.h"
+#include "tier1/utlbuffer.h"
+#include "iregistry.h"
+#include "vgui/ivgui.h"
+#include "vgui_controls/listpanel.h"
+#include "vgui_controls/textentry.h"
+#include "vgui_controls/checkbutton.h"
+#include "vgui_controls/combobox.h"
+#include "vgui_controls/radiobutton.h"
+#include "vgui_controls/messagebox.h"
+#include "vgui_controls/scrollbar.h"
+#include "vcdblockdoc.h"
+#include "vcdblocktool.h"
+#include "datamodel/dmelement.h"
+#include "dmevmfentity.h"
+#include "dme_controls/soundpicker.h"
+#include "dme_controls/soundrecordpanel.h"
+#include "matsys_controls/picker.h"
+#include "vgui_controls/fileopendialog.h"
+#include "filesystem.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+class CScrollableEditablePanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CScrollableEditablePanel, vgui::EditablePanel );
+
+public:
+ CScrollableEditablePanel( vgui::Panel *pParent, vgui::EditablePanel *pChild, const char *pName );
+ virtual ~CScrollableEditablePanel() {}
+ virtual void PerformLayout();
+
+ MESSAGE_FUNC( OnScrollBarSliderMoved, "ScrollBarSliderMoved" );
+
+private:
+ vgui::ScrollBar *m_pScrollBar;
+ vgui::EditablePanel *m_pChild;
+};
+
+
+CScrollableEditablePanel::CScrollableEditablePanel( vgui::Panel *pParent, vgui::EditablePanel *pChild, const char *pName ) :
+ BaseClass( pParent, pName )
+{
+ m_pChild = pChild;
+ m_pChild->SetParent( this );
+
+ m_pScrollBar = new vgui::ScrollBar( this, "VerticalScrollBar", true );
+ m_pScrollBar->SetWide( 16 );
+ m_pScrollBar->SetAutoResize( PIN_TOPRIGHT, AUTORESIZE_DOWN, 0, 0, -16, 0 );
+ m_pScrollBar->AddActionSignalTarget( this );
+}
+
+void CScrollableEditablePanel::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ m_pChild->SetWide( GetWide() - 16 );
+ m_pScrollBar->SetRange( 0, m_pChild->GetTall() );
+ m_pScrollBar->SetRangeWindow( GetTall() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when the scroll bar moves
+//-----------------------------------------------------------------------------
+void CScrollableEditablePanel::OnScrollBarSliderMoved()
+{
+ InvalidateLayout();
+
+ int nScrollAmount = m_pScrollBar->GetValue();
+ m_pChild->SetPos( 0, -nScrollAmount );
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CInfoTargetPropertiesPanel::CInfoTargetPropertiesPanel( CVcdBlockDoc *pDoc, vgui::Panel* pParent )
+ : BaseClass( pParent, "InfoTargetPropertiesPanel" ), m_pDoc( pDoc )
+{
+ SetPaintBackgroundEnabled( true );
+ SetKeyBoardInputEnabled( true );
+
+ m_pInfoTarget = new vgui::EditablePanel( (vgui::Panel*)NULL, "InfoTarget" );
+
+ m_pTargetName = new vgui::TextEntry( m_pInfoTarget, "TargetName" );
+ m_pTargetName->AddActionSignalTarget( this );
+
+ m_pTargetPosition[0] = new vgui::TextEntry( m_pInfoTarget, "PositionX" );
+ m_pTargetPosition[0]->AddActionSignalTarget( this );
+ m_pTargetPosition[1] = new vgui::TextEntry( m_pInfoTarget, "PositionY" );
+ m_pTargetPosition[1]->AddActionSignalTarget( this );
+ m_pTargetPosition[2] = new vgui::TextEntry( m_pInfoTarget, "PositionZ" );
+ m_pTargetPosition[2]->AddActionSignalTarget( this );
+
+ m_pTargetOrientation[0] = new vgui::TextEntry( m_pInfoTarget, "Pitch" );
+ m_pTargetOrientation[0]->AddActionSignalTarget( this );
+ m_pTargetOrientation[1] = new vgui::TextEntry( m_pInfoTarget, "Yaw" );
+ m_pTargetOrientation[1]->AddActionSignalTarget( this );
+ m_pTargetOrientation[2] = new vgui::TextEntry( m_pInfoTarget, "Roll" );
+ m_pTargetOrientation[2]->AddActionSignalTarget( this );
+
+ m_pInfoTarget->LoadControlSettings( "resource/infotargetpropertiessubpanel_target.res" );
+
+ m_pInfoTargetScroll = new CScrollableEditablePanel( this, m_pInfoTarget, "InfoTargetScroll" );
+
+ LoadControlSettings( "resource/infotargetpropertiespanel.res" );
+
+ m_pInfoTargetScroll->SetVisible( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Text to attribute...
+//-----------------------------------------------------------------------------
+void CInfoTargetPropertiesPanel::TextEntryToAttribute( vgui::TextEntry *pEntry, const char *pAttributeName )
+{
+ int nLen = pEntry->GetTextLength();
+ char *pBuf = (char*)_alloca( nLen+1 );
+ pEntry->GetText( pBuf, nLen+1 );
+ m_hEntity->SetValue( pAttributeName, pBuf );
+}
+
+void CInfoTargetPropertiesPanel::TextEntriesToVector( vgui::TextEntry *pEntry[3], const char *pAttributeName )
+{
+ Vector vec;
+ for ( int i = 0; i < 3; ++i )
+ {
+ int nLen = pEntry[i]->GetTextLength();
+ char *pBuf = (char*)_alloca( nLen+1 );
+ pEntry[i]->GetText( pBuf, nLen+1 );
+ vec[i] = atof( pBuf );
+ }
+ m_hEntity->SetValue( pAttributeName, vec );
+ clienttools->MarkClientRenderableDirty( m_hEntity );
+}
+
+
+//-----------------------------------------------------------------------------
+// Updates entity state when text fields change
+//-----------------------------------------------------------------------------
+void CInfoTargetPropertiesPanel::UpdateInfoTarget()
+{
+ if ( !m_hEntity.Get() )
+ return;
+
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Info Target Change", "Info Target Change" );
+ TextEntryToAttribute( m_pTargetName, "targetname" );
+ TextEntriesToVector( m_pTargetPosition, "origin" );
+ TextEntriesToVector( m_pTargetOrientation, "angles" );
+ m_hEntity->MarkDirty();
+}
+
+
+//-----------------------------------------------------------------------------
+// Populates the info_target fields
+//-----------------------------------------------------------------------------
+void CInfoTargetPropertiesPanel::PopulateInfoTargetFields()
+{
+ if ( !m_hEntity.Get() )
+ return;
+
+ m_pTargetName->SetText( m_hEntity->GetTargetName() );
+
+ Vector vecPosition = m_hEntity->GetRenderOrigin();
+ QAngle vecAngles = m_hEntity->GetRenderAngles();
+
+ for ( int i = 0; i < 3; ++i )
+ {
+ char pTemp[512];
+ Q_snprintf( pTemp, sizeof(pTemp), "%.2f", vecPosition[i] );
+ m_pTargetPosition[i]->SetText( pTemp );
+
+ Q_snprintf( pTemp, sizeof(pTemp), "%.2f", vecAngles[i] );
+ m_pTargetOrientation[i]->SetText( pTemp );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the object to look at
+//-----------------------------------------------------------------------------
+void CInfoTargetPropertiesPanel::SetObject( CDmeVMFEntity *pEntity )
+{
+ m_hEntity = pEntity;
+ m_pInfoTargetScroll->SetVisible( false );
+
+ if ( pEntity )
+ {
+ if ( !Q_stricmp( pEntity->GetClassName(), "info_target" ) )
+ {
+ PopulateInfoTargetFields();
+ m_pInfoTargetScroll->SetVisible( true );
+ m_pTargetName->RequestFocus();
+ return;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when text is changed
+//-----------------------------------------------------------------------------
+void CInfoTargetPropertiesPanel::OnTextChanged( KeyValues *pParams )
+{
+ vgui::Panel *pPanel = (vgui::Panel*)pParams->GetPtr( "panel" );
+ if ( pPanel->GetParent() == m_pInfoTarget )
+ {
+ UpdateInfoTarget();
+ return;
+ }
+}
+
+
+
diff --git a/tools/vcdblock/infotargetpropertiespanel.h b/tools/vcdblock/infotargetpropertiespanel.h
new file mode 100644
index 0000000..b43b62b
--- /dev/null
+++ b/tools/vcdblock/infotargetpropertiespanel.h
@@ -0,0 +1,76 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#ifndef INFOTARGETPROPERTIESPANEL_H
+#define INFOTARGETPROPERTIESPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/editablepanel.h"
+#include "tier1/utlstring.h"
+#include "datamodel/dmehandle.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CVcdBlockDoc;
+class CDmeVMFEntity;
+class CScrollableEditablePanel;
+
+namespace vgui
+{
+ class ComboBox;
+ class Button;
+ class TextEntry;
+ class ListPanel;
+ class CheckButton;
+ class RadioButton;
+}
+
+
+//-----------------------------------------------------------------------------
+// Panel that shows all entities in the level
+//-----------------------------------------------------------------------------
+class CInfoTargetPropertiesPanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CInfoTargetPropertiesPanel, vgui::EditablePanel );
+
+public:
+ CInfoTargetPropertiesPanel( CVcdBlockDoc *pDoc, vgui::Panel* pParent ); // standard constructor
+
+ // Sets the object to look at
+ void SetObject( CDmeVMFEntity *pEntity );
+
+private:
+ // Populates the info_target fields
+ void PopulateInfoTargetFields();
+
+ // Text to attribute...
+ void TextEntryToAttribute( vgui::TextEntry *pEntry, const char *pAttributeName );
+ void TextEntriesToVector( vgui::TextEntry *pEntry[3], const char *pAttributeName );
+
+ // Updates entity state when text fields change
+ void UpdateInfoTarget();
+
+ // Messages handled
+ MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", kv );
+
+ CVcdBlockDoc *m_pDoc;
+
+ vgui::EditablePanel *m_pInfoTargetScroll;
+ vgui::EditablePanel *m_pInfoTarget;
+
+ vgui::TextEntry *m_pTargetName;
+ vgui::TextEntry *m_pTargetPosition[3];
+ vgui::TextEntry *m_pTargetOrientation[3];
+
+ CDmeHandle< CDmeVMFEntity > m_hEntity;
+};
+
+
+#endif // INFOTARGETPROPERTIESPANEL_H
diff --git a/tools/vcdblock/vcdblock.vpc b/tools/vcdblock/vcdblock.vpc
new file mode 100644
index 0000000..187efc7
--- /dev/null
+++ b/tools/vcdblock/vcdblock.vpc
@@ -0,0 +1,64 @@
+//-----------------------------------------------------------------------------
+// VCDBLOCK.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin\tools"
+
+$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
+
+$Configuration
+{
+ $Compiler
+ {
+ $AdditionalIncludeDirectories "$BASE,.\,..\common;$SRCDIR\game\shared"
+ $PreprocessorDefinitions "$BASE;VCDBLOCK_EXPORTS"
+ }
+
+ $Linker
+ {
+ $AdditionalDependencies "$BASE Psapi.lib"
+ }
+}
+
+$Project "Vcdblock"
+{
+ $Folder "Source Files"
+ {
+ $File "dmevmfentity.cpp"
+ $File "infotargetbrowserpanel.cpp"
+ $File "infotargetpropertiespanel.cpp"
+ $File "$SRCDIR\public\interpolatortypes.cpp"
+ $File "$SRCDIR\public\registry.cpp"
+ $File "vcdblockdoc.cpp"
+ $File "vcdblocktool.cpp"
+ $File "$SRCDIR\public\vgui_controls\vgui_controls.cpp"
+ }
+
+ $Folder "Header Files"
+ {
+ $File "dmevmfentity.h"
+ $File "infotargetbrowserpanel.h"
+ $File "infotargetpropertiespanel.h"
+ $File "$SRCDIR\public\mathlib\mathlib.h"
+ $File "vcdblockdoc.h"
+ $File "vcdblocktool.h"
+ }
+
+ $Folder "Link Libraries"
+ {
+ $Lib datamodel
+ $Lib dme_controls
+ $Lib dmserializers
+ $Lib mathlib
+ $Lib matsys_controls
+ $Lib movieobjects
+ $Lib sfmobjects
+ $Lib tier2
+ $Lib tier3
+ $Lib toolutils
+ $Lib vgui_controls
+ }
+}
diff --git a/tools/vcdblock/vcdblockdoc.cpp b/tools/vcdblock/vcdblockdoc.cpp
new file mode 100644
index 0000000..313e83f
--- /dev/null
+++ b/tools/vcdblock/vcdblockdoc.cpp
@@ -0,0 +1,630 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "vcdblockdoc.h"
+#include "tier1/KeyValues.h"
+#include "tier1/utlbuffer.h"
+#include "toolutils/enginetools_int.h"
+#include "filesystem.h"
+#include "vcdblocktool.h"
+#include "toolframework/ienginetool.h"
+#include "dmevmfentity.h"
+#include "datamodel/idatamodel.h"
+#include "toolutils/attributeelementchoicelist.h"
+#include "infotargetbrowserpanel.h"
+#include "vgui_controls/messagebox.h"
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CVcdBlockDoc::CVcdBlockDoc( IVcdBlockDocCallback *pCallback ) : m_pCallback( pCallback )
+{
+ m_hVMFRoot = NULL;
+ m_hEditRoot = NULL;
+ m_pBSPFileName[0] = 0;
+ m_pVMFFileName[0] = 0;
+ m_pEditFileName[0] = 0;
+ m_bDirty = false;
+ g_pDataModel->InstallNotificationCallback( this );
+}
+
+CVcdBlockDoc::~CVcdBlockDoc()
+{
+ g_pDataModel->RemoveNotificationCallback( this );
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from INotifyUI
+//-----------------------------------------------------------------------------
+void CVcdBlockDoc::NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ OnDataChanged( pReason, nNotifySource, nNotifyFlags );
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the file name
+//-----------------------------------------------------------------------------
+const char *CVcdBlockDoc::GetBSPFileName()
+{
+ return m_pBSPFileName;
+}
+
+const char *CVcdBlockDoc::GetVMFFileName()
+{
+ return m_pVMFFileName;
+}
+
+void CVcdBlockDoc::SetVMFFileName( const char *pFileName )
+{
+ Q_strncpy( m_pVMFFileName, pFileName, sizeof( m_pVMFFileName ) );
+ Q_FixSlashes( m_pVMFFileName );
+ SetDirty( true );
+}
+
+const char *CVcdBlockDoc::GetEditFileName()
+{
+ return m_pEditFileName;
+}
+
+void CVcdBlockDoc::SetEditFileName( const char *pFileName )
+{
+ Q_strncpy( m_pEditFileName, pFileName, sizeof( m_pEditFileName ) );
+ Q_FixSlashes( m_pEditFileName );
+ SetDirty( true );
+}
+
+//-----------------------------------------------------------------------------
+// Dirty bits
+//-----------------------------------------------------------------------------
+void CVcdBlockDoc::SetDirty( bool bDirty )
+{
+ m_bDirty = bDirty;
+}
+
+bool CVcdBlockDoc::IsDirty() const
+{
+ return m_bDirty;
+}
+
+
+//-----------------------------------------------------------------------------
+// Saves/loads from file
+//-----------------------------------------------------------------------------
+bool CVcdBlockDoc::LoadFromFile( const char *pFileName )
+{
+ Assert( !m_hVMFRoot.Get() );
+ Assert( !m_hEditRoot.Get() );
+
+ CAppDisableUndoScopeGuard guard( "CVcdBlockDoc::LoadFromFile", NOTIFY_CHANGE_OTHER );
+ SetDirty( false );
+
+ if ( !pFileName[0] )
+ return false;
+
+ // Construct VMF file name from the BSP
+ const char *pGame = Q_stristr( pFileName, "\\game\\" );
+ if ( !pGame )
+ {
+ pGame = Q_stristr( pFileName, "\\content\\" );
+ if ( !pGame )
+ return false;
+ }
+
+ // Compute the map name
+ const char *pMaps = Q_stristr( pFileName, "\\maps\\" );
+ if ( !pMaps )
+ return false;
+
+ // Build map name
+ char mapname[ 256 ];
+ Q_StripExtension( pFileName, mapname, sizeof(mapname) );
+ char *pszFileName = (char*)Q_UnqualifiedFileName(mapname);
+
+ int nLen = (int)( (size_t)pGame - (size_t)pFileName ) + 1;
+ Q_strncpy( m_pVMFFileName, pFileName, nLen );
+ Q_strncat( m_pVMFFileName, "\\content\\", sizeof(m_pVMFFileName) );
+ Q_strncat( m_pVMFFileName, pGame + 6, sizeof(m_pVMFFileName) );
+ Q_SetExtension( m_pVMFFileName, ".vmf", sizeof(m_pVMFFileName) );
+
+ // Make sure new entities start with ids at 0
+ CDmeVMFEntity::SetNextEntityId( 0 );
+
+ // Build the Edit file name
+ Q_StripExtension( m_pVMFFileName, m_pEditFileName, sizeof(m_pEditFileName) );
+ Q_strncat( m_pEditFileName, ".vle", sizeof( m_pEditFileName ) );
+
+ // Store the BSP file name
+ Q_strncpy( m_pBSPFileName, pFileName, sizeof( m_pBSPFileName ) );
+
+ // Set the txt file name.
+ // If we loaded a .bsp, clear out what we're doing
+ // load the Edits file into memory, assign it as our "root"
+ CDmElement *pEdit = NULL;
+ if ( !V_stricmp( Q_GetFileExtension( pFileName ), "vle" ) )
+ {
+ if ( g_pDataModel->RestoreFromFile( m_pEditFileName, NULL, "vmf", &pEdit ) != DMFILEID_INVALID )
+ {
+ // If we successfully read the file in, ask it for the max hammer id
+ //int nMaxHammerId = pVMF->GetAttributeValue<int>( "maxHammerId" );
+ //CDmeVMFEntity::SetNextEntityId( nMaxHammerId + 1 );
+ m_hEditRoot = pEdit;
+ SetDirty( false );
+ }
+ }
+
+ if (pEdit == NULL)
+ {
+ if ( g_pFileSystem->FileExists( m_pEditFileName ) )
+ {
+ char pBuf[1024];
+ Q_snprintf( pBuf, sizeof(pBuf), "File %s already exists!\n", m_pEditFileName );
+ m_pEditFileName[0] = 0;
+ vgui::MessageBox *pMessageBox = new vgui::MessageBox( "Unable to overwrite file!\n", pBuf, g_pVcdBlockTool );
+ pMessageBox->DoModal( );
+ return false;
+ }
+
+ DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( m_pEditFileName );
+ m_hEditRoot = CreateElement<CDmElement>( "root", fileid );
+ m_hEditRoot->AddAttribute( "entities", AT_ELEMENT_ARRAY );
+ g_pDataModel->SetFileRoot( fileid, m_hEditRoot );
+ SetDirty( true );
+ }
+
+ guard.Release();
+
+ // tell the engine to actually load the map
+ char cmd[ 256 ];
+ Q_snprintf( cmd, sizeof( cmd ), "disconnect; map %s\n", pszFileName );
+ enginetools->Command( cmd );
+ enginetools->Execute( );
+
+ return true;
+}
+
+
+void CVcdBlockDoc::SaveToFile( )
+{
+ if ( m_hEditRoot.Get() && m_pEditFileName && m_pEditFileName[0] )
+ {
+ g_pDataModel->SaveToFile( m_pEditFileName, NULL, "keyvalues", "vmf", m_hEditRoot );
+ }
+
+ SetDirty( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the root object
+//-----------------------------------------------------------------------------
+CDmElement *CVcdBlockDoc::GetRootObject()
+{
+ return m_hEditRoot;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the entity list
+//-----------------------------------------------------------------------------
+CDmAttribute *CVcdBlockDoc::GetEntityList()
+{
+ return m_hEditRoot ? m_hEditRoot->GetAttribute( "entities", AT_ELEMENT_ARRAY ) : NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CVcdBlockDoc::AddNewInfoTarget( const Vector &vecOrigin, const QAngle &angAngles )
+{
+ CDmrElementArray<> entities = GetEntityList();
+
+ CDmeVMFEntity *pTarget;
+ {
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Add Info Target", "Add Info Target" );
+
+ pTarget = CreateElement<CDmeVMFEntity>( "", entities.GetOwner()->GetFileId() );
+ pTarget->SetValue( "classname", "info_target" );
+ pTarget->SetRenderOrigin( vecOrigin );
+ pTarget->SetRenderAngles( angAngles );
+
+ entities.AddToTail( pTarget );
+ pTarget->MarkDirty();
+ pTarget->DrawInEngine( true );
+ }
+
+ g_pVcdBlockTool->GetInfoTargetBrowser()->SelectNode( pTarget );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CVcdBlockDoc::AddNewInfoTarget( void )
+{
+ Vector vecOrigin;
+ QAngle angAngles;
+ float flFov;
+ clienttools->GetLocalPlayerEyePosition( vecOrigin, angAngles, flFov );
+ AddNewInfoTarget( vecOrigin, vec3_angle );
+}
+
+
+//-----------------------------------------------------------------------------
+// Deletes a commentary node
+//-----------------------------------------------------------------------------
+void CVcdBlockDoc::DeleteInfoTarget( CDmeVMFEntity *pNode )
+{
+ CDmrElementArray<CDmElement> entities = GetEntityList();
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ if ( pNode == entities[i] )
+ {
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Delete Info Target", "Delete Info Target" );
+ CDmeVMFEntity *pNode = CastElement< CDmeVMFEntity >( entities[ i ] );
+ pNode->DrawInEngine( false );
+ entities.FastRemove( i );
+ return;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &vecOrigin -
+// &angAbsAngles -
+// Output : CDmeVMFEntity
+//-----------------------------------------------------------------------------
+CDmeVMFEntity *CVcdBlockDoc::GetInfoTargetForLocation( Vector &vecOrigin, QAngle &angAbsAngles )
+{
+ const CDmrElementArray<> entities = GetEntityList();
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeVMFEntity *pNode = CastElement< CDmeVMFEntity >( entities[ i ] );
+ Vector &vecAngles = *(Vector*)(&pNode->GetRenderAngles());
+ if ( pNode->GetRenderOrigin().DistTo( vecOrigin ) < 1e-3 && vecAngles.DistTo( *(Vector*)&angAbsAngles ) < 1e-1 )
+ return pNode;
+ }
+
+ return NULL;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &vecStart -
+// &vecEnd -
+// Output : CDmeVMFEntity
+//-----------------------------------------------------------------------------
+CDmeVMFEntity *CVcdBlockDoc::GetInfoTargetForLocation( Vector &vecStart, Vector &vecEnd )
+{
+ Vector vecDelta;
+ float flEndDist;
+
+ vecDelta = vecEnd - vecStart;
+ flEndDist = VectorNormalize( vecDelta );
+
+ CDmeVMFEntity *pSelectedNode = NULL;
+ float flMinDistFromLine = 1E30;
+
+ const CDmrElementArray<CDmElement> entities = GetEntityList();
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeVMFEntity *pNode = CastElement< CDmeVMFEntity >( entities[ i ] );
+ float flDistAway = DotProduct( pNode->GetRenderOrigin() - vecStart, vecDelta );
+
+ if (flDistAway > 0.0 && flDistAway < flEndDist)
+ {
+ float flDistFromLine = (pNode->GetRenderOrigin() - vecStart - vecDelta * flDistAway).Length();
+ if (flDistFromLine < flMinDistFromLine)
+ {
+ pSelectedNode = pNode;
+ flMinDistFromLine = flDistFromLine;
+ }
+ }
+ }
+ return pSelectedNode;
+}
+
+
+//-----------------------------------------------------------------------------
+// Populate string choice lists
+//-----------------------------------------------------------------------------
+bool CVcdBlockDoc::GetStringChoiceList( const char *pChoiceListType, CDmElement *pElement,
+ const char *pAttributeName, bool bArrayElement, StringChoiceList_t &list )
+{
+ if ( !Q_stricmp( pChoiceListType, "info_targets" ) )
+ {
+ const CDmrElementArray<> entities = GetEntityList();
+
+ StringChoice_t sChoice;
+ sChoice.m_pValue = "";
+ sChoice.m_pChoiceString = "";
+ list.AddToTail( sChoice );
+
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeVMFEntity *pNode = CastElement< CDmeVMFEntity >( entities[ i ] );
+ if ( !V_stricmp( pNode->GetClassName(), "info_target" ) )
+ {
+ StringChoice_t sChoice;
+ sChoice.m_pValue = pNode->GetTargetName();
+ sChoice.m_pChoiceString = pNode->GetTargetName();
+ list.AddToTail( sChoice );
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Populate element choice lists
+//-----------------------------------------------------------------------------
+bool CVcdBlockDoc::GetElementChoiceList( const char *pChoiceListType, CDmElement *pElement,
+ const char *pAttributeName, bool bArrayElement, ElementChoiceList_t &list )
+{
+ if ( !Q_stricmp( pChoiceListType, "allelements" ) )
+ {
+ AddElementsRecursively( m_hEditRoot, list );
+ return true;
+ }
+
+ if ( !Q_stricmp( pChoiceListType, "info_targets" ) )
+ {
+ const CDmrElementArray<> entities = GetEntityList();
+
+ bool bFound = false;
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeVMFEntity *pNode = CastElement< CDmeVMFEntity >( entities[ i ] );
+ if ( !V_stricmp( pNode->GetClassName(), "info_target" ) )
+ {
+ bFound = true;
+ ElementChoice_t sChoice;
+ sChoice.m_pValue = pNode;
+ sChoice.m_pChoiceString = pNode->GetTargetName();
+ list.AddToTail( sChoice );
+ }
+ }
+ return bFound;
+ }
+
+ // by default, try to treat the choice list type as a Dme element type
+ AddElementsRecursively( m_hEditRoot, list, pChoiceListType );
+
+ return list.Count() > 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when data changes
+//-----------------------------------------------------------------------------
+void CVcdBlockDoc::OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ SetDirty( nNotifyFlags & NOTIFY_SETDIRTYFLAG ? true : false );
+ m_pCallback->OnDocChanged( pReason, nNotifySource, nNotifyFlags );
+}
+
+
+
+//-----------------------------------------------------------------------------
+// List of all entity classnames to copy over from the original block
+//-----------------------------------------------------------------------------
+static const char *s_pUseOriginalClasses[] =
+{
+ "worldspawn",
+ "func_occluder",
+ NULL
+};
+
+
+//-----------------------------------------------------------------------------
+// The server just loaded, populate the list with the entities is has
+//-----------------------------------------------------------------------------
+void CVcdBlockDoc::ServerLevelInitPostEntity( void )
+{
+ CDmrElementArray<> entityList = GetEntityList();
+
+ if ( entityList.Count() )
+ {
+ VerifyAllEdits( entityList );
+ }
+ else
+ {
+ InitializeFromServer( entityList );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Create a list of entities based on what the server has
+//-----------------------------------------------------------------------------
+void CVcdBlockDoc::InitializeFromServer( CDmrElementArray<> &entityList )
+{
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Initialize From Server" );
+
+ entityList.RemoveAll();
+
+ // initialize list with entities on the server
+ CBaseEntity *pServerEnt = servertools->FirstEntity();
+ while (pServerEnt)
+ {
+ char classname[256];
+
+ if (servertools->GetKeyValue( pServerEnt, "classname", classname, sizeof( classname ) ) )
+ {
+ if ( !Q_stricmp( classname, "info_target" ))
+ {
+ char hammerid[256];
+ if ( servertools->GetKeyValue( pServerEnt, "hammerid", hammerid, sizeof( hammerid ) ) )
+ {
+ int nextId = CDmeVMFEntity::GetNextEntityId();
+ CDmeVMFEntity::SetNextEntityId( atoi( hammerid ) );
+
+ CDmeVMFEntity *pTarget = CreateElement<CDmeVMFEntity>( "", entityList.GetOwner()->GetFileId() );
+
+ CDmeVMFEntity::SetNextEntityId( nextId );
+
+ if ( pTarget->CopyFromServer( pServerEnt ) )
+ {
+ entityList.AddToTail( pTarget );
+ }
+ }
+ }
+ }
+ pServerEnt = servertools->NextEntity( pServerEnt );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Check the list of entities on the server against the edits that are already made
+//-----------------------------------------------------------------------------
+void CVcdBlockDoc::VerifyAllEdits( const CDmrElementArray<> &entityList )
+{
+ // already filled in
+ for (int i = 0; i < entityList.Count(); i++)
+ {
+ CDmeVMFEntity *pEntity = CastElement<CDmeVMFEntity>( entityList[i] );
+
+ CBaseEntity *pServerEntity = servertools->FindEntityByHammerID( pEntity->GetEntityId() );
+
+ if (pServerEntity != NULL)
+ {
+ if (!pEntity->IsSameOnServer( pServerEntity ))
+ {
+ pEntity->MarkDirty();
+ }
+ else
+ {
+ pEntity->MarkDirty(false);
+ }
+ }
+ else
+ {
+ pEntity->CreateOnServer();
+ pEntity->MarkDirty();
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Load the VMF file, merge in all the edits, write it back out
+//-----------------------------------------------------------------------------
+bool CVcdBlockDoc::CopyEditsToVMF( )
+{
+ const CDmrElementArray<CDmElement> entityList = GetEntityList();
+
+ CDmElement *pVMF = NULL;
+ DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( m_pVMFFileName );
+ if ( g_pDataModel->RestoreFromFile( m_pVMFFileName, NULL, "vmf", &pVMF ) == DMFILEID_INVALID )
+ {
+ // needs some kind of error message
+ return false;
+ }
+
+ CDmrElementArray<CDmElement> vmfEntities( pVMF, "entities" );
+
+ int nVMFCount = vmfEntities.Count();
+ for (int i = 0; i < nVMFCount; i++)
+ {
+ CDmElement *pVMFEntity = vmfEntities[i];
+
+ char classname[256];
+ pVMFEntity->GetValueAsString( "classname", classname, sizeof( classname ) );
+
+ if ( Q_stricmp( "info_target", classname ) )
+ continue;
+
+ int nHammerID = atoi( pVMFEntity->GetName() );
+
+ // find a match.
+ int nCount = entityList.Count();
+ for (int j = 0; j < nCount; j++)
+ {
+ CDmeVMFEntity *pEntity = CastElement<CDmeVMFEntity>( entityList[j] );
+
+ if ( pEntity->IsDirty() && pEntity->GetEntityId() == nHammerID)
+ {
+ char text[256];
+ pEntity->GetValueAsString( "targetname", text, sizeof( text ) );
+ pVMFEntity->SetValueFromString( "targetname", text );
+ pEntity->GetValueAsString( "origin", text, sizeof( text ) );
+ pVMFEntity->SetValueFromString( "origin", text );
+ pEntity->GetValueAsString( "angles", text, sizeof( text ) );
+ pVMFEntity->SetValueFromString( "angles", text );
+
+ pEntity->MarkDirty(false);
+ }
+ }
+ }
+
+ // add the new entities
+ int nCount = entityList.Count();
+ for (int j = 0; j < nCount; j++)
+ {
+ CDmeVMFEntity *pEntity = CastElement<CDmeVMFEntity>( entityList[j] );
+
+ if ( pEntity->IsDirty())
+ {
+ CDmElement *pVMFEntity = CreateElement<CDmElement>( pEntity->GetName(), fileid );
+
+ char text[256];
+ pEntity->GetValueAsString( "classname", text, sizeof( text ) );
+ pVMFEntity->SetValue( "classname", text );
+ pEntity->GetValueAsString( "targetname", text, sizeof( text ) );
+ pVMFEntity->SetValue( "targetname", text );
+ pEntity->GetValueAsString( "origin", text, sizeof( text ) );
+ pVMFEntity->SetValue( "origin", text );
+ pEntity->GetValueAsString( "angles", text, sizeof( text ) );
+ pVMFEntity->SetValue( "angles", text );
+
+ vmfEntities.AddToTail( pVMFEntity );
+
+ pEntity->MarkDirty(false);
+ }
+ }
+
+ // currently, don't overwrite the vmf, not sure if this is serializing correctly yet
+ char tmpname[ 256 ];
+ Q_StripExtension( m_pVMFFileName, tmpname, sizeof(tmpname) );
+ Q_SetExtension( tmpname, ".vme", sizeof(tmpname) );
+
+ if (!g_pDataModel->SaveToFile( tmpname, NULL, "keyvalues", "vmf", pVMF ))
+ {
+ // needs some kind of error message
+ return false;
+ }
+
+ /*
+ // If we successfully read the file in, ask it for the max hammer id
+ int nMaxHammerId = pVMF->GetAttributeValue<int>( "maxHammerId" );
+ CDmeVMFEntity::SetNextEntityId( nMaxHammerId + 1 );
+ m_hVMFRoot = pVMF;
+ */
+
+ return true;
+}
+
+
+bool CVcdBlockDoc::RememberPlayerPosition()
+{
+ return true;
+}
diff --git a/tools/vcdblock/vcdblockdoc.h b/tools/vcdblock/vcdblockdoc.h
new file mode 100644
index 0000000..51d6293
--- /dev/null
+++ b/tools/vcdblock/vcdblockdoc.h
@@ -0,0 +1,108 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef VCDBLOCKDOC_H
+#define VCDBLOCKDOC_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "dme_controls/inotifyui.h"
+#include "datamodel/dmehandle.h"
+#include "datamodel/dmelement.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class IVcdBlockDocCallback;
+class CVcdBlockDoc;
+class CDmeVMFEntity;
+
+
+//-----------------------------------------------------------------------------
+// Contains all editable state
+//-----------------------------------------------------------------------------
+class CVcdBlockDoc : public IDmNotify
+{
+public:
+ CVcdBlockDoc( IVcdBlockDocCallback *pCallback );
+ ~CVcdBlockDoc();
+
+ // Inherited from INotifyUI
+ virtual void NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+
+ // Sets/Gets the file name
+ const char *GetBSPFileName();
+ const char *GetVMFFileName();
+ const char *GetEditFileName();
+ void SetVMFFileName( const char *pFileName );
+ void SetEditFileName( const char *pFileName );
+
+ // Dirty bits (has it changed since the last time it was saved?)
+ void SetDirty( bool bDirty );
+ bool IsDirty() const;
+
+ // Saves/loads from file
+ bool LoadFromFile( const char *pFileName );
+ void SaveToFile( );
+
+ // Returns the root object
+ CDmElement *GetRootObject();
+
+ // Called when data changes (see INotifyUI for flags)
+ void OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+
+ // Create a text block the engine can parse containing the entity data to spawn
+ void ServerLevelInitPostEntity( void );
+
+ // Returns the entity list
+ CDmAttribute *GetEntityList();
+
+ // Adds a new info_target
+ void AddNewInfoTarget( void );
+ void AddNewInfoTarget( const Vector &vecOrigin, const QAngle &angAngles );
+
+ // Deletes a commentary node
+ void DeleteInfoTarget( CDmeVMFEntity *pNode );
+
+ // Returns the commentary node at the specified location
+ CDmeVMFEntity *GetInfoTargetForLocation( Vector &vecOrigin, QAngle &angAbsAngles );
+
+ // Returns the info target that's closest to this line
+ CDmeVMFEntity *GetInfoTargetForLocation( Vector &vecStart, Vector &vecEnd );
+
+ // For element choice lists. Return false if it's an unknown choice list type
+ virtual bool GetStringChoiceList( const char *pChoiceListType, CDmElement *pElement,
+ const char *pAttributeName, bool bArrayElement, StringChoiceList_t &list );
+ virtual bool GetElementChoiceList( const char *pChoiceListType, CDmElement *pElement,
+ const char *pAttributeName, bool bArrayElement, ElementChoiceList_t &list );
+
+
+ void VerifyAllEdits( const CDmrElementArray<> &entityList );
+ void InitializeFromServer( CDmrElementArray<> &entityList );
+
+ bool CopyEditsToVMF( void );
+
+ bool RememberPlayerPosition( void );
+
+private:
+ IVcdBlockDocCallback *m_pCallback;
+ CDmeHandle< CDmElement > m_hVMFRoot; // VMF file
+ CDmeHandle< CDmElement > m_hEditRoot; // VMF Edits file
+ char m_pBSPFileName[512];
+ char m_pVMFFileName[512];
+ char m_pEditFileName[512];
+ bool m_bDirty;
+};
+
+
+
+#endif // VCDBLOCKDOC_H
diff --git a/tools/vcdblock/vcdblocktool.cpp b/tools/vcdblock/vcdblocktool.cpp
new file mode 100644
index 0000000..b9a143f
--- /dev/null
+++ b/tools/vcdblock/vcdblocktool.cpp
@@ -0,0 +1,1300 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Core Movie Maker UI API
+//
+//=============================================================================
+
+#include "vcdblocktool.h"
+#include "vgui_controls/Menu.h"
+#include "tier1/KeyValues.h"
+#include "vgui/IInput.h"
+#include "vgui/KeyCode.h"
+#include "vgui_controls/FileOpenDialog.h"
+#include "filesystem.h"
+#include "vgui/ilocalize.h"
+#include "tier0/icommandline.h"
+#include "materialsystem/imaterialsystem.h"
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "vcdblockdoc.h"
+#include "infotargetbrowserpanel.h"
+#include "infotargetpropertiespanel.h"
+#include "dme_controls/AttributeStringChoicePanel.h"
+#include "tier3/tier3.h"
+#include "tier2/fileutils.h"
+#include "vgui/ivgui.h"
+#include "view_shared.h"
+
+// for tracing
+#include "cmodel.h"
+#include "engine/ienginetrace.h"
+
+using namespace vgui;
+
+
+const char *GetVGuiControlsModuleName()
+{
+ return "VcdBlockTool";
+}
+
+//-----------------------------------------------------------------------------
+// Connect, disconnect
+//-----------------------------------------------------------------------------
+bool ConnectTools( CreateInterfaceFn factory )
+{
+ return (materials != NULL) && (g_pMatSystemSurface != NULL) && (mdlcache != NULL) &&
+ (studiorender != NULL) && (g_pMaterialSystemHardwareConfig != NULL);
+}
+
+void DisconnectTools( )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Singleton
+//-----------------------------------------------------------------------------
+CVcdBlockTool *g_pVcdBlockTool = NULL;
+
+void CreateTools()
+{
+ g_pVcdBlockTool = new CVcdBlockTool();
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CVcdBlockTool::CVcdBlockTool()
+{
+ m_bInNodeDropMode = false;
+ m_pMenuBar = NULL;
+ m_pDoc = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Init, shutdown
+//-----------------------------------------------------------------------------
+bool CVcdBlockTool::Init( )
+{
+ m_pDoc = NULL;
+ m_RecentFiles.LoadFromRegistry( GetRegistryName() );
+
+ // NOTE: This has to happen before BaseClass::Init
+ g_pVGuiLocalize->AddFile( "resource/toolvcdblock_%language%.txt" );
+
+ if ( !BaseClass::Init( ) )
+ return false;
+
+ {
+ m_hPreviewTarget = CreateElement<CDmeVMFEntity>( "preview target", DMFILEID_INVALID );
+ m_hPreviewTarget->SetValue( "classname", "info_target" );
+ }
+
+ return true;
+}
+
+void CVcdBlockTool::Shutdown()
+{
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+ g_pDataModel->DestroyElement( m_hPreviewTarget );
+
+ BaseClass::Shutdown();
+}
+
+
+//-----------------------------------------------------------------------------
+// returns the document
+//-----------------------------------------------------------------------------
+inline CVcdBlockDoc *CVcdBlockTool::GetDocument()
+{
+ return m_pDoc;
+}
+
+
+//-----------------------------------------------------------------------------
+// Tool activation/deactivation
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OnToolActivate()
+{
+ BaseClass::OnToolActivate();
+
+ enginetools->Command( "commentary 1\n" );
+}
+
+void CVcdBlockTool::OnToolDeactivate()
+{
+ BaseClass::OnToolDeactivate();
+
+ enginetools->Command( "commentary 0\n" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Enter mode where we preview dropping nodes
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::EnterTargetDropMode()
+{
+ // Can only do it in editor mode
+ if ( IsGameInputEnabled() )
+ return;
+
+ m_bInNodeDropMode = true;
+ SetMode( true, IsFullscreen() );
+ {
+ CDisableUndoScopeGuard guard;
+ m_hPreviewTarget->DrawInEngine( true );
+ }
+ SetMiniViewportText( "Left Click To Place Info Target\nESC to exit" );
+ enginetools->Command( "noclip\n" );
+}
+
+void CVcdBlockTool::LeaveTargetDropMode()
+{
+ Assert( m_bInNodeDropMode );
+
+ m_bInNodeDropMode = false;
+ SetMode( false, IsFullscreen() );
+ {
+ CDisableUndoScopeGuard guard;
+ m_hPreviewTarget->DrawInEngine( false );
+ }
+ SetMiniViewportText( NULL );
+ enginetools->Command( "noclip\n" );
+}
+
+
+//-----------------------------------------------------------------------------
+// figure out if the click is in the miniviewport, and where it's aiming
+//-----------------------------------------------------------------------------
+bool CVcdBlockTool::IsMiniViewportCursor( int x, int y, Vector &org, Vector &forward )
+{
+ // when dealing with the miniviewport, it just wants the screen area
+ int minx, miny, width, height;
+ GetMiniViewportEngineBounds( minx, miny, width, height );
+ x = x - minx;
+ y = y - miny;
+ if (x >= 0 && x < width && y >= 0 && y < height)
+ {
+ CViewSetup view;
+ if (enginetools->GetPlayerView( view, 0, 0, width, height ))
+ {
+ // get a ray into the world
+ enginetools->CreatePickingRay( view, x, y, org, forward );
+ return true;
+ }
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::QuickLoad( void )
+{
+ m_bHasPlayerPosition = true;
+ float flFov;
+ clienttools->GetLocalPlayerEyePosition( m_vecPlayerOrigin, m_vecPlayerAngles, flFov );
+
+ enginetools->Command( "load quick\n" );
+ enginetools->Execute( );
+}
+
+
+//-----------------------------------------------------------------------------
+//
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::QuickSave( void )
+{
+ enginetools->Command( "save quick\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Gets the position of the preview object
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::GetPlacementInfo( Vector &vecOrigin, QAngle &angAngles )
+{
+ // Places the placement objects
+ float flFov;
+ clienttools->GetLocalPlayerEyePosition( vecOrigin, angAngles, flFov );
+
+ Vector vecForward;
+ AngleVectors( angAngles, &vecForward );
+ VectorMA( vecOrigin, 40.0f, vecForward, vecOrigin );
+
+ // Eliminate pitch
+ angAngles.x = 0.0f;
+}
+
+
+//-----------------------------------------------------------------------------
+// Place the preview object before rendering
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::ClientPreRender()
+{
+ BaseClass::ClientPreRender();
+ if ( !m_bInNodeDropMode )
+ return;
+
+ // Places the placement objects
+ Vector vecOrigin;
+ QAngle angAngles;
+ GetPlacementInfo( vecOrigin, angAngles );
+
+ CDisableUndoScopeGuard guard;
+ m_hPreviewTarget->SetRenderOrigin( vecOrigin );
+ m_hPreviewTarget->SetRenderAngles( angAngles );
+}
+
+
+//-----------------------------------------------------------------------------
+// Let tool override key events (ie ESC and ~)
+//-----------------------------------------------------------------------------
+bool CVcdBlockTool::TrapKey( ButtonCode_t key, bool down )
+{
+ // Don't hook keyboard if not topmost
+ if ( !IsActiveTool() )
+ return false; // didn't trap, continue processing
+
+ // Don't hook these methods if the game isn't running
+ if ( !enginetools->IsInGame() )
+ return false;
+
+ if ( !m_bInNodeDropMode )
+ {
+ if ( key == MOUSE_LEFT )
+ {
+ if ( m_bInNodeDragMode && down == false )
+ {
+ m_bInNodeDragMode = false;
+ }
+ else if ( !m_bInNodeDragMode && down == true )
+ {
+ int x, y;
+ input()->GetCursorPos(x, y);
+
+ Vector org, forward;
+ if (IsMiniViewportCursor( x, y, org, forward ))
+ {
+ // trace to something solid
+ Ray_t ray;
+ CTraceFilterWorldAndPropsOnly traceFilter;
+ CBaseTrace tr;
+ ray.Init( org, org + forward * 1000.0 );
+ enginetools->TraceRayServer( ray, MASK_OPAQUE, &traceFilter, &tr );
+
+#if 1
+ CDmeVMFEntity *pSelection = m_pDoc->GetInfoTargetForLocation( tr.startpos, tr.endpos );
+ if (pSelection)
+ {
+ GetInfoTargetBrowser()->SelectNode( pSelection );
+ m_bInNodeDragMode = true;
+ m_iDragX = x;
+ m_iDragY = y;
+ return true;
+ }
+#else
+ if (tr.fraction < 1.0f)
+ {
+ // needs a better angle initialization
+ Vector vecOrigin;
+ QAngle angAngles;
+ GetPlacementInfo( vecOrigin, angAngles );
+ m_pDoc->AddNewInfoTarget( tr.endpos, angAngles );
+ return true; // trapping this key, stop processing
+ }
+#endif
+ }
+ }
+ }
+ return BaseClass::TrapKey( key, down );
+ }
+
+ if ( !down )
+ return false;
+
+ if ( key == KEY_ESCAPE )
+ {
+ LeaveTargetDropMode();
+ return true; // trapping this key, stop processing
+ }
+
+ if ( key == MOUSE_LEFT )
+ {
+ Vector vecOrigin;
+ QAngle angAngles;
+ GetPlacementInfo( vecOrigin, angAngles );
+ m_pDoc->AddNewInfoTarget( vecOrigin, angAngles );
+ return true; // trapping this key, stop processing
+ }
+
+ return false; // didn't trap, continue processing
+}
+
+
+//-----------------------------------------------------------------------------
+// Used to hook DME VMF entities into the render lists
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::DrawEntitiesInEngine( bool bDrawInEngine )
+{
+ if ( !m_pDoc )
+ return;
+
+ const CDmrElementArray<CDmElement> entities( m_pDoc->GetEntityList() );
+ if ( !entities.IsValid() )
+ return;
+
+ CDisableUndoScopeGuard guard;
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeVMFEntity *pEntity = CastElement<CDmeVMFEntity>( entities[i] );
+ Assert( pEntity );
+ pEntity->DrawInEngine( bDrawInEngine );
+ }
+}
+
+void CVcdBlockTool::ClientLevelInitPostEntity()
+{
+ BaseClass::ClientLevelInitPostEntity();
+ DrawEntitiesInEngine( true );
+
+ AttachAllEngineEntities();
+}
+
+void CVcdBlockTool::ClientLevelShutdownPreEntity()
+{
+ DrawEntitiesInEngine( false );
+ BaseClass::ClientLevelShutdownPreEntity();
+}
+
+
+//-----------------------------------------------------------------------------
+// Derived classes can implement this to get a new scheme to be applied to this tool
+//-----------------------------------------------------------------------------
+vgui::HScheme CVcdBlockTool::GetToolScheme()
+{
+ return vgui::scheme()->LoadSchemeFromFile( "Resource/BoxRocket.res", "BoxRocket" );
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// The View menu
+//
+//-----------------------------------------------------------------------------
+class CVcdBlockViewMenuButton : public CToolMenuButton
+{
+ DECLARE_CLASS_SIMPLE( CVcdBlockViewMenuButton, CToolMenuButton );
+public:
+ CVcdBlockViewMenuButton( CVcdBlockTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget );
+ virtual void OnShowMenu(vgui::Menu *menu);
+
+private:
+ CVcdBlockTool *m_pTool;
+};
+
+CVcdBlockViewMenuButton::CVcdBlockViewMenuButton( CVcdBlockTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget )
+ : BaseClass( parent, panelName, text, pActionSignalTarget )
+{
+ m_pTool = parent;
+
+ AddCheckableMenuItem( "properties", "#VcdBlockProperties", new KeyValues( "OnToggleProperties" ), pActionSignalTarget );
+ AddCheckableMenuItem( "entityreport", "#VcdBlockEntityReport", new KeyValues( "O|�glaEq��pyOeport" ), pActionSignalTarget );
+
+ AddSeparator();
+
+ AddMenuItem( "defaultlayout", "#VcdBlockViewDefault", new KeyValues( "OnDefaultLayout" ), pActionSignalTarget );
+
+ SetMenu(m_pMenu);
+}
+
+void CVcdBlockViewMenuButton::OnShowMenu(vgui::Menu *menu)
+{
+ BaseClass::OnShowMenu( menu );
+
+ // Update the menu
+ int id;
+
+ CVcdBlockDoc *pDoc = m_pTool->GetDocument();
+ if ( pDoc )
+ {
+ id = m_Items.Find( "properties" );
+ m_pMenu->SetItemEnabled( id, true );
+
+ Panel *p;
+ p = m_pTool->GetProperties();
+ Assert( p );
+ m_pMenu->SetMenuItemChecked( id, ( p && p->GetParent() ) ? true : false );
+
+ id = m_Items.Find( "entityreport" );
+ m_pMenu->SetItemEnabled( id, true );
+
+ p = m_pTool->GetInfoTargetBrowser();
+ Assert( p );
+ m_pMenu->SetMenuItemChecked( id, ( p && p->GetParent() ) ? true : false );
+ }
+ else
+ {
+ id = m_Items.Find( "properties" );
+ m_pMenu->SetItemEnabled( id, false );
+ id = m_Items.Find( "entityreport" );
+ m_pMenu->SetItemEnabled( id, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// The Tool menu
+//
+//-----------------------------------------------------------------------------
+class CVcdBlockToolMenuButton : public CToolMenuButton
+{
+ DECLARE_CLASS_SIMPLE( CVcdBlockToolMenuButton, CToolMenuButton );
+public:
+ CVcdBlockToolMenuButton( CVcdBlockTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget );
+ virtual void OnShowMenu(vgui::Menu *menu);
+
+private:
+ CVcdBlockTool *m_pTool;
+};
+
+CVcdBlockToolMenuButton::CVcdBlockToolMenuButton( CVcdBlockTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget )
+ : BaseClass( parent, panelName, text, pActionSignalTarget )
+{
+ m_pTool = parent;
+
+ AddMenuItem( "addnewnodes", "#VcdBlockAddNewNodes", new KeyValues( "AddNewNodes" ), pActionSignalTarget, NULL, "VcdBlockAddNewNodes" );
+ AddMenuItem( "copyeditstovmf", "#VcdBlockCopyEditsToVMF", new KeyValues( "CopyEditsToVMF" ), pActionSignalTarget, NULL, "VcdBlockCopyEditsToVMF" );
+
+ AddSeparator();
+
+ AddCheckableMenuItem( "rememberposition", "#VcdBlockRememberPosition", new KeyValues( "RememberPosition" ), pActionSignalTarget, NULL, "VcdBlockRememberPosition" );
+
+ SetMenu(m_pMenu);
+}
+
+void CVcdBlockToolMenuButton::OnShowMenu(vgui::Menu *menu)
+{
+ BaseClass::OnShowMenu( menu );
+
+ // Update the menu
+ int id;
+
+ CVcdBlockDoc *pDoc = m_pTool->GetDocument();
+
+ id = m_Items.Find( "addnewnodes" );
+ m_pMenu->SetItemEnabled( id, pDoc != NULL );
+
+ id = m_Items.Find( "rememberposition" );
+ m_pMenu->SetMenuItemChecked( id, m_pTool->GetRememberPlayerPosition() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes the menu bar
+//-----------------------------------------------------------------------------
+vgui::MenuBar *CVcdBlockTool::CreateMenuBar( CBaseToolSystem *pParent )
+{
+ m_pMenuBar = new CToolFileMenuBar( pParent, "Main Menu Bar" );
+
+ // Sets info in the menu bar
+ char title[ 64 ];
+ ComputeMenuBarTitle( title, sizeof( title ) );
+ m_pMenuBar->SetInfo( title );
+ m_pMenuBar->SetToolName( GetToolName() );
+
+ // Add menu buttons
+ CToolMenuButton *pFileButton = CreateToolFileMenuButton( m_pMenuBar, "File", "&File", GetActionTarget(), this );
+ CToolMenuButton *pEditButton = CreateToolEditMenuButton( this, "Edit", "&Edit", GetActionTarget() );
+ CVcdBlockToolMenuButton *pToolButton = new CVcdBlockToolMenuButton( this, "VcdBlock", "&VcdBlock", GetActionTarget() );
+ CVcdBlockViewMenuButton *pViewButton = new CVcdBlockViewMenuButton( this, "View", "&View", GetActionTarget() );
+ CToolMenuButton *pSwitchButton = CreateToolSwitchMenuButton( m_pMenuBar, "Switcher", "&Tools", GetActionTarget() );
+
+ m_pMenuBar->AddButton( pFileButton );
+ m_pMenuBar->AddButton( pEditButton );
+ m_pMenuBar->AddButton( pToolButton );
+ m_pMenuBar->AddButton( pViewButton );
+ m_pMenuBar->AddButton( pSwitchButton );
+
+ return m_pMenuBar;
+}
+
+
+//-----------------------------------------------------------------------------
+// Updates the menu bar based on the current file
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::UpdateMenuBar( )
+{
+ if ( !m_pDoc )
+ {
+ m_pMenuBar->SetFileName( "#VcdBlockNoFile" );
+ return;
+ }
+
+ const char *pEditFile = m_pDoc->GetEditFileName();
+ if ( !pEditFile[0] )
+ {
+ m_pMenuBar->SetFileName( "#VcdBlockNoFile" );
+ return;
+ }
+
+ if ( m_pDoc->IsDirty() )
+ {
+ char sz[ 512 ];
+ Q_snprintf( sz, sizeof( sz ), "* %s", pEditFile );
+ m_pMenuBar->SetFileName( sz );
+ }
+ else
+ {
+ m_pMenuBar->SetFileName( pEditFile );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets at tool windows
+//-----------------------------------------------------------------------------
+CInfoTargetPropertiesPanel *CVcdBlockTool::GetProperties()
+{
+ return m_hProperties.Get();
+}
+
+CInfoTargetBrowserPanel *CVcdBlockTool::GetInfoTargetBrowser()
+{
+ return m_hInfoTargetBrowser.Get();
+}
+
+
+//-----------------------------------------------------------------------------
+// Shows element properties
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::ShowElementProperties( )
+{
+ if ( !m_pDoc )
+ return;
+
+ // It should already exist
+ Assert( m_hProperties.Get() );
+ if ( m_hProperties.Get() )
+ {
+ m_hProperties->SetObject( m_hCurrentEntity );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Destroys all tool windows
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::ShowEntityInEntityProperties( CDmeVMFEntity *pEntity )
+{
+ Assert( m_hProperties.Get() );
+ m_hCurrentEntity = pEntity;
+ m_hProperties->SetObject( m_hCurrentEntity );
+}
+
+
+//-----------------------------------------------------------------------------
+// Destroys all tool windows
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::DestroyToolContainers()
+{
+ int c = ToolWindow::GetToolWindowCount();
+ for ( int i = c - 1; i >= 0 ; --i )
+ {
+ ToolWindow *kill = ToolWindow::GetToolWindow( i );
+ delete kill;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets up the default layout
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OnDefaultLayout()
+{
+ int y = m_pMenuBar->GetTall();
+
+ int usew, useh;
+ GetSize( usew, useh );
+
+ DestroyToolContainers();
+
+ Assert( ToolWindow::GetToolWindowCount() == 0 );
+
+ CInfoTargetPropertiesPanel *properties = GetProperties();
+ CInfoTargetBrowserPanel *pEntityReport = GetInfoTargetBrowser();
+
+ // Need three containers
+ ToolWindow *pPropertyWindow = m_ToolWindowFactory.InstanceToolWindow( GetClientArea(), false, properties, "#VcdBlockProperties", false );
+ ToolWindow *pEntityReportWindow = m_ToolWindowFactory.InstanceToolWindow( GetClientArea(), false, pEntityReport, "#VcdBlockEntityReport", false );
+
+ int halfScreen = usew / 2;
+ int bottom = useh - y;
+ int sy = (bottom - y) / 2;
+ SetMiniViewportBounds( halfScreen, y, halfScreen, sy - y );
+ pEntityReportWindow->SetBounds( 0, y, halfScreen, bottom );
+ pPropertyWindow->SetBounds( halfScreen, sy, halfScreen, bottom - sy );
+}
+
+void CVcdBlockTool::OnToggleProperties()
+{
+ if ( m_hProperties.Get() )
+ {
+ ToggleToolWindow( m_hProperties.Get(), "#VcdBlockProperties" );
+ }
+}
+
+void CVcdBlockTool::OnToggleEntityReport()
+{
+ if ( m_hInfoTargetBrowser.Get() )
+ {
+ ToggleToolWindow( m_hInfoTargetBrowser.Get(), "#VcdBlockEntityReport" );
+ }
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Creates
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::CreateTools( CVcdBlockDoc *doc )
+{
+ if ( !m_hProperties.Get() )
+ {
+ m_hProperties = new CInfoTargetPropertiesPanel( m_pDoc, this );
+ }
+
+ if ( !m_hInfoTargetBrowser.Get() )
+ {
+ m_hInfoTargetBrowser = new CInfoTargetBrowserPanel( m_pDoc, this, "InfoTargetBrowserPanel" );
+ }
+
+ RegisterToolWindow( m_hProperties );
+ RegisterToolWindow( m_hInfoTargetBrowser );
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes the tools
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::InitTools()
+{
+ ShowElementProperties();
+
+ // FIXME: There are no tool windows here; how should this work?
+ // These panels are saved
+ windowposmgr->RegisterPanel( "properties", m_hProperties, false );
+ windowposmgr->RegisterPanel( "entityreport", m_hInfoTargetBrowser, false );
+
+ if ( !windowposmgr->LoadPositions( "cfg/vcdblock.txt", this, &m_ToolWindowFactory, "VcdBlock" ) )
+ {
+ OnDefaultLayout();
+ }
+}
+
+
+void CVcdBlockTool::DestroyTools()
+{
+ m_hCurrentEntity = NULL;
+
+ if ( m_hProperties.Get() && m_hInfoTargetBrowser.Get() )
+ {
+ windowposmgr->SavePositions( "cfg/vcdblock.txt", "VcdBlock" );
+ }
+
+ int c = ToolWindow::GetToolWindowCount();
+ for ( int i = c - 1; i >= 0 ; --i )
+ {
+ ToolWindow *kill = ToolWindow::GetToolWindow( i );
+ delete kill;
+ }
+
+ UnregisterAllToolWindows();
+
+ if ( m_hProperties.Get() )
+ {
+ windowposmgr->UnregisterPanel( m_hProperties.Get() );
+ delete m_hProperties.Get();
+ m_hProperties = NULL;
+ }
+
+ if ( m_hInfoTargetBrowser.Get() )
+ {
+ windowposmgr->UnregisterPanel( m_hInfoTargetBrowser.Get() );
+ delete m_hInfoTargetBrowser.Get();
+ m_hInfoTargetBrowser = NULL;
+ }
+}
+
+
+void CVcdBlockTool::ShowToolWindow( Panel *tool, char const *toolName, bool visible )
+{
+ Assert( tool );
+
+ if ( tool->GetParent() == NULL && visible )
+ {
+ m_ToolWindowFactory.InstanceToolWindow( this, false, tool, toolName, false );
+ }
+ else if ( !visible )
+ {
+ ToolWindow *tw = dynamic_cast< ToolWindow * >( tool->GetParent()->GetParent() );
+ Assert( tw );
+ tw->RemovePage( tool );
+ }
+}
+
+void CVcdBlockTool::ToggleToolWindow( Panel *tool, char const *toolName )
+{
+ Assert( tool );
+
+ if ( tool->GetParent() == NULL )
+ {
+ ShowToolWindow( tool, toolName, true );
+ }
+ else
+ {
+ ShowToolWindow( tool, toolName, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates the action menu
+//-----------------------------------------------------------------------------
+vgui::Menu *CVcdBlockTool::CreateActionMenu( vgui::Panel *pParent )
+{
+ vgui::Menu *pActionMenu = new Menu( pParent, "ActionMenu" );
+ pActionMenu->AddMenuItem( "#ToolHide", new KeyValues( "Command", "command", "HideActionMenu" ), GetActionTarget() );
+ return pActionMenu;
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from IFileMenuCallbacks
+//-----------------------------------------------------------------------------
+int CVcdBlockTool::GetFileMenuItemsEnabled( )
+{
+ int nFlags = FILE_ALL;
+ if ( m_RecentFiles.IsEmpty() )
+ {
+ nFlags &= ~(FILE_RECENT | FILE_CLEAR_RECENT);
+ }
+ return nFlags;
+}
+
+void CVcdBlockTool::AddRecentFilesToMenu( vgui::Menu *pMenu )
+{
+ m_RecentFiles.AddToMenu( pMenu, GetActionTarget(), "OnRecent" );
+}
+
+bool CVcdBlockTool::GetPerforceFileName( char *pFileName, int nMaxLen )
+{
+ if ( !m_pDoc )
+ return false;
+
+ Q_strncpy( pFileName, m_pDoc->GetEditFileName(), nMaxLen );
+ return pFileName[0] != 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OnExit()
+{
+ enginetools->Command( "quit\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Handle commands from the action menu and other menus
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OnCommand( const char *cmd )
+{
+ if ( !V_stricmp( cmd, "HideActionMenu" ) )
+ {
+ if ( GetActionMenu() )
+ {
+ GetActionMenu()->SetVisible( false );
+ }
+ }
+ else if ( const char *pSuffix = StringAfterPrefix( cmd, "OnRecent" ) )
+ {
+ int idx = Q_atoi( pSuffix );
+ OpenFileFromHistory( idx );
+ }
+ else if( const char *pSuffix = StringAfterPrefix( cmd, "OnTool" ) )
+ {
+ int idx = Q_atoi( pSuffix );
+ enginetools->SwitchToTool( idx );
+ }
+ else if ( !V_stricmp( cmd, "OnUndo" ) )
+ {
+ OnUndo();
+ }
+ else if ( !V_stricmp( cmd, "OnRedo" ) )
+ {
+ OnRedo();
+ }
+ else if ( !V_stricmp( cmd, "OnDescribeUndo" ) )
+ {
+ OnDescribeUndo();
+ }
+ else
+ {
+ BaseClass::OnCommand( cmd );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Command handlers
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OnNew()
+{
+ int nFlags = 0;
+ const char *pSaveFileName = NULL;
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
+ pSaveFileName = m_pDoc->GetEditFileName();
+ }
+
+ // Bring up the file open dialog to choose a .bsp file
+ OpenFile( "bsp", pSaveFileName, "vle", nFlags );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when the File->Open menu is selected
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OnOpen( )
+{
+ int nFlags = 0;
+ const char *pSaveFileName = NULL;
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
+ pSaveFileName = m_pDoc->GetEditFileName();
+ }
+
+ OpenFile( "vle", pSaveFileName, "vle", nFlags );
+}
+
+
+bool CVcdBlockTool::OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ OnCloseNoSave();
+
+ if ( !LoadDocument( pFileName ) )
+ return false;
+
+ m_RecentFiles.Add( pFileName, pFileFormat );
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+ UpdateMenuBar();
+ return true;
+}
+
+void CVcdBlockTool::Save()
+{
+ if ( m_pDoc )
+ {
+ SaveFile( m_pDoc->GetEditFileName(), "vle", FOSM_SHOW_PERFORCE_DIALOGS );
+ }
+}
+
+void CVcdBlockTool::OnSaveAs()
+{
+ if ( m_pDoc )
+ {
+ SaveFile( NULL, "vle", FOSM_SHOW_PERFORCE_DIALOGS );
+ }
+}
+
+void CVcdBlockTool::OnRestartLevel()
+{
+ // FIXME: We may want to use this instead of completely restarting,
+ // but it's less well tested. Should be a lot faster though
+
+ // Reloads the map, entities only, will reload every entity
+ // enginetools->Command( "respawn_entities\n" );
+ enginetools->Command( "restart" );
+ enginetools->Execute();
+
+ const CDmrElementArray<> entities = m_pDoc->GetEntityList();
+ if ( !entities.IsValid() )
+ return;
+
+ int nCount = entities.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeVMFEntity *pEntity = CastElement<CDmeVMFEntity>( entities[i] );
+ Assert( pEntity );
+ pEntity->MarkDirty( false );
+ }
+}
+
+void CVcdBlockTool::SaveAndTest()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ SaveFile( m_pDoc->GetEditFileName(), "vle", FOSM_SHOW_PERFORCE_DIALOGS,
+ new KeyValues( "RestartLevel" ) );
+ }
+ else
+ {
+ OnRestartLevel();
+ }
+}
+
+void CVcdBlockTool::RestartMap()
+{
+ OnRestartLevel();
+}
+
+bool CVcdBlockTool::OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ if ( !m_pDoc )
+ return true;
+
+ m_pDoc->SetEditFileName( pFileName );
+ m_pDoc->SaveToFile( );
+
+ m_RecentFiles.Add( pFileName, pFileFormat );
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+ UpdateMenuBar();
+ return true;
+}
+
+void CVcdBlockTool::OnClose()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ SaveFile( m_pDoc->GetEditFileName(), "vle", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnClose" ) );
+ return;
+ }
+
+ OnCloseNoSave();
+}
+
+void CVcdBlockTool::OnCloseNoSave()
+{
+ DestroyTools();
+
+ if ( m_pDoc )
+ {
+ CAppNotifyScopeGuard sg( "CVcdBlockTool::OnCloseNoSave", NOTIFY_CHANGE_OTHER );
+
+ delete m_pDoc;
+ m_pDoc = NULL;
+
+ if ( m_hProperties )
+ {
+ m_hProperties->SetObject( NULL );
+ }
+ }
+
+ UpdateMenuBar( );
+}
+
+void CVcdBlockTool::OnMarkNotDirty()
+{
+ if ( m_pDoc )
+ {
+ m_pDoc->SetDirty( false );
+ }
+}
+
+
+void CVcdBlockTool::OnCopyEditsToVMF()
+{
+ if ( m_pDoc )
+ {
+ m_pDoc->CopyEditsToVMF();
+ }
+}
+
+
+void CVcdBlockTool::OnRememberPosition()
+{
+ m_bRememberPlayerPosition = !m_bRememberPlayerPosition;
+}
+
+
+void CVcdBlockTool::AttachAllEngineEntities()
+{
+ if ( !clienttools || !m_pDoc )
+ return;
+
+ /*
+ NOTE: This doesn't work for infotargets because they are server-only entities
+ for ( EntitySearchResult sr = clienttools->FirstEntity(); sr != NULL; sr = clienttools->NextEntity( sr ) )
+ {
+ if ( !sr )
+ continue;
+
+ HTOOLHANDLE handle = clienttools->AttachToEntity( sr );
+
+ const char *pClassName = clienttools->GetClassname( handle );
+ if ( Q_strcmp( pClassName, "class C_InfoTarget" ) == 0 )
+ {
+ Vector vecOrigin = clienttools->GetAbsOrigin( handle );
+ QAngle angAngles = clienttools->GetAbsAngles( handle );
+
+ // Find the associated commentary node entry in our doc
+ CDmeVMFEntity *pNode = m_pDoc->GetInfoTargetForLocation( vecOrigin, angAngles );
+ if ( pNode )
+ {
+ pNode->AttachToEngineEntity( handle );
+ }
+ }
+ }
+ */
+}
+
+
+//-----------------------------------------------------------------------------
+// Open a specific file
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OpenSpecificFile( const char *pFileName )
+{
+ int nFlags = 0;
+ const char *pSaveFileName = NULL;
+ if ( m_pDoc )
+ {
+ // File is already open
+ if ( !Q_stricmp( m_pDoc->GetEditFileName(), pFileName ) )
+ return;
+
+ if ( m_pDoc->IsDirty() )
+ {
+ nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
+ pSaveFileName = m_pDoc->GetEditFileName();
+ }
+ }
+
+ OpenFile( pFileName, "bsp", pSaveFileName, "vle", nFlags );
+}
+
+
+//-----------------------------------------------------------------------------
+// Show the save document query dialog
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OpenFileFromHistory( int slot )
+{
+ const char *pFileName = m_RecentFiles.GetFile( slot );
+ if ( !pFileName )
+ return;
+ OpenSpecificFile( pFileName );
+}
+
+
+//-----------------------------------------------------------------------------
+// Derived classes can implement this to get notified when files are saved/loaded
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues )
+{
+ if ( bWroteFile )
+ {
+ OnMarkNotDirty();
+ }
+
+ if ( !pContextKeyValues )
+ return;
+
+ if ( state != FileOpenStateMachine::SUCCESSFUL )
+ return;
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnClose" ) )
+ {
+ OnCloseNoSave();
+ return;
+ }
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnQuit" ) )
+ {
+ OnCloseNoSave();
+ vgui::ivgui()->PostMessage( GetVPanel(), new KeyValues( "OnExit" ), 0 );
+ return;
+ }
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "RestartLevel" ) )
+ {
+ OnRestartLevel();
+ return;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Show the File browser dialog
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ char pStartingDir[ MAX_PATH ];
+
+ if ( !Q_stricmp( pFileFormat, "bsp" ) )
+ {
+ GetModSubdirectory( "maps", pStartingDir, sizeof(pStartingDir) );
+ pDialog->SetTitle( "Choose Valve BSP File", true );
+ pDialog->SetStartDirectoryContext( "vcdblock_bsp_session", pStartingDir );
+ pDialog->AddFilter( "*.bsp", "Valve BSP File (*.bsp)", true );
+ }
+ else
+ {
+ GetModContentSubdirectory( "maps", pStartingDir, sizeof(pStartingDir) );
+ pDialog->SetTitle( "Choose Valve VLE File", true );
+ pDialog->SetStartDirectoryContext( "vcdblock_vle_session", pStartingDir );
+ pDialog->AddFilter( "*.vle", "Valve VLE File (*.vle)", true );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Can we quit?
+//-----------------------------------------------------------------------------
+bool CVcdBlockTool::CanQuit()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ // Show Save changes Yes/No/Cancel and re-quit if hit yes/no
+ SaveFile( m_pDoc->GetEditFileName(), "vle", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnQuit" ) );
+ return false;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Various command handlers related to the Edit menu
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OnUndo()
+{
+ CDisableUndoScopeGuard guard;
+ g_pDataModel->Undo();
+}
+
+void CVcdBlockTool::OnRedo()
+{
+ CDisableUndoScopeGuard guard;
+ g_pDataModel->Redo();
+}
+
+void CVcdBlockTool::OnDescribeUndo()
+{
+ CUtlVector< UndoInfo_t > list;
+ g_pDataModel->GetUndoInfo( list );
+
+ Msg( "%i operations in stack\n", list.Count() );
+
+ for ( int i = list.Count() - 1; i >= 0; --i )
+ {
+ UndoInfo_t& entry = list[ i ];
+ if ( entry.terminator )
+ {
+ Msg( "[ '%s' ] - %i operations\n", entry.undo, entry.numoperations );
+ }
+
+ Msg( " +%s\n", entry.desc );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// VcdBlock menu items
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OnAddNewNodes()
+{
+ if ( !m_pDoc )
+ return;
+
+ EnterTargetDropMode();
+}
+
+
+//-----------------------------------------------------------------------------
+// Background
+//-----------------------------------------------------------------------------
+const char *CVcdBlockTool::GetLogoTextureName()
+{
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from IVcdBlockDocCallback
+//-----------------------------------------------------------------------------
+void CVcdBlockTool::OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ if ( GetInfoTargetBrowser() )
+ {
+ if (nNotifyFlags & NOTIFY_CHANGE_TOPOLOGICAL)
+ {
+ GetInfoTargetBrowser()->UpdateEntityList();
+ }
+ else if (nNotifyFlags & NOTIFY_CHANGE_ATTRIBUTE_VALUE)
+ {
+ GetInfoTargetBrowser()->Refresh();
+ }
+ }
+
+ UpdateMenuBar();
+
+ /*
+ if ( bRefreshUI && m_hProperties.Get() )
+ {
+ m_hProperties->Refresh();
+ }
+ */
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads up a new document
+//-----------------------------------------------------------------------------
+bool CVcdBlockTool::LoadDocument( const char *pDocName )
+{
+ Assert( !m_pDoc );
+
+ DestroyTools();
+
+ m_pDoc = new CVcdBlockDoc( this );
+ if ( !m_pDoc->LoadFromFile( pDocName ) )
+ {
+ delete m_pDoc;
+ m_pDoc = NULL;
+ Warning( "Fatal error loading '%s'\n", pDocName );
+ return false;
+ }
+
+ ShowMiniViewport( true );
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// The engine entities now exist, find them.
+//-----------------------------------------------------------------------------
+
+void CVcdBlockTool::ServerLevelInitPostEntity()
+{
+ if (!m_pDoc)
+ return;
+
+ m_pDoc->ServerLevelInitPostEntity();
+
+ CreateTools( m_pDoc );
+ InitTools();
+
+ if (m_bRememberPlayerPosition && m_bHasPlayerPosition)
+ {
+ m_bHasPlayerPosition = false;
+ servertools->SnapPlayerToPosition( m_vecPlayerOrigin, m_vecPlayerAngles );
+ }
+
+}
diff --git a/tools/vcdblock/vcdblocktool.h b/tools/vcdblock/vcdblocktool.h
new file mode 100644
index 0000000..f3a38d2
--- /dev/null
+++ b/tools/vcdblock/vcdblocktool.h
@@ -0,0 +1,239 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: VcdBlock tool; main UI smarts class
+//
+//=============================================================================
+
+#ifndef VCDBLOCKTOOL_H
+#define VCDBLOCKTOOL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "tier0/platform.h"
+#include "toolutils/basetoolsystem.h"
+#include "toolutils/recentfilelist.h"
+#include "toolutils/toolmenubar.h"
+#include "toolutils/toolswitchmenubutton.h"
+#include "toolutils/tooleditmenubutton.h"
+#include "toolutils/toolfilemenubutton.h"
+#include "toolutils/toolmenubutton.h"
+#include "datamodel/dmelement.h"
+#include "dmevmfentity.h"
+#include "toolframework/ienginetool.h"
+#include "toolutils/enginetools_int.h"
+#include "toolutils/savewindowpositions.h"
+#include "toolutils/toolwindowfactory.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CDmElement;
+class CVcdBlockDoc;
+class CInfoTargetPropertiesPanel;
+class CInfoTargetBrowserPanel;
+
+namespace vgui
+{
+ class Panel;
+}
+
+
+//-----------------------------------------------------------------------------
+// Allows the doc to call back into the VcdBlock editor tool
+//-----------------------------------------------------------------------------
+abstract_class IVcdBlockDocCallback
+{
+public:
+ // Called by the doc when the data changes
+ virtual void OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags ) = 0;
+};
+
+
+//-----------------------------------------------------------------------------
+// Global methods of the VCD Blocking tool
+//-----------------------------------------------------------------------------
+abstract_class IVcdBlockTool
+{
+public:
+ // Gets at the rool panel (for modal dialogs)
+ virtual vgui::Panel *GetRootPanel() = 0;
+
+ // Gets the registry name (for saving settings)
+ virtual const char *GetRegistryName() = 0;
+
+ // Shows a particular entity in the entity properties dialog
+ virtual void ShowEntityInEntityProperties( CDmeVMFEntity *pEntity ) = 0;
+};
+
+//-----------------------------------------------------------------------------
+// Implementation of the VcdBlock tool
+//-----------------------------------------------------------------------------
+class CVcdBlockTool : public CBaseToolSystem, public IFileMenuCallbacks, public IVcdBlockDocCallback, public IVcdBlockTool
+{
+ DECLARE_CLASS_SIMPLE( CVcdBlockTool, CBaseToolSystem );
+
+public:
+ CVcdBlockTool();
+
+ // Inherited from IToolSystem
+ virtual const char *GetToolName() { return "VCD Blocking Tool"; }
+ virtual bool Init( );
+ virtual void Shutdown();
+ virtual bool CanQuit();
+ virtual void OnToolActivate();
+ virtual void OnToolDeactivate();
+ virtual void ServerLevelInitPostEntity();
+ virtual void DrawEntitiesInEngine( bool bDrawInEngine );
+ virtual void ClientLevelInitPostEntity();
+ virtual void ClientLevelShutdownPreEntity();
+ virtual bool TrapKey( ButtonCode_t key, bool down );
+ virtual void ClientPreRender();
+
+ // Inherited from IFileMenuCallbacks
+ virtual int GetFileMenuItemsEnabled( );
+ virtual void AddRecentFilesToMenu( vgui::Menu *menu );
+ virtual bool GetPerforceFileName( char *pFileName, int nMaxLen );
+
+ // Inherited from IVcdBlockDocCallback
+ virtual void OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+ virtual vgui::Panel *GetRootPanel() { return this; }
+ virtual void ShowEntityInEntityProperties( CDmeVMFEntity *pEntity );
+
+ // Inherited from CBaseToolSystem
+ virtual vgui::HScheme GetToolScheme();
+ virtual vgui::Menu *CreateActionMenu( vgui::Panel *pParent );
+ virtual void OnCommand( const char *cmd );
+ virtual const char *GetRegistryName() { return "VcdBlockTool"; }
+ virtual const char *GetBindingsContextFile() { return "cfg/VcdBlock.kb"; }
+ virtual vgui::MenuBar *CreateMenuBar( CBaseToolSystem *pParent );
+
+ MESSAGE_FUNC( Save, "OnSave" );
+ void SaveAndTest();
+ void RestartMap();
+
+ // Enter mode where we preview dropping nodes
+ void EnterTargetDropMode();
+ void LeaveTargetDropMode();
+
+ bool IsMiniViewportCursor( int x, int y, Vector &org, Vector &forward );
+
+ // Save/Load game state
+ void SetRememberPlayerPosition( bool state = true ) { m_bRememberPlayerPosition = state; };
+ bool GetRememberPlayerPosition( void ) { return m_bRememberPlayerPosition; };
+ void QuickLoad();
+ void QuickSave();
+
+ bool IsInNodeDrag( void ) { return m_bInNodeDragMode; };
+
+public:
+ MESSAGE_FUNC( OnRestartLevel, "RestartLevel" );
+ MESSAGE_FUNC( OnNew, "OnNew" );
+ MESSAGE_FUNC( OnOpen, "OnOpen" );
+ MESSAGE_FUNC( OnSaveAs, "OnSaveAs" );
+ MESSAGE_FUNC( OnClose, "OnClose" );
+ MESSAGE_FUNC( OnCloseNoSave, "OnCloseNoSave" );
+ MESSAGE_FUNC( OnMarkNotDirty, "OnMarkNotDirty" );
+ MESSAGE_FUNC( OnExit, "OnExit" );
+
+ // Commands related to the edit menu
+ void OnDescribeUndo();
+
+ // Methods related to the VcdBlock menu
+ MESSAGE_FUNC( OnAddNewNodes, "AddNewNodes" );
+ MESSAGE_FUNC( OnCopyEditsToVMF, "CopyEditsToVMF" );
+ MESSAGE_FUNC( OnRememberPosition, "RememberPosition" );
+
+ // Methods related to the view menu
+ MESSAGE_FUNC( OnToggleProperties, "OnToggleProperties" );
+ MESSAGE_FUNC( OnToggleEntityReport, "OnToggleEntityReport" );
+ MESSAGE_FUNC( OnDefaultLayout, "OnDefaultLayout" );
+
+ // Keybindings
+ KEYBINDING_FUNC( undo, KEY_Z, vgui::MODIFIER_CONTROL, OnUndo, "#undo_help", 0 );
+ KEYBINDING_FUNC( redo, KEY_Z, vgui::MODIFIER_CONTROL | vgui::MODIFIER_SHIFT, OnRedo, "#redo_help", 0 );
+ KEYBINDING_FUNC_NODECLARE( VcdBlockAddNewNodes, KEY_A, vgui::MODIFIER_CONTROL, OnAddNewNodes, "#VcdBlockAddNewNodesHelp", 0 );
+
+ void OpenFileFromHistory( int slot );
+ void OpenSpecificFile( const char *pFileName );
+ virtual void SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual bool OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual bool OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual void OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues );
+
+ void AttachAllEngineEntities();
+
+ // returns the document
+ CVcdBlockDoc *GetDocument();
+
+ // Gets at tool windows
+ CInfoTargetPropertiesPanel *GetProperties();
+ CInfoTargetBrowserPanel *GetInfoTargetBrowser();
+
+ CDmeHandle< CDmeVMFEntity > GetCurrentEntity( void ) { return m_hCurrentEntity; }
+
+private:
+ // Loads up a new document
+ bool LoadDocument( const char *pDocName );
+
+ // Updates the menu bar based on the current file
+ void UpdateMenuBar( );
+
+ // Shows element properties
+ void ShowElementProperties( );
+
+ virtual const char *GetLogoTextureName();
+
+ // Creates, destroys tools
+ void CreateTools( CVcdBlockDoc *doc );
+ void DestroyTools();
+
+ // Initializes the tools
+ void InitTools();
+
+ // Shows, toggles tool windows
+ void ToggleToolWindow( Panel *tool, char const *toolName );
+ void ShowToolWindow( Panel *tool, char const *toolName, bool visible );
+
+ // Kills all tool windows
+ void DestroyToolContainers();
+
+ // Gets the position of the preview object
+ void GetPlacementInfo( Vector &vecOrigin, QAngle &angles );
+
+private:
+ // Document
+ CVcdBlockDoc *m_pDoc;
+
+ // The menu bar
+ CToolFileMenuBar *m_pMenuBar;
+
+ // Element properties for editing material
+ vgui::DHANDLE< CInfoTargetPropertiesPanel > m_hProperties;
+
+ // The entity report
+ vgui::DHANDLE< CInfoTargetBrowserPanel > m_hInfoTargetBrowser;
+
+ // The currently viewed entity
+ CDmeHandle< CDmeVMFEntity > m_hCurrentEntity;
+
+ // Separate undo context for the act busy tool
+ bool m_bInNodeDropMode;
+ bool m_bInNodeDragMode;
+ int m_iDragX;
+ int m_iDragY;
+ CDmeHandle< CDmeVMFEntity > m_hPreviewTarget;
+ CToolWindowFactory< ToolWindow > m_ToolWindowFactory;
+
+ // remembered player position
+ bool m_bRememberPlayerPosition;
+ bool m_bHasPlayerPosition;
+ Vector m_vecPlayerOrigin;
+ QAngle m_vecPlayerAngles;
+};
+
+extern CVcdBlockTool *g_pVcdBlockTool;
+
+#endif // VCDBLOCKTOOL_H