summaryrefslogtreecommitdiff
path: root/hammer/sculptoptions.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/sculptoptions.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'hammer/sculptoptions.cpp')
-rw-r--r--hammer/sculptoptions.cpp3933
1 files changed, 3933 insertions, 0 deletions
diff --git a/hammer/sculptoptions.cpp b/hammer/sculptoptions.cpp
new file mode 100644
index 0000000..6aa0a72
--- /dev/null
+++ b/hammer/sculptoptions.cpp
@@ -0,0 +1,3933 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+// SculptOptions.cpp : implementation file
+//
+
+#include <stdafx.h>
+#include "hammer.h"
+#include "CollisionUtils.h"
+#include "resource.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 "bitmap/tgaloader.h"
+#include "tier1/utlbuffer.h"
+#include "Material.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imaterialsystem.h"
+#include "materialsystem/MaterialSystemUtil.h"
+#include "materialsystem/itexture.h"
+#include "../materialsystem/itextureinternal.h"
+#include "pixelwriter.h"
+#include "TextureSystem.h"
+#include "SculptOptions.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+
+extern CToolDisplace* GetDisplacementTool();
+extern void FaceListSewEdges( void );
+
+
+CUtlMap<EditDispHandle_t, CMapDisp *> CSculptTool::m_OrigMapDisp( 3, 3, CSculptTool::MapDispLessFunc );
+
+
+//-----------------------------------------------------------------------------
+// Purpose: constructor
+//-----------------------------------------------------------------------------
+CSculptTool::CSculptTool()
+{
+ m_PaintOwner = NULL;
+
+ m_MousePoint.Init();
+ m_StartingCollisionNormal.Init();
+
+ m_OriginalCollisionPoint.Init();
+
+ m_bAltDown = m_bCtrlDown = m_bShiftDown = false;
+
+ m_bLMBDown = m_bRMBDown = false;
+ m_ValidPaintingSpot = false;
+ m_BrushSize = 50;
+
+ m_StartingProjectedRadius = m_OriginalProjectedRadius = 10.0f;
+
+ m_OriginalCollisionValid = m_CurrentCollisionValid = false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: destructor
+//-----------------------------------------------------------------------------
+CSculptTool::~CSculptTool()
+{
+ FOR_EACH_MAP( m_OrigMapDisp, pos )
+ {
+ delete m_OrigMapDisp.Element( pos );
+ }
+ m_OrigMapDisp.Purge();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: setup for starting to paint on the displacement
+// Input : pView - the 3d view
+// vPoint - the initial click point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptTool::BeginPaint( CMapView3D *pView, const Vector2D &vPoint )
+{
+ DuplicateSelectedDisp();
+
+ GetStartingSpot( pView, vPoint );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: main routine called when mouse move has happened to start painting
+// Input : pView - the 3d view
+// vPoint - the mouse point
+// SpatialData - the spatial data ( mostly ignored )
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptTool::Paint( CMapView3D *pView, const Vector2D &vPoint, SpatialPaintData_t &SpatialData )
+{
+ m_SpatialData = SpatialData;
+
+ // Successful paint operation.
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: determines if any of the special keys ( control, shift, alt ) are pressed
+//-----------------------------------------------------------------------------
+void CSculptTool::DetermineKeysDown()
+{
+ m_bCtrlDown = ( ( GetAsyncKeyState( VK_CONTROL ) & 0x8000 ) != 0 );
+ m_bShiftDown = ( ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) != 0 );
+ m_bAltDown = ( ( GetAsyncKeyState( VK_MENU ) & 0x8000 ) != 0 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handles the left mouse button up in the 3d view
+// Input : pView - the 3d view
+// nFlags - the button flags
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptTool::OnLMouseUp3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ DetermineKeysDown();
+
+ // left button up
+ m_bLMBDown = false;
+ m_MousePoint = vPoint;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handles the left mouse button down in the 3d view
+// Input : pView - the 3d view
+// nFlags - the button flags
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptTool::OnLMouseDown3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ DetermineKeysDown();
+
+ // left button down
+ m_bLMBDown = true;
+ m_MousePoint = vPoint;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handles the right mouse button up in the 3d view
+// Input : pView - the 3d view
+// nFlags - the button flags
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptTool::OnRMouseUp3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ DetermineKeysDown();
+
+ // right button up
+ m_bRMBDown = false;
+ m_MousePoint = vPoint;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handles the right mouse button down in the 3d view
+// Input : pView - the 3d view
+// nFlags - the button flags
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptTool::OnRMouseDown3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ DetermineKeysDown();
+
+ // right button down
+ m_bRMBDown = true;
+ m_MousePoint = vPoint;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handles the mouse move in the 3d view
+// Input : pView - the 3d view
+// nFlags - the button flags
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptTool::OnMouseMove3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ DetermineKeysDown();
+
+ m_MousePoint = vPoint;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: called just before painting begins to gather reference information
+// Input : pView - the 3d view
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptTool::PrePaint( CMapView3D *pView, const Vector2D &vPoint )
+{
+ Vector2D RadiusPoint = vPoint;
+ Vector vecStart, vecEnd;
+
+ RadiusPoint.x += m_BrushSize;
+ pView->GetCamera()->BuildRay( RadiusPoint, vecStart, vecEnd );
+
+ m_OriginalCollisionValid = FindCollisionIntercept( pView->GetCamera(), vPoint, true, m_OriginalCollisionPoint, m_OriginalCollisionNormal, m_OriginalCollisionIntercept );
+ if ( m_OriginalCollisionValid )
+ {
+ m_OriginalProjectedRadius = CalcDistanceToLine( m_OriginalCollisionPoint, vecStart, vecEnd );
+ }
+
+ m_CurrentCollisionValid = FindCollisionIntercept( pView->GetCamera(), vPoint, false, m_CurrentCollisionPoint, m_CurrentCollisionNormal, m_CurrentCollisionIntercept );
+ if ( m_CurrentCollisionValid )
+ {
+ m_CurrentProjectedRadius = CalcDistanceToLine( m_CurrentCollisionPoint, vecStart, vecEnd );
+ }
+
+ m_SpatialData.m_flRadius = 128.0f;
+ m_SpatialData.m_flRadius2 = ( m_SpatialData.m_flRadius * m_SpatialData.m_flRadius );
+ m_SpatialData.m_flOORadius2 = 1.0f / m_SpatialData.m_flRadius2;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: called after painting finishes to finalize things
+// Input : bAutoSew - should we sew the edges
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptTool::PostPaint( bool bAutoSew )
+{
+ // Get the displacement manager from the active map document.
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+ if( !pDispMgr )
+ return false;
+
+ // Update the modified displacements.
+ int nDispCount = pDispMgr->SelectCount();
+ for ( int iDisp = 0; iDisp < nDispCount; iDisp++ )
+ {
+ CMapDisp *pDisp = pDispMgr->GetFromSelect( iDisp );
+ if ( pDisp )
+ {
+ pDisp->Paint_Update( false );
+ }
+ }
+
+ // Auto "sew" if necessary.
+ if ( bAutoSew )
+ {
+ FaceListSewEdges();
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: called to dispatch the painting routine across all selected displacements
+// Input : pView - the 3d view
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptTool::DoPaint( CMapView3D *pView, const Vector2D &vPoint )
+{
+ // Get the displacement manager from the active map document.
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+ if( !pDispMgr )
+ return false;
+
+ // For each displacement surface is the selection list attempt to paint on it.
+ int nDispCount = pDispMgr->SelectCount();
+ for ( int iDisp = 0; iDisp < nDispCount; iDisp++ )
+ {
+ CMapDisp *pDisp = pDispMgr->GetFromSelect( iDisp );
+ if ( pDisp )
+ {
+ CMapDisp *OrigDisp = NULL;
+ int index = m_OrigMapDisp.Find( pDisp->GetEditHandle() );
+
+ if ( index != m_OrigMapDisp.InvalidIndex() )
+ {
+ OrigDisp = m_OrigMapDisp[ index ];
+ }
+ DoPaintOperation( pView, vPoint, pDisp, OrigDisp );
+ }
+ }
+
+ // Successful paint.
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: checks to see if a given displacement vert lies within the 2d screenspace of the circle
+// Input : pView - the 3d view
+// pDisp - the displacement the vert belongs to
+// pOrigDisp - the displacement prior to any moving
+// nVertIndex - the vert index
+// bUseOrigDisplacement - should we use the vert from the original displacement
+// bUseCurrentPosition - should we use the current collision test point
+// Output : returns true if the point is within the circle
+//-----------------------------------------------------------------------------
+bool CSculptTool::IsPointInScreenCircle( CMapView3D *pView, CMapDisp *pDisp, CMapDisp *pOrigDisp, int nVertIndex, bool bUseOrigDisplacement, bool bUseCurrentPosition, float *pflLengthPercent )
+{
+ Vector vVert, vTestVert;
+
+ pDisp->GetVert( nVertIndex, vVert );
+
+ if ( pOrigDisp && bUseOrigDisplacement )
+ {
+ pOrigDisp->GetVert( nVertIndex, vTestVert );
+ }
+ else
+ {
+ vTestVert = vVert;
+ }
+
+#if 0
+ Vector2D ViewVert;
+ pView->GetCamera()->WorldToView( vTestVert, ViewVert );
+
+ Vector2D Offset = ViewVert - m_MousePoint;
+ float Length = Offset.Length();
+
+ return ( Length <= m_BrushSize );
+#else
+ if ( bUseCurrentPosition )
+ {
+ if ( !m_CurrentCollisionValid )
+ {
+ return false;
+ }
+
+ Vector Offset = m_CurrentCollisionPoint - vTestVert;
+ float Length = Offset.Length();
+
+ if ( pflLengthPercent )
+ {
+ *pflLengthPercent = Length / m_CurrentProjectedRadius;
+ }
+
+ return ( Length <= m_CurrentProjectedRadius );
+ }
+ else
+ {
+ if ( !m_OriginalCollisionValid )
+ {
+ return false;
+ }
+
+ Vector Offset = m_OriginalCollisionPoint - vTestVert;
+ float Length = Offset.Length();
+
+ if ( pflLengthPercent )
+ {
+ *pflLengthPercent = Length / m_OriginalProjectedRadius;
+ }
+
+#if 0
+ if ( Length <= m_OriginalProjectedRadius || vertIndex == 66 )
+ {
+ Msg( "%d: ( %g %g %g ) from %g <= %g at ( %g %g %g )\n", vertIndex, vTestVert.x, vTestVert.y, vTestVert.z, Length, m_OriginalProjectedRadius, m_OriginalCollisionPoint.x, m_OriginalCollisionPoint.y, m_OriginalCollisionPoint.z );
+ }
+#endif
+ return ( Length <= m_OriginalProjectedRadius );
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds a displacement to the undo manager
+// Input : pDisp - the displacement
+//-----------------------------------------------------------------------------
+void CSculptTool::AddToUndo( CMapDisp **pDisp )
+{
+ CMapDisp *pUndoDisp = *pDisp;
+ if ( pUndoDisp->Paint_IsDirty() )
+ return;
+
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+ if( pDispMgr )
+ {
+ EditDispHandle_t handle = pUndoDisp->GetEditHandle();
+ pDispMgr->Undo( handle, false );
+ *pDisp = EditDispMgr()->GetDisp( handle );
+ }
+}
+
+
+#if 0
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input :
+// Output :
+//-----------------------------------------------------------------------------
+void CSculptTool::DoPaintEqual( SpatialPaintData_t &spatialData, CMapDisp *pDisp )
+{
+ Vector vPaintPos, vVert, vFlatVert;
+ float flDistance2;
+
+ int nVertCount = pDisp->GetSize();
+ for ( int iVert = 0; iVert < nVertCount; iVert++ )
+ {
+ // Get the current vert.
+ pDisp->GetVert( iVert, vVert );
+
+ if ( IsInSphereRadius( spatialData.m_vCenter, spatialData.m_flRadius2, vVert, flDistance2 ) )
+ {
+ // Get the base vert.
+ pDisp->GetFlatVert( iVert, vFlatVert );
+
+ // Build the new position (paint value) and set it.
+ DoPaintOne( spatialData, vFlatVert, vPaintPos );
+ AddToUndo( &pDisp );
+ pDisp->Paint_SetValue( iVert, vPaintPos );
+ }
+ }
+}
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Purpose: this routine does the smoothing operation
+// Input : pView - the 3d view
+// vPoint - the mouse point
+// pDisp - the displacement to smooth
+// pOrigDisp - the displacement prior to the paint operation
+// Output :
+//-----------------------------------------------------------------------------
+void CSculptTool::DoPaintSmooth( CMapView3D *pView, const Vector2D &vPoint, CMapDisp *pDisp, CMapDisp *pOrigDisp )
+{
+ Vector vPaintPos, vVert;
+
+ pDisp->GetSurfNormal( m_SpatialData.m_vPaintAxis );
+
+ int nVertCount = pDisp->GetSize();
+ for ( int iVert = 0; iVert < nVertCount; iVert++ )
+ {
+ if ( IsPointInScreenCircle( pView, pDisp, pOrigDisp, iVert, false, true ) )
+ {
+// Msg( "Checking Vert %d\n", iVert );
+ // Get the current vert.
+ pDisp->GetVert( iVert, vVert );
+
+ // Build the new smoothed position and set it.
+ if ( DoPaintSmoothOneOverExp( vVert, vPaintPos ) )
+ {
+ AddToUndo( &pDisp );
+ pDisp->Paint_SetValue( iVert, vPaintPos );
+// Msg( "Vert %d Updated: from %g %g %g to %g %g %g\n", iVert, vVert.x, vVert.y, vVert.z, vPaintPos.x, vPaintPos.y, vPaintPos.z );
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: checks to see if the paint sphere is within the bounding box
+// Input : vCenter - center of the sphere
+// flRadius - sphere radius
+// vBBoxMin - bounding box mins
+// vBBoxMax - bounding box maxs
+// Output : returns two if the two intersect
+//-----------------------------------------------------------------------------
+bool CSculptTool::PaintSphereDispBBoxOverlap( const Vector &vCenter, float flRadius, const Vector &vBBoxMin, const Vector &vBBoxMax )
+{
+ return IsBoxIntersectingSphere( vBBoxMin, vBBoxMax, vCenter, flRadius );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: checkes to see if the two spheres intersect
+// Input : vCenter - center of the sphere
+// flRadius2 - sphere radius squared
+// vPos - point to test
+// flDistance2 - radius of point
+// Output : returns true if the two spheres intersect
+//-----------------------------------------------------------------------------
+bool CSculptTool::IsInSphereRadius( const Vector &vCenter, float flRadius2, const Vector &vPos, float &flDistance2 )
+{
+ Vector vTmp;
+ VectorSubtract( vPos, vCenter, vTmp );
+ flDistance2 = ( vTmp.x * vTmp.x ) + ( vTmp.y * vTmp.y ) + ( vTmp.z * vTmp.z );
+ return ( flDistance2 < flRadius2 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: calculates the smoothing radius squared
+// Input : vPoint - the point to be smoothed
+// Output : returns the smoothing radius squared
+//-----------------------------------------------------------------------------
+float CSculptTool::CalcSmoothRadius2( const Vector &vPoint )
+{
+ Vector vTmp;
+ VectorSubtract( m_SpatialData.m_vCenter, vPoint, vTmp );
+ float flDistance2 = ( vTmp.x * vTmp.x ) + ( vTmp.y * vTmp.y ) + ( vTmp.z * vTmp.z );
+
+ float flRatio = flDistance2 / m_SpatialData.m_flRadius2;
+ flRatio = 1.0f - flRatio;
+
+ float flRadius = flRatio * m_SpatialData.m_flRadius;
+ return ( flRadius * flRadius );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: smooths all displacements
+// Input : vNewCenter - calculate the smoothing center
+// Output : returns true if successful
+// vPaintPos - the new smoothing position
+//-----------------------------------------------------------------------------
+bool CSculptTool::DoPaintSmoothOneOverExp( const Vector &vNewCenter, Vector &vPaintPos )
+{
+ // Get the displacement manager from the active map document.
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+ if( !pDispMgr )
+ return false;
+
+ // Calculate the smoothing radius.
+ float flNewRadius2 = CalcSmoothRadius2( vNewCenter );
+ flNewRadius2 *= 2.0f;
+ float flNewRadius = ( float )sqrt( flNewRadius2 );
+
+
+ // Test all selected surfaces for smoothing.
+ float flWeight = 0.0f;
+ float flSmoothDist = 0.0f;
+
+ // Calculate the plane dist.
+ float flPaintDist = m_SpatialData.m_vPaintAxis.Dot( vNewCenter );
+
+ int nDispCount = pDispMgr->SelectCount();
+ for ( int iDisp = 0; iDisp < nDispCount; iDisp++ )
+ {
+ CMapDisp *pDisp = pDispMgr->GetFromSelect( iDisp );
+ if ( pDisp )
+ {
+ // Test paint sphere displacement bbox for overlap.
+ Vector vBBoxMin, vBBoxMax;
+ pDisp->GetBoundingBox( vBBoxMin, vBBoxMax );
+ if ( PaintSphereDispBBoxOverlap( vNewCenter, flNewRadius, vBBoxMin, vBBoxMax ) )
+ {
+ Vector vVert;
+ int nVertCount = pDisp->GetSize();
+ for ( int iVert = 0; iVert < nVertCount; iVert++ )
+ {
+ // Get the current vert.
+ pDisp->GetVert( iVert, vVert );
+
+ float flDistance2 = 0.0f;
+ if ( IsInSphereRadius( vNewCenter, flNewRadius2, vVert, flDistance2 ) )
+ {
+ float flRatio = flDistance2 / flNewRadius2;
+ float flFactor = 1.0f / exp( flRatio );
+ if ( flFactor != 1.0f )
+ {
+ flFactor *= 1.0f / ( m_SpatialData.m_flScalar * 2.0f );
+ }
+
+ Vector vProjectVert;
+ float flProjectDist = DotProduct( vVert, m_SpatialData.m_vPaintAxis ) - flPaintDist;
+ flSmoothDist += ( flProjectDist * flFactor );
+ flWeight += flFactor;
+// Msg( "Factoring %d: %g %g %g at %g\n", iVert, vVert.x, vVert.y, vVert.z, flNewRadius2 );
+ }
+ }
+ }
+ }
+ }
+
+ if ( flWeight == 0.0f )
+ {
+ return false;
+ }
+
+ // Re-normalize the smoothing position.
+ flSmoothDist /= flWeight;
+ vPaintPos = vNewCenter + ( m_SpatialData.m_vPaintAxis * flSmoothDist );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: gets the starting position when the paint operation begins
+// Input : pView - the 3d view
+// vPoint - the mouse point
+// Output : returns the starting position
+//-----------------------------------------------------------------------------
+bool CSculptTool::GetStartingSpot( CMapView3D *pView, const Vector2D &vPoint )
+{
+ m_ValidPaintingSpot = FindCollisionIntercept( pView->GetCamera(), vPoint, false, m_StartingCollisionPoint, m_StartingCollisionNormal, m_StartingCollisionIntercept );
+
+ if ( m_ValidPaintingSpot )
+ {
+ Vector2D RadiusPoint = vPoint;
+ Vector vecStart, vecEnd;
+
+ RadiusPoint.x += m_BrushSize;
+ pView->GetCamera()->BuildRay( RadiusPoint, vecStart, vecEnd );
+ m_StartingProjectedRadius = CalcDistanceToLine( m_StartingCollisionPoint, vecStart, vecEnd );
+
+ }
+
+ return m_ValidPaintingSpot;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Draws a 2d line to represent the direction
+// Input : pRender - the renderer
+// Direction - direction / normal
+// Towards - the color to be used if the direction is towards the viewer
+// Away - the color to be used if the direction is away from the view
+//-----------------------------------------------------------------------------
+void CSculptTool::DrawDirection( CRender3D *pRender, Vector Direction, Color Towards, Color Away )
+{
+ Vector ViewPoint, ViewDir;
+ Vector2D ViewVert;
+
+ VMatrix Matrix;
+ pRender->GetCamera()->GetViewProjMatrix( Matrix );
+ Matrix.SetTranslation( Vector( 0.0f, 0.0f, 0.0f ) );
+ Vector3DMultiply( Matrix, Direction, ViewDir );
+ VectorNormalize( ViewDir );
+
+ ViewVert = m_MousePoint + ( Vector2D( ViewDir.x, -ViewDir.y ) * m_BrushSize );
+
+ if ( ViewDir.z > 0.0f )
+ {
+ pRender->SetDrawColor( Away.r(), Away.g(), Away.b() );
+ }
+ else
+ {
+ pRender->SetDrawColor( Towards.r(), Towards.g(), Towards.b() );
+ }
+
+ bool bPopMode = pRender->BeginClientSpace();
+ pRender->DrawLine( Vector( m_MousePoint.x, m_MousePoint.y, 0.0f ), Vector( ViewVert.x, ViewVert.y, 0.0f ) );
+ if ( bPopMode )
+ {
+ pRender->EndClientSpace();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: this function will copy all the selected displacements
+//-----------------------------------------------------------------------------
+void CSculptTool::DuplicateSelectedDisp( )
+{
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+ if( !pDispMgr )
+ {
+ return;
+ }
+
+ FOR_EACH_MAP( m_OrigMapDisp, pos )
+ {
+ delete m_OrigMapDisp.Element( pos );
+ }
+ m_OrigMapDisp.Purge();
+
+ int nDispCount = pDispMgr->SelectCount();
+
+ for ( int iDisp = 0; iDisp < nDispCount; iDisp++ )
+ {
+ CMapDisp *pDisp = pDispMgr->GetFromSelect( iDisp );
+ if ( pDisp )
+ {
+ CMapDisp *pCopy = new CMapDisp();
+
+ pCopy->CopyFrom( pDisp, false );
+ m_OrigMapDisp.Insert( pDisp->GetEditHandle(), pCopy );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: this function will initialize all selected displacements for updating
+//-----------------------------------------------------------------------------
+void CSculptTool::PrepareDispForPainting( )
+{
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+ if( !pDispMgr )
+ {
+ return;
+ }
+
+ int nDispCount = pDispMgr->SelectCount();
+
+ for ( int iDisp = 0; iDisp < nDispCount; iDisp++ )
+ {
+ CMapDisp *pDisp = pDispMgr->GetFromSelect( iDisp );
+ if ( pDisp )
+ {
+ pDisp->Paint_Init( DISPPAINT_CHANNEL_POSITION );
+ }
+ }
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: this function will find the collision location within the selected displacements
+// Input : pCamera - the camera
+// vPoint - the 2d point on screen
+// bUseOrigPosition - should we use the original displacements prior to updating
+// Output : returns true if the point intercepted one of the selected displacements
+// vCollisionPoint the 3d interception point
+// vCollisionNormal - the normal of the tri hit
+// flCollisionIntercept - the intercept
+//-----------------------------------------------------------------------------
+bool CSculptTool::FindCollisionIntercept( CCamera *pCamera, const Vector2D &vPoint, bool bUseOrigPosition, Vector &vCollisionPoint, Vector &vCollisionNormal, float &flCollisionIntercept )
+{
+ Vector vecStart, vecEnd;
+ float flFraction, flLeastFraction;
+
+ flLeastFraction = -1.0f;
+
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+ if( !pDispMgr )
+ {
+ return false;
+ }
+
+ int nDispCount = pDispMgr->SelectCount();
+ pCamera->BuildRay( vPoint, vecStart, vecEnd );
+
+ for ( int iDisp = 0; iDisp < nDispCount; iDisp++ )
+ {
+ CMapDisp *pDisp = pDispMgr->GetFromSelect( iDisp );
+ if ( pDisp )
+ {
+ if ( bUseOrigPosition )
+ {
+ CMapDisp *OrigDisp = NULL;
+ int index = m_OrigMapDisp.Find( pDisp->GetEditHandle() );
+
+ if ( index != m_OrigMapDisp.InvalidIndex() )
+ {
+ OrigDisp = m_OrigMapDisp[ index ];
+ }
+
+ if ( OrigDisp )
+ {
+ pDisp = OrigDisp;
+ }
+ }
+
+ int iTri = pDisp->CollideWithDispTri( vecStart, vecEnd, flFraction, false );
+ if ( iTri != -1 && ( flLeastFraction == -1.0f || flFraction < flLeastFraction ) )
+ {
+ flLeastFraction = flFraction;
+ vCollisionPoint = vecStart + ( ( vecEnd - vecStart ) * flFraction );
+
+ unsigned short v1, v2, v3;
+ Vector vec1, vec2, vec3;
+
+ pDisp->GetTriIndices( iTri, v1, v2, v3 );
+ pDisp->GetVert( v1, vec1 );
+ pDisp->GetVert( v2, vec2 );
+ pDisp->GetVert( v3, vec3 );
+
+ ComputeTrianglePlane( vec1, vec2, vec3, vCollisionNormal, flCollisionIntercept );
+ }
+ }
+ }
+
+ return ( flLeastFraction != -1.0f );
+}
+
+
+
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: constructor
+//-----------------------------------------------------------------------------
+CSculptPainter::CSculptPainter() :
+ CSculptTool()
+{
+ m_InSizingMode = m_InPaintingMode = false;
+ m_OrigBrushSize = m_BrushSize;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: destructor
+//-----------------------------------------------------------------------------
+CSculptPainter::~CSculptPainter( )
+{
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: setup for starting to paint on the displacement
+// Input : pView - the 3d view
+// vPoint - the initial click point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptPainter::BeginPaint( CMapView3D *pView, const Vector2D &vPoint )
+{
+ CSculptTool::BeginPaint( pView, vPoint );
+
+ PrepareDispForPainting();
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: main routine called when mouse move has happened to start painting
+// Input : pView - the 3d view
+// vPoint - the mouse point
+// SpatialData - the spatial data ( mostly ignored )
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptPainter::Paint( CMapView3D *pView, const Vector2D &vPoint, SpatialPaintData_t &SpatialData )
+{
+ __super::Paint( pView, vPoint, SpatialData );
+
+ if ( m_bRMBDown )
+ {
+ if ( !m_bAltDown )
+ {
+ DoSizing( vPoint );
+ }
+ }
+ else if ( m_bLMBDown )
+ {
+ if ( !m_ValidPaintingSpot )
+ {
+ if ( !GetStartingSpot( pView, vPoint ) )
+ {
+ return false;
+ }
+ }
+
+ // Setup painting.
+ if ( !PrePaint( pView, vPoint ) )
+ {
+ return false;
+ }
+
+ // Handle painting.
+ if ( !DoPaint( pView, vPoint ) )
+ {
+ return false;
+ }
+
+ // Finish painting.
+ if ( !PostPaint( m_PaintOwner->GetAutoSew() ) )
+ {
+ return false;
+ }
+ }
+
+ // Successful paint operation.
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handles the left mouse button up in the 3d view
+// Input : pView - the 3d view
+// nFlags - the button flags
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptPainter::OnLMouseUp3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ CSculptTool::OnLMouseUp3D( pView, nFlags, vPoint );
+
+ m_InPaintingMode = false;
+
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+ if( pDispMgr )
+ {
+ pDispMgr->PostUndo();
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handles the left mouse button down in the 3d view
+// Input : pView - the 3d view
+// nFlags - the button flags
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptPainter::OnLMouseDown3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ CSculptTool::OnLMouseDown3D( pView, nFlags, vPoint );
+
+ m_InPaintingMode = true;
+
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+ if( pDispMgr )
+ {
+ pDispMgr->PreUndo( "Displacement Modifier" );
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handles the right mouse button up in the 3d view
+// Input : pView - the 3d view
+// nFlags - the button flags
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptPainter::OnRMouseUp3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ CSculptTool::OnRMouseUp3D( pView, nFlags, vPoint );
+
+ m_InSizingMode = false;
+
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+ if( pDispMgr )
+ {
+ pDispMgr->PostUndo();
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handles the right mouse button down in the 3d view
+// Input : pView - the 3d view
+// nFlags - the button flags
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptPainter::OnRMouseDown3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ CSculptTool::OnRMouseDown3D( pView, nFlags, vPoint );
+
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+ if( pDispMgr )
+ {
+ pDispMgr->PreUndo( "Displacement Modifier" );
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handles the mouse move in the 3d view
+// Input : pView - the 3d view
+// nFlags - the button flags
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptPainter::OnMouseMove3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ return CSculptTool::OnMouseMove3D( pView, nFlags, vPoint );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: toggles the sizing mode
+// Input : vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptPainter::DoSizing( const Vector2D &vPoint )
+{
+ if ( !m_InSizingMode )
+ {
+ m_InSizingMode = true;
+ m_StartSizingPoint = vPoint;
+ m_OrigBrushSize = m_BrushSize;
+ }
+ else
+ {
+ m_BrushSize = m_OrigBrushSize + ( vPoint.x - m_StartSizingPoint.x );
+ if ( m_BrushSize < 1.0f )
+ {
+ m_BrushSize = 1.0f;
+ }
+ }
+
+ return true;
+}
+
+
+
+
+
+
+
+
+// CSculptPushOptions dialog
+
+IMPLEMENT_DYNAMIC(CSculptPushOptions, CDialog)
+
+
+//-----------------------------------------------------------------------------
+// Purpose: constructor
+//-----------------------------------------------------------------------------
+CSculptPushOptions::CSculptPushOptions(CWnd* pParent /*=NULL*/) :
+ CDialog(CSculptPushOptions::IDD, pParent),
+ CSculptPainter()
+{
+ m_OffsetMode = OFFSET_MODE_ABSOLUTE;
+ m_NormalMode = NORMAL_MODE_Z;
+ m_DensityMode = DENSITY_MODE_ADDITIVE;
+ m_OffsetDistance = 10.0f;
+ m_OffsetAmount = 1.0f;
+ m_SmoothAmount = 0.2f;
+ m_Direction = 1.0f;
+ m_SelectedNormal.Init( 0.0f, 0.0f, 0.0f );
+
+ m_flFalloffSpot = 0.5f;
+ m_flFalloffEndingValue = 0.0f;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: destructor
+//-----------------------------------------------------------------------------
+CSculptPushOptions::~CSculptPushOptions()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: initializes the dialog
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+BOOL CSculptPushOptions::OnInitDialog( void )
+{
+ char temp[ 1024 ];
+
+ CDialog::OnInitDialog();
+
+ m_OffsetModeControl.InsertString( -1, "Adaptive" );
+ m_OffsetModeControl.InsertString( -1, "Absolute" );
+ m_OffsetModeControl.SetCurSel( m_OffsetMode );
+
+ m_OffsetDistanceControl.EnableWindow( ( m_OffsetMode == OFFSET_MODE_ABSOLUTE ) );
+ m_OffsetAmountControl.EnableWindow( ( m_OffsetMode == OFFSET_MODE_ADAPTIVE ) );
+
+ sprintf( temp, "%g", m_OffsetDistance );
+ m_OffsetDistanceControl.SetWindowText( temp );
+
+ sprintf( temp, "%g%%", m_OffsetAmount * 100.0f );
+ m_OffsetAmountControl.SetWindowText( temp );
+
+ sprintf( temp, "%g%%", m_SmoothAmount * 100.0f );
+ m_SmoothAmountControl.SetWindowText( temp );
+
+ sprintf( temp, "%g%%", m_flFalloffSpot * 100.0f );
+ m_FalloffPositionControl.SetWindowText( temp );
+
+ sprintf( temp, "%g%%", m_flFalloffEndingValue * 100.0f );
+ m_FalloffFinalControl.SetWindowText( temp );
+
+ m_NormalModeControl.InsertString( -1, "Brush Center" );
+ m_NormalModeControl.InsertString( -1, "Screen" );
+ m_NormalModeControl.InsertString( -1, "Screen XY" );
+ m_NormalModeControl.InsertString( -1, "X" );
+ m_NormalModeControl.InsertString( -1, "Y" );
+ m_NormalModeControl.InsertString( -1, "Z" );
+ m_NormalModeControl.InsertString( -1, "Selected" );
+ m_NormalModeControl.SetCurSel( m_NormalMode );
+
+ m_DensityModeControl.InsertString( -1, "Additive" );
+ m_DensityModeControl.InsertString( -1, "Attenuated" );
+ m_DensityModeControl.SetCurSel( m_DensityMode );
+
+ return TRUE;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: prevent the dialog from closing
+//-----------------------------------------------------------------------------
+void CSculptPushOptions::OnOK()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: prevent the dialog from closing
+//-----------------------------------------------------------------------------
+void CSculptPushOptions::OnCancel()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: set up the data exchange for the variables
+// Input : pDX - the data exchange object
+//-----------------------------------------------------------------------------
+void CSculptPushOptions::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ DDX_Control(pDX, IDC_SCULPT_PUSH_OPTION_OFFSET_MODE, m_OffsetModeControl);
+ DDX_Control(pDX, IDC_SCULPT_PUSH_OPTION_OFFSET_DISTANCE, m_OffsetDistanceControl);
+ DDX_Control(pDX, IDC_SCULPT_PUSH_OPTION_OFFSET_AMOUNT, m_OffsetAmountControl);
+ DDX_Control(pDX, IDC_SCULPT_PUSH_OPTION_SMOOTH_AMOUNT, m_SmoothAmountControl);
+ DDX_Control(pDX, IDC_SCULPT_PUSH_OPTION_DENSITY_MODE, m_DensityModeControl);
+ DDX_Control(pDX, IDC_IDC_SCULPT_PUSH_OPTION_NORMAL_MODE, m_NormalModeControl);
+ DDX_Control(pDX, IDC_SCULPT_PUSH_OPTION_FALLOFF_POSITION, m_FalloffPositionControl);
+ DDX_Control(pDX, IDC_SCULPT_PUSH_OPTION_FALLOFF_FINAL, m_FalloffFinalControl);
+}
+
+
+BEGIN_MESSAGE_MAP(CSculptPushOptions, CDialog)
+ ON_CBN_SELCHANGE(IDC_IDC_SCULPT_PUSH_OPTION_NORMAL_MODE, &CSculptPushOptions::OnCbnSelchangeIdcSculptPushOptionNormalMode)
+ ON_CBN_SELCHANGE(IDC_SCULPT_PUSH_OPTION_OFFSET_MODE, &CSculptPushOptions::OnCbnSelchangeSculptPushOptionOffsetMode)
+ ON_EN_CHANGE(IDC_SCULPT_PUSH_OPTION_OFFSET_DISTANCE, &CSculptPushOptions::OnEnChangeSculptPushOptionOffsetDistance)
+ ON_CBN_SELCHANGE(IDC_SCULPT_PUSH_OPTION_DENSITY_MODE, &CSculptPushOptions::OnCbnSelchangeSculptPushOptionDensityMode)
+ ON_EN_KILLFOCUS(IDC_SCULPT_PUSH_OPTION_SMOOTH_AMOUNT, &CSculptPushOptions::OnEnKillfocusSculptPushOptionSmoothAmount)
+ ON_EN_KILLFOCUS(IDC_SCULPT_PUSH_OPTION_OFFSET_AMOUNT, &CSculptPushOptions::OnEnKillfocusSculptPushOptionOffsetAmount)
+ ON_EN_KILLFOCUS(IDC_SCULPT_PUSH_OPTION_FALLOFF_POSITION, &CSculptPushOptions::OnEnKillfocusSculptPushOptionFalloffPosition)
+ ON_EN_KILLFOCUS(IDC_SCULPT_PUSH_OPTION_FALLOFF_FINAL, &CSculptPushOptions::OnEnKillfocusSculptPushOptionFalloffFinal)
+END_MESSAGE_MAP()
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the normal mode of the sculpt operation
+//-----------------------------------------------------------------------------
+void CSculptPushOptions::OnCbnSelchangeIdcSculptPushOptionNormalMode()
+{
+ m_NormalMode = ( NormalMode )m_NormalModeControl.GetCurSel();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the offset mode of the sculpt operation
+//-----------------------------------------------------------------------------
+void CSculptPushOptions::OnCbnSelchangeSculptPushOptionOffsetMode()
+{
+ m_OffsetMode = ( OffsetMode )m_OffsetModeControl.GetCurSel();
+
+ m_OffsetDistanceControl.EnableWindow( ( m_OffsetMode == OFFSET_MODE_ABSOLUTE ) );
+ m_OffsetAmountControl.EnableWindow( ( m_OffsetMode == OFFSET_MODE_ADAPTIVE ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: setup for starting to paint on the displacement
+// Input : pView - the 3d view
+// vPoint - the initial click point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptPushOptions::BeginPaint( CMapView3D *pView, const Vector2D &vPoint )
+{
+ __super::BeginPaint( pView, vPoint );
+
+ if ( m_bCtrlDown )
+ {
+ m_Direction = -1.0f;
+ }
+ else
+ {
+ m_Direction = 1.0f;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: draws the tool in the 3d view
+// Input : pRender - the 3d renderer
+//-----------------------------------------------------------------------------
+void CSculptPushOptions::RenderTool3D( CRender3D *pRender )
+{
+// pRender->DrawText( "mouse", m_MousePoint.x, m_MousePoint.y, 0 );
+// Msg( "%g %g\n", m_MousePoint.x, m_MousePoint.y );
+
+ pRender->PushRenderMode( RENDER_MODE_WIREFRAME );
+
+ if ( m_InSizingMode )
+ { // yellow for sizing mode
+ pRender->BeginClientSpace();
+ pRender->SetDrawColor( 255, 255, 0 );
+ pRender->DrawCircle( Vector( m_StartSizingPoint.x, m_StartSizingPoint.y, 0.0f ), Vector( 0.0f, 0.0f, 1.0f ), m_BrushSize, 32 );
+ if ( m_flFalloffSpot > 0.0f )
+ {
+ pRender->SetDrawColor( 192, 192, 0 );
+ pRender->DrawCircle( Vector( m_StartSizingPoint.x, m_StartSizingPoint.y, 0.0f ), Vector( 0.0f, 0.0f, 1.0f ), m_BrushSize * m_flFalloffSpot, 32 );
+ }
+ pRender->EndClientSpace();
+ }
+ else if ( m_bShiftDown )
+ { // purple for smoothing
+ pRender->SetDrawColor( 255, 0, 255 );
+ pRender->BeginClientSpace();
+ pRender->DrawCircle( Vector( m_MousePoint.x, m_MousePoint.y, 0.0f ), Vector( 0.0f, 0.0f, 1.0f ), m_BrushSize, 32 );
+ pRender->EndClientSpace();
+ }
+ else if ( m_bCtrlDown )
+ { // red for negative sculpting
+ pRender->BeginClientSpace();
+ pRender->SetDrawColor( 255, 0, 0 );
+ pRender->DrawCircle( Vector( m_MousePoint.x, m_MousePoint.y, 0.0f ), Vector( 0.0f, 0.0f, 1.0f ), m_BrushSize, 32 );
+ if ( m_flFalloffSpot > 0.0f )
+ {
+ pRender->SetDrawColor( 192, 0, 0 );
+ pRender->DrawCircle( Vector( m_MousePoint.x, m_MousePoint.y, 0.0f ), Vector( 0.0f, 0.0f, 1.0f ), m_BrushSize * m_flFalloffSpot, 32 );
+ }
+ pRender->EndClientSpace();
+
+ Vector vPaintAxis;
+ GetPaintAxis( pRender->GetCamera(), m_MousePoint, vPaintAxis );
+ DrawDirection( pRender, -vPaintAxis, Color( 255, 255, 255 ), Color( 255, 128, 128 ) );
+ }
+ else
+ { // green for positive sculpting
+ pRender->BeginClientSpace();
+ pRender->SetDrawColor( 0, 255, 0 );
+ pRender->DrawCircle( Vector( m_MousePoint.x, m_MousePoint.y, 0.0f ), Vector( 0.0f, 0.0f, 1.0f ), m_BrushSize, 32 );
+ if ( m_flFalloffSpot > 0.0f )
+ {
+ pRender->SetDrawColor( 0, 192, 0 );
+ pRender->DrawCircle( Vector( m_MousePoint.x, m_MousePoint.y, 0.0f ), Vector( 0.0f, 0.0f, 1.0f ), m_BrushSize * m_flFalloffSpot, 32 );
+ }
+ pRender->EndClientSpace();
+
+ Vector vPaintAxis;
+ GetPaintAxis( pRender->GetCamera(), m_MousePoint, vPaintAxis );
+ DrawDirection( pRender, vPaintAxis, Color( 255, 255, 255 ), Color( 255, 128, 128 ) );
+ }
+
+#if 0
+ FindColissionIntercept( pRender->GetCamera(), m_MousePoint, true, m_CurrentCollisionPoint, m_CurrentCollisionNormal, m_CurrentCollisionIntercept );
+
+ Vector2D RadiusPoint = m_MousePoint;
+ Vector vecStart, vecEnd;
+
+ RadiusPoint.x += m_BrushSize;
+ pRender->GetCamera()->BuildRay( RadiusPoint, vecStart, vecEnd );
+
+ m_CurrentProjectedRadius = CalcDistanceToLine( m_CurrentCollisionPoint, vecStart, vecEnd );
+
+ pRender->RenderWireframeSphere( m_CurrentCollisionPoint, m_CurrentProjectedRadius, 12, 12, 0, 255, 255 );
+#endif
+
+#if 0
+
+ // Get the displacement manager from the active map document.
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+
+ // For each displacement surface is the selection list attempt to paint on it.
+ int nDispCount = pDispMgr->SelectCount();
+ for ( int iDisp = 0; iDisp < nDispCount; iDisp++ )
+ {
+ CMapDisp *pDisp = pDispMgr->GetFromSelect( iDisp );
+ if ( pDisp )
+ {
+ CMapDisp *OrigDisp = NULL;
+ int index = m_OrigMapDisp.Find( pDisp->GetEditHandle() );
+
+ if ( index != m_OrigMapDisp.InvalidIndex() )
+ {
+ OrigDisp = m_OrigMapDisp[ index ];
+ }
+ Vector vPaintPos, vVert;
+
+ int nVertCount = pDisp->GetSize();
+ for ( int iVert = 0; iVert < nVertCount; iVert++ )
+ {
+ if ( IsPointInScreenCircle( pView, pDisp, pOrigDisp, iVert, false ) )
+ {
+ // Get the current vert.
+ pDisp->GetVert( iVert, vVert );
+ }
+ }
+ }
+ }
+#endif
+
+
+ pRender->PopRenderMode();
+
+#if 0
+ if ( !FindColissionIntercept( pRender->GetCamera(), m_MousePoint, true, m_CurrentCollisionPoint, m_CurrentCollisionNormal, m_CurrentCollisionIntercept ) )
+ {
+ return;
+ }
+
+ Vector2D RadiusPoint = m_MousePoint;
+ Vector vecStart, vecEnd;
+
+ RadiusPoint.x += m_BrushSize;
+ pRender->GetCamera()->BuildRay( RadiusPoint, vecStart, vecEnd );
+ m_CurrentProjectedRadius = CalcDistanceToLine( m_CurrentCollisionPoint, vecStart, vecEnd );
+
+ Msg( "Dist = %g at %g,%g,%g\n", m_CurrentProjectedRadius, m_CurrentCollisionPoint.x, m_CurrentCollisionPoint.y, m_CurrentCollisionPoint.z );
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handles the right mouse button down in the 3d view
+// Input : pView - the 3d view
+// nFlags - the button flags
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptPushOptions::OnRMouseDown3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ CSculptTool::OnRMouseDown3D( pView, nFlags, vPoint );
+
+ if ( m_bAltDown )
+ {
+ m_NormalMode = NORMAL_MODE_Z;
+ m_NormalModeControl.SetCurSel( m_NormalMode );
+
+#if 0
+
+ //
+ // 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 true;
+ }
+
+ // trace a line and get the normal -- will get a displacement normal
+ // if one exists
+ CMapFace *pFace = pSolid->GetFace( ulFace );
+ if( !pFace )
+ {
+ return true;
+ }
+
+ Vector vRayStart, vRayEnd;
+ pView->GetCamera()->BuildRay( vPoint, vRayStart, vRayEnd );
+
+ Vector vHitPos, vHitNormal;
+ if( pFace->TraceLine( vHitPos, vHitNormal, vRayStart, vRayEnd ) )
+ {
+ // set the paint direction
+ m_SelectedNormal = vHitNormal;
+
+ m_NormalMode = NORMAL_MODE_SELECTED;
+ m_NormalModeControl.SetCurSel( m_NormalMode );
+ }
+ }
+ }
+#else
+ Vector CollisionPoint, CollisionNormal;
+ float CollisionIntercept;
+
+ if ( FindCollisionIntercept( pView->GetCamera(), vPoint, false, CollisionPoint, CollisionNormal, CollisionIntercept ) )
+ {
+ // set the paint direction
+ m_SelectedNormal = -CollisionNormal;
+
+ m_NormalMode = NORMAL_MODE_SELECTED;
+ m_NormalModeControl.SetCurSel( m_NormalMode );
+ }
+#endif
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the painting direction
+// Input : pCamera - the 3d camera
+// vPoint - the 2d mouse point
+// Output : vPaintAxis - the direction the painting should go
+//-----------------------------------------------------------------------------
+void CSculptPushOptions::GetPaintAxis( CCamera *pCamera, const Vector2D &vPoint, Vector &vPaintAxis )
+{
+ switch( m_NormalMode )
+ {
+ case NORMAL_MODE_SCREEN:
+ pCamera->GetViewForward( vPaintAxis );
+ vPaintAxis = -vPaintAxis;
+ break;
+
+ case NORMAL_MODE_SCREEN_XY:
+ pCamera->GetViewForward( vPaintAxis );
+ vPaintAxis = -vPaintAxis;
+ vPaintAxis.z = 0.f;
+ break;
+
+ case NORMAL_MODE_BRUSH_CENTER:
+ if ( !m_InPaintingMode )
+ {
+ Vector CollisionPoint, CollisionNormal;
+ float CollisionIntercept;
+
+ FindCollisionIntercept( pCamera, vPoint, false, CollisionPoint, CollisionNormal, CollisionIntercept );
+
+ vPaintAxis = -CollisionNormal;
+ }
+ else
+ {
+ vPaintAxis = -m_StartingCollisionNormal;
+ }
+ break;
+
+ case NORMAL_MODE_X:
+ vPaintAxis.Init( 1.0f, 0.0f, 0.0f );
+ break;
+
+ case NORMAL_MODE_Y:
+ vPaintAxis.Init( 0.0f, 1.0f, 0.0f );
+ break;
+
+ case NORMAL_MODE_Z:
+ vPaintAxis.Init( 0.0f, 0.0f, 1.0f );
+ break;
+
+ case NORMAL_MODE_SELECTED:
+ vPaintAxis = m_SelectedNormal;
+ break;
+
+ default:
+ vPaintAxis.Init( 0.0f, 0.0f, 1.0f );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: applies the specific push operation onto the displacement
+// Input : pView - the 3d view
+// vPoint - the mouse point
+// pDisp - the displacement to apply the push to
+// pOrigDisp - the original displacement prior to any adjustments
+//-----------------------------------------------------------------------------
+void CSculptPushOptions::DoPaintOperation( CMapView3D *pView, const Vector2D &vPoint, CMapDisp *pDisp, CMapDisp *pOrigDisp )
+{
+ Vector vPaintPos, vVert, vDirection;
+ float flMaxDistance = 0.0f;
+ float flDistance;
+ float flLengthPercent;
+ Vector vPaintAxis;
+
+ if ( m_bShiftDown )
+ {
+// DoSmoothOperation( pView, vPoint, pDisp, pOrigDisp );
+// m_SpatialData.m_flRadius = 256.0f;
+// m_SpatialData.m_flScalar = 5.0f / m_SmoothAmount;
+
+// m_SpatialData.m_flRadius = m_StartingProjectedRadius * 1.5f;
+ m_SpatialData.m_flRadius = m_CurrentProjectedRadius * 2.0f;
+ m_SpatialData.m_flRadius2 = ( m_SpatialData.m_flRadius * m_SpatialData.m_flRadius );
+ m_SpatialData.m_flOORadius2 = 1.0f / m_SpatialData.m_flRadius2;
+ m_SpatialData.m_flScalar = 10.0f / m_SmoothAmount;
+ m_SpatialData.m_vCenter = m_CurrentCollisionPoint;
+
+ DoPaintSmooth( pView, vPoint, pDisp, pOrigDisp );
+ return;
+ }
+
+ GetPaintAxis( pView->GetCamera(), vPoint, vPaintAxis );
+
+ vDirection = vPaintAxis * m_Direction;
+
+ switch( m_OffsetMode )
+ {
+ case OFFSET_MODE_ADAPTIVE:
+ flMaxDistance = m_StartingProjectedRadius * m_OffsetAmount;
+ break;
+ case OFFSET_MODE_ABSOLUTE:
+ flMaxDistance = m_OffsetDistance;
+ break;
+ }
+
+ int nVertCount = pDisp->GetSize();
+ for ( int iVert = 0; iVert < nVertCount; iVert++ )
+ {
+ if ( IsPointInScreenCircle( pView, pDisp, pOrigDisp, iVert, true, false, &flLengthPercent ) )
+ {
+ pDisp->GetVert( iVert, vVert );
+
+ if ( flLengthPercent > m_flFalloffSpot )
+ {
+ flLengthPercent = ( flLengthPercent - m_flFalloffSpot ) / ( 1.0f - m_flFalloffSpot );
+ flLengthPercent = 1.0 - flLengthPercent;
+ flDistance = ( ( 1.0f - m_flFalloffEndingValue ) * flLengthPercent * flMaxDistance ) + ( m_flFalloffEndingValue * flMaxDistance );
+ }
+ else
+ {
+ flDistance = flMaxDistance;
+ }
+
+ if ( flDistance == 0.0f )
+ {
+ continue;
+ }
+
+ switch( m_DensityMode )
+ {
+ case DENSITY_MODE_ADDITIVE:
+ VectorScale( vDirection, flDistance, vPaintPos );
+ VectorAdd( vPaintPos, vVert, vPaintPos );
+ break;
+
+ case DENSITY_MODE_ATTENUATED:
+ VectorScale( vDirection, flDistance, vPaintPos );
+ VectorAdd( vPaintPos, vVert, vPaintPos );
+
+ if ( pOrigDisp )
+ {
+ Vector vOrigVert, vDiff;
+ float Length;
+
+ pOrigDisp->GetVert( iVert, vOrigVert );
+ vDiff = ( vPaintPos - vOrigVert );
+ Length = vDiff.Length() / flMaxDistance;
+ if ( Length > 1.0f )
+ {
+ Length = 1.0f;
+ }
+
+ vPaintPos = vOrigVert + ( Length * vDirection * flMaxDistance );
+ }
+ break;
+ }
+
+ AddToUndo( &pDisp );
+ pDisp->Paint_SetValue( iVert, vPaintPos );
+ }
+ }
+}
+
+
+#if 0
+
+typedef enum
+{
+ DISP_DIR_LEFT_TO_RIGHT = 0, // adjoining displacement is to the left
+ DISP_DIR_TOP_TO_BOTTOM = 1, // adjoining displacement is to the top
+ DISP_DIR_RIGHT_TO_LEFT = 2, // adjoining displacement is to the right
+ DISP_DIR_BOTTOM_TO_TOP = 3, // adjoining displacement is to the bottom
+} DispDirections;
+
+typedef enum
+{
+ MOVE_DIR_RIGHT = 0,
+ MOVE_DIR_UP,
+ MOVE_DIR_LEFT,
+ MOVE_DIR_DOWN,
+
+ MOVE_DIR_MAX
+} MoveDirections;
+
+
+class CDispGrid
+{
+public:
+ CDispGrid( CMapDisp *pDisp, bool DoPopulate = false, int GridExpand = 2 );
+ ~CDispGrid( );
+
+ void Populate( CMapDisp *pDisp );
+ bool GetPosition( int x, int y, int OffsetX, int OffsetY, Vector &Position );
+ bool GetFlatPosition( int x, int y, int OffsetX, int OffsetY, Vector &FlatPosition );
+
+ void SetPosition( int x, int y, Vector &NewPosition );
+ void UpdatePositions( void );
+
+ void CalcSpringForce( int x, int y, int OffsetX, int OffsetY, float Ks, Vector &SpringForce );
+
+
+private:
+ typedef struct SDispPoint
+ {
+ bool m_IsSet;
+ int m_DispPos;
+ Vector m_Position, m_UpdatePosition;
+ Vector m_FlatPosition;
+ } TDispPoint;
+
+ int m_Width, m_Height;
+ int m_GridWidth, m_GridHeight;
+ int m_GridExpand;
+ TDispPoint *m_Grid;
+
+ void PopulateUp( CMapDisp *pDisp );
+ void PopulateDown( CMapDisp *pDisp );
+ void PopulateRight( CMapDisp *pDisp );
+ void PopulateLeft( CMapDisp *pDisp );
+};
+
+CDispGrid::CDispGrid( CMapDisp *pDisp, bool DoPopulate, int GridExpand )
+{
+ m_GridExpand = GridExpand;
+ m_Width = pDisp->GetWidth();
+ m_Height = pDisp->GetHeight();
+ m_GridWidth = m_Width + ( GridExpand * 2 );
+ m_GridHeight = m_Height + ( GridExpand * 2 );
+
+ m_Grid = new TDispPoint[ m_GridWidth * m_GridHeight ];
+ for( int i = 0; i < m_GridWidth * m_GridHeight; i++ )
+ {
+ m_Grid[ i ].m_IsSet = false;
+ }
+
+ if ( DoPopulate )
+ {
+ Populate( pDisp );
+ }
+}
+
+CDispGrid::~CDispGrid( )
+{
+ delete [] m_Grid;
+}
+
+void CDispGrid::PopulateUp( CMapDisp *pDisp )
+{
+ EditDispHandle_t handle;
+ int orient;
+
+ pDisp->GetEdgeNeighbor( DISP_DIR_TOP_TO_BOTTOM, handle, orient );
+ if ( handle == EDITDISPHANDLE_INVALID )
+ {
+ return;
+ }
+ pDisp = EditDispMgr()->GetDisp( handle );
+
+ if ( pDisp->GetWidth() != m_Width || pDisp->GetHeight() != m_Height )
+ { // don't support ones which aren't of the same subdivision
+ return;
+ }
+
+ if ( orient != MOVE_DIR_DOWN )
+ { // don't support rotation for now
+ return;
+ }
+
+
+ for( int x = 0; x < m_Width; x++ )
+ {
+ for( int y = 0; y < m_GridExpand; y++ )
+ {
+ int GridPos = ( ( m_GridHeight - y - 1 ) * m_GridWidth ) + ( x + m_GridExpand );
+
+ m_Grid[ GridPos ].m_DispPos = ( ( m_GridExpand - y ) * m_Width ) + x; // don't do inner row, as that is sewed
+ pDisp->GetVert( m_Grid[ GridPos ].m_DispPos, m_Grid[ GridPos ].m_Position );
+ m_Grid[ GridPos ].m_UpdatePosition = m_Grid[ GridPos ].m_Position;
+ pDisp->GetFlatVert( m_Grid[ GridPos ].m_DispPos, m_Grid[ GridPos ].m_FlatPosition );
+ m_Grid[ GridPos ].m_IsSet = true;
+ }
+ }
+}
+
+void CDispGrid::PopulateDown( CMapDisp *pDisp )
+{
+ EditDispHandle_t handle;
+ int orient;
+
+ pDisp->GetEdgeNeighbor( DISP_DIR_BOTTOM_TO_TOP, handle, orient );
+ if ( handle == EDITDISPHANDLE_INVALID )
+ {
+ return;
+ }
+ pDisp = EditDispMgr()->GetDisp( handle );
+
+ if ( pDisp->GetWidth() != m_Width || pDisp->GetHeight() != m_Height )
+ { // don't support ones which aren't of the same subdivision
+ return;
+ }
+
+ if ( orient != MOVE_DIR_UP )
+ { // don't support rotation for now
+ return;
+ }
+
+
+ for( int x = 0; x < m_Width; x++ )
+ {
+ for( int y = 0; y < m_GridExpand; y++ )
+ {
+ int GridPos = ( ( y ) * m_GridWidth ) + ( x + m_GridExpand );
+
+ m_Grid[ GridPos ].m_DispPos = ( ( m_Height - m_GridExpand + y - 1 ) * m_Width ) + x; // don't do inner row, as that is sewed
+ pDisp->GetVert( m_Grid[ GridPos ].m_DispPos, m_Grid[ GridPos ].m_Position );
+ m_Grid[ GridPos ].m_UpdatePosition = m_Grid[ GridPos ].m_Position;
+ pDisp->GetFlatVert( m_Grid[ GridPos ].m_DispPos, m_Grid[ GridPos ].m_FlatPosition );
+ m_Grid[ GridPos ].m_IsSet = true;
+ }
+ }
+}
+
+void CDispGrid::PopulateRight( CMapDisp *pDisp )
+{
+ EditDispHandle_t handle;
+ int orient;
+
+ pDisp->GetEdgeNeighbor( DISP_DIR_RIGHT_TO_LEFT, handle, orient );
+ if ( handle == EDITDISPHANDLE_INVALID )
+ {
+ return;
+ }
+ pDisp = EditDispMgr()->GetDisp( handle );
+
+ if ( pDisp->GetWidth() != m_Width || pDisp->GetHeight() != m_Height )
+ { // don't support ones which aren't of the same subdivision
+ return;
+ }
+
+ if ( orient != MOVE_DIR_RIGHT )
+ { // don't support rotation for now
+ return;
+ }
+
+
+ for( int x = 0; x < m_GridExpand; x++ )
+ {
+ for( int y = 0; y < m_Height; y++ )
+ {
+ int GridPos = ( ( y + m_GridExpand ) * m_GridWidth ) + ( x + m_GridExpand + m_Width );
+
+ m_Grid[ GridPos ].m_DispPos = ( ( y ) * m_Width ) + x + 1; // don't do inner row, as that is sewed
+ pDisp->GetVert( m_Grid[ GridPos ].m_DispPos, m_Grid[ GridPos ].m_Position );
+ m_Grid[ GridPos ].m_UpdatePosition = m_Grid[ GridPos ].m_Position;
+ pDisp->GetFlatVert( m_Grid[ GridPos ].m_DispPos, m_Grid[ GridPos ].m_FlatPosition );
+ m_Grid[ GridPos ].m_IsSet = true;
+ }
+ }
+}
+
+void CDispGrid::PopulateLeft( CMapDisp *pDisp )
+{
+ EditDispHandle_t handle;
+ int orient;
+
+ pDisp->GetEdgeNeighbor( DISP_DIR_LEFT_TO_RIGHT, handle, orient );
+ if ( handle == EDITDISPHANDLE_INVALID )
+ {
+ return;
+ }
+ pDisp = EditDispMgr()->GetDisp( handle );
+
+ if ( pDisp->GetWidth() != m_Width || pDisp->GetHeight() != m_Height )
+ { // don't support ones which aren't of the same subdivision
+ return;
+ }
+
+ if ( orient != MOVE_DIR_LEFT )
+ { // don't support rotation for now
+ return;
+ }
+
+
+ for( int x = 0; x < m_GridExpand; x++ )
+ {
+ for( int y = 0; y < m_Height; y++ )
+ {
+ int GridPos = ( ( y + m_GridExpand ) * m_GridWidth ) + ( x );
+
+ m_Grid[ GridPos ].m_DispPos = ( ( y ) * m_Width ) + ( m_Width - m_GridExpand + x - 1 ); // don't do inner row, as that is sewed
+ pDisp->GetVert( m_Grid[ GridPos ].m_DispPos, m_Grid[ GridPos ].m_Position );
+ m_Grid[ GridPos ].m_UpdatePosition = m_Grid[ GridPos ].m_Position;
+ pDisp->GetFlatVert( m_Grid[ GridPos ].m_DispPos, m_Grid[ GridPos ].m_FlatPosition );
+ m_Grid[ GridPos ].m_IsSet = true;
+ }
+ }
+}
+
+void CDispGrid::Populate( CMapDisp *pDisp )
+{
+ for( int x = 0; x < m_Width; x++ )
+ {
+ for( int y = 0; y < m_Height; y++ )
+ {
+ int GridPos = ( ( y + m_GridExpand ) * m_GridWidth ) + ( x + m_GridExpand );
+
+ m_Grid[ GridPos ].m_DispPos = ( y * m_Width ) + x;
+ pDisp->GetVert( m_Grid[ GridPos ].m_DispPos, m_Grid[ GridPos ].m_Position );
+ m_Grid[ GridPos ].m_UpdatePosition = m_Grid[ GridPos ].m_Position;
+ pDisp->GetFlatVert( m_Grid[ GridPos ].m_DispPos, m_Grid[ GridPos ].m_FlatPosition );
+ m_Grid[ GridPos ].m_IsSet = true;
+ }
+ }
+
+ PopulateUp( pDisp );
+ PopulateDown( pDisp );
+ PopulateRight( pDisp );
+ PopulateLeft( pDisp );
+}
+
+bool CDispGrid::GetPosition( int x, int y, int OffsetX, int OffsetY, Vector &Position )
+{
+ x += OffsetX;
+ y += OffsetY;
+
+ int GridPos = ( ( y + m_GridExpand ) * m_GridWidth ) + ( x + m_GridExpand );
+
+ if ( !m_Grid[ GridPos ].m_IsSet )
+ {
+ return false;
+ }
+
+ Position = m_Grid[ GridPos ].m_Position;
+
+ return true;
+}
+
+bool CDispGrid::GetFlatPosition( int x, int y, int OffsetX, int OffsetY, Vector &FlatPosition )
+{
+ x += OffsetX;
+ y += OffsetY;
+
+ int GridPos = ( ( y + m_GridExpand ) * m_GridWidth ) + ( x + m_GridExpand );
+
+ if ( !m_Grid[ GridPos ].m_IsSet )
+ {
+ return false;
+ }
+
+ FlatPosition = m_Grid[ GridPos ].m_FlatPosition;
+
+ return true;
+}
+
+void CDispGrid::SetPosition( int x, int y, Vector &NewPosition )
+{
+ int GridPos = ( ( y + m_GridExpand ) * m_GridWidth ) + ( x + m_GridExpand );
+
+ if ( !m_Grid[ GridPos ].m_IsSet )
+ {
+ return;
+ }
+
+ m_Grid[ GridPos ].m_UpdatePosition = NewPosition;
+}
+
+void CDispGrid::UpdatePositions( void )
+{
+ for( int i = 0; i < m_GridWidth * m_GridHeight; i++ )
+ {
+ m_Grid[ i ].m_Position = m_Grid[ i ].m_UpdatePosition ;
+ }
+}
+
+void CDispGrid::CalcSpringForce( int x, int y, int OffsetX, int OffsetY, float Ks, Vector &SpringForce )
+{
+ Vector currentP1, currentP2;
+ Vector restP1, restP2;
+ Vector currentDelta, restDelta;
+ float currentDistance, restDistance;
+
+ SpringForce.Init();
+
+ if ( !GetPosition( x, y, 0, 0, currentP1 ) )
+ {
+ return;
+ }
+ if ( !GetPosition( x, y, OffsetX, OffsetY, currentP2 ) )
+ {
+ return;
+ }
+ if ( !GetFlatPosition( x, y, 0, 0, restP1 ) )
+ {
+ return;
+ }
+ if ( !GetFlatPosition( x, y, OffsetX, OffsetY, restP2 ) )
+ {
+ return;
+ }
+
+ currentDelta = currentP1 - currentP2;
+ currentDistance = currentDelta.Length();
+
+ if ( currentDistance == 0.0f )
+ {
+ return;
+ }
+
+ restDelta = restP1 - restP2;
+ restDistance = restDelta.Length();
+
+ float Hterm = (currentDistance - restDistance) * Ks;
+
+ // VectorDifference(&p1->v,&p2->v,&deltaV); // Delta Velocity Vector
+ // Dterm = (DotProduct(&deltaV,&deltaP) * spring->Kd) / dist; // Damping Term
+ float Dterm = 0.0f;
+
+
+ SpringForce = currentDelta * ( 1.0f / currentDistance );
+ SpringForce = SpringForce * -(Hterm + Dterm);
+
+
+ //VectorSum(&p1->f,&springForce,&p1->f); // Apply to Particle 1
+ //VectorDifference(&p2->f,&springForce,&p2->f); // - Force on Particle 2
+}
+
+
+void CSculptPushOptions::DoSmoothOperation( CMapView3D *pView, const Vector2D &vPoint, CMapDisp *pDisp, CMapDisp *pOrigDisp )
+{
+ Vector SpringForce;
+ int width = pDisp->GetWidth();
+ int height = pDisp->GetHeight();
+ Vector *Forces = ( Vector * )_alloca( sizeof( *Forces ) * width * height );
+ bool *DoCalc = ( bool * )_alloca( sizeof( *DoCalc ) * width * height );
+
+ const float SPRING_CONSTANT = 0.02f;
+ const float SPRING_CONSTANT_TO_NORMAL = 0.4f;
+
+ Vector SurfaceNormal;
+
+ pDisp->GetSurfNormal( SurfaceNormal );
+
+
+ for( int x = 0; x < width; x++ )
+ {
+ for( int y = 0; y < height; y++ )
+ {
+ int pVert = ( x * width ) + y;
+ Vector pos, vTestVert;
+
+ pDisp->GetVert( pVert, pos );
+
+ if ( pOrigDisp && 0 )
+ {
+ pOrigDisp->GetVert( pVert, vTestVert );
+ }
+ else
+ {
+ vTestVert = pos;
+ }
+
+ Vector2D ViewVert;
+ pView->GetCamera()->WorldToView( vTestVert, ViewVert );
+
+ Vector2D Offset = ViewVert - m_MousePoint;
+ float Length = Offset.Length();
+ if ( Length <= m_BrushSize || 0 )
+ {
+ DoCalc[ pVert ] = true;
+ }
+ else
+ {
+ DoCalc[ pVert ] = false;
+ }
+ }
+ }
+
+#if 0
+ EditDispHandle_t handle;
+ int orient;
+ for( int i = 0; i < 4; i++ )
+ {
+ pDisp->GetEdgeNeighbor( i, handle, orient );
+ if ( handle != EDITDISPHANDLE_INVALID )
+ {
+ Msg( "Handle at %d orient %d\n", i, orient );
+ }
+ }
+
+ int x = 0;
+ int y = 0;
+ CMapDisp *pNextDisp = pDisp;
+ Vector Vert;
+ Vector FlatVert;
+
+ while( 1 )
+ {
+ if ( !GetAdjoiningPoint( x, y, MOVE_DIR_UP, 1, pNextDisp, Vert, FlatVert ) || pDisp != pNextDisp )
+ {
+ break;
+ }
+
+ y++;
+ }
+
+ return;
+#endif
+
+ CDispGrid DispGrid( pDisp, true );
+
+ const float StepAmount = 1.0f;
+
+ float CurrentSmooth = m_SmoothAmount;
+ while( CurrentSmooth > 0.0f )
+ {
+ float SpringAmount;
+ float SpringToNormalAmount;
+ if ( CurrentSmooth > StepAmount )
+ {
+ SpringAmount = SPRING_CONSTANT * StepAmount;
+ SpringToNormalAmount = SPRING_CONSTANT_TO_NORMAL * StepAmount;
+ }
+ else
+ {
+ SpringAmount = SPRING_CONSTANT * CurrentSmooth;
+ SpringToNormalAmount = SPRING_CONSTANT_TO_NORMAL * CurrentSmooth;
+ }
+ CurrentSmooth -= StepAmount;
+
+ for( int x = 0; x < width; x++ )
+ {
+ for( int y = 0; y < height; y++ )
+ {
+ int pVert = ( y * width ) + x;
+
+ if ( !DoCalc[ pVert ] )
+ {
+ continue;
+ }
+
+ Forces[ pVert ].Init();
+
+ // structural springs
+ DispGrid.CalcSpringForce( x, y, 1, 0, SpringAmount, SpringForce );
+ Forces[ pVert ] += SpringForce;
+
+ DispGrid.CalcSpringForce( x, y, -1, 0, SpringAmount, SpringForce );
+ Forces[ pVert ] += SpringForce;
+
+ DispGrid.CalcSpringForce( x, y, 0, 1, SpringAmount, SpringForce );
+ Forces[ pVert ] += SpringForce;
+
+ DispGrid.CalcSpringForce( x, y, 0, -1, SpringAmount, SpringForce );
+ Forces[ pVert ] += SpringForce;
+
+
+ // shear springs
+ DispGrid.CalcSpringForce( x, y, 1, 1, SpringAmount, SpringForce );
+ Forces[ pVert ] += SpringForce;
+
+ DispGrid.CalcSpringForce( x, y, -1, 1, SpringAmount, SpringForce );
+ Forces[ pVert ] += SpringForce;
+
+ DispGrid.CalcSpringForce( x, y, 1, -1, SpringAmount, SpringForce );
+ Forces[ pVert ] += SpringForce;
+
+ DispGrid.CalcSpringForce( x, y, -1, -1, SpringAmount, SpringForce );
+ Forces[ pVert ] += SpringForce;
+
+ // bend springs
+ DispGrid.CalcSpringForce( x, y, 2, 0, SpringAmount, SpringForce );
+ Forces[ pVert ] += SpringForce;
+
+ DispGrid.CalcSpringForce( x, y, -2, 0, SpringAmount, SpringForce );
+ Forces[ pVert ] += SpringForce;
+
+ DispGrid.CalcSpringForce( x, y, 0, 2, SpringAmount, SpringForce );
+ Forces[ pVert ] += SpringForce;
+
+ DispGrid.CalcSpringForce( x, y, 0, -2, SpringAmount, SpringForce );
+ Forces[ pVert ] += SpringForce;
+
+ Vector Vert, FlatVert, FlatVertExtended, ClosestPoint;
+
+ DispGrid.GetPosition( x, y, 0, 0, Vert );
+ DispGrid.GetFlatPosition( x, y, 0, 0, FlatVert );
+
+ FlatVertExtended = FlatVert + ( SurfaceNormal * 10.0f );
+ CalcClosestPointOnLine( Vert, FlatVert, FlatVertExtended, ClosestPoint );
+ Vector Difference = ( Vert - ClosestPoint );
+ float Distance = Difference.Length();
+
+ if ( Distance > 0.0f )
+ {
+ float Hterm = Distance * SpringToNormalAmount;
+ float Dterm = 0.0f;
+
+ SpringForce = ( Difference ) * ( 1.0f / Distance );
+ SpringForce = SpringForce * -(Hterm + Dterm);
+ Forces[ pVert ] += SpringForce;
+ }
+
+ Vector pos;
+
+ DispGrid.GetPosition( x, y, 0, 0, pos );
+ pos += Forces[ pVert ];
+
+ AddToUndo( &pDisp );
+ pDisp->Paint_SetValue( pVert, pos );
+
+ DispGrid.SetPosition( x, y, pos );
+ }
+ }
+ DispGrid.UpdatePositions();
+ }
+}
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the offset distance
+//-----------------------------------------------------------------------------
+void CSculptPushOptions::OnEnChangeSculptPushOptionOffsetDistance()
+{
+ char temp[ 1024 ];
+
+ m_OffsetDistanceControl.GetWindowText( temp, sizeof( temp ) );
+ m_OffsetDistance = atof( temp );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the density mode
+//-----------------------------------------------------------------------------
+void CSculptPushOptions::OnCbnSelchangeSculptPushOptionDensityMode()
+{
+ m_DensityMode = ( DensityMode )m_DensityModeControl.GetCurSel();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the smooth amount
+//-----------------------------------------------------------------------------
+void CSculptPushOptions::OnEnKillfocusSculptPushOptionSmoothAmount()
+{
+ char temp[ 1024 ], t2[ 1024 ];
+
+ m_SmoothAmountControl.GetWindowText( temp, sizeof( temp ) );
+ sscanf( temp, "%f%%", &m_SmoothAmount );
+ m_SmoothAmount /= 100.0f;
+
+ if ( m_SmoothAmount <= 0.0f )
+ {
+ m_SmoothAmount = 0.2f;
+ }
+
+ sprintf( t2, "%g%%", m_SmoothAmount * 100.0f );
+
+ if ( strcmpi( temp, t2 ) != 0 )
+ {
+ m_SmoothAmountControl.SetWindowText( t2 );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the offset amount
+//-----------------------------------------------------------------------------
+void CSculptPushOptions::OnEnKillfocusSculptPushOptionOffsetAmount()
+{
+ char temp[ 1024 ], t2[ 1024 ];
+
+ m_OffsetAmountControl.GetWindowText( temp, sizeof( temp ) );
+ sscanf( temp, "%f%%", &m_OffsetAmount );
+ m_OffsetAmount /= 100.0f;
+
+ if ( m_OffsetAmount <= 0.0f )
+ {
+ m_OffsetAmount = 1.0f;
+ }
+
+ sprintf( t2, "%g%%", m_OffsetAmount * 100.0f );
+
+ if ( strcmpi( temp, t2 ) != 0 )
+ {
+ m_OffsetAmountControl.SetWindowText( t2 );
+ }
+}
+
+void CSculptPushOptions::OnEnKillfocusSculptPushOptionFalloffPosition()
+{
+ char temp[ 1024 ], t2[ 1024 ];
+
+ m_FalloffPositionControl.GetWindowText( temp, sizeof( temp ) );
+ sscanf( temp, "%f%%", &m_flFalloffSpot );
+ m_flFalloffSpot /= 100.0f;
+
+ if ( m_flFalloffSpot <= 0.0f )
+ {
+ m_flFalloffSpot = 0.0f;
+ }
+
+ if ( m_flFalloffSpot > 1.0f )
+ {
+ m_flFalloffSpot = 1.0f;
+ }
+
+ sprintf( t2, "%g%%", m_flFalloffSpot * 100.0f );
+
+ if ( strcmpi( temp, t2 ) != 0 )
+ {
+ m_FalloffPositionControl.SetWindowText( t2 );
+ }
+}
+
+void CSculptPushOptions::OnEnKillfocusSculptPushOptionFalloffFinal()
+{
+ char temp[ 1024 ], t2[ 1024 ];
+
+ m_FalloffFinalControl.GetWindowText( temp, sizeof( temp ) );
+ sscanf( temp, "%f%%", &m_flFalloffEndingValue);
+ m_flFalloffEndingValue /= 100.0f;
+
+ if ( m_flFalloffEndingValue <= 0.0f )
+ {
+ m_flFalloffEndingValue = 0.0f;
+ }
+
+ if ( m_flFalloffEndingValue > 1.0f )
+ {
+ m_flFalloffEndingValue = 1.0f;
+ }
+
+ sprintf( t2, "%g%%", m_flFalloffEndingValue * 100.0f );
+
+ if ( strcmpi( temp, t2 ) != 0 )
+ {
+ m_FalloffFinalControl.SetWindowText( t2 );
+ }
+}
+
+
+
+
+
+
+// CSculptCarveOptions dialog
+
+IMPLEMENT_DYNAMIC(CSculptCarveOptions, CDialog)
+
+
+//-----------------------------------------------------------------------------
+// Purpose: constructor
+//-----------------------------------------------------------------------------
+CSculptCarveOptions::CSculptCarveOptions(CWnd* pParent /*=NULL*/) :
+ CDialog(CSculptCarveOptions::IDD, pParent),
+ CSculptPainter()
+{
+ m_OffsetMode = OFFSET_MODE_ABSOLUTE;
+ m_NormalMode = NORMAL_MODE_Z;
+ m_DensityMode = DENSITY_MODE_ADDITIVE;
+ m_OffsetDistance = 10.0f;
+ m_OffsetAmount = 1.0f;
+ m_SmoothAmount = 0.2f;
+ m_Direction = 1.0f;
+ m_SelectedNormal.Init( 0.0f, 0.0f, 0.0f );
+ m_BrushLocation = -1;
+ m_StartLine.Init( -1.0f, -1.0f );
+ m_EndLine.Init( -1.0f, -1.0f );
+
+ for( int i = 0; i < MAX_SCULPT_SIZE; i++ )
+ {
+ m_BrushPoints[ i ] = ( i / ( float )MAX_SCULPT_SIZE ); // 0.0f;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: destructor
+//-----------------------------------------------------------------------------
+CSculptCarveOptions::~CSculptCarveOptions()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: initializes the dialog
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+BOOL CSculptCarveOptions::OnInitDialog( )
+{
+ char temp[ 1024 ];
+
+ CDialog::OnInitDialog();
+
+ m_OffsetModeControl.InsertString( -1, "Adaptive" );
+ m_OffsetModeControl.InsertString( -1, "Absolute" );
+ m_OffsetModeControl.SetCurSel( m_OffsetMode );
+
+ m_OffsetDistanceControl.EnableWindow( ( m_OffsetMode == OFFSET_MODE_ABSOLUTE ) );
+ m_OffsetAmountControl.EnableWindow( ( m_OffsetMode == OFFSET_MODE_ADAPTIVE ) );
+
+ sprintf( temp, "%g", m_OffsetDistance );
+ m_OffsetDistanceControl.SetWindowText( temp );
+
+ sprintf( temp, "%g%%", m_OffsetAmount * 100.0f );
+ m_OffsetAmountControl.SetWindowText( temp );
+
+ sprintf( temp, "%g%%", m_SmoothAmount * 100.0f );
+ m_SmoothAmountControl.SetWindowText( temp );
+
+ m_NormalModeControl.InsertString( -1, "Brush Center" );
+ m_NormalModeControl.InsertString( -1, "Screen" );
+ m_NormalModeControl.InsertString( -1, "Screen XY" );
+ m_NormalModeControl.InsertString( -1, "X" );
+ m_NormalModeControl.InsertString( -1, "Y" );
+ m_NormalModeControl.InsertString( -1, "Z" );
+ m_NormalModeControl.InsertString( -1, "Selected" );
+ m_NormalModeControl.SetCurSel( m_NormalMode );
+
+ m_DensityModeControl.InsertString( -1, "Additive" );
+ m_DensityModeControl.InsertString( -1, "Attenuated" );
+ m_DensityModeControl.SetCurSel( m_DensityMode );
+
+ return TRUE;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: prevent the dialog from closing
+//-----------------------------------------------------------------------------
+void CSculptCarveOptions::OnOK( )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: prevent the dialog from closing
+//-----------------------------------------------------------------------------
+void CSculptCarveOptions::OnCancel( )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: set up the data exchange for the variables
+// Input : pDX - the data exchange object
+//-----------------------------------------------------------------------------
+void CSculptCarveOptions::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ DDX_Control(pDX, IDC_SCULPT_PUSH_OPTION_OFFSET_MODE, m_OffsetModeControl);
+ DDX_Control(pDX, IDC_SCULPT_PUSH_OPTION_OFFSET_DISTANCE, m_OffsetDistanceControl);
+ DDX_Control(pDX, IDC_SCULPT_PUSH_OPTION_OFFSET_AMOUNT, m_OffsetAmountControl);
+ DDX_Control(pDX, IDC_SCULPT_PUSH_OPTION_SMOOTH_AMOUNT, m_SmoothAmountControl);
+ DDX_Control(pDX, IDC_SCULPT_PUSH_OPTION_DENSITY_MODE, m_DensityModeControl);
+ DDX_Control(pDX, IDC_IDC_SCULPT_PUSH_OPTION_NORMAL_MODE, m_NormalModeControl);
+ DDX_Control(pDX, IDC_CARVE_BRUSH, m_CarveBrushControl);
+}
+
+
+BEGIN_MESSAGE_MAP(CSculptCarveOptions, CDialog)
+ ON_CBN_SELCHANGE(IDC_IDC_SCULPT_PUSH_OPTION_NORMAL_MODE, &CSculptCarveOptions::OnCbnSelchangeIdcSculptPushOptionNormalMode)
+ ON_CBN_SELCHANGE(IDC_SCULPT_PUSH_OPTION_OFFSET_MODE, &CSculptCarveOptions::OnCbnSelchangeSculptPushOptionOffsetMode)
+ ON_EN_CHANGE(IDC_SCULPT_PUSH_OPTION_OFFSET_DISTANCE, &CSculptCarveOptions::OnEnChangeSculptPushOptionOffsetDistance)
+ ON_CBN_SELCHANGE(IDC_SCULPT_PUSH_OPTION_DENSITY_MODE, &CSculptCarveOptions::OnCbnSelchangeSculptPushOptionDensityMode)
+ ON_EN_KILLFOCUS(IDC_SCULPT_PUSH_OPTION_SMOOTH_AMOUNT, &CSculptCarveOptions::OnEnKillfocusSculptPushOptionSmoothAmount)
+ ON_EN_KILLFOCUS(IDC_SCULPT_PUSH_OPTION_OFFSET_AMOUNT, &CSculptCarveOptions::OnEnKillfocusSculptPushOptionOffsetAmount)
+
+ ON_WM_PAINT()
+ ON_WM_LBUTTONDOWN()
+ ON_WM_LBUTTONUP()
+ ON_WM_MOUSEMOVE()
+END_MESSAGE_MAP()
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the normal mode
+//-----------------------------------------------------------------------------
+void CSculptCarveOptions::OnCbnSelchangeIdcSculptPushOptionNormalMode()
+{
+ m_NormalMode = ( NormalMode )m_NormalModeControl.GetCurSel();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the offset mode
+//-----------------------------------------------------------------------------
+void CSculptCarveOptions::OnCbnSelchangeSculptPushOptionOffsetMode()
+{
+ m_OffsetMode = ( OffsetMode )m_OffsetModeControl.GetCurSel();
+
+ m_OffsetDistanceControl.EnableWindow( ( m_OffsetMode == OFFSET_MODE_ABSOLUTE ) );
+ m_OffsetAmountControl.EnableWindow( ( m_OffsetMode == OFFSET_MODE_ADAPTIVE ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: setup for starting to paint on the displacement
+// Input : pView - the 3d view
+// vPoint - the initial click point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptCarveOptions::BeginPaint( CMapView3D *pView, const Vector2D &vPoint )
+{
+ __super::BeginPaint( pView, vPoint );
+
+ if ( m_bCtrlDown )
+ {
+ m_Direction = -1.0f;
+ }
+ else
+ {
+ m_Direction = 1.0f;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: calculates the normal / direction of the drawing line
+// Input : nPointIndex - which point to factor from
+// Output : returns true if we found a valid normal
+// vNormal - the normal we found
+//-----------------------------------------------------------------------------
+#if 0
+bool CSculptCarveOptions::CalculatePointNormal( int nPointIndex, Vector2D &vNormal )
+{
+ float count = 0.0;
+ Vector2D vAverage( 0.0f, 0.0f );
+ const int max_backsize = 3;
+
+ // keep going back from the current point until you get a total distance
+ for( int j = 0; j < max_backsize; j++ )
+ {
+ int index = ( nPointIndex - max_backsize + j );
+ if ( index < 0 )
+ {
+ continue;
+ }
+ int index2 = nPointIndex;
+
+ Vector2D vDiff( m_DrawPoints[ index2 ].x - m_DrawPoints[ index ].x, m_DrawPoints[ index2 ].y - m_DrawPoints[ index ].y );
+ float Length = Vector2DNormalize( vDiff );
+
+ if ( Length == 0.0f )
+ {
+ continue;
+ }
+
+ float factor = ( ( j + 1 ) * 100 ); // * Length; // * 8 * Length;
+ vAverage += ( vDiff * factor );
+ count += factor;
+ }
+
+ if ( count > 0.0f )
+ {
+ vAverage /= count;
+ Vector2DNormalize( vAverage );
+
+ vNormal = vAverage;
+ return true;
+ }
+
+ return false;
+}
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Purpose: calculates the normal / direction of the drawing line
+// Input : nPointIndex - which point to factor from
+// Output : returns true if we found a valid normal
+// vNormal - the normal we found
+//-----------------------------------------------------------------------------
+bool CSculptCarveOptions::CalculateQueuePoint( Vector2D &vPoint, Vector2D &vNormal )
+{
+ float count = 0.0;
+ Vector2D vAverage( 0.0f, 0.0f );
+ const float fMaxLength = 40.0f;
+ float fTotalLength = 0.0f;
+ Vector2D vInitialDir;
+ bool bInitialDirSet = false;
+
+ int PointIndex = m_PointQueue.Count() - 1;
+ if ( PointIndex <= 1 )
+ {
+ return false;
+ }
+
+ vPoint = m_PointQueue[ PointIndex ];
+
+ // keep going back from the current point until you get a total distance
+ for( int j = PointIndex - 1; j >= 0; j-- )
+ {
+ int index = j;
+ int index2 = PointIndex;
+
+ Vector2D vDiff( m_PointQueue[ index2 ].x - m_PointQueue[ index ].x, m_PointQueue[ index2 ].y - m_PointQueue[ index ].y );
+ float Length = Vector2DNormalize( vDiff );
+
+ if ( Length == 0.0f )
+ {
+ continue;
+ }
+
+ if ( bInitialDirSet == false )
+ {
+ vInitialDir = vDiff;
+ bInitialDirSet = true;
+ }
+
+ if ( DotProduct2D( vInitialDir, vDiff ) <= 0.5f )
+ {
+ break;
+ }
+
+ fTotalLength += Length;
+
+ float factor;
+
+#if 0
+ factor = 1.0f - ( fTotalLength / fMaxLength );
+ if ( factor <= 0.0f )
+ {
+ factor = 0.01;
+ }
+ factor *= 20.0f;
+#endif
+ factor = Length;
+
+ //= Length; // ( ( j + 1 ) * 100 ); // * Length; // * 8 * Length;
+ vAverage += ( vDiff * factor );
+ count += factor;
+
+ if ( fTotalLength >= fMaxLength )
+ {
+ break;
+ }
+ }
+
+ if ( count > 0.0f )
+ {
+ vAverage /= count;
+ Vector2DNormalize( vAverage );
+
+ vNormal = vAverage;
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: adds the point and normal to the queue
+// Input : vPoint - the point to be added
+// bDrawIt - if we should add this point to the draw / normal lists
+//-----------------------------------------------------------------------------
+void CSculptCarveOptions::AddQueuePoint( const Vector2D &vPoint, bool bDrawIt )
+{
+ m_PointQueue.AddToTail( vPoint );
+ if ( m_PointQueue.Count() > MAX_QUEUE_SIZE )
+ {
+ m_PointQueue.Remove( 0 );
+ }
+
+ Vector2D vNewPoint, vNewNormal;
+
+ if ( bDrawIt && CalculateQueuePoint( vNewPoint, vNewNormal ) )
+ {
+ m_DrawPoints.AddToTail( vNewPoint );
+ m_DrawNormal.AddToTail( vNewNormal );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: draws the tool in the 3d view
+// Input : pRender - the 3d renderer
+//-----------------------------------------------------------------------------
+void CSculptCarveOptions::RenderTool3D( CRender3D *pRender )
+{
+// pRender->DrawText( "mouse", m_MousePoint.x, m_MousePoint.y, 0 );
+// Msg( "%g %g\n", m_MousePoint.x, m_MousePoint.y );
+
+ pRender->PushRenderMode( RENDER_MODE_WIREFRAME );
+
+ pRender->BeginClientSpace();
+
+ Vector2D vMousePoint, vMouseNormal;
+
+ if ( CalculateQueuePoint( vMousePoint, vMouseNormal ) )
+ {
+ Vector2D vRight( -vMouseNormal.y, vMouseNormal.x );
+
+ pRender->SetDrawColor( 255, 255, 0 );
+ pRender->DrawLine( Vector( vMousePoint.x, vMousePoint.y, 0.0f ), Vector( vMousePoint.x + vRight.x * m_BrushSize, vMousePoint.y + vRight.y * m_BrushSize, 0.0f ) );
+ pRender->DrawLine( Vector( vMousePoint.x, vMousePoint.y, 0.0f ), Vector( vMousePoint.x - ( vRight.x * m_BrushSize ), vMousePoint.y - ( vRight.y * m_BrushSize ), 0.0f ) );
+ }
+
+#if 0
+ for( int i = 2; i < m_DrawPoints.Count(); i++ )
+ {
+ Vector2D vPoint = m_DrawPoints[ i ];
+ Vector2D vPreviousPoint = m_DrawPoints[ i - 1];
+ Vector2D vNormal = m_DrawNormal[ i ];
+ Vector2D vRight( -m_DrawNormal[ i ].y, m_DrawNormal[ i ].x );
+ Vector2D vDelta = vPoint - vPreviousPoint;
+ float Length = Vector2DLength( vDelta );
+
+ pRender->SetDrawColor( 255, 255, 0 );
+ pRender->DrawLine( Vector( vPreviousPoint.x, vPreviousPoint.y, 0.0f ), Vector( vPoint.x, vPoint.y, 0.0f ) );
+
+ pRender->SetDrawColor( 255, 0, 0 );
+ pRender->DrawLine( Vector( vPoint.x, vPoint.y, 0.0f ), Vector( vPoint.x + vRight.x * m_BrushSize, vPoint.y + vRight.y * m_BrushSize, 0.0f ) );
+// pRender->DrawLine( Vector( vPoint.x, vPoint.y, 0.0f ), Vector( vPoint.x - ( vRight.x * m_BrushSize ), vPoint.y - ( vRight.y * m_BrushSize ), 0.0f ) );
+
+ vNormal *= Length;
+ pRender->SetDrawColor( 0, 255, 0 );
+ pRender->DrawLine( Vector( vPoint.x - vNormal.x, vPoint.y - vNormal.y, 0.0f ), Vector( vPoint.x, vPoint.y, 0.0f ) );
+ }
+
+ pRender->SetDrawColor( 255, 0, 255 );
+ pRender->SetHandleStyle( 6, CRender::HANDLE_SQUARE );
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+ if( pDispMgr )
+ {
+ int nDispCount = pDispMgr->SelectCount();
+ for ( int iDisp = 0; iDisp < nDispCount; iDisp++ )
+ {
+ CMapDisp *pDisp = pDispMgr->GetFromSelect( iDisp );
+ if ( pDisp )
+ {
+ int nVertCount = pDisp->GetSize();
+ for ( int iVert = 0; iVert < nVertCount; iVert++ )
+ {
+ Vector vVert;
+ Vector2D vViewVert;
+
+ pDisp->GetVert( iVert, vVert );
+ pRender->GetCamera()->WorldToView( vVert, vViewVert );
+
+ for( int i = 2; i < m_DrawPoints.Count(); i++ )
+ {
+ float distance;
+
+ float tolerance = DotProduct2D( m_DrawNormal[ i ], m_DrawNormal[ i - 1 ] );
+ if ( tolerance <= 0.5f )
+ {
+ continue;
+ }
+
+ distance = DotProduct2D( m_DrawNormal[ i ], m_DrawPoints[ i ] );
+ if ( DotProduct2D( m_DrawNormal[ i ], vViewVert ) > distance )
+ {
+ continue;
+ }
+ distance = DotProduct2D( m_DrawNormal[ i - 1 ], m_DrawPoints[ i - 1 ] );
+ if ( DotProduct2D( m_DrawNormal[ i - 1 ], vViewVert ) < distance )
+ {
+ continue;
+ }
+
+ Vector2D vRight( -m_DrawNormal[ i ].y, m_DrawNormal[ i ].x );
+ Vector2D vPoint;
+
+ vPoint = m_DrawPoints[ i ] + ( vRight * m_BrushSize );
+ distance = DotProduct2D( vRight, vPoint );
+ if ( DotProduct2D( vRight, vViewVert ) > distance )
+ {
+ continue;
+ }
+
+ vPoint = m_DrawPoints[ i ] - ( vRight * m_BrushSize );
+ distance = DotProduct2D( vRight, vPoint );
+ if ( DotProduct2D( vRight, vViewVert ) < distance )
+ {
+ continue;
+ }
+
+// pRender->DrawHandle( Vector( vViewVert.x, vViewVert.y, 0.0f ) );
+ pRender->DrawHandle( vVert );
+ break;
+ }
+ }
+ }
+ }
+ }
+#endif
+
+ pRender->EndClientSpace();
+
+#if 0
+ if ( m_InSizingMode )
+ { // yellow for sizing mode
+ pRender->SetDrawColor( 255, 255, 0 );
+ pRender->BeginClientSpace();
+ pRender->DrawCircle( Vector( m_StartSizingPoint.x, m_StartSizingPoint.y, 0.0f ), Vector( 0.0f, 0.0f, 1.0f ), m_BrushSize, 32 );
+ pRender->EndClientSpace();
+ }
+ else if ( m_bShiftDown )
+ { // purple for smoothing
+ pRender->SetDrawColor( 255, 0, 255 );
+ pRender->BeginClientSpace();
+ pRender->DrawCircle( Vector( m_MousePoint.x, m_MousePoint.y, 0.0f ), Vector( 0.0f, 0.0f, 1.0f ), m_BrushSize, 32 );
+ pRender->EndClientSpace();
+ }
+ else if ( m_bCtrlDown )
+ { // red for negative sculpting
+ pRender->SetDrawColor( 255, 0, 0 );
+ pRender->BeginClientSpace();
+ pRender->DrawCircle( Vector( m_MousePoint.x, m_MousePoint.y, 0.0f ), Vector( 0.0f, 0.0f, 1.0f ), m_BrushSize, 32 );
+ pRender->EndClientSpace();
+
+ Vector vPaintAxis;
+ GetPaintAxis( pRender->GetCamera(), m_MousePoint, vPaintAxis );
+ DrawDirection( pRender, -vPaintAxis, Color( 255, 255, 255 ), Color( 255, 128, 128 ) );
+ }
+ else
+ { // green for positive sculpting
+ pRender->SetDrawColor( 0, 255, 0 );
+ pRender->BeginClientSpace();
+ pRender->DrawCircle( Vector( m_MousePoint.x, m_MousePoint.y, 0.0f ), Vector( 0.0f, 0.0f, 1.0f ), m_BrushSize, 32 );
+ pRender->EndClientSpace();
+
+ Vector vPaintAxis;
+ GetPaintAxis( pRender->GetCamera(), m_MousePoint, vPaintAxis );
+ DrawDirection( pRender, vPaintAxis, Color( 255, 255, 255 ), Color( 255, 128, 128 ) );
+ }
+#endif
+
+#if 0
+ FindColissionIntercept( pRender->GetCamera(), m_MousePoint, true, m_CurrentCollisionPoint, m_CurrentCollisionNormal, m_CurrentCollisionIntercept );
+
+ Vector2D RadiusPoint = m_MousePoint;
+ Vector vecStart, vecEnd;
+
+ RadiusPoint.x += m_BrushSize;
+ pRender->GetCamera()->BuildRay( RadiusPoint, vecStart, vecEnd );
+
+ m_CurrentProjectedRadius = CalcDistanceToLine( m_CurrentCollisionPoint, vecStart, vecEnd );
+
+ pRender->RenderWireframeSphere( m_CurrentCollisionPoint, m_CurrentProjectedRadius, 12, 12, 0, 255, 255 );
+#endif
+
+#if 0
+
+ // Get the displacement manager from the active map document.
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+
+ // For each displacement surface is the selection list attempt to paint on it.
+ int nDispCount = pDispMgr->SelectCount();
+ for ( int iDisp = 0; iDisp < nDispCount; iDisp++ )
+ {
+ CMapDisp *pDisp = pDispMgr->GetFromSelect( iDisp );
+ if ( pDisp )
+ {
+ CMapDisp *OrigDisp = NULL;
+ int index = m_OrigMapDisp.Find( pDisp->GetEditHandle() );
+
+ if ( index != m_OrigMapDisp.InvalidIndex() )
+ {
+ OrigDisp = m_OrigMapDisp[ index ];
+ }
+ Vector vPaintPos, vVert;
+
+ int nVertCount = pDisp->GetSize();
+ for ( int iVert = 0; iVert < nVertCount; iVert++ )
+ {
+ if ( IsPointInScreenCircle( pView, pDisp, pOrigDisp, iVert, false ) )
+ {
+ // Get the current vert.
+ pDisp->GetVert( iVert, vVert );
+ }
+ }
+ }
+ }
+#endif
+
+
+ pRender->PopRenderMode();
+
+#if 0
+ if ( !FindColissionIntercept( pRender->GetCamera(), m_MousePoint, true, m_CurrentCollisionPoint, m_CurrentCollisionNormal, m_CurrentCollisionIntercept ) )
+ {
+ return;
+ }
+
+ Vector2D RadiusPoint = m_MousePoint;
+ Vector vecStart, vecEnd;
+
+ RadiusPoint.x += m_BrushSize;
+ pRender->GetCamera()->BuildRay( RadiusPoint, vecStart, vecEnd );
+ m_CurrentProjectedRadius = CalcDistanceToLine( m_CurrentCollisionPoint, vecStart, vecEnd );
+
+ Msg( "Dist = %g at %g,%g,%g\n", m_CurrentProjectedRadius, m_CurrentCollisionPoint.x, m_CurrentCollisionPoint.y, m_CurrentCollisionPoint.z );
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handles the left mouse button up in the 3d view
+// Input : pView - the 3d view
+// nFlags - the button flags
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptCarveOptions::OnLMouseUp3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ __super::OnLMouseUp3D( pView, nFlags, vPoint );
+
+ AddQueuePoint( vPoint, true );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handles the left mouse button down in the 3d view
+// Input : pView - the 3d view
+// nFlags - the button flags
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptCarveOptions::OnLMouseDown3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ __super::OnLMouseDown3D( pView, nFlags, vPoint );
+
+ m_DrawPoints.Purge();
+ m_DrawNormal.Purge();
+ AddQueuePoint( vPoint, true );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handles the right mouse button down in the 3d view
+// Input : pView - the 3d view
+// nFlags - the button flags
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptCarveOptions::OnRMouseDown3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ __super::OnRMouseDown3D( pView, nFlags, vPoint );
+
+ if ( m_bAltDown )
+ {
+ m_NormalMode = NORMAL_MODE_Z;
+ m_NormalModeControl.SetCurSel( m_NormalMode );
+
+#if 0
+
+ //
+ // 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 true;
+ }
+
+ // trace a line and get the normal -- will get a displacement normal
+ // if one exists
+ CMapFace *pFace = pSolid->GetFace( ulFace );
+ if( !pFace )
+ {
+ return true;
+ }
+
+ Vector vRayStart, vRayEnd;
+ pView->GetCamera()->BuildRay( vPoint, vRayStart, vRayEnd );
+
+ Vector vHitPos, vHitNormal;
+ if( pFace->TraceLine( vHitPos, vHitNormal, vRayStart, vRayEnd ) )
+ {
+ // set the paint direction
+ m_SelectedNormal = vHitNormal;
+
+ m_NormalMode = NORMAL_MODE_SELECTED;
+ m_NormalModeControl.SetCurSel( m_NormalMode );
+ }
+ }
+ }
+#else
+ Vector CollisionPoint, CollisionNormal;
+ float CollisionIntercept;
+
+ if ( FindCollisionIntercept( pView->GetCamera(), vPoint, false, CollisionPoint, CollisionNormal, CollisionIntercept ) )
+ {
+ // set the paint direction
+ m_SelectedNormal = -CollisionNormal;
+
+ m_NormalMode = NORMAL_MODE_SELECTED;
+ m_NormalModeControl.SetCurSel( m_NormalMode );
+ }
+#endif
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handles the mouse move in the 3d view
+// Input : pView - the 3d view
+// nFlags - the button flags
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptCarveOptions::OnMouseMove3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ __super::OnMouseMove3D( pView, nFlags, vPoint );
+
+ AddQueuePoint( vPoint, m_bLMBDown );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the painting direction
+// Input : pCamera - the 3d camera
+// vPoint - the 2d mouse point
+// Output : vPaintAxis - the direction the painting should go
+//-----------------------------------------------------------------------------
+void CSculptCarveOptions::GetPaintAxis( CCamera *pCamera, const Vector2D &vPoint, Vector &vPaintAxis )
+{
+ switch( m_NormalMode )
+ {
+ case NORMAL_MODE_SCREEN:
+ pCamera->GetViewForward( vPaintAxis );
+ vPaintAxis = -vPaintAxis;
+ break;
+
+ case NORMAL_MODE_SCREEN_XY:
+ pCamera->GetViewForward( vPaintAxis );
+ vPaintAxis = -vPaintAxis;
+ vPaintAxis.z = 0.f;
+ break;
+
+ case NORMAL_MODE_BRUSH_CENTER:
+ if ( !m_InPaintingMode )
+ {
+ Vector CollisionPoint, CollisionNormal;
+ float CollisionIntercept;
+
+ FindCollisionIntercept( pCamera, vPoint, false, CollisionPoint, CollisionNormal, CollisionIntercept );
+
+ vPaintAxis = -CollisionNormal;
+ }
+ else
+ {
+ vPaintAxis = -m_StartingCollisionNormal;
+ }
+ break;
+
+ case NORMAL_MODE_X:
+ vPaintAxis.Init( 1.0f, 0.0f, 0.0f );
+ break;
+
+ case NORMAL_MODE_Y:
+ vPaintAxis.Init( 0.0f, 1.0f, 0.0f );
+ break;
+
+ case NORMAL_MODE_Z:
+ vPaintAxis.Init( 0.0f, 0.0f, 1.0f );
+ break;
+
+ case NORMAL_MODE_SELECTED:
+ vPaintAxis = m_SelectedNormal;
+ break;
+
+ default:
+ vPaintAxis.Init( 0.0f, 0.0f, 1.0f );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: determines if a displacement point is affected by the carve
+// Input : pView - the 3d view
+// pDisp - the displacement
+// pOrigDisp - the displacement prior to any updates
+// nVertIndex - the vertex to look at
+// nBrushPoint - which list point to check against
+// bUseOrigDisplacement - should we use the vert from the original displacement
+// bUseCurrentPosition - should we use the current collision test point
+// Output : returns true if the point is affected
+// vViewVert - the 2d view vert location
+//-----------------------------------------------------------------------------
+bool CSculptCarveOptions::IsPointAffected( CMapView3D *pView, CMapDisp *pDisp, CMapDisp *pOrigDisp, int vertIndex, int nBrushPoint, Vector2D &vViewVert, bool bUseOrigDisplacement, bool bUseCurrentPosition )
+{
+ Vector vVert, vTestVert;
+
+ pDisp->GetVert( vertIndex, vVert );
+
+ if ( pOrigDisp && bUseOrigDisplacement )
+ {
+ pOrigDisp->GetVert( vertIndex, vTestVert );
+ }
+ else
+ {
+ vTestVert = vVert;
+ }
+
+ pView->GetCamera()->WorldToView( vTestVert, vViewVert );
+
+ float distance;
+
+ float tolerance = DotProduct2D( m_DrawNormal[ nBrushPoint ], m_DrawNormal[ nBrushPoint - 1 ] );
+ if ( tolerance <= 0.5f )
+ {
+ return false;
+ }
+
+ distance = DotProduct2D( m_DrawNormal[ nBrushPoint ], m_DrawPoints[ nBrushPoint ] );
+ if ( DotProduct2D( m_DrawNormal[ nBrushPoint ], vViewVert ) > distance )
+ {
+ return false;
+ }
+ distance = DotProduct2D( m_DrawNormal[ nBrushPoint - 1 ], m_DrawPoints[ nBrushPoint - 1 ] );
+ if ( DotProduct2D( m_DrawNormal[ nBrushPoint - 1 ], vViewVert ) < distance )
+ {
+ return false;
+ }
+
+ Vector2D vRight( -m_DrawNormal[ nBrushPoint ].y, m_DrawNormal[ nBrushPoint ].x );
+ Vector2D vPoint;
+
+ vPoint = m_DrawPoints[ nBrushPoint ] + ( vRight * m_BrushSize );
+ distance = DotProduct2D( vRight, vPoint );
+ if ( DotProduct2D( vRight, vViewVert ) > distance )
+ {
+ return false;
+ }
+
+ vPoint = m_DrawPoints[ nBrushPoint ] - ( vRight * m_BrushSize );
+ distance = DotProduct2D( vRight, vPoint );
+ if ( DotProduct2D( vRight, vViewVert ) < distance )
+ {
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: applies the specific push operation onto the displacement
+// Input : pView - the 3d view
+// vPoint - the mouse point
+// pDisp - the displacement to apply the push to
+// pOrigDisp - the original displacement prior to any adjustments
+//-----------------------------------------------------------------------------
+void CSculptCarveOptions::DoPaintOperation( CMapView3D *pView, const Vector2D &vPoint, CMapDisp *pDisp, CMapDisp *pOrigDisp )
+{
+ Vector vPaintPos, vVert, vDirection;
+ Vector2D vViewVert;
+ float flDistance = 0.0f;
+ Vector vPaintAxis;
+
+ int nTestPoint = m_DrawPoints.Count() - 1;
+ if ( nTestPoint < 2 )
+ {
+ return;
+ }
+
+ if ( m_bShiftDown )
+ {
+// DoSmoothOperation( pView, vPoint, pDisp, pOrigDisp );
+// m_SpatialData.m_flRadius = 256.0f;
+// m_SpatialData.m_flScalar = 5.0f / m_SmoothAmount;
+
+// m_SpatialData.m_flRadius = m_StartingProjectedRadius * 1.5f;
+ m_SpatialData.m_flRadius = m_CurrentProjectedRadius * 2.0f;
+ m_SpatialData.m_flRadius2 = ( m_SpatialData.m_flRadius * m_SpatialData.m_flRadius );
+ m_SpatialData.m_flOORadius2 = 1.0f / m_SpatialData.m_flRadius2;
+ m_SpatialData.m_flScalar = 10.0f / m_SmoothAmount;
+ m_SpatialData.m_vCenter = m_CurrentCollisionPoint;
+
+ DoPaintSmooth( pView, vPoint, pDisp, pOrigDisp );
+ return;
+ }
+
+ GetPaintAxis( pView->GetCamera(), vPoint, vPaintAxis );
+
+ vDirection = vPaintAxis * m_Direction;
+
+ switch( m_OffsetMode )
+ {
+ case OFFSET_MODE_ADAPTIVE:
+ flDistance = m_StartingProjectedRadius * m_OffsetAmount;
+ break;
+ case OFFSET_MODE_ABSOLUTE:
+ flDistance = m_OffsetDistance;
+ break;
+ }
+
+ int nVertCount = pDisp->GetSize();
+ for ( int iVert = 0; iVert < nVertCount; iVert++ )
+ {
+ if ( IsPointAffected( pView, pDisp, pOrigDisp, iVert, nTestPoint, vViewVert ) )
+ {
+ pDisp->GetVert( iVert, vVert );
+
+ Vector2D vRight( -m_DrawNormal[ nTestPoint ].y, m_DrawNormal[ nTestPoint ].x );
+ float fLineDistance = DotProduct2D( vRight, m_DrawPoints[ nTestPoint ] ) - DotProduct2D( vRight, vViewVert );
+
+ fLineDistance = ( fLineDistance + m_BrushSize ) / ( m_BrushSize * 2.0f );
+ int index = ( int )( fLineDistance * MAX_SCULPT_SIZE );
+
+ index = clamp( index, 0, MAX_SCULPT_SIZE - 1 );
+ index = MAX_SCULPT_SIZE - index - 1;
+
+ float fScaledDistance = m_BrushPoints[ index ] * flDistance;
+
+ if ( fScaledDistance == 0.0f )
+ {
+ continue;
+ }
+
+ switch( m_DensityMode )
+ {
+ case DENSITY_MODE_ADDITIVE:
+ VectorScale( vDirection, fScaledDistance, vPaintPos );
+ VectorAdd( vPaintPos, vVert, vPaintPos );
+ break;
+
+ case DENSITY_MODE_ATTENUATED:
+ VectorScale( vDirection, fScaledDistance, vPaintPos );
+ VectorAdd( vPaintPos, vVert, vPaintPos );
+
+ if ( pOrigDisp )
+ {
+ Vector vOrigVert, vDiff;
+ float Length;
+
+ pOrigDisp->GetVert( iVert, vOrigVert );
+ vDiff = ( vPaintPos - vOrigVert );
+ Length = vDiff.Length() / flDistance;
+ if ( Length > 1.0f )
+ {
+ Length = 1.0f;
+ }
+
+ vPaintPos = vOrigVert + ( Length * vDirection * flDistance );
+ }
+ break;
+ }
+
+ AddToUndo( &pDisp );
+ pDisp->Paint_SetValue( iVert, vPaintPos );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the offset distance
+//-----------------------------------------------------------------------------
+void CSculptCarveOptions::OnEnChangeSculptPushOptionOffsetDistance()
+{
+ char temp[ 1024 ];
+
+ m_OffsetDistanceControl.GetWindowText( temp, sizeof( temp ) );
+ m_OffsetDistance = atof( temp );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the density mode
+//-----------------------------------------------------------------------------
+void CSculptCarveOptions::OnCbnSelchangeSculptPushOptionDensityMode()
+{
+ m_DensityMode = ( DensityMode )m_DensityModeControl.GetCurSel();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the smooth amount
+//-----------------------------------------------------------------------------
+void CSculptCarveOptions::OnEnKillfocusSculptPushOptionSmoothAmount()
+{
+ char temp[ 1024 ], t2[ 1024 ];
+
+ m_SmoothAmountControl.GetWindowText( temp, sizeof( temp ) );
+ sscanf( temp, "%f%%", &m_SmoothAmount );
+ m_SmoothAmount /= 100.0f;
+
+ if ( m_SmoothAmount <= 0.0f )
+ {
+ m_SmoothAmount = 0.2f;
+ }
+
+ sprintf( t2, "%g%%", m_SmoothAmount * 100.0f );
+
+ if ( strcmpi( temp, t2 ) != 0 )
+ {
+ m_SmoothAmountControl.SetWindowText( t2 );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the offset amount
+//-----------------------------------------------------------------------------
+void CSculptCarveOptions::OnEnKillfocusSculptPushOptionOffsetAmount()
+{
+ char temp[ 1024 ], t2[ 1024 ];
+
+ m_OffsetAmountControl.GetWindowText( temp, sizeof( temp ) );
+ sscanf( temp, "%f%%", &m_OffsetAmount );
+ m_OffsetAmount /= 100.0f;
+
+ if ( m_OffsetAmount <= 0.0f )
+ {
+ m_OffsetAmount = 1.0f;
+ }
+
+ sprintf( t2, "%g%%", m_OffsetAmount * 100.0f );
+
+ if ( strcmpi( temp, t2 ) != 0 )
+ {
+ m_OffsetAmountControl.SetWindowText( t2 );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: paints the carve brush
+//-----------------------------------------------------------------------------
+void CSculptCarveOptions::OnPaint()
+{
+ CPaintDC dc(this); // device context for painting
+
+ CBrush black( RGB( 0, 0, 0 ) );
+ CBrush red( RGB( 255, 0, 0 ) );
+ CBrush green( RGB( 0, 255, 0 ) );
+ CBrush blue_red( RGB( 64, 0, 128 ) );
+ CBrush blue_green( RGB( 0, 64, 128 ) );
+ CBrush blue( RGB( 0, 0, 255 ) );
+
+ CRect WindowRect;
+ m_CarveBrushControl.GetWindowRect( &WindowRect );
+ ScreenToClient( &WindowRect );
+ dc.FillRect( WindowRect, &black );
+
+ float center = ( WindowRect.bottom + WindowRect.top ) / 2;
+ float height = ( WindowRect.bottom - WindowRect.top ) - 1;
+
+ if ( m_BrushLocation != -1 )
+ {
+ CRect rect;
+
+ rect.left = ( m_BrushLocation * 2 ) + WindowRect.left;
+ rect.right = rect.left + 2;
+ rect.bottom = WindowRect.bottom;
+ rect.top = WindowRect.top;
+ dc.FillRect( rect, &blue );
+ }
+
+ for( int i = 0; i < MAX_SCULPT_SIZE; i++ )
+ {
+ float size = height / 2.0f * m_BrushPoints[ i ];
+ CRect rect;
+ CBrush *pBrush;
+
+ rect.left = ( i * 2 ) + WindowRect.left;
+ rect.right = rect.left + 2;
+ rect.bottom = center - size;
+ rect.top = center;
+
+ if ( m_BrushPoints[ i ] >= 0.0f )
+ {
+ if ( m_BrushLocation == i )
+ {
+ pBrush = &blue_green;
+ }
+ else
+ {
+ pBrush = &green;
+ }
+ }
+ else
+ {
+ if ( m_BrushLocation == i )
+ {
+ pBrush = &blue_red;
+ }
+ else
+ {
+ pBrush = &red;
+ }
+ }
+ dc.FillRect( rect, pBrush );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: adjusts the carve brush
+// Input : x - location to set the height to
+// y - offset into the brush
+//-----------------------------------------------------------------------------
+void CSculptCarveOptions::AdjustBrush( int x, int y )
+{
+ CRect WindowRect;
+ CPoint MousePoint( x, y );
+
+ m_CarveBrushControl.GetWindowRect( &WindowRect );
+ ClientToScreen( &MousePoint );
+
+ if ( MousePoint.x >= WindowRect.left && MousePoint.x < WindowRect.right &&
+ MousePoint.y >= WindowRect.top && MousePoint.y < WindowRect.bottom )
+ {
+ int pos = ( MousePoint.x - WindowRect.left ) / 2;
+ float center = ( WindowRect.bottom + WindowRect.top ) / 2;
+ float value = ( center - MousePoint.y ) / ( WindowRect.bottom - WindowRect.top ) * 2.0f;
+
+ value = clamp( value, -1.0f, 1.0f );
+ if ( pos >= 0 && pos < MAX_SCULPT_SIZE )
+ {
+ m_BrushPoints[ pos ] = value;
+ Invalidate();
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the brush cursor location
+// Input : x - x location of mouse
+// y - y location of mouse
+//-----------------------------------------------------------------------------
+void CSculptCarveOptions::AdjustBrushCursor( int x, int y )
+{
+ CRect WindowRect;
+ int OldBrushLocation = m_BrushLocation;
+ CPoint MousePoint( x, y );
+
+ m_CarveBrushControl.GetWindowRect( &WindowRect );
+ ClientToScreen( &MousePoint );
+
+ if ( MousePoint.x >= WindowRect.left && MousePoint.x < WindowRect.right &&
+ MousePoint.y >= WindowRect.top && MousePoint.y < WindowRect.bottom )
+ {
+ m_BrushLocation = ( MousePoint.x - WindowRect.left ) / 2;
+ }
+ else
+ {
+ m_BrushLocation = -1;
+ }
+
+ if ( OldBrushLocation != m_BrushLocation )
+ {
+ Invalidate();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handles adjusting the brush
+// Input : nFlags - mouse buttons
+// point - mouse point
+//-----------------------------------------------------------------------------
+void CSculptCarveOptions::OnLButtonDown(UINT nFlags, CPoint point)
+{
+ AdjustBrush( point.x, point.y );
+ AdjustBrushCursor( point.x, point.y );
+
+ __super::OnLButtonDown(nFlags, point);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handles adjusting the brush
+// Input : nFlags - mouse buttons
+// point - mouse point
+//-----------------------------------------------------------------------------
+void CSculptCarveOptions::OnLButtonUp(UINT nFlags, CPoint point)
+{
+ AdjustBrush( point.x, point.y );
+ AdjustBrushCursor( point.x, point.y );
+
+ __super::OnLButtonUp(nFlags, point);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handles adjusting the brush
+// Input : nFlags - mouse buttons
+// point - mouse point
+//-----------------------------------------------------------------------------
+void CSculptCarveOptions::OnMouseMove(UINT nFlags, CPoint point)
+{
+ if ( nFlags & MK_LBUTTON )
+ {
+ AdjustBrush( point.x, point.y );
+ }
+ AdjustBrushCursor( point.x, point.y );
+
+ __super::OnMouseMove(nFlags, point);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: we want to handle the messages for mouse events
+//-----------------------------------------------------------------------------
+BOOL CSculptCarveOptions::PreTranslateMessage( MSG* pMsg )
+{
+ if ( pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_MOUSEMOVE )
+ {
+ return FALSE;
+ }
+
+ return __super::PreTranslateMessage( pMsg );
+}
+
+
+
+
+
+
+#if 0
+
+class CSculptRegenerator : public ITextureRegenerator
+{
+public:
+ CSculptRegenerator( unsigned char *ImageData, int Width, int Height, enum ImageFormat Format ) :
+ m_ImageData( ImageData ),
+ m_Width( Width ),
+ m_Height( Height ),
+ m_Format( Format )
+ {
+ }
+
+ virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pSubRect )
+ {
+ for (int iFrame = 0; iFrame < pVTFTexture->FrameCount(); ++iFrame )
+ {
+ for (int iFace = 0; iFace < pVTFTexture->FaceCount(); ++iFace )
+ {
+ int nWidth = pVTFTexture->Width();
+ int nHeight = pVTFTexture->Height();
+ int nDepth = pVTFTexture->Depth();
+ for (int z = 0; z < nDepth; ++z)
+ {
+ // Fill mip 0 with a checkerboard
+ CPixelWriter pixelWriter;
+ pixelWriter.SetPixelMemory( pVTFTexture->Format(), pVTFTexture->ImageData( iFrame, iFace, 0, 0, 0, z ), pVTFTexture->RowSizeInBytes( 0 ) );
+
+ switch( m_Format )
+ {
+ case IMAGE_FORMAT_BGR888:
+ {
+ unsigned char *data = m_ImageData;
+
+ for (int y = 0; y < nHeight; ++y)
+ {
+ pixelWriter.Seek( 0, y );
+ for (int x = 0; x < nWidth; ++x)
+ {
+ pixelWriter.WritePixel( *( data + 2 ), *( data + 1 ), *( data ), 255 );
+ data += 3;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ virtual void Release()
+ {
+ delete this;
+ }
+
+private:
+ unsigned char *m_ImageData;
+ int m_Width;
+ int m_Height;
+ enum ImageFormat m_Format;
+};
+
+
+
+
+// CSculptProjectOptions dialog
+
+IMPLEMENT_DYNAMIC(CSculptProjectOptions, CDialog)
+
+CSculptProjectOptions::CSculptProjectOptions(CWnd* pParent /*=NULL*/) :
+ CDialog(CSculptProjectOptions::IDD, pParent),
+ CSculptTool()
+{
+ m_FileDialog = new CFileDialog(TRUE, NULL, NULL, OFN_LONGNAMES | OFN_NOCHANGEDIR | OFN_FILEMUSTEXIST, "Image Files (*.tga)|*.tga||");
+ m_FileDialog->m_ofn.lpstrInitialDir = "";
+
+ m_ImagePixels = NULL;
+ m_pTexture = NULL;
+ m_pMaterial = NULL;
+
+ m_ProjectX = 100;
+ m_ProjectY = 100;
+ m_ProjectWidth = 100;
+ m_ProjectHeight = 100;
+ m_TileWidth = m_TileHeight = 1.0;
+ m_OriginalTileWidth = m_TileWidth;
+ m_OriginalTileHeight = m_TileHeight;
+
+ m_ProjectLocation.Init( 100.0f, 100.0f, 0.0f );
+ m_OriginalProjectLocation = m_ProjectLocation;
+ m_ProjectSize.Init( 100.0f, 100.0f, 0.0f );
+ m_OriginalProjectSize = m_ProjectSize;
+
+ m_ToolMode = PROJECT_MODE_NONE;
+}
+
+CSculptProjectOptions::~CSculptProjectOptions()
+{
+ delete m_FileDialog;
+
+ if ( m_ImagePixels )
+ {
+ delete [] m_ImagePixels;
+ }
+
+ if ( m_pTexture )
+ {
+ m_pTexture->DecrementReferenceCount();
+ m_pTexture = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: set up the data exchange for the variables
+// Input : pDX - the data exchange object
+//-----------------------------------------------------------------------------
+void CSculptProjectOptions::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ DDX_Control(pDX, IDC_PROJECT_SIZE, m_ProjectSizeControl);
+ DDX_Control(pDX, IDC_PROJECT_SIZE_NUM, m_ProjectSizeNumControl);
+}
+
+
+BEGIN_MESSAGE_MAP(CSculptProjectOptions, CDialog)
+ ON_BN_CLICKED(IDC_LOAD_IMAGE, &CSculptProjectOptions::OnBnClickedLoadImage)
+ ON_NOTIFY(NM_CUSTOMDRAW, IDC_PROJECT_SIZE, &CSculptProjectOptions::OnNMCustomdrawProjectSize)
+END_MESSAGE_MAP()
+
+bool CSculptProjectOptions::Paint( CMapView3D *pView, const Vector2D &vPoint, SpatialPaintData_t &spatialData )
+{
+ CSculptTool::Paint( pView, vPoint, spatialData );
+
+ switch( m_ToolMode )
+ {
+ case PROJECT_MODE_SIZE:
+ DoSizing( vPoint );
+ break;
+
+ case PROJECT_MODE_POSITION:
+ DoPosition( vPoint );
+ break;
+
+ case PROJECT_MODE_TILE:
+ DoTiling( vPoint );
+ break;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: draws the tool in the 3d view
+// Input : pRender - the 3d renderer
+//-----------------------------------------------------------------------------
+void CSculptProjectOptions::RenderTool3D(CRender3D *pRender)
+{
+ if ( !m_pMaterial )
+ {
+ return;
+ }
+
+ pRender->PushRenderMode( RENDER_MODE_TEXTURED );
+ bool bPopMode = pRender->BeginClientSpace();
+
+ CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
+ pRender->BindMaterial( m_pMaterial );
+ IMesh* pMesh = pRenderContext->GetDynamicMesh();
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_QUADS, 4 );
+
+ meshBuilder.Position3f( m_ProjectLocation.x, m_ProjectLocation.y, m_ProjectLocation.z );
+ meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
+ meshBuilder.Color4ub( 255, 255, 255, 128 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( m_ProjectLocation.x + m_ProjectSize.x, m_ProjectLocation.y, m_ProjectLocation.z );
+ meshBuilder.TexCoord2f( 0, m_TileWidth, 0.0f );
+ meshBuilder.Color4ub( 255, 255, 255, 128 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( m_ProjectLocation.x + m_ProjectSize.x, m_ProjectLocation.y + m_ProjectSize.y, m_ProjectLocation.z );
+ meshBuilder.TexCoord2f( 0, m_TileWidth, m_TileHeight );
+ meshBuilder.Color4ub( 255, 255, 255, 128 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( m_ProjectLocation.x, m_ProjectLocation.y + m_ProjectSize.y, m_ProjectLocation.z );
+ meshBuilder.TexCoord2f( 0, 0.0f, m_TileHeight );
+ meshBuilder.Color4ub( 255, 255, 255, 128 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+
+ if ( bPopMode )
+ {
+ pRender->EndClientSpace();
+ }
+ pRender->PopRenderMode();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: handles the left mouse button up in the 3d view
+// Input : pView - the 3d view
+// nFlags - the button flags
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptProjectOptions::OnLMouseUp3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ CSculptTool::OnLMouseUp3D( pView, nFlags, vPoint );
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: handles the left mouse button down in the 3d view
+// Input : pView - the 3d view
+// nFlags - the button flags
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptProjectOptions::OnLMouseDown3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ CSculptTool::OnLMouseDown3D( pView, nFlags, vPoint );
+
+ IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
+ if( pDispMgr )
+ {
+ pDispMgr->PreUndo( "Displacement Modifier" );
+ }
+
+ PrepareDispForPainting();
+
+ // Handle painting.
+ if ( !DoPaint( pView, vPoint ) )
+ {
+ return false;
+ }
+
+ // Finish painting.
+ if ( !PostPaint( m_PaintOwner->GetAutoSew() ) )
+ {
+ return false;
+ }
+
+ if( pDispMgr )
+ {
+ pDispMgr->PostUndo();
+ }
+
+ return true;
+}
+
+bool CSculptProjectOptions::OnRMouseUp3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ CSculptTool::OnRMouseUp3D( pView, nFlags, vPoint );
+
+ m_ToolMode = PROJECT_MODE_NONE;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: handles the right mouse button down in the 3d view
+// Input : pView - the 3d view
+// nFlags - the button flags
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptProjectOptions::OnRMouseDown3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ CSculptTool::OnRMouseDown3D( pView, nFlags, vPoint );
+
+ m_OriginalProjectSize = m_ProjectSize;
+ m_OriginalProjectLocation = m_ProjectLocation;
+ m_StartSizingPoint = vPoint;
+
+ if ( m_bCtrlDown )
+ {
+ m_ToolMode = PROJECT_MODE_SIZE;
+ }
+ else if ( m_bShiftDown )
+ {
+ m_ToolMode = PROJECT_MODE_TILE;
+ }
+ else
+ {
+ m_ToolMode = PROJECT_MODE_POSITION;
+ }
+
+ m_StartSizingPoint = vPoint;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: handles the mouse move in the 3d view
+// Input : pView - the 3d view
+// nFlags - the button flags
+// vPoint - the mouse point
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+bool CSculptProjectOptions::OnMouseMove3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
+{
+ CSculptTool::OnMouseMove3D( pView, nFlags, vPoint );
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: applies the specific push operation onto the displacement
+// Input : pView - the 3d view
+// vPoint - the mouse point
+// pDisp - the displacement to apply the push to
+// pOrigDisp - the original displacement prior to any adjustments
+//-----------------------------------------------------------------------------
+void CSculptProjectOptions::DoPaintOperation( CMapView3D *pView, const Vector2D &vPoint, CMapDisp *pDisp, CMapDisp *pOrigDisp )
+{
+ Vector vPaintPos, vVert;
+ Vector vPaintAxis;
+
+ pView->GetCamera()->GetViewForward( vPaintAxis );
+ vPaintAxis = -vPaintAxis;
+
+ vPaintAxis *= ( m_ProjectSizeControl.GetPos() * 16.0f );
+
+ int nVertCount = pDisp->GetSize();
+ for ( int iVert = 0; iVert < nVertCount; iVert++ )
+ {
+ Vector2D ViewVert;
+ Vector vTestVert;
+
+ pDisp->GetVert( iVert, vTestVert );
+ pView->GetCamera()->WorldToView( vTestVert, ViewVert );
+
+ if ( ViewVert.x >= m_ProjectLocation.x &&
+ ViewVert.y >= m_ProjectLocation.y &&
+ ViewVert.x <= m_ProjectLocation.x + m_ProjectSize.x &&
+ ViewVert.y <= m_ProjectLocation.y + m_ProjectSize.y )
+ {
+ pDisp->GetVert( iVert, vVert );
+
+ float sCoord = ( ViewVert.x - m_ProjectLocation.x ) / m_ProjectSize.x;
+ float tCoord = ( ViewVert.y - m_ProjectLocation.y ) / m_ProjectSize.y;
+
+ sCoord *= m_TileWidth;
+ tCoord *= m_TileHeight;
+
+ sCoord -= ( int )sCoord;
+ tCoord -= ( int )tCoord;
+
+ int x = ( sCoord * m_Width );
+ int y = ( tCoord * m_Height );
+
+ unsigned char *pos = &m_ImagePixels[ ( y * m_Width * 3 ) + ( x * 3 ) ];
+ float gray = ( 0.3f * pos[ 2 ] ) + ( 0.59f * pos[ 1 ] ) + ( 0.11f * pos[ 0 ] );
+ gray /= 255.0f;
+
+ vPaintPos = vVert + ( vPaintAxis * gray );
+
+ AddToUndo( &pDisp );
+ pDisp->Paint_SetValue( iVert, vPaintPos );
+ }
+ }
+}
+
+void CSculptProjectOptions::OnBnClickedLoadImage()
+{
+ if ( m_FileDialog->DoModal() == IDCANCEL )
+ {
+ return;
+ }
+
+ ReadImage( m_FileDialog->GetPathName() );
+}
+
+bool CSculptProjectOptions::ReadImage( CString &FileName )
+{
+ enum ImageFormat imageFormat;
+ float sourceGamma;
+ CUtlBuffer buf;
+
+ if ( !g_pFullFileSystem->ReadFile( FileName, NULL, buf ) )
+ {
+ return false;
+ }
+
+ if ( !TGALoader::GetInfo( buf, &m_Width, &m_Height, &imageFormat, &sourceGamma ) )
+ {
+ return false;
+ }
+
+ if ( m_ImagePixels )
+ {
+ delete [] m_ImagePixels;
+ }
+
+ int memRequired = ImageLoader::GetMemRequired( m_Width, m_Height, 1, imageFormat, false );
+ m_ImagePixels = new unsigned char[ memRequired ];
+
+ buf.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
+ TGALoader::Load( m_ImagePixels, buf, m_Width, m_Height, imageFormat, sourceGamma, false );
+
+ m_pTexture = dynamic_cast< ITextureInternal * >( g_pMaterialSystem->CreateProceduralTexture( "SculptProject", TEXTURE_GROUP_OTHER, m_Width, m_Height, imageFormat,
+ TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_PROCEDURAL ) );
+
+ ITextureRegenerator *pRegen = new CSculptRegenerator( m_ImagePixels, m_Width, m_Height, imageFormat );
+ m_pTexture->SetTextureRegenerator( pRegen );
+ m_pTexture->Download();
+
+ m_pMaterial = MaterialSystemInterface()->FindMaterial( "editor/sculpt", TEXTURE_GROUP_OTHER );
+
+ return true;
+}
+
+bool CSculptProjectOptions::DoSizing( const Vector2D &vPoint )
+{
+ m_ProjectSize.x = m_OriginalProjectSize.x + ( vPoint.x - m_StartSizingPoint.x );
+ if ( m_ProjectSize.x < 1.0f )
+ {
+ m_ProjectSize.x = 1.0f;
+ }
+ m_ProjectSize.y = m_OriginalProjectSize.y + ( vPoint.y - m_StartSizingPoint.y );
+ if ( m_ProjectSize.y < 1.0f )
+ {
+ m_ProjectSize.y = 1.0f;
+ }
+
+ return true;
+}
+
+bool CSculptProjectOptions::DoPosition( const Vector2D &vPoint )
+{
+ m_ProjectLocation.x = m_OriginalProjectLocation.x + ( vPoint.x - m_StartSizingPoint.x );
+ m_ProjectLocation.y = m_OriginalProjectLocation.y + ( vPoint.y - m_StartSizingPoint.y );
+
+ return true;
+}
+
+bool CSculptProjectOptions::DoTiling( const Vector2D &vPoint )
+{
+ m_TileWidth += ( vPoint.x - m_StartSizingPoint.x ) / m_ProjectSize.x;
+ m_TileHeight += ( vPoint.y - m_StartSizingPoint.y ) / m_ProjectSize.y;
+
+ m_StartSizingPoint = vPoint;
+
+ return true;
+}
+
+void CSculptProjectOptions::OnNMCustomdrawProjectSize(NMHDR *pNMHDR, LRESULT *pResult)
+{
+// LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
+
+ char temp[ 128 ];
+ sprintf( temp, "%d", m_ProjectSizeControl.GetPos() * 16 );
+
+ m_ProjectSizeNumControl.SetWindowText( temp );
+
+ *pResult = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: initializes the dialog
+// Output : returns true if successful
+//-----------------------------------------------------------------------------
+BOOL CSculptProjectOptions::OnInitDialog()
+{
+ __super::OnInitDialog();
+
+ m_ProjectSizeControl.SetRange( 1, 32 );
+ m_ProjectSizeControl.SetTicFreq( 1 );
+ m_ProjectSizeControl.SetPageSize( 4 );
+ m_ProjectSizeControl.SetLineSize( 4 );
+
+ return TRUE;
+}
+
+#endif
+
+// current mouse position updates location of rectangle
+// then rmb = size
+// +control = st adjust
+
+
+#include <tier0/memdbgoff.h>