diff options
Diffstat (limited to 'tools/foundry')
| -rw-r--r-- | tools/foundry/DmeVMFEntity.cpp | 246 | ||||
| -rw-r--r-- | tools/foundry/DmeVMFEntity.h | 88 | ||||
| -rw-r--r-- | tools/foundry/entityreportpanel.cpp | 639 | ||||
| -rw-r--r-- | tools/foundry/entityreportpanel.h | 122 | ||||
| -rw-r--r-- | tools/foundry/foundry.vpc | 67 | ||||
| -rw-r--r-- | tools/foundry/foundrydoc.cpp | 345 | ||||
| -rw-r--r-- | tools/foundry/foundrydoc.h | 83 | ||||
| -rw-r--r-- | tools/foundry/foundrytool.cpp | 1172 | ||||
| -rw-r--r-- | tools/foundry/foundrytool.h | 65 |
9 files changed, 2827 insertions, 0 deletions
diff --git a/tools/foundry/DmeVMFEntity.cpp b/tools/foundry/DmeVMFEntity.cpp new file mode 100644 index 0000000..29446ae --- /dev/null +++ b/tools/foundry/DmeVMFEntity.cpp @@ -0,0 +1,246 @@ +//========= 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 "foundrytool.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 ); + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CDmeVMFEntity::OnConstruction() +{ + m_ClassName.Init( this, "classname" ); + m_TargetName.Init( this, "targetname" ); + m_bIsPlaceholder.InitAndSet( this, "_placeholder", false, FATTRIB_DONTSAVE ); + m_vecLocalOrigin.Init( this, "origin" ); + m_vecLocalAngles.Init( this, "angles" ); + + // 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_hEngineEntity = HTOOLHANDLE_INVALID; + + m_Wireframe.Init( "debug/debugwireframe", "editor" ); +} + +void CDmeVMFEntity::OnDestruction() +{ + // Unhook it from the engine + AttachToEngineEntity( false ); + m_Wireframe.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; + } +} + + +//----------------------------------------------------------------------------- +// Returns the entity ID +//----------------------------------------------------------------------------- +int CDmeVMFEntity::GetEntityId() const +{ + return atoi( GetName() ); +} + + +//----------------------------------------------------------------------------- +// 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( bool bAttach ) +{ + if ( !bAttach ) + { + m_hEngineEntity = HTOOLHANDLE_INVALID; + } + else + { + } +} + + +//----------------------------------------------------------------------------- +// Draws the helper for the entity +//----------------------------------------------------------------------------- +int CDmeVMFEntity::DrawModel( int flags ) +{ + Assert( IsDrawingInEngine() ); + + matrix3x4_t mat; + AngleMatrix( m_vecLocalAngles, m_vecLocalOrigin, mat ); + + CMatRenderContextPtr rc( g_pMaterialSystem->GetRenderContext() ); + + rc->MatrixMode( MATERIAL_MODEL ); + rc->PushMatrix(); + rc->LoadMatrix( mat ); + + int nTheta = 20, nPhi = 20; + float flRadius = SPHERE_RADIUS; + int nVertices = nTheta * nPhi; + int nIndices = 2 * ( nTheta + 1 ) * ( nPhi - 1 ); + + rc->FogMode( MATERIAL_FOG_NONE ); + rc->SetNumBoneWeights( 0 ); + rc->Bind( m_Wireframe ); + rc->CullMode( MATERIAL_CULLMODE_CW ); + + IMesh* pMesh = rc->GetDynamicMesh(); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, nVertices, nIndices ); + + // + // Build the index buffer. + // + int i, j; + for ( i = 0; i < nPhi; ++i ) + { + for ( j = 0; j < nTheta; ++j ) + { + float u = j / ( float )(nTheta - 1); + float v = i / ( float )(nPhi - 1); + float theta = ( j != nTheta-1 ) ? 2.0f * M_PI * u : 0.0f; + float phi = M_PI * v; + + Vector vecPos; + vecPos.x = flRadius * sin(phi) * cos(theta); + vecPos.y = flRadius * cos(phi); + vecPos.z = -flRadius * sin(phi) * sin(theta); + + unsigned char red = (int)( u * 255.0f ); + unsigned char green = (int)( v * 255.0f ); + unsigned char blue = (int)( v * 255.0f ); + unsigned char alpha = (int)( v * 255.0f ); + + meshBuilder.Position3fv( vecPos.Base() ); + meshBuilder.Color4ub( red, green, blue, alpha ); + meshBuilder.TexCoord2f( 0, u, v ); + meshBuilder.BoneWeight( 0, 1.0f ); + meshBuilder.BoneMatrix( 0, 0 ); + meshBuilder.AdvanceVertex(); + } + } + + // + // Emit the triangle strips. + // + int idx = 0; + for ( i = 0; i < nPhi - 1; ++i ) + { + for ( j = 0; j < nTheta; ++j ) + { + idx = nTheta * i + j; + + meshBuilder.FastIndex( idx ); + meshBuilder.FastIndex( idx + nTheta ); + } + + // + // Emit a degenerate triangle to skip to the next row without + // a connecting triangle. + // + if ( i < nPhi - 2 ) + { + meshBuilder.FastIndex( idx + 1 ); + meshBuilder.FastIndex( idx + 1 + nTheta ); + } + } + + meshBuilder.End(); + pMesh->Draw(); + + rc->CullMode( MATERIAL_CULLMODE_CCW ); + rc->MatrixMode( MATERIAL_MODEL ); + rc->PopMatrix(); + + return 0; +} + + +//----------------------------------------------------------------------------- +// Position and bounds for the model +//----------------------------------------------------------------------------- +const Vector &CDmeVMFEntity::GetRenderOrigin( void ) +{ + return m_vecLocalOrigin; +} + +const QAngle &CDmeVMFEntity::GetRenderAngles( void ) +{ + return m_vecLocalAngles; +} + +void CDmeVMFEntity::GetRenderBounds( Vector& mins, Vector& maxs ) +{ + mins.Init( -SPHERE_RADIUS, -SPHERE_RADIUS, -SPHERE_RADIUS ); + maxs.Init( SPHERE_RADIUS, SPHERE_RADIUS, SPHERE_RADIUS ); +} diff --git a/tools/foundry/DmeVMFEntity.h b/tools/foundry/DmeVMFEntity.h new file mode 100644 index 0000000..b5388cd --- /dev/null +++ b/tools/foundry/DmeVMFEntity.h @@ -0,0 +1,88 @@ +//========= 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/dmerenderable.h" +#include "datamodel/dmelement.h" +#include "toolframework/itoolentity.h" +#include "materialsystem/MaterialSystemUtil.h" + + +//----------------------------------------------------------------------------- +// Represents an editable entity; draws its helpers +//----------------------------------------------------------------------------- +class CDmeVMFEntity : public CDmeVisibilityControl< CDmeRenderable< CDmElement > > +{ + DEFINE_ELEMENT( CDmeVMFEntity, CDmeVisibilityControl< CDmeRenderable< 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 void GetRenderBounds( Vector& mins, Vector& maxs ); + +public: + int GetEntityId() const; + + 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( bool bAttach ); + +private: + bool IsEntityKey( CDmAttribute *pEntityKey ); + + CDmaVar<Vector> m_vecLocalOrigin; + CDmaVar<QAngle> m_vecLocalAngles; + + 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; +}; + + +//----------------------------------------------------------------------------- +// 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/foundry/entityreportpanel.cpp b/tools/foundry/entityreportpanel.cpp new file mode 100644 index 0000000..7e3907a --- /dev/null +++ b/tools/foundry/entityreportpanel.cpp @@ -0,0 +1,639 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Singleton dialog that generates and presents the entity report. +// +//===========================================================================// + +#include "EntityReportPanel.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 "dmevmfentity.h" +#include "foundrydoc.h" +#include "foundrytool.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 +//----------------------------------------------------------------------------- +CEntityReportPanel::CEntityReportPanel( CFoundryDoc *pDoc, vgui::Panel* pParent, const char *pName ) + : BaseClass( pParent, pName ), m_pDoc( pDoc ) +{ + m_bSuppressEntityListUpdate = false; + m_iFilterByType = FILTER_SHOW_EVERYTHING; + m_bFilterByKeyvalue = false; + m_bFilterByClass = false; + m_bFilterByHidden = false; + m_bFilterByKeyvalue = false; + m_bExact = false; + m_bFilterTextChanged = false; + + 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 Entities" ); + // m_pEntities->SetDragEnabled( true ); + m_pEntities->AddActionSignalTarget( this ); + m_pEntities->SetSortFunc( 0, TargetNameSortFunc ); + m_pEntities->SetSortFunc( 1, ClassNameSortFunc ); + m_pEntities->SetSortColumn( 0 ); + + // Filtering checkboxes + m_pFilterByClass = new vgui::CheckButton( this, "ClassnameCheck", "" ); + m_pFilterByClass->AddActionSignalTarget( this ); + m_pFilterByKeyvalue = new vgui::CheckButton( this, "KeyvalueCheck", "" ); + m_pFilterByKeyvalue->AddActionSignalTarget( this ); + m_pFilterByHidden = new vgui::CheckButton( this, "HiddenCheck", "" ); + m_pFilterByHidden->AddActionSignalTarget( this ); + m_pExact = new vgui::CheckButton( this, "ExactCheck", "" ); + m_pExact->AddActionSignalTarget( this ); + + // Filtering text entries + m_pFilterKey = new vgui::TextEntry( this, "KeyTextEntry" ); + m_pFilterValue = new vgui::TextEntry( this, "ValueTextEntry" ); + + // Classname combobox + m_pFilterClass = new vgui::ComboBox( this, "ClassNameComboBox", 16, true ); + + // Filter by type radio buttons + m_pFilterEverything = new vgui::RadioButton( this, "EverythingRadio", "" ); + m_pFilterPointEntities = new vgui::RadioButton( this, "PointRadio", "" ); + m_pFilterBrushModels = new vgui::RadioButton( this, "BrushRadio", "" ); + + LoadControlSettings( "resource/entityreportpanel.res" ); + + ReadSettingsFromRegistry(); + + // Used for updating filter while changing text + ivgui()->AddTickSignal( GetVPanel(), 300 ); +} + + +//----------------------------------------------------------------------------- +// Reads settings from registry +//----------------------------------------------------------------------------- +void CEntityReportPanel::ReadSettingsFromRegistry() +{ + m_bSuppressEntityListUpdate = true; + + const char *pKeyBase = g_pFoundryTool->GetRegistryName(); + m_pFilterByKeyvalue->SetSelected( registry->ReadInt(pKeyBase, "FilterByKeyvalue", 0) ); + m_pFilterByClass->SetSelected( registry->ReadInt(pKeyBase, "FilterByClass", 0) ); + m_pFilterByHidden->SetSelected( registry->ReadInt(pKeyBase, "FilterByHidden", 1) ); + m_pExact->SetSelected( registry->ReadInt(pKeyBase, "Exact", 0) ); + + m_iFilterByType = (FilterType_t)registry->ReadInt(pKeyBase, "FilterByType", FILTER_SHOW_EVERYTHING); + m_pFilterEverything->SetSelected( m_iFilterByType == FILTER_SHOW_EVERYTHING ); + m_pFilterPointEntities->SetSelected( m_iFilterByType == FILTER_SHOW_POINT_ENTITIES ); + m_pFilterBrushModels->SetSelected( m_iFilterByType == FILTER_SHOW_BRUSH_ENTITIES ); + + // Gotta call change functions manually since SetText doesn't post an action signal + const char *pValue = registry->ReadString( pKeyBase, "FilterClass", "" ); + m_pFilterClass->SetText( pValue ); + OnChangeFilterclass( pValue ); + + pValue = registry->ReadString( pKeyBase, "FilterKey", "" ); + m_pFilterKey->SetText( pValue ); + OnChangeFilterkey( pValue ); + + pValue = registry->ReadString( pKeyBase, "FilterValue", "" ); + m_pFilterValue->SetText( pValue ); + OnChangeFiltervalue( pValue ); + + m_bSuppressEntityListUpdate = false; + UpdateEntityList(); +} + + +//----------------------------------------------------------------------------- +// Writes settings to registry +//----------------------------------------------------------------------------- +void CEntityReportPanel::SaveSettingsToRegistry() +{ + const char *pKeyBase = g_pFoundryTool->GetRegistryName(); + registry->WriteInt(pKeyBase, "FilterByKeyvalue", m_bFilterByKeyvalue); + registry->WriteInt(pKeyBase, "FilterByClass", m_bFilterByClass); + registry->WriteInt(pKeyBase, "FilterByHidden", m_bFilterByHidden); + registry->WriteInt(pKeyBase, "FilterByType", m_iFilterByType); + registry->WriteInt(pKeyBase, "Exact", m_bExact); + + registry->WriteString(pKeyBase, "FilterClass", m_szFilterClass); + registry->WriteString(pKeyBase, "FilterKey", m_szFilterKey); + registry->WriteString(pKeyBase, "FilterValue", m_szFilterValue); +} + + +//----------------------------------------------------------------------------- +// Purpose: Shows the most recent selected object in properties window +//----------------------------------------------------------------------------- +void CEntityReportPanel::OnProperties(void) +{ + int iSel = m_pEntities->GetSelectedItem( 0 ); + KeyValues *kv = m_pEntities->GetItem( iSel ); + CDmeVMFEntity *pEntity = (CDmeVMFEntity *)kv->GetPtr( "entity" ); + g_pFoundryTool->ShowEntityInEntityProperties( pEntity ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Deletes the marked objects. +//----------------------------------------------------------------------------- +void CEntityReportPanel::OnDeleteEntities(void) +{ + // This is undoable + CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Delete Entities", "Delete Entities" ); + + int iSel = m_pEntities->GetSelectedItem( 0 ); + + // + // 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->DeleteEntity( pEntity ); + } + } + + guard.Release(); + + UpdateEntityList(); + + // Update the list box selection. + if (iSel >= m_pEntities->GetItemCount()) + { + iSel = m_pEntities->GetItemCount() - 1; + } + m_pEntities->SetSingleSelectedItem( iSel ); +} + + +//----------------------------------------------------------------------------- +// Called when buttons are clicked +//----------------------------------------------------------------------------- +void CEntityReportPanel::OnCommand( const char *pCommand ) +{ + if ( !Q_stricmp( pCommand, "delete" ) ) + { + // Confirm we want to do it + MessageBox *pConfirm = new MessageBox( "#FoundryDeleteObjects", "#FoundryDeleteObjectsMsg", g_pFoundryTool->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, "ShowProperties" ) ) + { + OnProperties(); + return; + } +} + + +//----------------------------------------------------------------------------- +// Call this when our settings are dirty +//----------------------------------------------------------------------------- +void CEntityReportPanel::MarkDirty( bool bFilterDirty ) +{ + float flTime = Plat_FloatTime(); + m_bRegistrySettingsChanged = true; + m_flRegistryTime = flTime; + if ( bFilterDirty && !m_bFilterTextChanged ) + { + m_bFilterTextChanged = true; + m_flFilterTime = flTime; + } +} + + +//----------------------------------------------------------------------------- +// Methods related to filtering +//----------------------------------------------------------------------------- +void CEntityReportPanel::OnFilterByHidden( bool bState ) +{ + m_bFilterByHidden = bState; + UpdateEntityList(); + MarkDirty( false ); +} + +void CEntityReportPanel::OnFilterByKeyvalue( bool bState ) +{ + m_bFilterByKeyvalue = bState; + UpdateEntityList(); + MarkDirty( false ); + + m_pFilterKey->SetEnabled( bState ); + m_pFilterValue->SetEnabled( bState ); + m_pExact->SetEnabled( bState ); +} + +void CEntityReportPanel::OnFilterKeyValueExact( bool bState ) +{ + m_bExact = bState; + UpdateEntityList(); + MarkDirty( false ); +} + +void CEntityReportPanel::OnFilterByType( FilterType_t type ) +{ + m_iFilterByType = type; + UpdateEntityList(); + MarkDirty( false ); +} + +void CEntityReportPanel::OnFilterByClass( bool bState ) +{ + m_bFilterByClass = bState; + UpdateEntityList(); + MarkDirty( false ); + + m_pFilterClass->SetEnabled( bState ); +} + +void CEntityReportPanel::OnChangeFilterkey( const char *pText ) +{ + m_szFilterKey = pText; + MarkDirty( true ); +} + +void CEntityReportPanel::OnChangeFiltervalue( const char *pText ) +{ + m_szFilterValue = pText; + MarkDirty( true ); +} + +void CEntityReportPanel::OnChangeFilterclass( const char *pText ) +{ + m_szFilterClass = pText; + MarkDirty( true ); +} + + +//----------------------------------------------------------------------------- +// Deals with all check buttons +//----------------------------------------------------------------------------- +void CEntityReportPanel::OnTextChanged( KeyValues *kv ) +{ + TextEntry *pPanel = (TextEntry*)kv->GetPtr( "panel", NULL ); + + int nLength = pPanel->GetTextLength(); + char *pBuf = (char*)_alloca( nLength + 1 ); + pPanel->GetText( pBuf, nLength+1 ); + + if ( pPanel == m_pFilterClass ) + { + OnChangeFilterclass( pBuf ); + return; + } + if ( pPanel == m_pFilterKey ) + { + OnChangeFilterkey( pBuf ); + return; + } + if ( pPanel == m_pFilterValue ) + { + OnChangeFiltervalue( pBuf ); + return; + } +} + + +//----------------------------------------------------------------------------- +// Deals with all check buttons +//----------------------------------------------------------------------------- +void CEntityReportPanel::OnButtonToggled( KeyValues *kv ) +{ + Panel *pPanel = (Panel*)kv->GetPtr( "panel", NULL ); + bool bState = kv->GetInt( "state", 0 ) != 0; + + if ( pPanel == m_pFilterByClass ) + { + OnFilterByClass( bState ); + return; + } + if ( pPanel == m_pFilterByKeyvalue ) + { + OnFilterByKeyvalue( bState ); + return; + } + if ( pPanel == m_pFilterByHidden ) + { + OnFilterByHidden( bState ); + return; + } + if ( pPanel == m_pExact ) + { + OnFilterKeyValueExact( bState ); + return; + } + if ( pPanel == m_pFilterEverything ) + { + OnFilterByType( FILTER_SHOW_EVERYTHING ); + return; + } + if ( pPanel == m_pFilterPointEntities ) + { + OnFilterByType( FILTER_SHOW_POINT_ENTITIES ); + return; + } + if ( pPanel == m_pFilterBrushModels ) + { + OnFilterByType( FILTER_SHOW_BRUSH_ENTITIES ); + return; + } +} + + +//----------------------------------------------------------------------------- +// FIXME: Necessary because SetSelected doesn't cause a ButtonToggled message to trigger +//----------------------------------------------------------------------------- +void CEntityReportPanel::OnCheckButtonChecked( KeyValues *kv ) +{ + OnButtonToggled( kv ); +} + +void CEntityReportPanel::OnRadioButtonChecked( KeyValues *kv ) +{ + OnButtonToggled( kv ); +} + + +#if 0 + +//----------------------------------------------------------------------------- +// Purpose: Centers the 2D and 3D views on the selected entities. +//----------------------------------------------------------------------------- +void CEntityReportPanel::OnGoto() +{ + MarkSelectedEntities(); + m_pDoc->CenterViewsOnSelection(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEntityReportPanel::MarkSelectedEntities() +{ + m_pDoc->SelectObject(NULL, CMapDoc::scClear); + + for(int i = 0; i < m_cEntities.GetCount(); i++) + { + if(!m_cEntities.GetSel(i)) + continue; + CMapEntity *pEntity = (CMapEntity*) m_cEntities.GetItemDataPtr(i); + m_pDoc->SelectObject(pEntity, CMapDoc::scSelect); + } + + m_pDoc->SelectObject(NULL, CMapDoc::scUpdateDisplay); +} + +#endif + +void CEntityReportPanel::OnTick( ) +{ + BaseClass::OnTick(); + + // check filters + float flTime = Plat_FloatTime(); + if ( m_bFilterTextChanged ) + { + if ( (flTime - m_flFilterTime) > 1e-3 ) + { + m_bFilterTextChanged = false; + m_flFilterTime = flTime; + UpdateEntityList(); + } + } + if ( m_bRegistrySettingsChanged ) + { + if ( (flTime - m_flRegistryTime) > 1e-3 ) + { + m_bRegistrySettingsChanged = false; + m_flRegistryTime = flTime; + SaveSettingsToRegistry(); + } + } +} + +bool CEntityReportPanel::ShouldAddEntityToList( CDmeVMFEntity *pEntity ) +{ + // nope. + if ( !m_bFilterByHidden && !pEntity->IsVisible() ) + return false; + + /* + if (!pDlg->m_pDoc->selection.IsEmpty() && !pEntity->IsSelected()) + return true; + */ + + if ( m_iFilterByType == FILTER_SHOW_POINT_ENTITIES && pEntity->IsPlaceholder() ) + return false; + + if ( m_iFilterByType == FILTER_SHOW_BRUSH_ENTITIES && !pEntity->IsPlaceholder() ) + return false; + + const char* pClassName = pEntity->GetClassName(); + + if ( m_bFilterByClass ) + { + if ( !m_szFilterClass.IsEmpty() ) + { + if ( !Q_stristr( pClassName, m_szFilterClass ) ) + return false; + } + } + + if ( !m_bFilterByKeyvalue || m_szFilterValue.IsEmpty() ) + return true; + + CUtlBuffer buf( 256, 0, CUtlBuffer::TEXT_BUFFER ); + for ( CDmAttribute *pKey = pEntity->FirstEntityKey(); pKey; pKey = pEntity->NextEntityKey( pKey ) ) + { + // first, check key + if ( m_szFilterKey.IsEmpty() || !Q_stricmp( m_szFilterKey, pKey->GetName() ) ) + { + // now, check value (as a string) + buf.Clear(); + pKey->Serialize( buf ); + const char *pValue = (const char*)buf.Base(); + if ( (!m_bExact && Q_stristr( pValue, m_szFilterValue ) ) || !Q_stricmp( pValue, m_szFilterValue ) ) + return true; + } + } + + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEntityReportPanel::UpdateEntityList(void) +{ + if ( m_bSuppressEntityListUpdate ) + return; + + m_bFilterTextChanged = false; + + m_pEntities->RemoveAll(); + + const CDmrElementArray<CDmElement> entityList( m_pDoc->GetEntityList() ); + int nCount = entityList.Count(); + for ( int i = 0; i < nCount; ++i ) + { + CDmeVMFEntity *pEntity = CastElement<CDmeVMFEntity>( entityList[i] ); + if ( ShouldAddEntityToList( pEntity ) ) + { + const char *pClassName = pEntity->GetClassName( ); + const char *pTargetName = pEntity->GetTargetName( ); + if ( !pTargetName || !pTargetName[0] ) + { + pTargetName = "<no name>"; + } + if ( !pClassName || !pClassName[0] ) + { + pClassName = "<no class>"; + } + + KeyValues *kv = new KeyValues( "node", "targetname", pTargetName ); + kv->SetString( "classname", pClassName ); + kv->SetPtr( "entity", pEntity ); + + m_pEntities->AddItem( kv, 0, false, false ); + } + } + m_pEntities->SortList(); +} + + +#if 0 +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEntityReportPanel::GenerateReport() +{ + POSITION p = pGD->Classes.GetHeadPosition(); + CString str; + while(p) + { + GDclass *pc = pGD->Classes.GetNext(p); + if(!pc->IsBaseClass()) + { + str = pc->GetName(); + if(str != "worldspawn") + m_cFilterClass.AddString(str); + } + } + + SetTimer(1, 500, NULL); + + OnFilterbykeyvalue(); + OnFilterbytype(); + OnFilterbyclass(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEntityReportPanel::OnSelChangeEntityList() +{ + MarkSelectedEntities(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEntityReportPanel::OnDblClkEntityList() +{ + m_pDoc->CenterViewsOnSelection(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEntityReportPanel::OnOK() +{ + DestroyWindow(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEntityReportPanel::OnClose() +{ + DestroyWindow(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Called when our window is being destroyed. +//----------------------------------------------------------------------------- +void CEntityReportPanel::OnDestroy() +{ + SaveToIni(); + s_pDlg = NULL; + delete this; +} +#endif
\ No newline at end of file diff --git a/tools/foundry/entityreportpanel.h b/tools/foundry/entityreportpanel.h new file mode 100644 index 0000000..2b72ff8 --- /dev/null +++ b/tools/foundry/entityreportpanel.h @@ -0,0 +1,122 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#ifndef ENTITYREPORTPANEL_H +#define ENTITYREPORTPANEL_H +#ifdef _WIN32 +#pragma once +#endif + +#include "vgui_controls/editablepanel.h" +#include "tier1/utlstring.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CFoundryDoc; +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 CEntityReportPanel : public vgui::EditablePanel +{ + DECLARE_CLASS_SIMPLE( CEntityReportPanel, vgui::EditablePanel ); + +public: + CEntityReportPanel( CFoundryDoc *pDoc, vgui::Panel* pParent, const char *pName ); // standard constructor + +// Inherited from Panel + virtual void OnTick(); + virtual void OnCommand( const char *pCommand ); + +private: + enum FilterType_t + { + FILTER_SHOW_EVERYTHING = 0, + FILTER_SHOW_POINT_ENTITIES = 1, + FILTER_SHOW_BRUSH_ENTITIES = 2 + }; + + // Messages handled + MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", kv ); + MESSAGE_FUNC_PARAMS( OnButtonToggled, "ButtonToggled", kv ); + MESSAGE_FUNC( OnDeleteEntities, "DeleteEntities" ); + + // FIXME: Necessary because SetSelected doesn't cause a ButtonToggled message to trigger + MESSAGE_FUNC_PARAMS( OnCheckButtonChecked, "CheckButtonChecked", kv ); + MESSAGE_FUNC_PARAMS( OnRadioButtonChecked, "RadioButtonChecked", kv ); + + // Methods related to filtering + void OnFilterByHidden( bool bState ); + void OnFilterByKeyvalue( bool bState ); + void OnFilterByClass( bool bState ); + void OnFilterKeyValueExact( bool bState ); + void OnFilterByType( FilterType_t type ); + void OnChangeFilterkey( const char *pText ); + void OnChangeFiltervalue( const char *pText ); + void OnChangeFilterclass( const char *pText ); + + // Methods related to updating the listpanel + void UpdateEntityList(); + bool ShouldAddEntityToList( CDmeVMFEntity *pEntity ); + + // Methods related to saving settings + void ReadSettingsFromRegistry(); + void SaveSettingsToRegistry(); + + // Call this when our settings are dirty + void MarkDirty( bool bFilterDirty ); + + // Shows the most recent selected object in properties window + void OnProperties(); + + CFoundryDoc *m_pDoc; + FilterType_t m_iFilterByType; + bool m_bFilterByClass; + bool m_bFilterByHidden; + bool m_bFilterByKeyvalue; + bool m_bExact; + bool m_bSuppressEntityListUpdate; + + CUtlString m_szFilterKey; + CUtlString m_szFilterValue; + CUtlString m_szFilterClass; + + bool m_bFilterTextChanged; + float m_flFilterTime; + + bool m_bRegistrySettingsChanged; + float m_flRegistryTime; + + vgui::CheckButton *m_pExact; + vgui::ComboBox *m_pFilterClass; + vgui::CheckButton *m_pFilterByClass; + vgui::ListPanel *m_pEntities; + vgui::TextEntry *m_pFilterKey; + vgui::TextEntry *m_pFilterValue; + vgui::CheckButton *m_pFilterByKeyvalue; + vgui::CheckButton *m_pFilterByHidden; + + vgui::RadioButton *m_pFilterEverything; + vgui::RadioButton *m_pFilterPointEntities; + vgui::RadioButton *m_pFilterBrushModels; +}; + + +#endif // ENTITYREPORTPANEL_H diff --git a/tools/foundry/foundry.vpc b/tools/foundry/foundry.vpc new file mode 100644 index 0000000..9d211ac --- /dev/null +++ b/tools/foundry/foundry.vpc @@ -0,0 +1,67 @@ +//----------------------------------------------------------------------------- +// FOUNDRY.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin\tools" + +$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc" + +$Configuration +{ + $Compiler + { + $AdditionalIncludeDirectories "$BASE,.\,$SRCDIR\game\shared" + $PreprocessorDefinitions "$BASE;FOUNDRY_EXPORTS" + } + + $Linker + { + $AdditionalDependencies "$BASE Psapi.lib" + } +} + +$Project "foundry" +{ + $Folder "Source Files" + { + $File "DmeVMFEntity.cpp" + $File "DmeVMFEntity.h" + $File "entityreportpanel.cpp" + $File "entityreportpanel.h" + $File "foundrydoc.cpp" + $File "foundrytool.cpp" + $File "$SRCDIR\public\interpolatortypes.cpp" + $File "$SRCDIR\public\registry.cpp" + $File "$SRCDIR\public\vgui_controls\vgui_controls.cpp" + } + + $Folder "Header Files" + { + $File "foundrydoc.h" + $File "foundrytool.h" + } + + $Folder "Public Header Files" + { + $File "$SRCDIR\public\mathlib\mathlib.h" + } + + $Folder "Link Libraries" + { + $Lib datamodel + $Lib dmxloader + $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/foundry/foundrydoc.cpp b/tools/foundry/foundrydoc.cpp new file mode 100644 index 0000000..9d3b5d1 --- /dev/null +++ b/tools/foundry/foundrydoc.cpp @@ -0,0 +1,345 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "foundrydoc.h" +#include "tier1/KeyValues.h" +#include "tier1/utlbuffer.h" +#include "datamodel/dmelement.h" +#include "toolutils/enginetools_int.h" +#include "filesystem.h" +#include "foundrytool.h" +#include "toolframework/ienginetool.h" +#include "dmevmfentity.h" + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CFoundryDoc::CFoundryDoc( IFoundryDocCallback *pCallback ) : m_pCallback( pCallback ) +{ + m_hRoot = NULL; + m_pBSPFileName[0] = 0; + m_pVMFFileName[0] = 0; + m_bDirty = false; + g_pDataModel->InstallNotificationCallback( this ); +} + +CFoundryDoc::~CFoundryDoc() +{ + g_pDataModel->RemoveNotificationCallback( this ); +} + + +//----------------------------------------------------------------------------- +// Inherited from INotifyUI +//----------------------------------------------------------------------------- +void CFoundryDoc::NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags ) +{ + OnDataChanged( pReason, nNotifySource, nNotifyFlags ); +} + + +//----------------------------------------------------------------------------- +// Gets the file name +//----------------------------------------------------------------------------- +const char *CFoundryDoc::GetBSPFileName() +{ + return m_pBSPFileName; +} + +const char *CFoundryDoc::GetVMFFileName() +{ + return m_pVMFFileName; +} + +void CFoundryDoc::SetVMFFileName( const char *pFileName ) +{ + Q_strncpy( m_pVMFFileName, pFileName, sizeof( m_pVMFFileName ) ); + Q_FixSlashes( m_pVMFFileName ); + SetDirty( true ); +} + + +//----------------------------------------------------------------------------- +// Dirty bits +//----------------------------------------------------------------------------- +void CFoundryDoc::SetDirty( bool bDirty ) +{ + m_bDirty = bDirty; +} + +bool CFoundryDoc::IsDirty() const +{ + return m_bDirty; +} + + +//----------------------------------------------------------------------------- +// Saves/loads from file +//----------------------------------------------------------------------------- +bool CFoundryDoc::LoadFromFile( const char *pFileName ) +{ + Assert( !m_hRoot.Get() ); + + // This is not undoable + CAppDisableUndoScopeGuard guard( "CFoundryDoc::LoadFromFile", 0 ); + SetDirty( false ); + + if ( !pFileName[0] ) + return false; + + // Store the BSP file name + Q_strncpy( m_pBSPFileName, pFileName, sizeof( m_pBSPFileName ) ); + + // Construct VMF file name from the BSP + const char *pGame = Q_stristr( pFileName, "\\game\\" ); + if ( !pGame ) + return false; + + // Compute the map name + char mapname[ 256 ]; + const char *pMaps = Q_stristr( pFileName, "\\maps\\" ); + if ( !pMaps ) + return false; + + Q_strncpy( mapname, pMaps + 6, sizeof( 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) ); + + CDmElement *pVMF = NULL; + if ( g_pDataModel->RestoreFromFile( m_pVMFFileName, NULL, "vmf", &pVMF ) == DMFILEID_INVALID ) + { + m_pBSPFileName[0] = 0; + m_pVMFFileName[0] = 0; + return false; + } + + m_hRoot = pVMF; + + guard.Release(); + SetDirty( false ); + + char cmd[ 256 ]; + Q_snprintf( cmd, sizeof( cmd ), "disconnect; map %s\n", mapname ); + enginetools->Command( cmd ); + enginetools->Execute( ); + + return true; +} + +void CFoundryDoc::SaveToFile( ) +{ + if ( m_hRoot.Get() && m_pVMFFileName && m_pVMFFileName[0] ) + { + g_pDataModel->SaveToFile( m_pVMFFileName, NULL, "keyvalues", "vmf", m_hRoot ); + } + + SetDirty( false ); +} + + +//----------------------------------------------------------------------------- +// Returns the root object +//----------------------------------------------------------------------------- +CDmElement *CFoundryDoc::GetRootObject() +{ + return m_hRoot; +} + + +//----------------------------------------------------------------------------- +// Returns the entity list +//----------------------------------------------------------------------------- +CDmAttribute *CFoundryDoc::GetEntityList() +{ + return m_hRoot ? m_hRoot->GetAttribute( "entities", AT_ELEMENT_ARRAY ) : NULL; +} + + +//----------------------------------------------------------------------------- +// Deletes an entity +//----------------------------------------------------------------------------- +void CFoundryDoc::DeleteEntity( CDmeVMFEntity *pEntity ) +{ + CDmrElementArray<> entities( GetEntityList() ); + if ( !entities.IsValid() ) + return; + + int nCount = entities.Count(); + for ( int i = 0; i < nCount; ++i ) + { + if ( pEntity == CastElement< CDmeVMFEntity >( entities[i] ) ) + { + entities.FastRemove( i ); + return; + } + } +} + + +//----------------------------------------------------------------------------- +// Called when data changes +//----------------------------------------------------------------------------- +void CFoundryDoc::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 +}; + + +//----------------------------------------------------------------------------- +// Always copy the worldspawn and other entities that had data built into them by VBSP out +//----------------------------------------------------------------------------- +void CFoundryDoc::AddOriginalEntities( CUtlBuffer &entityBuf, const char *pActualEntityData ) +{ + while ( *pActualEntityData ) + { + pActualEntityData = strchr( pActualEntityData, '{' ); + if ( !pActualEntityData ) + break; + + const char *pBlockStart = pActualEntityData; + + pActualEntityData = strstr( pActualEntityData, "\"classname\"" ); + if ( !pActualEntityData ) + break; + + // Skip "classname" + pActualEntityData += 11; + + pActualEntityData = strchr( pActualEntityData, '\"' ); + if ( !pActualEntityData ) + break; + + // Skip " + ++pActualEntityData; + + char pClassName[512]; + int j = 0; + while (*pActualEntityData != 0 && *pActualEntityData != '\"' ) + { + pClassName[j++] = *pActualEntityData++; + } + pClassName[j] = 0; + + pActualEntityData = strchr( pActualEntityData, '}' ); + if ( !pActualEntityData ) + break; + + // Skip } + ++pActualEntityData; + + for ( int i = 0; s_pUseOriginalClasses[i]; ++i ) + { + if ( !Q_stricmp( pClassName, s_pUseOriginalClasses[i] ) ) + { + // Found one we need to keep, add it to the buffer + int nBytes = (int)( (size_t)pActualEntityData - (size_t)pBlockStart ); + entityBuf.Put( pBlockStart, nBytes ); + entityBuf.PutChar( '\n' ); + break; + } + } + } +} + + +//----------------------------------------------------------------------------- +// Copy in other entities from the editable VMF +//----------------------------------------------------------------------------- +void CFoundryDoc::AddVMFEntities( CUtlBuffer &entityBuf, const char *pActualEntityData ) +{ + const CDmrElementArray<CDmElement> entityArray( m_hRoot, "entities" ); + if ( !entityArray.IsValid() ) + return; + + int nCount = entityArray.Count(); + for ( int iEntity = 0; iEntity < nCount; ++iEntity ) + { + CDmElement *pEntity = entityArray[iEntity]; + const char *pClassName = pEntity->GetValueString( "classname" ); + if ( !pClassName || !pClassName[0] ) + continue; + + // Don't spawn those classes we grab from the actual compiled map + bool bDontUse = false; + for ( int i = 0; s_pUseOriginalClasses[i]; ++i ) + { + if ( !Q_stricmp( pClassName, s_pUseOriginalClasses[i] ) ) + { + bDontUse = true; + break; + } + } + + if ( bDontUse ) + continue; + + entityBuf.PutString( "{\n" ); + entityBuf.Printf( "\"id\" \"%d\"\n", atol( pEntity->GetName() ) ); + + for( CDmAttribute *pAttribute = pEntity->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() ) + { + if ( pAttribute->IsFlagSet( FATTRIB_STANDARD ) ) + continue; + + if ( IsArrayType( pAttribute->GetType() ) ) + continue; + + if ( !Q_stricmp( pAttribute->GetName(), "editorType" ) || !Q_stricmp( pAttribute->GetName(), "editor" ) ) + continue; + + entityBuf.Printf( "\"%s\" ", pAttribute->GetName() ); + + // FIXME: Set up standard delimiters + entityBuf.PutChar( '\"' ); + pAttribute->Serialize( entityBuf ); + entityBuf.PutString( "\"\n" ); + } + + entityBuf.PutString( "}\n" ); + } +} + + +//----------------------------------------------------------------------------- +// Create a text block the engine can parse containing the entity data to spawn +//----------------------------------------------------------------------------- +const char* CFoundryDoc::GenerateEntityData( const char *pActualEntityData ) +{ + if ( !m_hRoot.Get() ) + return pActualEntityData; + + // Contains the text block the engine can parse containing the entity data to spawn + static CUtlBuffer entityBuf( 2048, 2048, CUtlBuffer::TEXT_BUFFER ); + entityBuf.Clear(); + + // Always copy the worldspawn and other entities that had data built into them by VBSP out + AddOriginalEntities( entityBuf, pActualEntityData ); + + // Copy in other entities from the editable VMF + AddVMFEntities( entityBuf, pActualEntityData ); + + return (const char*)entityBuf.Base(); +} + diff --git a/tools/foundry/foundrydoc.h b/tools/foundry/foundrydoc.h new file mode 100644 index 0000000..73a5144 --- /dev/null +++ b/tools/foundry/foundrydoc.h @@ -0,0 +1,83 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#ifndef FOUNDRYDOC_H +#define FOUNDRYDOC_H + +#ifdef _WIN32 +#pragma once +#endif + + +#include "dme_controls/inotifyui.h" +#include "datamodel/dmehandle.h" + + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class IFoundryDocCallback; +class CDmeVMFEntity; + + +//----------------------------------------------------------------------------- +// Contains all editable state +//----------------------------------------------------------------------------- +class CFoundryDoc : public IDmNotify +{ +public: + CFoundryDoc( IFoundryDocCallback *pCallback ); + ~CFoundryDoc(); + + // Inherited from INotifyUI + virtual void NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags ); + + // Sets/Gets the file name + const char *GetBSPFileName(); + const char *GetVMFFileName(); + void SetVMFFileName( 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 + const char* GenerateEntityData( const char *pActualEntityData ); + + // Returns the entity list + CDmAttribute *GetEntityList(); + + // Deletes an entity + void DeleteEntity( CDmeVMFEntity *pEntity ); + +private: + // Always copy the worldspawn and other entities that had data built into them by VBSP out + void AddOriginalEntities( CUtlBuffer &entityBuf, const char *pActualEntityData ); + + // Copy in other entities from the editable VMF + void AddVMFEntities( CUtlBuffer &entityBuf, const char *pActualEntityData ); + + IFoundryDocCallback *m_pCallback; + CDmeHandle< CDmElement > m_hRoot; + char m_pBSPFileName[512]; + char m_pVMFFileName[512]; + bool m_bDirty; +}; + + +#endif // FOUNDRYDOC_H diff --git a/tools/foundry/foundrytool.cpp b/tools/foundry/foundrytool.cpp new file mode 100644 index 0000000..9f3338e --- /dev/null +++ b/tools/foundry/foundrytool.cpp @@ -0,0 +1,1172 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Core Movie Maker UI API +// +//============================================================================= + +#include "foundrytool.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 "vgui_controls/Menu.h" +#include "tier1/KeyValues.h" +#include "toolutils/enginetools_int.h" +#include "toolframework/ienginetool.h" +#include "vgui/IInput.h" +#include "vgui/KeyCode.h" +#include "vgui_controls/FileOpenDialog.h" +#include "filesystem.h" +#include "vgui/ilocalize.h" +#include "dme_controls/elementpropertiestree.h" +#include "tier0/icommandline.h" +#include "materialsystem/imaterialsystem.h" +#include "VGuiMatSurface/IMatSystemSurface.h" +#include "toolutils/savewindowpositions.h" +#include "foundrydoc.h" +#include "toolutils/toolwindowfactory.h" +#include "toolutils/basepropertiescontainer.h" +#include "entityreportpanel.h" +#include "datamodel/dmelement.h" +#include "movieobjects/dmeeditortypedictionary.h" +#include "dmevmfentity.h" +#include "tier3/tier3.h" +#include "tier2/fileutils.h" +#include "vgui/ivgui.h" + + +using namespace vgui; + +//----------------------------------------------------------------------------- +// Singleton interfaces +//----------------------------------------------------------------------------- +CDmeEditorTypeDictionary *g_pEditorTypeDict; + + +const char *GetVGuiControlsModuleName() +{ + return "FoundryTool"; +} + +//----------------------------------------------------------------------------- +// Connect, disconnect +//----------------------------------------------------------------------------- +bool ConnectTools( CreateInterfaceFn factory ) +{ + return (materials != NULL) && (g_pMatSystemSurface != NULL); +} + +void DisconnectTools( ) +{ +} + + +//----------------------------------------------------------------------------- +// Implementation of the Foundry tool +//----------------------------------------------------------------------------- +class CFoundryTool : public CBaseToolSystem, public IFileMenuCallbacks, public IFoundryDocCallback, public IFoundryTool +{ + DECLARE_CLASS_SIMPLE( CFoundryTool, CBaseToolSystem ); + +public: + CFoundryTool(); + + // Inherited from IToolSystem + virtual const char *GetToolName() { return "Foundry"; } + virtual const char *GetBindingsContextFile() { return "cfg/Foundry.kb"; } + virtual bool Init( ); + virtual void Shutdown(); + virtual bool CanQuit(); + virtual void OnToolActivate(); + virtual void OnToolDeactivate(); + virtual const char* GetEntityData( const char *pActualEntityData ); + virtual void ClientLevelInitPostEntity(); + virtual void ClientLevelShutdownPreEntity(); + + // Inherited from IFileMenuCallbacks + virtual int GetFileMenuItemsEnabled( ); + virtual void AddRecentFilesToMenu( vgui::Menu *menu ); + virtual bool GetPerforceFileName( char *pFileName, int nMaxLen ); + + // Inherited from IFoundryDocCallback + 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 "FoundryTool"; } + virtual vgui::MenuBar *CreateMenuBar( CBaseToolSystem *pParent ); + +public: + MESSAGE_FUNC( OnNew, "OnNew" ); + MESSAGE_FUNC( OnOpen, "OnOpen" ); + MESSAGE_FUNC( OnSave, "OnSave" ); + 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 + 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 ); + void OnDescribeUndo(); + + // Methods related to the Foundry menu + MESSAGE_FUNC( OnReload, "ReloadMap" ); + MESSAGE_FUNC( OnReloadFromSave, "ReloadFromSave" ); + + // Methods related to the view menu + MESSAGE_FUNC( OnToggleProperties, "OnToggleProperties" ); + MESSAGE_FUNC( OnToggleEntityReport, "OnToggleEntityReport" ); + MESSAGE_FUNC( OnDefaultLayout, "OnDefaultLayout" ); + + void PerformNew(); + 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 ); + + // returns the document + CFoundryDoc *GetDocument(); + + // Gets at tool windows + CBasePropertiesContainer *GetProperties(); + CEntityReportPanel *GetEntityReport(); + +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( CFoundryDoc *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(); + + // Create custom editors + void InitEditorDict(); + + // Used to hook DME VMF entities into the render lists + void DrawVMFEntitiesInEngine( bool bDrawInEngine ); + +private: + // Document + CFoundryDoc *m_pDoc; + + // The menu bar + CToolFileMenuBar *m_pMenuBar; + + // Element properties for editing material + vgui::DHANDLE< CBasePropertiesContainer > m_hProperties; + + // The entity report + vgui::DHANDLE< CEntityReportPanel > m_hEntityReport; + + // The currently viewed entity + CDmeHandle< CDmeVMFEntity > m_hCurrentEntity; + + // Separate undo context for the act busy tool + CToolWindowFactory< ToolWindow > m_ToolWindowFactory; + + CUtlVector< DmElementHandle_t > m_toolElements; +}; + + +//----------------------------------------------------------------------------- +// Singleton +//----------------------------------------------------------------------------- +CFoundryTool *g_pFoundryToolImp = NULL; +IFoundryTool *g_pFoundryTool = NULL; + +void CreateTools() +{ + g_pFoundryTool = g_pFoundryToolImp = new CFoundryTool(); +} + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CFoundryTool::CFoundryTool() +{ + m_pMenuBar = NULL; + m_pDoc = NULL; +} + + +//----------------------------------------------------------------------------- +// Init, shutdown +//----------------------------------------------------------------------------- +bool CFoundryTool::Init( ) +{ + m_pDoc = NULL; + m_RecentFiles.LoadFromRegistry( GetRegistryName() ); + + // NOTE: This has to happen before BaseClass::Init + g_pVGuiLocalize->AddFile( "resource/toolfoundry_%language%.txt" ); + + if ( !BaseClass::Init( ) ) + return false; + + InitEditorDict(); + + return true; +} + +void CFoundryTool::Shutdown() +{ + m_RecentFiles.SaveToRegistry( GetRegistryName() ); + + { + CDisableUndoScopeGuard guard; + int nElements = m_toolElements.Count(); + for ( int i = 0; i < nElements; ++i ) + { + g_pDataModel->DestroyElement( m_toolElements[ i ] ); + } + } + + BaseClass::Shutdown(); +} + + +//----------------------------------------------------------------------------- +// Create custom editors +//----------------------------------------------------------------------------- +void CFoundryTool::InitEditorDict() +{ + CDmeEditorAttributeInfo *pInfo; + + // FIXME: This eventually will move to an .fgd-like file. + g_pEditorTypeDict = CreateElement<CDmeEditorTypeDictionary>( "DmeEditorTypeDictionary", DMFILEID_INVALID ); + m_toolElements.AddToTail( g_pEditorTypeDict->GetHandle() ); + + CDmeEditorType *pEditorType = CreateElement<CDmeEditorType>( "vmfEntity", DMFILEID_INVALID ); + m_toolElements.AddToTail( pEditorType->GetHandle() ); + + pInfo = CreateElement<CDmeEditorAttributeInfo>( "name info", DMFILEID_INVALID ); + pInfo->m_bIsVisible = false; + pEditorType->AddAttributeInfo( "name", pInfo ); + m_toolElements.AddToTail( pInfo->GetHandle() ); + + pInfo = CreateElement<CDmeEditorAttributeInfo>( "type info", DMFILEID_INVALID ); + pInfo->m_bIsVisible = false; + pEditorType->AddAttributeInfo( "type", pInfo ); + m_toolElements.AddToTail( pInfo->GetHandle() ); + + pInfo = CreateElement<CDmeEditorAttributeInfo>( "id info", DMFILEID_INVALID ); + pInfo->m_bIsVisible = false; + pEditorType->AddAttributeInfo( "id", pInfo ); + m_toolElements.AddToTail( pInfo->GetHandle() ); + + pInfo = CreateElement<CDmeEditorAttributeInfo>( "editor type info", DMFILEID_INVALID ); + pInfo->m_bIsVisible = false; + pEditorType->AddAttributeInfo( "editorType", pInfo ); + m_toolElements.AddToTail( pInfo->GetHandle() ); + + pInfo = CreateElement<CDmeEditorAttributeInfo>( "editor info", DMFILEID_INVALID ); + pInfo->m_bIsVisible = false; + pEditorType->AddAttributeInfo( "editor", pInfo ); + m_toolElements.AddToTail( pInfo->GetHandle() ); + + pInfo = CreateElement<CDmeEditorAttributeInfo>( "other info", DMFILEID_INVALID ); + pInfo->m_bIsVisible = false; + pEditorType->AddAttributeInfo( "other", pInfo ); + m_toolElements.AddToTail( pInfo->GetHandle() ); + + pInfo = CreateElement<CDmeEditorAttributeInfo>( "_visible info", DMFILEID_INVALID ); + pInfo->m_bIsVisible = false; + pEditorType->AddAttributeInfo( "_visible", pInfo ); + m_toolElements.AddToTail( pInfo->GetHandle() ); + + pInfo = CreateElement<CDmeEditorAttributeInfo>( "_placeholder info", DMFILEID_INVALID ); + pInfo->m_bIsVisible = false; + pEditorType->AddAttributeInfo( "_placeholder", pInfo ); + m_toolElements.AddToTail( pInfo->GetHandle() ); + + g_pEditorTypeDict->AddEditorType( pEditorType ); +} + + +//----------------------------------------------------------------------------- +// returns the document +//----------------------------------------------------------------------------- +inline CFoundryDoc *CFoundryTool::GetDocument() +{ + return m_pDoc; +} + + +//----------------------------------------------------------------------------- +// Tool activation/deactivation +//----------------------------------------------------------------------------- +void CFoundryTool::OnToolActivate() +{ + BaseClass::OnToolActivate(); +} + +void CFoundryTool::OnToolDeactivate() +{ + BaseClass::OnToolDeactivate(); +} + + +//----------------------------------------------------------------------------- +// Used to hook DME VMF entities into the render lists +//----------------------------------------------------------------------------- +void CFoundryTool::DrawVMFEntitiesInEngine( bool bDrawInEngine ) +{ + if ( !m_pDoc ) + return; + + const CDmrElementArray<> entities( m_pDoc->GetEntityList() ); + int nCount = entities.Count(); + for ( int i = 0; i < nCount; ++i ) + { + CDmeVMFEntity* pEntity = CastElement<CDmeVMFEntity>( entities[i] ); + Assert( pEntity ); + pEntity->DrawInEngine( bDrawInEngine ); + pEntity->AttachToEngineEntity( bDrawInEngine ); + } +} + +void CFoundryTool::ClientLevelInitPostEntity() +{ + BaseClass::ClientLevelInitPostEntity(); + DrawVMFEntitiesInEngine( true ); +} + +void CFoundryTool::ClientLevelShutdownPreEntity() +{ + DrawVMFEntitiesInEngine( false ); + BaseClass::ClientLevelShutdownPreEntity(); +} + + +//----------------------------------------------------------------------------- +// Derived classes can implement this to get a new scheme to be applied to this tool +//----------------------------------------------------------------------------- +vgui::HScheme CFoundryTool::GetToolScheme() +{ + return vgui::scheme()->LoadSchemeFromFile( "Resource/BoxRocket.res", "BoxRocket" ); +} + + +//----------------------------------------------------------------------------- +// +// The View menu +// +//----------------------------------------------------------------------------- +class CFoundryViewMenuButton : public CToolMenuButton +{ + DECLARE_CLASS_SIMPLE( CFoundryViewMenuButton, CToolMenuButton ); +public: + CFoundryViewMenuButton( CFoundryTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget ); + virtual void OnShowMenu(vgui::Menu *menu); + +private: + CFoundryTool *m_pTool; +}; + +CFoundryViewMenuButton::CFoundryViewMenuButton( CFoundryTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget ) + : BaseClass( parent, panelName, text, pActionSignalTarget ) +{ + m_pTool = parent; + + AddCheckableMenuItem( "properties", "#FoundryProperties", new KeyValues( "OnToggleProperties" ), pActionSignalTarget ); + AddCheckableMenuItem( "entityreport", "#FoundryEntityReport", new KeyValues( "OnToggleEntityReport" ), pActionSignalTarget ); + + AddSeparator(); + + AddMenuItem( "defaultlayout", "#FoundryViewDefault", new KeyValues( "OnDefaultLayout" ), pActionSignalTarget ); + + SetMenu(m_pMenu); +} + +void CFoundryViewMenuButton::OnShowMenu(vgui::Menu *menu) +{ + BaseClass::OnShowMenu( menu ); + + // Update the menu + int id; + + CFoundryDoc *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->GetEntityReport(); + 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 CFoundryToolMenuButton : public CToolMenuButton +{ + DECLARE_CLASS_SIMPLE( CFoundryToolMenuButton, CToolMenuButton ); +public: + CFoundryToolMenuButton( CFoundryTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget ); + virtual void OnShowMenu(vgui::Menu *menu); + +private: + CFoundryTool *m_pTool; +}; + +CFoundryToolMenuButton::CFoundryToolMenuButton( CFoundryTool *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget ) + : BaseClass( parent, panelName, text, pActionSignalTarget ) +{ + m_pTool = parent; + + AddMenuItem( "reload", "#FoundryReload", new KeyValues( "ReloadMap" ), pActionSignalTarget ); + AddMenuItem( "reloadsave", "#FoundryReloadFromSave", new KeyValues( "ReloadFromSave" ), pActionSignalTarget ); + + SetMenu(m_pMenu); +} + +void CFoundryToolMenuButton::OnShowMenu(vgui::Menu *menu) +{ + BaseClass::OnShowMenu( menu ); + + // Update the menu + int id; + + CFoundryDoc *pDoc = m_pTool->GetDocument(); + id = m_Items.Find( "reload" ); + m_pMenu->SetItemEnabled( id, pDoc != NULL ); + id = m_Items.Find( "reloadsave" ); + m_pMenu->SetItemEnabled( id, pDoc != NULL ); +} + + +//----------------------------------------------------------------------------- +// Initializes the menu bar +//----------------------------------------------------------------------------- +vgui::MenuBar *CFoundryTool::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() ); + CFoundryToolMenuButton *pToolButton = new CFoundryToolMenuButton( this, "Foundry", "F&oundry", GetActionTarget() ); + CFoundryViewMenuButton *pViewButton = new CFoundryViewMenuButton( 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 CFoundryTool::UpdateMenuBar( ) +{ + if ( !m_pDoc ) + { + m_pMenuBar->SetFileName( "#FoundryNoFile" ); + return; + } + + const char *pVMFFile = m_pDoc->GetVMFFileName(); + if ( !pVMFFile[0] ) + { + m_pMenuBar->SetFileName( "#FoundryNoFile" ); + return; + } + + if ( m_pDoc->IsDirty() ) + { + char sz[ 512 ]; + Q_snprintf( sz, sizeof( sz ), "* %s", pVMFFile ); + m_pMenuBar->SetFileName( sz ); + } + else + { + m_pMenuBar->SetFileName( pVMFFile ); + } +} + + +//----------------------------------------------------------------------------- +// Gets at tool windows +//----------------------------------------------------------------------------- +CBasePropertiesContainer *CFoundryTool::GetProperties() +{ + return m_hProperties.Get(); +} + +CEntityReportPanel *CFoundryTool::GetEntityReport() +{ + return m_hEntityReport.Get(); +} + + +//----------------------------------------------------------------------------- +// Shows element properties +//----------------------------------------------------------------------------- +void CFoundryTool::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 CFoundryTool::ShowEntityInEntityProperties( CDmeVMFEntity *pEntity ) +{ + Assert( m_hProperties.Get() ); + m_hCurrentEntity = pEntity; + m_hProperties->SetObject( m_hCurrentEntity ); +} + + +//----------------------------------------------------------------------------- +// Destroys all tool windows +//----------------------------------------------------------------------------- +void CFoundryTool::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 CFoundryTool::OnDefaultLayout() +{ + int y = m_pMenuBar->GetTall(); + + int usew, useh; + GetSize( usew, useh ); + + DestroyToolContainers(); + + Assert( ToolWindow::GetToolWindowCount() == 0 ); + + CBasePropertiesContainer *properties = GetProperties(); + CEntityReportPanel *pEntityReport = GetEntityReport(); + + // Need three containers + ToolWindow *pPropertyWindow = m_ToolWindowFactory.InstanceToolWindow( GetClientArea(), false, properties, "#FoundryProperties", false ); + ToolWindow *pEntityReportWindow = m_ToolWindowFactory.InstanceToolWindow( GetClientArea(), false, pEntityReport, "#FoundryEntityReport", 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 CFoundryTool::OnToggleProperties() +{ + if ( m_hProperties.Get() ) + { + ToggleToolWindow( m_hProperties.Get(), "#FoundryProperties" ); + } +} + +void CFoundryTool::OnToggleEntityReport() +{ + if ( m_hEntityReport.Get() ) + { + ToggleToolWindow( m_hEntityReport.Get(), "#FoundryEntityReport" ); + } +} + + + +//----------------------------------------------------------------------------- +// Creates +//----------------------------------------------------------------------------- +void CFoundryTool::CreateTools( CFoundryDoc *doc ) +{ + if ( !m_hProperties.Get() ) + { + m_hProperties = new CBasePropertiesContainer( NULL, m_pDoc, g_pEditorTypeDict ); + } + + if ( !m_hEntityReport.Get() ) + { + m_hEntityReport = new CEntityReportPanel( m_pDoc, this, "EntityReportPanel" ); + } + + RegisterToolWindow( m_hProperties ); + RegisterToolWindow( m_hEntityReport ); +} + + +//----------------------------------------------------------------------------- +// Initializes the tools +//----------------------------------------------------------------------------- +void CFoundryTool::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_hEntityReport, false ); + + if ( !windowposmgr->LoadPositions( "cfg/foundry.txt", this, &m_ToolWindowFactory, "Foundry" ) ) + { + OnDefaultLayout(); + } +} + + +void CFoundryTool::DestroyTools() +{ + m_hCurrentEntity = NULL; + + 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_hEntityReport.Get() ) + { + windowposmgr->UnregisterPanel( m_hEntityReport.Get() ); + delete m_hEntityReport.Get(); + m_hEntityReport = NULL; + } +} + + +void CFoundryTool::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 CFoundryTool::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 *CFoundryTool::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 CFoundryTool::GetFileMenuItemsEnabled( ) +{ + int nFlags = FILE_ALL & (~FILE_NEW); + if ( m_RecentFiles.IsEmpty() ) + { + nFlags &= ~(FILE_RECENT | FILE_CLEAR_RECENT); + } + return nFlags; +} + +void CFoundryTool::AddRecentFilesToMenu( vgui::Menu *pMenu ) +{ + m_RecentFiles.AddToMenu( pMenu, GetActionTarget(), "OnRecent" ); +} + +bool CFoundryTool::GetPerforceFileName( char *pFileName, int nMaxLen ) +{ + if ( !m_pDoc ) + return false; + + Q_strncpy( pFileName, m_pDoc->GetVMFFileName(), nMaxLen ); + return pFileName[0] != 0; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : - +//----------------------------------------------------------------------------- +void CFoundryTool::OnExit() +{ + windowposmgr->SavePositions( "cfg/foundry.txt", "Foundry" ); + + enginetools->Command( "quit\n" ); +} + +//----------------------------------------------------------------------------- +// Handle commands from the action menu and other menus +//----------------------------------------------------------------------------- +void CFoundryTool::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 *pSuffixTool = StringAfterPrefix( cmd, "OnTool" ) ) + { + int idx = Q_atoi( pSuffixTool ); + 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 CFoundryTool::PerformNew() +{ + // Can never do new + Assert( 0 ); +} + +void CFoundryTool::OnNew() +{ + if ( m_pDoc ) + { + if ( m_pDoc->IsDirty() ) + { + SaveFile( m_pDoc->GetVMFFileName(), "vmf", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY, + new KeyValues( "OnNew" ) ); + return; + } + } + PerformNew(); +} + +void CFoundryTool::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->GetVMFFileName(); + } + + OpenFile( "bsp", pSaveFileName, "vmf", nFlags ); +} + +bool CFoundryTool::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 CFoundryTool::OnSave() +{ + if ( m_pDoc ) + { + SaveFile( NULL, "vmf", FOSM_SHOW_PERFORCE_DIALOGS ); + } +} + +void CFoundryTool::OnSaveAs() +{ + if ( m_pDoc ) + { + SaveFile( m_pDoc->GetVMFFileName(), "vmf", FOSM_SHOW_PERFORCE_DIALOGS ); + } +} + +bool CFoundryTool::OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues ) +{ + if ( !m_pDoc ) + return true; + + m_pDoc->SetVMFFileName( pFileName ); + m_pDoc->SaveToFile( ); + + m_RecentFiles.Add( pFileName, pFileFormat ); + m_RecentFiles.SaveToRegistry( GetRegistryName() ); + UpdateMenuBar(); + return true; +} + +void CFoundryTool::OnClose() +{ + if ( m_pDoc && m_pDoc->IsDirty() ) + { + SaveFile( m_pDoc->GetVMFFileName(), "vmf", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY, + new KeyValues( "OnClose" ) ); + return; + } + + OnCloseNoSave(); +} + +void CFoundryTool::OnCloseNoSave() +{ + // FIXME: Implement +} + +void CFoundryTool::OnMarkNotDirty() +{ + // FIXME: Implement +} + + +//----------------------------------------------------------------------------- +// Open a specific file +//----------------------------------------------------------------------------- +void CFoundryTool::OpenSpecificFile( const char *pFileName ) +{ + int nFlags = 0; + const char *pSaveFileName = NULL; + if ( m_pDoc ) + { + // File is already open + if ( !Q_stricmp( m_pDoc->GetVMFFileName(), pFileName ) ) + return; + + if ( m_pDoc->IsDirty() ) + { + nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY; + pSaveFileName = m_pDoc->GetVMFFileName(); + } + else + { + OnCloseNoSave(); + } + } + + OpenFile( pFileName, "bsp", pSaveFileName, "vmf", nFlags ); +} + + +//----------------------------------------------------------------------------- +// Show the save document query dialog +//----------------------------------------------------------------------------- +void CFoundryTool::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 CFoundryTool::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(), "OnNew" ) ) + { + PerformNew(); + 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; + } +} + + +//----------------------------------------------------------------------------- +// Show the File browser dialog +//----------------------------------------------------------------------------- +void CFoundryTool::SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues ) +{ + char pStartingDir[ MAX_PATH ]; + + // We open BSPs, but save-as VMFs + if ( bOpenFile ) + { + GetModSubdirectory( "maps", pStartingDir, sizeof(pStartingDir) ); + pDialog->SetTitle( "Choose Valve BSP File", true ); + pDialog->SetStartDirectoryContext( "foundry_bsp_session", pStartingDir ); + pDialog->AddFilter( "*.bsp", "Valve BSP File (*.bsp)", true ); + } + else + { + GetModContentSubdirectory( "maps", pStartingDir, sizeof(pStartingDir) ); + pDialog->SetTitle( "Choose Valve VMF File", true ); + pDialog->SetStartDirectoryContext( "foundry_vmf_session", pStartingDir ); + pDialog->AddFilter( "*.vmf", "Valve VMF File (*.vmf)", true ); + } +} + + +//----------------------------------------------------------------------------- +// Can we quit? +//----------------------------------------------------------------------------- +bool CFoundryTool::CanQuit() +{ + if ( m_pDoc && m_pDoc->IsDirty() ) + { + // Show Save changes Yes/No/Cancel and re-quit if hit yes/no + SaveFile( m_pDoc->GetVMFFileName(), "vmf", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY, + new KeyValues( "OnQuit" ) ); + return false; + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Various command handlers related to the Edit menu +//----------------------------------------------------------------------------- +void CFoundryTool::OnUndo() +{ + CDisableUndoScopeGuard guard; + g_pDataModel->Undo(); +} + +void CFoundryTool::OnRedo() +{ + CDisableUndoScopeGuard guard; + g_pDataModel->Redo(); +} + +void CFoundryTool::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 ); + } +} + + +//----------------------------------------------------------------------------- +// Foundry menu items +//----------------------------------------------------------------------------- +void CFoundryTool::OnReload() +{ + // Reloads the map, entities only, will reload every entity + enginetools->Command( "respawn_entities\n" ); +} + +void CFoundryTool::OnReloadFromSave() +{ + // Reloads the map from a save point, overrides selected entities + // for now, this is hardcoded to be info_targets + enginetools->Command( "load quick\n" ); +} + + +//----------------------------------------------------------------------------- +// Background +//----------------------------------------------------------------------------- +const char *CFoundryTool::GetLogoTextureName() +{ + return "vgui/tools/sampletool/sampletool_logo"; +} + + +//----------------------------------------------------------------------------- +// Inherited from IFoundryDocCallback +//----------------------------------------------------------------------------- +void CFoundryTool::OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags ) +{ + UpdateMenuBar(); + + /* + if ( bRefreshUI && m_hProperties.Get() ) + { + m_hProperties->Refresh(); + } + */ +} + + +//----------------------------------------------------------------------------- +// Loads up a new document +//----------------------------------------------------------------------------- +bool CFoundryTool::LoadDocument( const char *pDocName ) +{ + Assert( !m_pDoc ); + + DestroyTools(); + + m_pDoc = new CFoundryDoc( this ); + if ( !m_pDoc->LoadFromFile( pDocName ) ) + { + delete m_pDoc; + m_pDoc = NULL; + Warning( "Fatal error loading '%s'\n", pDocName ); + return false; + } + + ShowMiniViewport( true ); + + CreateTools( m_pDoc ); + InitTools(); + return true; +} + + +//----------------------------------------------------------------------------- +// Create the entities that are in our VMF file +//----------------------------------------------------------------------------- +const char* CFoundryTool::GetEntityData( const char *pActualEntityData ) +{ + if ( !m_pDoc ) + return pActualEntityData; + + return m_pDoc->GenerateEntityData( pActualEntityData ); +} diff --git a/tools/foundry/foundrytool.h b/tools/foundry/foundrytool.h new file mode 100644 index 0000000..c2e81f7 --- /dev/null +++ b/tools/foundry/foundrytool.h @@ -0,0 +1,65 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Foundry tool; main UI smarts class +// +//============================================================================= + +#ifndef FOUNDRYTOOL_H +#define FOUNDRYTOOL_H + +#ifdef _WIN32 +#pragma once +#endif + +#include "tier0/platform.h" +#include "datamodel/idatamodel.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class CDmeEditorTypeDictionary; +class CDmeVMFEntity; + +namespace vgui +{ + class Panel; +} + + +//----------------------------------------------------------------------------- +// Singleton interfaces +//----------------------------------------------------------------------------- +extern CDmeEditorTypeDictionary *g_pEditorTypeDict; + + +//----------------------------------------------------------------------------- +// Allows the doc to call back into the Foundry editor tool +//----------------------------------------------------------------------------- +abstract_class IFoundryDocCallback +{ +public: + // Called by the doc when the data changes + virtual void OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags ) = 0; +}; + + +//----------------------------------------------------------------------------- +// Global methods of the foundry tool +//----------------------------------------------------------------------------- +abstract_class IFoundryTool +{ +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; +}; + +extern IFoundryTool *g_pFoundryTool; + + +#endif // FOUNDRYTOOL_H |