diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /hammer/ToolEntity.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'hammer/ToolEntity.cpp')
| -rw-r--r-- | hammer/ToolEntity.cpp | 730 |
1 files changed, 730 insertions, 0 deletions
diff --git a/hammer/ToolEntity.cpp b/hammer/ToolEntity.cpp new file mode 100644 index 0000000..71eaac7 --- /dev/null +++ b/hammer/ToolEntity.cpp @@ -0,0 +1,730 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Implements the entity/prefab placement tool. +// +//=============================================================================// + +#include "stdafx.h" +#include "History.h" +#include "MainFrm.h" +#include "MapDefs.h" +#include "MapSolid.h" +#include "MapDoc.h" +#include "MapView2D.h" +#include "MapView3D.h" +#include "Material.h" +#include "materialsystem/imesh.h" +#include "Render2D.h" +#include "Render3D.h" +#include "StatusBarIDs.h" +#include "TextureSystem.h" +#include "ToolEntity.h" +#include "ToolManager.h" +#include "hammer.h" +#include "vgui/Cursor.h" +#include "Selection.h" +#include "vstdlib/random.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include <tier0/memdbgon.h> + + +//#pragma warning(disable:4244) + + +static HCURSOR s_hcurEntity = NULL; + + +class CToolEntityMessageWnd : public CWnd +{ + public: + + bool Create(void); + void PreMenu2D(CToolEntity *pTool, CMapView2D *pView); + + protected: + + //{{AFX_MSG_MAP(CToolEntityMessageWnd) + afx_msg void OnCreateObject(); + //}}AFX_MSG + + DECLARE_MESSAGE_MAP() + + private: + + CToolEntity *m_pToolEntity; + CMapView2D *m_pView2D; +}; + + +static CToolEntityMessageWnd s_wndToolMessage; +static const char *g_pszClassName = "ValveEditor_EntityToolWnd"; + + +BEGIN_MESSAGE_MAP(CToolEntityMessageWnd, CWnd) + //{{AFX_MSG_MAP(CToolMessageWnd) + ON_COMMAND(ID_CREATEOBJECT, OnCreateObject) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +//----------------------------------------------------------------------------- +// Purpose: Creates the hidden window that receives context menu commands for the +// entity tool. +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CToolEntityMessageWnd::Create(void) +{ + WNDCLASS wndcls; + memset(&wndcls, 0, sizeof(WNDCLASS)); + wndcls.lpfnWndProc = AfxWndProc; + wndcls.hInstance = AfxGetInstanceHandle(); + wndcls.lpszClassName = g_pszClassName; + + if (!AfxRegisterClass(&wndcls)) + { + return(false); + } + + return(CWnd::CreateEx(0, g_pszClassName, g_pszClassName, 0, CRect(0, 0, 10, 10), NULL, 0) == TRUE); +} + + +//----------------------------------------------------------------------------- +// Purpose: Attaches the entity tool to this window before activating the context +// menu. +//----------------------------------------------------------------------------- +void CToolEntityMessageWnd::PreMenu2D(CToolEntity *pToolEntity, CMapView2D *pView) +{ + Assert(pToolEntity != NULL); + m_pToolEntity = pToolEntity; + m_pView2D = pView; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CToolEntityMessageWnd::OnCreateObject() +{ + m_pToolEntity->CreateMapObject(m_pView2D); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CToolEntity::CToolEntity(void) +{ + SetEmpty(); + + m_vecPos.Init(); + + if (s_hcurEntity == NULL) + { + s_hcurEntity = LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_ENTITY)); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CToolEntity::~CToolEntity(void) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pt - +// BOOL - +// Output : +//----------------------------------------------------------------------------- +int CToolEntity::HitTest(CMapView *pView, const Vector2D &ptClient, bool bTestHandles) +{ + return HitRect( pView, ptClient, m_vecPos, 8 )?TRUE:FALSE; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : bSave - +//----------------------------------------------------------------------------- +void CToolEntity::FinishTranslation(bool bSave) +{ + if (bSave) + { + TranslatePoint( m_vecPos ); + m_bEmpty = false; + } + + Tool3D::FinishTranslation(bSave); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pt - +// uFlags - +// size - +// Output : Returns true if the translation delta was nonzero. +//----------------------------------------------------------------------------- +bool CToolEntity::UpdateTranslation( const Vector &vUpdate, UINT uFlags) +{ + Vector vOldDelta = m_vTranslation; + + if ( !Tool3D::UpdateTranslation( vUpdate, uFlags ) ) + return false; + + // apply snap to grid constrain + if ( uFlags ) + { + ProjectOnTranslationPlane( m_vecPos + m_vTranslation, m_vTranslation, uFlags ); + m_vTranslation -= m_vecPos; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pRender - +//----------------------------------------------------------------------------- +void CToolEntity::RenderTool2D(CRender2D *pRender) +{ + Vector v = m_vecPos; + + if ( IsTranslating() ) + { + TranslatePoint( v ); + } + else if ( IsEmpty() ) + { + return; + } + + pRender->SetDrawColor( 35, 255, 75 ); + + // + // Draw center rect. + // + pRender->DrawRectangle( v, v, false, 6.0f ); + + // + // Draw crosshair + // + pRender->DrawLine( Vector( g_MIN_MAP_COORD, v.y, v.z), Vector( g_MAX_MAP_COORD, v.y , v.z) ); + pRender->DrawLine( Vector( v.x, g_MIN_MAP_COORD, v.z), Vector( v.x, g_MAX_MAP_COORD, v.z) ); + pRender->DrawLine( Vector( v.x, v.y, g_MIN_MAP_COORD), Vector( v.x, v.y, g_MAX_MAP_COORD) ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pView - +// point - +// Output : +//----------------------------------------------------------------------------- +bool CToolEntity::OnContextMenu2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint) +{ + if (!IsEmpty()) + { + CMapDoc *pDoc = pView->GetMapDoc(); + if (pDoc == NULL) + { + return true; + } + + if (!pView->PointInClientRect(vPoint)) + { + return true; + } + + if ( HitTest( pView, vPoint, false) ) + { + static CMenu menu, menuCreate; + static bool bInit = false; + + if (!bInit) + { + bInit = true; + menu.LoadMenu(IDR_POPUPS); + menuCreate.Attach(::GetSubMenu(menu.m_hMenu, 1)); + + // Create the window that handles menu messages. + s_wndToolMessage.Create(); + } + + CPoint ptScreen( vPoint.x,vPoint.y); + pView->ClientToScreen(&ptScreen); + + s_wndToolMessage.PreMenu2D(this, pView); + menuCreate.TrackPopupMenu(TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_LEFTALIGN, ptScreen.x, ptScreen.y, &s_wndToolMessage); + } + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pView - +// nChar - +// nRepCnt - +// nFlags - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CToolEntity::OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags) +{ + switch (nChar) + { + case VK_RETURN: + { + if (!IsEmpty()) + { + CreateMapObject(pView); + } + return true; + } + + case VK_ESCAPE: + { + OnEscape(); + return true; + } + } + + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : pView - +// nFlags - +// point - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CToolEntity::OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint) +{ + unsigned int uConstraints = GetConstraints( nFlags ); + + Tool3D::OnLMouseDown2D(pView, nFlags, vPoint); + + if ( HitTest( pView, vPoint, false) ) + { + // translate existing object + StartTranslation( pView, vPoint ); + } + else + { + Vector vecWorld; + pView->ClientToWorld(vecWorld, vPoint ); + + // + // Snap starting position to grid. + // + if ( uConstraints & constrainSnap ) + m_pDocument->Snap(vecWorld, uConstraints); + + // create new one, keep old third axis + m_vecPos[pView->axHorz] = vecWorld[pView->axHorz]; + m_vecPos[pView->axVert] = vecWorld[pView->axVert]; + m_bEmpty = false; + StartTranslation( pView, vPoint ); + } + + return true; +} + +// set temp transformation plane + +void CToolEntity::StartTranslation( CMapView *pView, const Vector2D &vPoint ) +{ + Vector vOrigin, v1,v2,v3; + + pView->GetBestTransformPlane( v1,v2,v3 ); + + SetTransformationPlane(m_vecPos, v1, v2, v3 ); + // align translation plane to world origin + ProjectOnTranslationPlane( vec3_origin, vOrigin, 0 ); + // set transformation plane + SetTransformationPlane(vOrigin, v1, v2, v3 ); + + Tool3D::StartTranslation( pView, vPoint, false ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : Pre CWnd::OnLButtonUp. +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CToolEntity::OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint) +{ + Tool3D::OnLMouseUp2D(pView, nFlags, vPoint); + + if (IsTranslating()) + { + FinishTranslation( true ); + } + + m_pDocument->UpdateStatusbar(); + + return true; +} + + +//----------------------------------------------------------------------------- +// Returns true if the message was handled, false otherwise. +//----------------------------------------------------------------------------- +bool CToolEntity::OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint) +{ + Tool3D::OnMouseMove2D(pView, nFlags, vPoint); + + vgui::HCursor hCursor = vgui::dc_arrow; + + unsigned int uConstraints = GetConstraints( nFlags ); + + // Convert to world coords. + + Vector vecWorld; + pView->ClientToWorld(vecWorld, vPoint); + + // Update status bar position display. + + char szBuf[128]; + + if ( uConstraints & constrainSnap ) + m_pDocument->Snap(vecWorld,uConstraints); + + sprintf(szBuf, " @%.0f, %.0f ", vecWorld[pView->axHorz], vecWorld[pView->axVert] ); + SetStatusText(SBI_COORDS, szBuf); + + // + // If we are currently dragging the marker, update that operation based on + // the current cursor position and keyboard state. + // + if (IsTranslating()) + { + Tool3D::UpdateTranslation( pView, vPoint, uConstraints ); + + // Don't change the cursor while dragging - it should remain a cross. + hCursor = vgui::dc_none; + } + else if (!IsEmpty()) + { + // Don't change the cursor while dragging - it should remain a cross. + hCursor = vgui::dc_crosshair; + } + + if ( hCursor != vgui::dc_none ) + pView->SetCursor( hCursor ); + + return true; +} + + +//----------------------------------------------------------------------------- +// Returns true if the message was handled, false otherwise. +//----------------------------------------------------------------------------- +bool CToolEntity::OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint) +{ + return true; +} + + +//----------------------------------------------------------------------------- +// Returns true if the message was handled, false otherwise. +//----------------------------------------------------------------------------- +bool CToolEntity::OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags) +{ + CMapDoc *pDoc = pView->GetMapDoc(); + if (pDoc == NULL) + { + return false; + } + + switch (nChar) + { + case VK_RETURN: + { + // + // Create the entity or prefab. + // + if (!IsEmpty()) + { + //CreateMapObject(pView); // TODO: support in 3D + } + return true; + } + + case VK_ESCAPE: + { + OnEscape(); + return true; + } + } + + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: Handles the escape key in the 2D or 3D views. +//----------------------------------------------------------------------------- +void CToolEntity::OnEscape(void) +{ + // + // Cancel the object creation tool. + // + if (!IsEmpty()) + { + SetEmpty(); + } + else + { + ToolManager()->SetTool(TOOL_POINTER); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pView - +// nFlags - +// point - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CToolEntity::OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint) +{ + ULONG ulFace; + VMatrix LocalMatrix, LocalMatrixNeg; + CMapClass *pObject = pView->NearestObjectAt( vPoint, ulFace, FLAG_OBJECTS_AT_RESOLVE_INSTANCES, &LocalMatrix ); + Tool3D::OnLMouseDown3D(pView, nFlags, vPoint); + + if (pObject != NULL) + { + CMapSolid *pSolid = dynamic_cast <CMapSolid *> (pObject); + if (pSolid == NULL) + { + // Clicked on a point entity - do nothing. + return true; + } + + LocalMatrix.InverseTR( LocalMatrixNeg ); + + // Build a ray to trace against the face that they clicked on to + // find the point of intersection. + + Vector Start,End; + pView->GetCamera()->BuildRay( vPoint, Start, End); + + Vector HitPos, HitNormal; + CMapFace *pFace = pSolid->GetFace(ulFace); + Vector vFinalStart, vFinalEnd; + LocalMatrixNeg.V3Mul( Start, vFinalStart ); + LocalMatrixNeg.V3Mul( End, vFinalEnd ); + if (pFace->TraceLine( HitPos, HitNormal, vFinalStart, vFinalEnd)) + { + Vector vFinalHitPos, vFinalHitNormal; + LocalMatrix.V3Mul( HitPos, vFinalHitPos ); + vFinalHitNormal = LocalMatrix.ApplyRotation( HitNormal ); + CMapClass *pNewObject = NULL; + + if (GetMainWnd()->m_ObjectBar.IsEntityToolCreatingPrefab()) + { + // + // Prefab creation. + // + unsigned int uConstraints = GetConstraints( nFlags ); + m_pDocument->Snap(vFinalHitPos,uConstraints); + + GetHistory()->MarkUndoPosition(m_pDocument->GetSelection()->GetList(), "New Prefab"); + + // Get prefab object + CMapClass *pPrefabObject = GetMainWnd()->m_ObjectBar.BuildPrefabObjectAtPoint(vFinalHitPos); + + // + // Add prefab to the world. + // + CMapWorld *pWorld = m_pDocument->GetMapWorld(); + m_pDocument->ExpandObjectKeywords(pPrefabObject, pWorld); + + pNewObject = pPrefabObject; + } + else if (GetMainWnd()->m_ObjectBar.IsEntityToolCreatingEntity()) + { + // + // Entity creation. + // + GetHistory()->MarkUndoPosition(m_pDocument->GetSelection()->GetList(), "New Entity"); + + CMapEntity *pEntity = new CMapEntity; + pEntity->SetPlaceholder(TRUE); + pEntity->SetOrigin(vFinalHitPos); + pEntity->SetClass(CObjectBar::GetDefaultEntityClass()); + + VPlane BeforeTransform( pFace->plane.normal, pFace->plane.dist ), AfterTransform; + LocalMatrix.TransformPlane( BeforeTransform, AfterTransform ); + + PLANE NewPlane; + + NewPlane.dist = AfterTransform.m_Dist; + NewPlane.normal = AfterTransform.m_Normal; + // Align the entity on the plane properly + pEntity->AlignOnPlane(vFinalHitPos, &NewPlane, (vFinalHitNormal.z > 0.0f) ? CMapEntity::ALIGN_BOTTOM : CMapEntity::ALIGN_TOP); + + pNewObject = pEntity; + } + + if ( pNewObject ) + { + if ( GetMainWnd()->m_ObjectBar.UseRandomYawOnEntityPlacement() ) + { + // They checked "random yaw" on the object bar, so come up with a random yaw. + VMatrix vmRotate, vmT1, vmT2; + Vector vOrigin; + QAngle angRandom( 0, RandomInt( -180, 180 ), 0 ); + + pNewObject->GetOrigin( vOrigin ); + + // Setup a matrix that translates them to the origin, rotates it, then translates back. + MatrixFromAngles( angRandom, vmRotate ); + MatrixBuildTranslation( vmT1, -vOrigin ); + MatrixBuildTranslation( vmT2, vOrigin ); + + // Transform the object. + pNewObject->Transform( vmT2 * vmRotate * vmT1 ); + } + + m_pDocument->AddObjectToWorld( pNewObject ); + GetHistory()->KeepNew( pNewObject ); + + // Select the new object. + m_pDocument->SelectObject( pNewObject, scClear|scSelect|scSaveChanges ); + + m_pDocument->SetModifiedFlag(); + } + } + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: Renders a selection gizmo at our bounds center. +// Input : pRender - Rendering interface. +//----------------------------------------------------------------------------- +void CToolEntity::RenderTool3D(CRender3D *pRender) +{ + Vector pos = m_vecPos; + + if ( IsTranslating() ) + { + TranslatePoint( pos ); + } + else if ( IsEmpty() ) + { + return; + } + + // + // Setup the renderer. + // + pRender->PushRenderMode( RENDER_MODE_WIREFRAME); + + CMeshBuilder meshBuilder; + CMatRenderContextPtr pRenderContext( MaterialSystemInterface() ); + IMesh* pMesh = pRenderContext->GetDynamicMesh(); + + meshBuilder.Begin(pMesh, MATERIAL_LINES, 3); + + meshBuilder.Position3f(g_MIN_MAP_COORD, pos.y, pos.z); + meshBuilder.Color3ub(255, 0, 0); + meshBuilder.AdvanceVertex(); + meshBuilder.Position3f(g_MAX_MAP_COORD, pos.y, pos.z); + meshBuilder.Color3ub(255, 0, 0); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f(pos.x, g_MIN_MAP_COORD, pos.z); + meshBuilder.Color3ub(0, 255, 0); + meshBuilder.AdvanceVertex(); + meshBuilder.Position3f(pos.x, g_MAX_MAP_COORD, pos.z); + meshBuilder.Color3ub(0, 255, 0); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f(pos.x, pos.y, g_MIN_MAP_COORD); + meshBuilder.Color3ub(0, 0, 255); + meshBuilder.AdvanceVertex(); + meshBuilder.Position3f(pos.x, pos.y, g_MAX_MAP_COORD); + meshBuilder.Color3ub(0, 0, 255); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); + + pRender->PopRenderMode(); +} + + +void CToolEntity::CreateMapObject(CMapView2D *pView) +{ + CMapWorld *pWorld = m_pDocument->GetMapWorld(); + CMapClass *pobj = NULL; + + // + // Handle prefab creation. + // + if (GetMainWnd()->m_ObjectBar.IsEntityToolCreatingPrefab()) + { + GetHistory()->MarkUndoPosition(m_pDocument->GetSelection()->GetList(), "New Prefab"); + + CMapClass *pPrefabObject = GetMainWnd()->m_ObjectBar.BuildPrefabObjectAtPoint(m_vecPos); + + if (pPrefabObject == NULL) + { + pView->MessageBox("Unable to load prefab", "Error", MB_OK); + SetEmpty(); + return; + } + + m_pDocument->ExpandObjectKeywords(pPrefabObject, pWorld); + m_pDocument->AddObjectToWorld(pPrefabObject); + + GetHistory()->KeepNew(pPrefabObject); + + pobj = pPrefabObject; + } + // + // Handle entity creation. + // + else if (GetMainWnd()->m_ObjectBar.IsEntityToolCreatingEntity()) + { + GetHistory()->MarkUndoPosition(m_pDocument->GetSelection()->GetList(), "New Entity"); + + CMapEntity *pEntity = new CMapEntity; + + pEntity->SetPlaceholder(TRUE); + pEntity->SetOrigin(m_vecPos); + pEntity->SetClass(CObjectBar::GetDefaultEntityClass()); + + m_pDocument->AddObjectToWorld(pEntity); + + pobj = pEntity; + + GetHistory()->KeepNew(pEntity); + } + + // + // Select the new object. + // + m_pDocument->SelectObject(pobj, scClear |scSelect|scSaveChanges); + + SetEmpty(); + + m_pDocument->SetModifiedFlag(); +} + + |