diff options
Diffstat (limited to 'tools/vcdblock')
| -rw-r--r-- | tools/vcdblock/dmevmfentity.cpp | 664 | ||||
| -rw-r--r-- | tools/vcdblock/dmevmfentity.h | 131 | ||||
| -rw-r--r-- | tools/vcdblock/infotargetbrowserpanel.cpp | 297 | ||||
| -rw-r--r-- | tools/vcdblock/infotargetbrowserpanel.h | 68 | ||||
| -rw-r--r-- | tools/vcdblock/infotargetpropertiespanel.cpp | 225 | ||||
| -rw-r--r-- | tools/vcdblock/infotargetpropertiespanel.h | 76 | ||||
| -rw-r--r-- | tools/vcdblock/vcdblock.vpc | 64 | ||||
| -rw-r--r-- | tools/vcdblock/vcdblockdoc.cpp | 630 | ||||
| -rw-r--r-- | tools/vcdblock/vcdblockdoc.h | 108 | ||||
| -rw-r--r-- | tools/vcdblock/vcdblocktool.cpp | 1300 | ||||
| -rw-r--r-- | tools/vcdblock/vcdblocktool.h | 239 |
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 |