summaryrefslogtreecommitdiff
path: root/hammer/tooldisplace.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /hammer/tooldisplace.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'hammer/tooldisplace.cpp')
-rw-r--r--hammer/tooldisplace.cpp1563
1 files changed, 1563 insertions, 0 deletions
diff --git a/hammer/tooldisplace.cpp b/hammer/tooldisplace.cpp
new file mode 100644
index 0000000..29bb5df
--- /dev/null
+++ b/hammer/tooldisplace.cpp
@@ -0,0 +1,1563 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include <stdafx.h>
+#include "hammer.h"
+#include "ToolDisplace.h"
+#include "MainFrm.h"
+#include "FaceEditSheet.h"
+#include "GlobalFunctions.h"
+#include "MapAtom.h"
+#include "MapSolid.h"
+#include "MapView3D.h"
+#include "History.h"
+#include "Camera.h"
+#include "MapDoc.h"
+#include "ChunkFile.h"
+#include "ToolManager.h"
+#include "SculptOptions.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+//=============================================================================
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+CToolDisplace::CToolDisplace()
+{
+ m_uiTool = DISPTOOL_SELECT;
+ m_uiEffect = DISPPAINT_EFFECT_RAISELOWER;
+ m_uiBrushType = DISPPAINT_BRUSHTYPE_SOFT;
+
+ m_iPaintChannel = DISPPAINT_CHANNEL_POSITION;
+ m_flPaintValueGeo = 5.0f;
+ m_flPaintValueData = 25.0f;
+ m_iPaintAxis = DISPPAINT_AXIS_FACE;
+ m_vecPaintAxis.Init( 0.0f, 0.0f, 1.0f );
+
+ m_bAutoSew = false;
+ m_bSpatial = false;
+ m_flSpatialRadius = 15.0f;
+ m_bSpatialRadius = false;
+
+ m_bSelectMaskTool = true;
+ m_bGridMaskTool = false;
+
+ m_bLMBDown = false;
+ m_bRMBDown = false;
+
+ m_bNudge = false;
+ m_bNudgeInit = false;
+ m_EditDispHandle = EDITDISPHANDLE_INVALID;
+
+ // load filters from file
+ static char szProgramDir[MAX_PATH];
+ APP()->GetDirectory( DIR_PROGRAM, szProgramDir );
+ strcat( szProgramDir, "filters\\dispfilters.txt" );
+ LoadFilters( szProgramDir );
+ AddFiltersToManagers();
+
+ m_SculptTool = NULL;
+ m_MousePoint.Init( 0.0f, 0.0f );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+CToolDisplace::~CToolDisplace()
+{
+ // destroy filters
+ m_FilterRaiseLowerMgr.Destroy();
+ m_FilterRaiseToMgr.Destroy();
+ m_FilterSmoothMgr.Destroy();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when the tool is activated.
+// Input : eOldTool - The ID of the previously active tool.
+//-----------------------------------------------------------------------------
+void CToolDisplace::OnActivate()
+{
+ //
+ // initialize masks
+ //
+ CMapDisp::SetSelectMask( m_bSelectMaskTool );
+ CMapDisp::SetGridMask( m_bGridMaskTool );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when the tool is deactivated.
+// Input : eNewTool - The ID of the tool that is being activated.
+//-----------------------------------------------------------------------------
+void CToolDisplace::OnDeactivate()
+{
+ //
+ // reset masks
+ //
+ CMapDisp::SetSelectMask( false );
+ CMapDisp::SetGridMask( false );
+
+ if ( m_pDocument->GetTools()->GetActiveToolID() != TOOL_FACEEDIT_MATERIAL )
+ {
+ // Clear the selected faces when we are deactivated.
+ m_pDocument->SelectFace(NULL, 0, scClear );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+inline void CToolDisplace::UpdateMapViews( CMapView3D *pView )
+{
+ CMapDoc *pDoc = pView->GetMapDoc();
+ if( pDoc )
+ {
+ pDoc->SetModifiedFlag();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+inline void CToolDisplace::CalcViewCenter( CMapView3D *pView )
+{
+ CRect windowRect;
+ pView->GetWindowRect( windowRect );
+ m_viewCenter = windowRect.CenterPoint();
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CToolDisplace::OnLMouseDown3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ // Set down flags
+ m_bLMBDown = true;
+
+ if( m_uiTool == DISPTOOL_PAINT_SCULPT )
+ {
+ m_SculptTool->OnLMouseDown3D( pView, nFlags, vPoint );
+ m_SculptTool->BeginPaint( pView, vPoint );
+ ApplySculptSpatialPaintTool( pView, nFlags, vPoint );
+
+ // update
+ UpdateMapViews( pView );
+
+ return true;
+ }
+
+ // Selection.
+ if( m_uiTool == DISPTOOL_SELECT || ( GetAsyncKeyState( VK_CONTROL ) & 0x8000 ) )
+ {
+ // handle selection at point
+ HandleSelection( pView, vPoint );
+
+ // update
+ UpdateMapViews( pView );
+ return true;
+ }
+
+ // Tagging.
+ if ( m_uiTool == DISPTOOL_TAG_WALKABLE || m_uiTool == DISPTOOL_TAG_BUILDABLE || m_uiTool == DISPTOOL_TAG_REMOVE )
+ {
+ // Do tagging.
+ HandleTagging( pView, vPoint );
+ return true;
+ }
+
+ // Resize the spatial painting sphere.
+ if( ( m_uiTool == DISPTOOL_PAINT ) && ( IsSpatialPainting() ) &&
+ ( GetAsyncKeyState( VK_MENU ) & 0x8000 ) )
+ {
+ ResizeSpatialRadius_Activate( pView );
+ return true;
+ }
+
+ // Nudging.
+ if( ( m_uiTool == DISPTOOL_PAINT ) && ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) )
+ {
+ // is the current effect raise/lower (nudge only works in raise/lower mode)
+ if( m_uiEffect == DISPPAINT_EFFECT_RAISELOWER )
+ {
+ EditDispHandle_t handle = GetHitPos( pView, vPoint );
+ if( handle != EDITDISPHANDLE_INVALID )
+ {
+ m_EditDispHandle = handle;
+
+ Nudge_Activate( pView, handle );
+ UpdateMapViews( pView );
+ return true;
+ }
+ }
+ }
+
+ // Painting.
+ if( m_uiTool == DISPTOOL_PAINT )
+ {
+ // get hit info
+ EditDispHandle_t handle = GetHitPos( pView, vPoint );
+ if( handle == EDITDISPHANDLE_INVALID )
+ return false;
+ m_EditDispHandle = handle;
+
+ CMapDisp *pDisp = EditDispMgr()->GetDisp( handle );
+
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+ if( !pDispMgr )
+ return false;
+
+ pDispMgr->PreUndo( "Displacement Modifier" );
+
+ // Paint using the correct mode.
+ if ( m_bSpatial )
+ {
+ int nDispCount = pDispMgr->SelectCount();
+ for ( int iDisp = 0; iDisp < nDispCount; iDisp++ )
+ {
+ CMapDisp *pDispSelect = pDispMgr->GetFromSelect( iDisp );
+ if ( pDispSelect )
+ {
+ pDispSelect->Paint_Init( DISPPAINT_CHANNEL_POSITION );
+ }
+ }
+
+ // setup for undo - modifying the displacement (painting)
+ ApplySpatialPaintTool( nFlags, vPoint, pDisp );
+ }
+ else
+ {
+ // setup for undo - modifying the displacement (painting)
+ pDispMgr->Undo( handle, true );
+ pDisp = EditDispMgr()->GetDisp( handle );
+ ApplyPaintTool( nFlags, vPoint, pDisp );
+ }
+
+ // update
+ UpdateMapViews( pView );
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CToolDisplace::OnLMouseUp3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ // left button up
+ m_bLMBDown = false;
+
+ if( m_uiTool == DISPTOOL_PAINT_SCULPT )
+ {
+ m_SculptTool->OnLMouseUp3D( pView, nFlags, vPoint );
+ return true;
+ }
+
+ if ( m_bNudge )
+ {
+ Nudge_Deactivate();
+ }
+
+ if ( m_bSpatialRadius )
+ {
+ ResizeSpatialRadius_Deactivate();
+ }
+
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+ if( pDispMgr )
+ {
+ pDispMgr->PostUndo();
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CToolDisplace::OnRMouseDown3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ // left button down
+ m_bRMBDown = true;
+
+ if( m_uiTool == DISPTOOL_PAINT_SCULPT )
+ {
+ m_SculptTool->OnRMouseDown3D( pView, nFlags, vPoint );
+ m_SculptTool->BeginPaint( pView, vPoint );
+ ApplySculptSpatialPaintTool( pView, nFlags, vPoint );
+
+ // update
+ UpdateMapViews( pView );
+
+ return true;
+ }
+
+ //
+ // lifting the face normal - painting with the axis set to "Face Normal"
+ //
+ if( ( m_uiTool == DISPTOOL_PAINT ) && ( m_iPaintAxis == DISPPAINT_AXIS_FACE ) &&
+ ( GetAsyncKeyState( VK_MENU ) & 0x8000 ) )
+ {
+ LiftFaceNormal( pView, vPoint );
+ return true;
+ }
+
+ // Tagging.
+ if ( m_uiTool == DISPTOOL_TAG_WALKABLE || m_uiTool == DISPTOOL_TAG_BUILDABLE || m_uiTool == DISPTOOL_TAG_REMOVE )
+ {
+ // Do tagging.
+ HandleTaggingReset( pView, vPoint );
+ return true;
+ }
+
+ //
+ // handle the normal paint procedure
+ //
+ if( m_uiTool == DISPTOOL_PAINT )
+ {
+ // get hit info
+ EditDispHandle_t handle = GetHitPos( pView, vPoint );
+ if( handle == EDITDISPHANDLE_INVALID )
+ return false;
+ m_EditDispHandle = handle;
+
+ CMapDisp *pDisp = EditDispMgr()->GetDisp( handle );
+
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+ if( !pDispMgr )
+ return false;
+
+ pDispMgr->PreUndo( "Displacement Modifier" );
+
+ // apply the current displacement tool
+ if ( m_bSpatial )
+ {
+ int nDispCount = pDispMgr->SelectCount();
+ for ( int iDisp = 0; iDisp < nDispCount; iDisp++ )
+ {
+ CMapDisp *pDispSelect = pDispMgr->GetFromSelect( iDisp );
+ if ( pDispSelect )
+ {
+ pDispSelect->Paint_Init( DISPPAINT_CHANNEL_POSITION );
+ }
+ }
+
+ ApplySpatialPaintTool( nFlags, vPoint, pDisp );
+ }
+ else
+ {
+ // setup for undo
+ pDispMgr->Undo( handle, true );
+ pDisp = EditDispMgr()->GetDisp( handle );
+ ApplyPaintTool( nFlags, vPoint, pDisp );
+ }
+
+ // update
+ UpdateMapViews( pView );
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CToolDisplace::OnRMouseUp3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ // left button up
+ m_bRMBDown = false;
+
+ if( m_uiTool == DISPTOOL_PAINT_SCULPT )
+ {
+ m_SculptTool->OnRMouseUp3D( pView, nFlags, vPoint );
+ return true;
+ }
+
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+ if( pDispMgr )
+ {
+ pDispMgr->PostUndo();
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CToolDisplace::OnMouseMove3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ m_MousePoint = vPoint;
+
+ if( m_uiTool == DISPTOOL_PAINT_SCULPT )
+ {
+ m_SculptTool->OnMouseMove3D( pView, nFlags, vPoint );
+
+ if( ( m_bLMBDown || m_bRMBDown ) )
+ {
+ ApplySculptSpatialPaintTool( pView, nFlags, vPoint );
+ }
+
+ // update
+ UpdateMapViews( pView );
+
+ return true;
+ }
+
+ // nudging
+ if ( ( m_uiTool == DISPTOOL_PAINT ) && ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) &&
+ m_bLMBDown && m_bNudge )
+ {
+ Nudge_Do();
+ }
+ // Resizing the spatial sphere.
+ else if ( ( m_uiTool == DISPTOOL_PAINT ) && ( GetAsyncKeyState( VK_MENU ) & 0x8000 ) &&
+ m_bLMBDown && m_bSpatialRadius )
+ {
+ ResizeSpatialRadius_Do();
+ }
+ // painting
+ else
+ {
+ // get hit info
+ EditDispHandle_t handle = GetHitPos( pView, vPoint );
+ if( handle == EDITDISPHANDLE_INVALID )
+ return false;
+ m_EditDispHandle = handle;
+
+ CMapDisp *pDisp = EditDispMgr()->GetDisp( handle );
+
+ //
+ // continue with tool operation?!
+ //
+ if( ( m_bLMBDown || m_bRMBDown ) && !( GetAsyncKeyState( VK_CONTROL ) & 0x8000 ) &&
+ ( m_uiTool == DISPTOOL_PAINT ) )
+ {
+ if ( m_bSpatial )
+ {
+ ApplySpatialPaintTool( nFlags, vPoint, pDisp );
+ }
+ else
+ {
+ ApplyPaintTool( nFlags, vPoint, pDisp );
+ }
+ }
+
+ // not nudging anymore -- if we were
+ if( m_bNudge )
+ {
+ Nudge_Deactivate();
+ }
+
+ if ( m_bSpatialRadius )
+ {
+ ResizeSpatialRadius_Deactivate();
+ }
+ }
+
+ // update
+ UpdateMapViews( pView );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CToolDisplace::LiftFaceNormal( CMapView3D *pView, const Vector2D &vPoint )
+{
+ //
+ // check for closest solid object
+ //
+ ULONG ulFace;
+ CMapClass *pObject;
+
+ if( ( ( pObject = pView->NearestObjectAt( vPoint, ulFace ) ) != NULL ) )
+ {
+ if( pObject->IsMapClass( MAPCLASS_TYPE( CMapSolid ) ) )
+ {
+ // get the solid
+ CMapSolid *pSolid = ( CMapSolid* )pObject;
+ if( !pSolid )
+ return;
+
+ // trace a line and get the normal -- will get a displacement normal
+ // if one exists
+ CMapFace *pFace = pSolid->GetFace( ulFace );
+ if( !pFace )
+ return;
+
+ Vector vRayStart, vRayEnd;
+ pView->GetCamera()->BuildRay( vPoint, vRayStart, vRayEnd );
+
+ Vector vHitPos, vHitNormal;
+ if( pFace->TraceLine( vHitPos, vHitNormal, vRayStart, vRayEnd ) )
+ {
+ // set the paint direction
+ m_vecPaintAxis = vHitNormal;
+ }
+ else
+ {
+ // will default to z if no normal found
+ m_vecPaintAxis.Init( 0.0f, 0.0f, 1.0f );
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CToolDisplace::Nudge_Activate( CMapView3D *pView, EditDispHandle_t dispHandle )
+{
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+ if( !pDispMgr )
+ return;
+
+ pDispMgr->PreUndo( "Displacement Nudge" );
+
+ // Setup paint (nudge) using the correct mode.
+ if ( m_bSpatial )
+ {
+ int nDispCount = pDispMgr->SelectCount();
+ for ( int iDisp = 0; iDisp < nDispCount; iDisp++ )
+ {
+ CMapDisp *pDisp = pDispMgr->GetFromSelect( iDisp );
+ if ( pDisp )
+ {
+ pDisp->Paint_Init( DISPPAINT_CHANNEL_POSITION );
+ }
+ }
+ }
+ else
+ {
+ // setup for undo
+ pDispMgr->Undo( dispHandle, true );
+ }
+
+ // setup the cursor for "nudging"
+ CalcViewCenter( pView );
+ SetCursorPos( m_viewCenter.x, m_viewCenter.y );
+ pView->SetCapture();
+
+ // set nudging
+ m_bNudge = true;
+ m_bNudgeInit = true;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CToolDisplace::Nudge_Deactivate( void )
+{
+ ReleaseCapture();
+ m_bNudge = false;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CToolDisplace::Nudge_Do( void )
+{
+ CMapDisp *pNudgeDisp = GetEditDisp();
+ if (pNudgeDisp == NULL)
+ {
+ return;
+ }
+
+ //
+ // find the greatest delta and "nudge"
+ //
+ // NOTE: using get cursor position, because it is different than the
+ // "point" incoming into mouse move????
+ //
+ CPoint nudgePos;
+ GetCursorPos( &nudgePos );
+
+ CPoint nudgeDelta;
+ nudgeDelta.x = nudgePos.x - m_viewCenter.x;
+ nudgeDelta.y = nudgePos.y - m_viewCenter.y;
+
+ float delta;
+ if( abs( nudgeDelta.x ) < abs( nudgeDelta.y ) )
+ {
+ delta = nudgeDelta.y;
+ }
+ else
+ {
+ delta = nudgeDelta.x;
+ }
+ delta = -delta;
+
+ if ( !IsSpatialPainting() )
+ {
+ CDispMapImageFilter *pFilter = m_FilterRaiseLowerMgr.GetActiveFilter();
+ if( !pFilter )
+ return;
+
+ // set the dynamic filter data
+ pFilter->m_DataType = DISPPAINT_CHANNEL_POSITION;
+ pFilter->m_Scale = ( delta * 0.25 ) * ( float )( ( int )( m_flPaintValueGeo / 10.0f ) + 1 ) ;
+
+ // apply the filter to the displacement surface(s)
+ m_FilterRaiseLowerMgr.Apply( pFilter, pNudgeDisp, m_iPaintAxis, m_vecPaintAxis, m_bAutoSew );
+ }
+ else
+ {
+ // Get the hit index and check for validity.
+ int iHit = pNudgeDisp->GetTexelHitIndex();
+ if ( iHit != -1 )
+ {
+ // Initialize the spatial paint data.
+ SpatialPaintData_t spatialData;
+ spatialData.m_nEffect = DISPPAINT_EFFECT_RAISELOWER;
+ spatialData.m_uiBrushType = m_uiBrushType;
+ spatialData.m_flRadius = m_flSpatialRadius;
+ spatialData.m_flScalar = delta;
+ spatialData.m_bNudge = true;
+ spatialData.m_bNudgeInit = m_bNudgeInit;
+ pNudgeDisp->GetVert( iHit, spatialData.m_vCenter );
+ VectorCopy( m_vecPaintAxis, spatialData.m_vPaintAxis );
+
+ m_DispPaintMgr.Paint( spatialData, m_bAutoSew );
+
+ // Done with the init.
+ m_bNudgeInit = false;
+ }
+ }
+
+ // reset the cursor pos
+ SetCursorPos( m_viewCenter.x, m_viewCenter.y );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CToolDisplace::ApplyPaintTool( UINT nFlags, const Vector2D &vPoint, CMapDisp *pDisp )
+{
+ switch( m_uiEffect )
+ {
+ case DISPPAINT_EFFECT_RAISELOWER:
+ {
+ CDispMapImageFilter *pFilter = m_FilterRaiseLowerMgr.GetActiveFilter();
+ if( pFilter )
+ {
+ pFilter->m_DataType = m_iPaintChannel;
+ if ( m_iPaintChannel == DISPPAINT_CHANNEL_POSITION )
+ {
+ pFilter->m_Scale = m_flPaintValueGeo;
+ }
+ else if ( m_iPaintChannel == DISPPAINT_CHANNEL_ALPHA )
+ {
+ pFilter->m_Scale = m_flPaintValueData;
+ }
+
+ if( m_bRMBDown )
+ {
+ pFilter->m_Scale = -pFilter->m_Scale;
+ }
+
+ // apply the filter to the displacement surface(s)
+ m_FilterRaiseLowerMgr.Apply( pFilter, pDisp, m_iPaintAxis, m_vecPaintAxis, m_bAutoSew );
+ }
+ return;
+ }
+ case DISPPAINT_EFFECT_MODULATE:
+ {
+ // no modulate filters or filter manager currently!
+ return;
+ }
+ case DISPPAINT_EFFECT_SMOOTH:
+ {
+ CDispMapImageFilter *pFilter = m_FilterSmoothMgr.GetActiveFilter();
+ if( pFilter )
+ {
+ pFilter->m_DataType = m_iPaintChannel;
+ pFilter->m_Scale = 1.0f;
+
+ int areaValue = 3;
+ if ( m_iPaintChannel == DISPPAINT_CHANNEL_POSITION )
+ {
+ areaValue = ( m_flPaintValueGeo * 2 ) + 1;
+ }
+ else if ( m_iPaintChannel == DISPPAINT_CHANNEL_ALPHA )
+ {
+ areaValue = ( m_flPaintValueData * 2 ) + 1;
+ }
+ if( areaValue < 3 ) { areaValue = 3; }
+ if( areaValue > 7 ) { areaValue = 7; }
+
+ pFilter->m_AreaHeight = areaValue;
+ pFilter->m_AreaWidth = areaValue;
+
+ // apply the filter to the displacement surface(s)
+ m_FilterSmoothMgr.Apply( pFilter, pDisp, m_iPaintAxis, m_vecPaintAxis, m_bAutoSew );
+ }
+ return;
+ }
+ case DISPPAINT_EFFECT_RAISETO:
+ {
+ CDispMapImageFilter *pFilter = m_FilterRaiseToMgr.GetActiveFilter();
+ if( pFilter )
+ {
+ pFilter->m_DataType = m_iPaintChannel;
+ if ( m_iPaintChannel == DISPPAINT_CHANNEL_POSITION )
+ {
+ pFilter->m_Scale = m_flPaintValueGeo;
+ }
+ else if ( m_iPaintChannel == DISPPAINT_CHANNEL_ALPHA )
+ {
+ pFilter->m_Scale = m_flPaintValueData;
+ }
+
+ // apply the filter to the displacement surface(s)
+ m_FilterRaiseToMgr.Apply( pFilter, pDisp, m_iPaintAxis, m_vecPaintAxis, m_bAutoSew );
+ }
+ return;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CToolDisplace::ApplySpatialPaintTool( UINT nFlags, const Vector2D &vPoint, CMapDisp *pDisp )
+{
+ // Right mouse button only used to paint in a Raise/Lower situation.
+ if ( ( m_uiEffect != DISPPAINT_EFFECT_RAISELOWER ) && m_bRMBDown )
+ return;
+
+ // Get the hit index and check for validity.
+ int iHit = pDisp->GetTexelHitIndex();
+ if ( iHit == -1 )
+ return;
+
+ // Initialize the spatial paint data.
+ SpatialPaintData_t spatialData;
+ spatialData.m_nEffect = m_uiEffect;
+ spatialData.m_uiBrushType = m_uiBrushType;
+ spatialData.m_flRadius = m_flSpatialRadius;
+ spatialData.m_flScalar = m_flPaintValueGeo;
+ spatialData.m_bNudge = false;
+ if ( m_bRMBDown )
+ {
+ spatialData.m_flScalar = -spatialData.m_flScalar;
+ }
+ pDisp->GetVert( iHit, spatialData.m_vCenter );
+ VectorCopy( m_vecPaintAxis, spatialData.m_vPaintAxis );
+
+ m_DispPaintMgr.Paint( spatialData, m_bAutoSew );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CToolDisplace::ApplySculptSpatialPaintTool( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ // Initialize the spatial paint data.
+ SpatialPaintData_t spatialData;
+
+ spatialData.m_vCenter.Init();
+
+ // get hit info
+ EditDispHandle_t handle = GetHitPos( pView, vPoint );
+ if( handle != EDITDISPHANDLE_INVALID )
+ {
+ m_EditDispHandle = handle;
+ CMapDisp *pDisp = EditDispMgr()->GetDisp( handle );
+
+ // Get the hit index and check for validity.
+ int iHit = pDisp->GetTexelHitIndex();
+ if ( iHit != -1 )
+ {
+ pDisp->GetVert( iHit, spatialData.m_vCenter );
+ }
+ }
+
+ spatialData.m_nEffect = m_uiEffect;
+ spatialData.m_uiBrushType = m_uiBrushType;
+ spatialData.m_flRadius = m_flSpatialRadius;
+ spatialData.m_flScalar = m_flPaintValueGeo;
+ spatialData.m_bNudge = false;
+ if ( m_bRMBDown )
+ {
+ spatialData.m_flScalar = -spatialData.m_flScalar;
+ }
+ VectorCopy( m_vecPaintAxis, spatialData.m_vPaintAxis );
+
+ m_SculptTool->Paint( pView, vPoint, spatialData );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CToolDisplace::ResizeSpatialRadius_Activate( CMapView3D *pView )
+{
+ // Calculate the center of the view and capture the mouse cursor.
+ CalcViewCenter( pView );
+ SetCursorPos( m_viewCenter.x, m_viewCenter.y );
+ pView->SetCapture();
+
+ m_bSpatialRadius = true;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CToolDisplace::ResizeSpatialRadius_Deactivate( void )
+{
+ ReleaseCapture();
+ m_bSpatialRadius = false;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CToolDisplace::ResizeSpatialRadius_Do( void )
+{
+ CPoint cursorPos;
+ GetCursorPos( &cursorPos );
+
+ // Calculate the delta between the cursor from last frame and this one.
+ CPoint cursorDelta;
+ cursorDelta.x = cursorPos.x - m_viewCenter.x;
+ cursorDelta.y = cursorPos.y - m_viewCenter.y;
+
+ float flDelta;
+ if( abs( cursorDelta.x ) < abs( cursorDelta.y ) )
+ {
+ flDelta = cursorDelta.y;
+ }
+ else
+ {
+ flDelta = cursorDelta.x;
+ }
+ flDelta = -flDelta;
+
+ // Adjust the sphere radius.
+ m_flSpatialRadius += flDelta;
+
+ // reset the cursor pos
+ SetCursorPos( m_viewCenter.x, m_viewCenter.y );
+
+ //
+ // Update the paint dialog.
+ //
+ CFaceEditSheet *pSheet = GetMainWnd()->GetFaceEditSheet();
+ if( pSheet )
+ {
+ pSheet->m_DispPage.UpdatePaintDialogs();
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CToolDisplace::HandleSelection( CMapView3D *pView, const Vector2D &vPoint )
+{
+ //
+ // check for closest solid object
+ //
+ ULONG ulFace;
+ CMapClass *pObject;
+
+ bool bShift = ( ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) != 0 );
+
+ if( ( ( pObject = pView->NearestObjectAt( vPoint, ulFace ) ) != NULL ) )
+ {
+ if( pObject->IsMapClass( MAPCLASS_TYPE( CMapSolid ) ) )
+ {
+ // get the solid
+ CMapSolid *pSolid = ( CMapSolid* )pObject;
+
+ // setup initial command state
+ int cmd = scToggle | scClear;
+
+ //
+ // don't "clear" if CTRL is pressed
+ //
+ if( GetAsyncKeyState( VK_CONTROL ) & 0x8000 )
+ {
+ cmd &= ~scClear;
+ }
+
+ CMapDoc *pDoc = pView->GetMapDoc();
+ if( !pDoc )
+ return;
+
+ // If they are holding down SHIFT, select the entire solid.
+ if ( bShift )
+ {
+ pDoc->SelectFace( pSolid, -1, cmd );
+ }
+ // Otherwise, select a single face.
+ else
+ {
+ pDoc->SelectFace( pSolid, ulFace, cmd );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle the overriding of displacement triangle tag.
+//-----------------------------------------------------------------------------
+void CToolDisplace::HandleTagging( CMapView3D *pView, const Vector2D &vPoint )
+{
+ // Get the displacement face (if any) at the 2d point.
+ ULONG ulFace;
+ CMapClass *pObject = NULL;
+
+ if( ( ( pObject = pView->NearestObjectAt( vPoint, ulFace ) ) != NULL ) )
+ {
+ if( pObject->IsMapClass( MAPCLASS_TYPE( CMapSolid ) ) )
+ {
+ // Get the face and check for a displacement.
+ CMapSolid *pSolid = ( CMapSolid* )pObject;
+ CMapFace *pFace = pSolid->GetFace( ( int )ulFace );
+ if ( pFace && pFace->HasDisp() )
+ {
+ EditDispHandle_t hDisp = pFace->GetDisp();
+ CMapDisp *pDisp = EditDispMgr()->GetDisp( hDisp );
+
+ Vector vecStart, vecEnd;
+ pView->GetCamera()->BuildRay( vPoint, vecStart, vecEnd );
+
+ float flFraction;
+ int iTri = pDisp->CollideWithDispTri( vecStart, vecEnd, flFraction );
+ if ( iTri != -1 )
+ {
+ if ( m_uiTool == DISPTOOL_TAG_WALKABLE )
+ {
+ if ( pDisp->IsTriTag( iTri, COREDISPTRI_TAG_FORCE_WALKABLE_BIT ) )
+ {
+ pDisp->ToggleTriTag( iTri, COREDISPTRI_TAG_FORCE_WALKABLE_VAL );
+ }
+ else
+ {
+ pDisp->SetTriTag( iTri, COREDISPTRI_TAG_FORCE_WALKABLE_BIT );
+ if ( !pDisp->IsTriTag( iTri, COREDISPTRI_TAG_WALKABLE ) )
+ {
+ pDisp->SetTriTag( iTri, COREDISPTRI_TAG_FORCE_WALKABLE_VAL );
+ }
+ else
+ {
+ pDisp->ResetTriTag( iTri, COREDISPTRI_TAG_FORCE_WALKABLE_VAL );
+ }
+ }
+
+ pDisp->UpdateWalkable();
+ }
+ else if ( m_uiTool == DISPTOOL_TAG_BUILDABLE )
+ {
+ if ( pDisp->IsTriTag( iTri, COREDISPTRI_TAG_FORCE_BUILDABLE_BIT ) )
+ {
+ pDisp->ToggleTriTag( iTri, COREDISPTRI_TAG_FORCE_BUILDABLE_VAL );
+ }
+ else
+ {
+ pDisp->SetTriTag( iTri, COREDISPTRI_TAG_FORCE_BUILDABLE_BIT );
+ if ( !pDisp->IsTriTag( iTri, COREDISPTRI_TAG_BUILDABLE ) )
+ {
+ pDisp->SetTriTag( iTri, COREDISPTRI_TAG_FORCE_BUILDABLE_VAL );
+ }
+ else
+ {
+ pDisp->ResetTriTag( iTri, COREDISPTRI_TAG_FORCE_BUILDABLE_VAL );
+ }
+ }
+
+ pDisp->UpdateBuildable();
+ }
+ else if ( m_uiTool == DISPTOOL_TAG_REMOVE )
+ {
+ HandleTaggingRemove( pDisp, iTri );
+ }
+ }
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CToolDisplace::HandleTaggingRemove( CMapDisp *pDisp, int nTriIndex )
+{
+ pDisp->ToggleTriTag( nTriIndex, COREDISPTRI_TAG_FORCE_REMOVE_BIT );
+ pDisp->UpdateTriRemove();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle the overriding of displacement triangle tag.
+//-----------------------------------------------------------------------------
+void CToolDisplace::HandleTaggingReset( CMapView3D *pView, const Vector2D &vPoint )
+{
+ // Get the displacement face (if any) at the 2d point.
+ ULONG ulFace;
+ CMapClass *pObject = NULL;
+
+ if( ( ( pObject = pView->NearestObjectAt( vPoint, ulFace ) ) != NULL ) )
+ {
+ if( pObject->IsMapClass( MAPCLASS_TYPE( CMapSolid ) ) )
+ {
+ // Get the face and check for a displacement.
+ CMapSolid *pSolid = ( CMapSolid* )pObject;
+ CMapFace *pFace = pSolid->GetFace( ( int )ulFace );
+ if ( pFace && pFace->HasDisp() )
+ {
+ EditDispHandle_t hDisp = pFace->GetDisp();
+ CMapDisp *pDisp = EditDispMgr()->GetDisp( hDisp );
+
+ Vector vecStart, vecEnd;
+ pView->GetCamera()->BuildRay( vPoint, vecStart, vecEnd );
+
+ float flFraction;
+ int iTri = pDisp->CollideWithDispTri( vecStart, vecEnd, flFraction );
+ if ( iTri != -1 )
+ {
+ if ( m_uiTool == DISPTOOL_TAG_WALKABLE )
+ {
+ pDisp->ResetTriTag( iTri, COREDISPTRI_TAG_FORCE_WALKABLE_BIT );
+ pDisp->UpdateWalkable();
+ }
+ else if ( m_uiTool == DISPTOOL_TAG_BUILDABLE )
+ {
+ pDisp->ResetTriTag( iTri, COREDISPTRI_TAG_FORCE_BUILDABLE_BIT );
+ pDisp->UpdateBuildable();
+ }
+ else if ( m_uiTool == DISPTOOL_TAG_REMOVE )
+ {
+ pDisp->ResetTriTag( iTri, COREDISPTRI_TAG_FORCE_REMOVE_BIT );
+ pDisp->UpdateBuildable();
+ }
+ }
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+EditDispHandle_t CToolDisplace::GetHitPos( CMapView3D *pView, const Vector2D &vPoint )
+{
+ //
+ // get ray info
+ //
+ Vector rayStart, rayEnd;
+ pView->GetCamera()->BuildRay( vPoint, rayStart, rayEnd );
+
+ // generate selected displacement list
+ int dispCount = GetSelectedDisps();
+ if( dispCount == 0 )
+ return NULL;
+
+ // collide against all "active" displacements and set texel hit data
+ return CollideWithSelectedDisps( rayStart, rayEnd );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+int CToolDisplace::GetSelectedDisps( void )
+{
+ //
+ // get a valid displacement manager
+ //
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+ if( !pDispMgr )
+ return 0;
+
+ // clear the selection list
+ pDispMgr->SelectClear();
+
+ //
+ // add all selected displacements to "displacement manager"'s selection list
+ //
+ CFaceEditSheet *pSheet = GetMainWnd()->GetFaceEditSheet();
+ if( !pSheet )
+ return 0;
+
+ int faceCount = pSheet->GetFaceListCount();
+ for( int i = 0; i < faceCount; i++ )
+ {
+ CMapFace *pFace = pSheet->GetFaceListDataFace( i );
+ if( !pFace )
+ continue;
+
+ if( pFace->HasDisp() )
+ {
+ EditDispHandle_t handle = pFace->GetDisp();
+ CMapDisp *pDisp = EditDispMgr()->GetDisp( handle );
+ pDisp->ResetTexelHitIndex();
+ pDispMgr->AddToSelect( handle );
+ }
+ }
+
+ // return the number of displacements in list
+ return pDispMgr->SelectCount();
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+EditDispHandle_t CToolDisplace::CollideWithSelectedDisps( const Vector &rayStart, const Vector &rayEnd )
+{
+ EditDispHandle_t handle = EDITDISPHANDLE_INVALID;
+ float minDist = 99999.9f;
+ int minIndex = -1;
+
+ //
+ // get a valid displacement manager
+ //
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+ if( !pDispMgr )
+ return NULL;
+
+ int dispCount = pDispMgr->SelectCount();
+ for( int i = 0; i < dispCount; i++ )
+ {
+ // get the current displacement
+ CMapDisp *pDisp = pDispMgr->GetFromSelect( i );
+ if( !pDisp )
+ continue;
+
+ bool bCollide = RayAABBTest( pDisp, rayStart, rayEnd );
+ if( bCollide )
+ {
+ Vector point;
+ int size = pDisp->GetSize();
+ for( int j = 0; j < size; j++ )
+ {
+ // get current point
+ pDisp->GetVert( j, point );
+
+ // find point closest to ray
+ float dist = DistFromPointToRay( rayStart, rayEnd, point );
+ if( dist < minDist )
+ {
+ CMapFace *pFace = ( CMapFace* )pDisp->GetParent();
+ handle = pFace->GetDisp();
+ minDist = dist;
+ minIndex = j;
+ }
+ }
+ }
+ }
+
+ //
+ // set the texel hit index
+ //
+ if( handle != EDITDISPHANDLE_INVALID )
+ {
+ CMapDisp *pDisp = EditDispMgr()->GetDisp( handle );
+ pDisp->SetTexelHitIndex( minIndex );
+ }
+
+ return handle;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CToolDisplace::RayAABBTest( CMapDisp *pDisp, const Vector &rayStart, const Vector &rayEnd )
+{
+ //
+ // make planes
+ //
+ PLANE planes[6];
+ Vector boxMin, boxMax;
+ pDisp->GetBoundingBox( boxMin, boxMax );
+ BuildParallelepiped( boxMin, boxMax, planes );
+
+ bool bCollide = false;
+ for( int planeIndex = 0; planeIndex < 6; planeIndex++ )
+ {
+ bCollide = RayPlaneTest( &planes[planeIndex], rayStart, rayEnd );
+ if( !bCollide )
+ return false;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CToolDisplace::BuildParallelepiped( const Vector &boxMin, const Vector &boxMax,
+ PLANE planes[6] )
+{
+ int planeIndex = 0;
+ for( int axis = 0; axis < 3; axis++ )
+ {
+ for( int direction = -1; direction < 2; direction += 2 )
+ {
+ // clear the current plane info
+ VectorClear( planes[planeIndex].normal );
+ planes[planeIndex].normal[axis] = direction;
+ if( direction == 1 )
+ {
+ planes[planeIndex].dist = boxMax[axis];
+ }
+ else
+ {
+ planes[planeIndex].dist = -boxMin[axis];
+ }
+
+ planeIndex++;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CToolDisplace::RayPlaneTest( PLANE *pPlane, const Vector& rayStart, const Vector& rayEnd /*, float *fraction*/ )
+{
+ //
+ // get the distances both trace start and end from the bloated plane
+ //
+ float distStart = DotProduct( rayStart, pPlane->normal ) - pPlane->dist;
+ float distEnd = DotProduct( rayEnd, pPlane->normal ) - pPlane->dist;
+
+ //
+ // no collision - both points are in front or behind of the given plane
+ //
+ if( ( distStart > 0.0f ) && ( distEnd > 0.0f ) )
+ return false;
+
+ if( ( distStart > 0.0f ) && ( distEnd > 0.0f ) )
+ return false;
+
+ // calculate the parameterized "t" component along the ray
+ //*fraction = distStart / ( distStart - distEnd );
+
+ // collision
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+float CToolDisplace::DistFromPointToRay( const Vector& rayStart, const Vector& rayEnd,
+ const Vector& point )
+{
+ //
+ // calculate the ray
+ //
+ Vector ray;
+ VectorSubtract( rayEnd, rayStart, ray );
+ VectorNormalize( ray );
+
+ //
+ // get a ray to point
+ //
+ Vector seg;
+ VectorSubtract( point, rayStart, seg );
+
+ //
+ // project point segment onto ray - get perpendicular point
+ //
+ float value = DotProduct( ray, seg );
+ VectorScale( ray, value, ray );
+ VectorAdd( rayStart, ray, ray );
+
+ //
+ // find the distance between the perpendicular point and point
+ //
+ VectorSubtract( ray, point, seg );
+ float dist = VectorLength( seg );
+
+ return dist;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CToolDisplace::AddFiltersToManagers( void )
+{
+ int count = m_FilterLoaderMgr.GetFilterCount();
+ for( int ndxFilter = 0; ndxFilter < count; ndxFilter++ )
+ {
+ CDispMapImageFilter *pFilter = m_FilterLoaderMgr.GetFilter( ndxFilter );
+ if( pFilter )
+ {
+ switch( pFilter->m_Type )
+ {
+ case DISPPAINT_EFFECT_RAISELOWER:
+ {
+ m_FilterRaiseLowerMgr.Add( pFilter );
+ break;
+ }
+ case DISPPAINT_EFFECT_RAISETO:
+ {
+ m_FilterRaiseToMgr.Add( pFilter );
+ break;
+ }
+ case DISPPAINT_EFFECT_SMOOTH:
+ {
+ m_FilterSmoothMgr.Add( pFilter );
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+bool CToolDisplace::LoadFilters( const char *filename )
+{
+ //
+ // Open the file.
+ //
+ CChunkFile File;
+ ChunkFileResult_t eResult = File.Open( filename, ChunkFile_Read );
+
+ if( eResult != ChunkFile_Ok )
+ {
+ Msg( mwError, "Couldn't load filter file %s!\n", filename );
+ }
+
+ //
+ // Read the file.
+ //
+ if (eResult == ChunkFile_Ok)
+ {
+ //
+ // Set up handlers for the subchunks that we are interested in.
+ //
+ CChunkHandlerMap Handlers;
+ Handlers.AddHandler( "Filter", ( ChunkHandler_t )CToolDisplace::LoadFiltersCallback, this );
+ File.PushHandlers( &Handlers );
+
+ //
+ // Read the sub-chunks. We ignore keys in the root of the file, so we don't pass a
+ // key value callback to ReadChunk.
+ //
+ while (eResult == ChunkFile_Ok)
+ {
+ eResult = File.ReadChunk();
+ }
+
+ if (eResult == ChunkFile_EOF)
+ {
+ eResult = ChunkFile_Ok;
+ }
+
+ File.PopHandlers();
+ }
+
+ return( eResult == ChunkFile_Ok );
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+ChunkFileResult_t CToolDisplace::LoadFiltersCallback( CChunkFile *pFile, CToolDisplace *pDisplaceTool )
+{
+ //
+ // allocate a new filter
+ //
+ CDispMapImageFilter *pFilter = pDisplaceTool->m_FilterLoaderMgr.Create();
+ if( !pFilter )
+ return ChunkFile_Fail;
+
+ // load the filter data
+ ChunkFileResult_t eResult = pFilter->LoadFilter( pFile );
+ return( eResult );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pRender -
+// *pTool -
+//-----------------------------------------------------------------------------
+void CToolDisplace::RenderPaintSphere( CRender3D *pRender )
+{
+ CMapDisp *pDisp = GetEditDisp();
+ if (pDisp == NULL)
+ return;
+
+ // Get the sphere center.
+ int iHit = pDisp->GetTexelHitIndex();
+ if ( iHit == -1 )
+ return;
+
+ // Get the sphere center and radius.
+ Vector vCenter;
+ pDisp->GetVert( iHit, vCenter );
+ float flRadius = GetSpatialRadius();
+
+ int size = ( int )( flRadius * 0.05f );
+ if ( size < 6 ) { size = 6; }
+ if ( size > 12 ) { size = 12; }
+
+ // Render the sphere.
+ if ( !IsNudging() )
+ {
+ pRender->RenderWireframeSphere( vCenter, flRadius, size, size, 0, 255, 0 );
+ }
+ else
+ {
+ pRender->RenderWireframeSphere( vCenter, flRadius, size, size, 255, 255, 0 );
+ }
+
+ // Render the displacement axis (as an arrow).
+ int nPaintAxis;
+ Vector vPaintAxis;
+ GetPaintAxis( nPaintAxis, vPaintAxis );
+ if( nPaintAxis == DISPPAINT_AXIS_SUBDIV )
+ {
+ pDisp->GetSubdivNormal( iHit, vPaintAxis );
+ }
+ float flBloat = flRadius * 0.15f;
+ pRender->RenderArrow( vCenter, vCenter + ( vPaintAxis * ( flRadius + flBloat ) ), 255, 255, 0 );
+
+ // Render cube at center point.
+ Vector vBoxMin, vBoxMax;
+ for ( int iAxis = 0; iAxis < 3; iAxis++ )
+ {
+ vBoxMin[iAxis] = vCenter[iAxis] - ( flBloat * 0.25f );
+ vBoxMax[iAxis] = vCenter[iAxis] + ( flBloat * 0.25f );
+ }
+ pRender->RenderBox( vBoxMin, vBoxMax, 255, 255, 0, SELECT_NONE );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : pRender -
+// bNudge -
+//-----------------------------------------------------------------------------
+void CToolDisplace::RenderHitBox( CRender3D *pRender )
+{
+ CMapDisp *pDisp = GetEditDisp();
+ if (pDisp == NULL)
+ return;
+
+ //
+ // get selection
+ //
+ int index = pDisp->GetTexelHitIndex();
+ if( index == -1 )
+ return;
+
+ //
+ // get the displacement map width and height
+ //
+ int width = pDisp->GetWidth();
+ int height = pDisp->GetHeight();
+
+ Vector seg[2];
+ Vector points[2];
+
+ pDisp->GetVert( 0, points[0] );
+ pDisp->GetVert( ( width - 1 ), points[1] );
+ VectorSubtract( points[1], points[0], seg[0] );
+ pDisp->GetVert( ( ( width - 1 ) * height ), points[1] );
+ VectorSubtract( points[1], points[0], seg[1] );
+
+ VectorAdd( seg[0], seg[1], seg[0] );
+ VectorScale( seg[0], 0.5f, seg[0] );
+
+ //
+ // determine a good size to make the "box" surrounding the selected point
+ //
+ float length = VectorLength( seg[0] );
+ length *= 0.025f;
+
+ //
+ // render the box
+ //
+ pDisp->GetVert( index, points[0] );
+
+ Vector minb, maxb;
+ minb[0] = points[0][0] - length;
+ minb[1] = points[0][1] - length;
+ minb[2] = points[0][2] - length;
+
+ maxb[0] = points[0][0] + length;
+ maxb[1] = points[0][1] + length;
+ maxb[2] = points[0][2] + length;
+
+ if( !IsNudging() )
+ {
+ pRender->RenderWireframeBox( minb, maxb, 0, 255, 0 );
+ }
+ else
+ {
+ pRender->RenderWireframeBox( minb, maxb, 255, 255, 0 );
+ }
+
+ //
+ // render the normal
+ //
+ // get hit box origin
+ Vector hbOrigin;
+ pDisp->GetVert( index, hbOrigin );
+
+ // get 4x length
+ float length4 = length * 4.0f;
+
+ int paintAxis;
+ Vector vecPaint;
+ GetPaintAxis( paintAxis, vecPaint );
+ if( paintAxis == DISPPAINT_AXIS_SUBDIV )
+ {
+ pDisp->GetSubdivNormal( index, vecPaint );
+ }
+
+ //
+ // render the normal -- just a yellow line at this point
+ //
+ pRender->RenderArrow( hbOrigin, hbOrigin + ( vecPaint * length4 ), 255, 255, 0 );
+#if 0
+ CMeshBuilder meshBuilder;
+ IMesh *pMesh = MaterialSystemInterface()->GetDynamicMesh();
+
+ meshBuilder.Begin( pMesh, MATERIAL_LINES, 1 );
+ meshBuilder.Position3f( hbOrigin.x, hbOrigin.y, hbOrigin.z );
+ meshBuilder.Color3ub( 255, 255, 0 );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.Position3f( hbOrigin.x + ( normal.x * length4 ),
+ hbOrigin.y + ( normal.y * length4 ),
+ hbOrigin.z + ( normal.z * length4 ) );
+ meshBuilder.Color3ub( 255, 255, 0 );
+ meshBuilder.AdvanceVertex();
+ meshBuilder.End();
+
+ pMesh->Draw();
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pRender -
+//-----------------------------------------------------------------------------
+void CToolDisplace::RenderTool3D(CRender3D *pRender)
+{
+ unsigned int uiTool = GetTool();
+ if ( uiTool == DISPTOOL_PAINT )
+ {
+ if ( IsSpatialPainting() )
+ {
+ RenderPaintSphere( pRender );
+ }
+ else
+ {
+ RenderHitBox( pRender );
+ }
+ }
+
+ if ( uiTool == DISPTOOL_PAINT_SCULPT )
+ {
+ m_SculptTool->RenderTool3D( pRender );
+ }
+}