Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4965 lines
141 KiB

// 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"
#include "tablet.h"
#include "vstdlib/random.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,
int *pnCollideDisplacement, int *pnCollideTri )
{
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 );
if ( pnCollideDisplacement != NULL )
{
*pnCollideDisplacement = iDisp;
}
if ( pnCollideTri != NULL )
{
*pnCollideTri = iTri;
}
}
}
}
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, "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_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 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_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, "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_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 flScaledDistance = m_BrushPoints[ index ] * flDistance;
if ( flScaledDistance == 0.0f )
{
continue;
}
switch( m_DensityMode )
{
case DENSITY_MODE_ADDITIVE:
VectorScale( vDirection, flScaledDistance, vPaintPos );
VectorAdd( vPaintPos, vVert, vPaintPos );
break;
case DENSITY_MODE_ATTENUATED:
VectorScale( vDirection, flScaledDistance, 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_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
CTextureButton::CTextureButton( ) :
CButton()
{
m_pTexure = NULL;
m_bSelected = false;
}
void CTextureButton::SetTexture( IEditorTexture *pTexture )
{
m_pTexure = pTexture;
}
void CTextureButton::SetSelected( bool bSelected )
{
m_bSelected = bSelected;
Invalidate();
}
BOOL CTextureButton::PreCreateWindow(CREATESTRUCT& cs)
{
cs.style |= BS_OWNERDRAW;
return __super::PreCreateWindow( cs );
}
void CTextureButton::DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct )
{
#if 0
UINT uStyle = DFCS_BUTTONPUSH;
// This code only works with buttons.
ASSERT(lpDrawItemStruct->CtlType == ODT_BUTTON);
// If drawing selected, add the pushed style to DrawFrameControl.
if (lpDrawItemStruct->itemState & ODS_SELECTED)
uStyle |= DFCS_PUSHED;
// Draw the button frame.
::DrawFrameControl(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem,
DFC_BUTTON, uStyle);
// Get the button's text.
CString strText;
GetWindowText(strText);
// Draw the button text using the text color red.
COLORREF crOldColor = ::SetTextColor(lpDrawItemStruct->hDC, RGB(255,0,0));
::DrawText(lpDrawItemStruct->hDC, strText, strText.GetLength(),
&lpDrawItemStruct->rcItem, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
::SetTextColor(lpDrawItemStruct->hDC, crOldColor);
#endif
UINT uStyle = DFCS_BUTTONPUSH;
COLORREF dwForeColor = GetSysColor( COLOR_BTNTEXT );
// If drawing selected, add the pushed style to DrawFrameControl.
if (lpDrawItemStruct->itemState & ODS_SELECTED)
{
dwForeColor = GetSysColor( COLOR_BTNTEXT );
uStyle |= DFCS_PUSHED;
}
if ( m_bSelected == true )
{
dwForeColor = RGB( 200, 0, 0 );
}
::DrawFrameControl( lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem, DFC_BUTTON, uStyle );
CDC dc;
dc.Attach( lpDrawItemStruct->hDC );
dc.SaveDC();
RECT& r = lpDrawItemStruct->rcItem;
int iFontHeight = dc.GetTextExtent( "J", 1 ).cy;
dc.SetROP2( R2_COPYPEN );
CPalette *pOldPalette = NULL;
if (m_pTexure != NULL)
{
m_pTexure->Load();
pOldPalette = dc.SelectPalette( m_pTexure->HasPalette() ? m_pTexure->GetPalette() : g_pGameConfig->Palette, FALSE );
dc.RealizePalette();
}
if ( m_pTexure != NULL )
{
char szName[ MAX_PATH ];
int iLen = m_pTexure->GetShortName( szName );
// crop to just the name without path
const char *pszTextureName = V_UnqualifiedFileName( szName );
iLen = strlen( pszTextureName );
DrawTexData_t DrawTexData;
DrawTexData.nFlags = 0;
int nWidth = m_pTexure->GetPreviewImageWidth();
int nHeight = m_pTexure->GetPreviewImageHeight();
CRect r2(r);
r2.InflateRect( -4, -4 );
if ( m_pTexure->IsLoaded() && nWidth > 0 && nHeight > 0 )
{
// draw graphic
int nDrawWidth = 64;
int nDrawHeight = nDrawWidth * nHeight / nWidth;
if ( nDrawHeight > r2.bottom - r2.top )
{
nDrawHeight = r2.bottom - r2.top;
nDrawWidth = nDrawHeight * nWidth / nHeight;
}
r2.right = r2.left + nDrawWidth;
r2.bottom = r2.top + nDrawHeight;
m_pTexure->Draw( &dc, r2, 0, 0, DrawTexData );
}
else
{
int nDrawSize = r2.bottom - r2.top;
r2.right = r2.left + nDrawSize;
r2.bottom = r2.top + nDrawSize;
}
// draw name
dc.SetTextColor( dwForeColor );
dc.SetBkMode( TRANSPARENT );
dc.TextOut( r2.right + 4, r2.top + 4, pszTextureName, iLen );
// draw size
sprintf( szName, "%dx%d", m_pTexure->GetWidth(), m_pTexure->GetHeight() );
dc.TextOut( r2.right + 4, r2.top + 4 + iFontHeight, szName, strlen( szName ) );
}
if (pOldPalette)
{
dc.SelectPalette( pOldPalette, FALSE );
}
dc.RestoreDC( -1 );
dc.Detach();
}
BEGIN_MESSAGE_MAP(CColorButton, CButton)
END_MESSAGE_MAP()
CColorButton::CColorButton( ) :
CButton()
{
m_flRed = m_flGreen = m_flBlue = 1.0f;
}
void CColorButton::SetColor( float flRed, float flGreen, float flBlue )
{
m_flRed = flRed;
m_flGreen = flGreen;
m_flBlue = flBlue;
Invalidate();
}
BOOL CColorButton::PreCreateWindow(CREATESTRUCT& cs)
{
cs.style |= BS_OWNERDRAW;
return __super::PreCreateWindow( cs );
}
void CColorButton::DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct )
{
UINT uStyle = DFCS_BUTTONPUSH;
// This code only works with buttons.
ASSERT(lpDrawItemStruct->CtlType == ODT_BUTTON);
// If drawing selected, add the pushed style to DrawFrameControl.
if (lpDrawItemStruct->itemState & ODS_SELECTED)
uStyle |= DFCS_PUSHED;
CDC dc;
dc.Attach( lpDrawItemStruct->hDC );
dc.SaveDC();
COLORREF dwBackColor = RGB( m_flRed * 255, m_flGreen * 255, m_flBlue * 255 );
// Draw the button frame.
::DrawFrameControl(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem,
DFC_BUTTON, uStyle);
// draw background
CBrush brush;
CRect r2( lpDrawItemStruct->rcItem );
brush.CreateSolidBrush( dwBackColor) ;
r2.InflateRect( -4, -4 );
dc.FillRect( &r2, &brush );
dc.RestoreDC( -1 );
dc.Detach();
}
// CSculptBlendOptions dialog
IMPLEMENT_DYNAMIC(CSculptBlendOptions, CDialog)
//-----------------------------------------------------------------------------
// Purpose: constructor
//-----------------------------------------------------------------------------
CSculptBlendOptions::CSculptBlendOptions(CWnd* pParent /*=NULL*/) :
CDialog(CSculptBlendOptions::IDD, pParent),
CSculptPainter()
{
m_flFalloffSpot = 0.5f;
m_flFalloffEndingValue = 0.0f;
m_Direction = 1.0f;
m_nSelectedTexture = 0;
for( int i = 0; i < MAX_MULTIBLEND_CHANNELS; i++ )
{
m_ColorMode[ i ] = COLOR_MODE_SINGLE;
m_vStartDrawColor[ i ].Init( 1.0f, 1.0f, 1.0f );
m_vEndDrawColor[ i ].Init( 1.0f, 1.0f, 1.0f );
}
m_nDefaultFalloffPosition = 50;
m_nDefaultFalloffFinal = 0;
m_nDefaultBlendAmount = 50;
m_nDefaultColorBlendAmount = 0;
m_nDefaultAlphaBlendAmount = 0;
m_b4WayBlendMode = false;
}
//-----------------------------------------------------------------------------
// Purpose: destructor
//-----------------------------------------------------------------------------
CSculptBlendOptions::~CSculptBlendOptions()
{
}
//-----------------------------------------------------------------------------
// Purpose: initializes the dialog
// Output : returns true if successful
//-----------------------------------------------------------------------------
BOOL CSculptBlendOptions::OnInitDialog( void )
{
CDialog::OnInitDialog();
m_FalloffPositionControl.SetRange( 0, 100 );
m_FalloffPositionControl.SetTicFreq( 10 );
m_FalloffPositionControl.SetPos( m_nDefaultFalloffPosition );
m_FalloffFinalControl.SetRange( 0, 100 );
m_FalloffFinalControl.SetTicFreq( 10 );
m_FalloffFinalControl.SetPos( m_nDefaultFalloffFinal );
m_BlendAmountControl.SetRange( 0, 100 );
m_BlendAmountControl.SetTicFreq( 10 );
m_BlendAmountControl.SetPos( m_nDefaultBlendAmount );
m_ColorBlendAmountControl.SetRange( 0, 100 );
m_ColorBlendAmountControl.SetTicFreq( 10 );
m_ColorBlendAmountControl.SetPos( m_nDefaultColorBlendAmount );
m_AlphaBlendAmountControl.SetRange( 0, 100 );
m_AlphaBlendAmountControl.SetTicFreq( 10 );
m_AlphaBlendAmountControl.SetPos( m_nDefaultAlphaBlendAmount );
m_BlendColorOperationControl.InsertString( -1, "Single");
m_BlendColorOperationControl.InsertString( -1, "Blend");
m_BlendColorOperationControl.InsertString( -1, "Or");
return TRUE;
}
void CSculptBlendOptions::SetColorMode( ColorMode NewMode, bool bSetDialog )
{
m_ColorMode[ m_nSelectedTexture ] = NewMode;
switch( m_ColorMode[ m_nSelectedTexture ] )
{
case COLOR_MODE_SINGLE:
m_ColorEndControl.ShowWindow( SW_HIDE );
break;
case COLOR_MODE_RANGE:
m_ColorEndControl.ShowWindow( SW_SHOW );
break;
case COLOR_MODE_OR:
m_ColorEndControl.ShowWindow( SW_SHOW );
break;
}
if ( bSetDialog == true )
{
m_BlendColorOperationControl.SetCurSel( m_ColorMode[ m_nSelectedTexture ] );
}
}
void CSculptBlendOptions::SelectTexture( int nTexture )
{
m_nSelectedTexture = nTexture;
m_ColorStartControl.SetColor( m_vStartDrawColor[ m_nSelectedTexture ].x, m_vStartDrawColor[ m_nSelectedTexture ].y, m_vStartDrawColor[ m_nSelectedTexture ].z );
m_ColorEndControl.SetColor( m_vEndDrawColor[ m_nSelectedTexture ].x, m_vEndDrawColor[ m_nSelectedTexture ].y, m_vEndDrawColor[ m_nSelectedTexture ].z );
SetColorMode( m_ColorMode[ m_nSelectedTexture ], true );
for( int i = 0; i < MAX_MULTIBLEND_CHANNELS; i++ )
{
m_ColorMaskControl[ i ].SetCheck( ( i == m_nSelectedTexture ? BST_CHECKED : BST_UNCHECKED ) );
}
}
//-----------------------------------------------------------------------------
// Purpose: prevent the dialog from closing
//-----------------------------------------------------------------------------
void CSculptBlendOptions::OnOK()
{
}
//-----------------------------------------------------------------------------
// Purpose: prevent the dialog from closing
//-----------------------------------------------------------------------------
void CSculptBlendOptions::OnCancel()
{
}
//-----------------------------------------------------------------------------
// Purpose: set up the data exchange for the variables
// Input : pDX - the data exchange object
//-----------------------------------------------------------------------------
void CSculptBlendOptions::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_BLEND_AMOUNT, m_BlendAmountControl);
DDX_Control(pDX, IDC_BLEND_AMOUNT_TEXT, m_BlendAmountTextControl);
DDX_Control(pDX, IDC_TEXTURE_BUTTON1, m_TextureControl[ 0 ]);
DDX_Control(pDX, IDC_TEXTURE_BUTTON2, m_TextureControl[ 1 ]);
DDX_Control(pDX, IDC_TEXTURE_BUTTON3, m_TextureControl[ 2 ]);
DDX_Control(pDX, IDC_TEXTURE_BUTTON4, m_TextureControl[ 3 ]);
DDX_Control(pDX, IDC_TEXTURE1_MASK, m_TextureMaskControl[ 0 ]);
DDX_Control(pDX, IDC_TEXTURE2_MASK, m_TextureMaskControl[ 1 ]);
DDX_Control(pDX, IDC_TEXTURE3_MASK, m_TextureMaskControl[ 2 ]);
DDX_Control(pDX, IDC_TEXTURE4_MASK, m_TextureMaskControl[ 3 ]);
DDX_Control(pDX, IDC_COLOR1_MASK, m_ColorMaskControl[ 0 ]);
DDX_Control(pDX, IDC_COLOR2_MASK, m_ColorMaskControl[ 1 ]);
DDX_Control(pDX, IDC_COLOR3_MASK, m_ColorMaskControl[ 2 ]);
DDX_Control(pDX, IDC_COLOR4_MASK, m_ColorMaskControl[ 3 ]);
DDX_Control(pDX, IDC_COLOR_BLEND_AMOUNT, m_ColorBlendAmountControl);
DDX_Control(pDX, IDC_COLOR_BLEND_AMOUNT_TEXT, m_ColorBlendAmountTextControl);
DDX_Control(pDX, IDC_SET_COLOR, m_ColorStartControl);
DDX_Control(pDX, IDC_SET_COLOR2, m_ColorEndControl);
DDX_Control(pDX, IDC_BLEND_COLOR_OPERATION, m_BlendColorOperationControl);
DDX_Control(pDX, IDC_SCULPT_PUSH_OPTION_FALLOFF_POSITION, m_FalloffPositionControl);
DDX_Control(pDX, IDC_SCULPT_PUSH_OPTION_FALLOFF_FINAL, m_FalloffFinalControl);
DDX_Control(pDX, IDC_ALPHA_BLEND_AMOUNT, m_AlphaBlendAmountControl);
DDX_Control(pDX, IDC_ALPHA_BLEND_AMOUNT_TEXT, m_AlphaBlendAmountTextControl);
}
BEGIN_MESSAGE_MAP(CSculptBlendOptions, CDialog)
ON_NOTIFY(NM_CUSTOMDRAW, IDC_BLEND_AMOUNT, &CSculptBlendOptions::OnNMCustomdrawBlendAmount)
ON_WM_SHOWWINDOW()
ON_BN_CLICKED(IDC_TEXTURE_BUTTON1, &CSculptBlendOptions::OnBnClickedTextureButton1)
ON_BN_CLICKED(IDC_TEXTURE_BUTTON2, &CSculptBlendOptions::OnBnClickedTextureButton2)
ON_BN_CLICKED(IDC_TEXTURE_BUTTON3, &CSculptBlendOptions::OnBnClickedTextureButton3)
ON_BN_CLICKED(IDC_TEXTURE_BUTTON4, &CSculptBlendOptions::OnBnClickedTextureButton4)
ON_COMMAND(ID_BLEND_SELECT_TEXTURE_1, &CSculptBlendOptions::OnBnClickedTextureButton1)
ON_COMMAND(ID_BLEND_SELECT_TEXTURE_2, &CSculptBlendOptions::OnBnClickedTextureButton2)
ON_COMMAND(ID_BLEND_SELECT_TEXTURE_3, &CSculptBlendOptions::OnBnClickedTextureButton3)
ON_COMMAND(ID_BLEND_SELECT_TEXTURE_4, &CSculptBlendOptions::OnBnClickedTextureButton4)
ON_COMMAND(ID_BLEND_SHRINK_BRUSH, &CSculptBlendOptions::ShrinkBrush)
ON_COMMAND(ID_BLEND_ENLARGE_BRUSH, &CSculptBlendOptions::EnlargeBrush)
ON_BN_CLICKED(IDC_SET_COLOR, &CSculptBlendOptions::OnBnClickedSetColor)
ON_BN_CLICKED(IDC_SET_COLOR2, &CSculptBlendOptions::OnBnClickedSetColor2)
ON_NOTIFY(NM_CUSTOMDRAW, IDC_COLOR_BLEND_AMOUNT, &CSculptBlendOptions::OnNMCustomdrawColorBlendAmount)
ON_CBN_SELCHANGE(IDC_BLEND_COLOR_OPERATION, &CSculptBlendOptions::OnCbnSelchangeBlendColorOperation)
ON_NOTIFY(NM_CUSTOMDRAW, IDC_ALPHA_BLEND_AMOUNT, &CSculptBlendOptions::OnNMCustomdrawAlphaBlendAmount)
ON_WM_RBUTTONDBLCLK()
END_MESSAGE_MAP()
void CSculptBlendOptions::OnShowWindow(BOOL bShow, UINT nStatus)
{
__super::OnShowWindow(bShow, nStatus);
if ( bShow == FALSE )
{
m_nDefaultFalloffPosition = m_FalloffPositionControl.GetPos();
m_nDefaultFalloffFinal = m_FalloffFinalControl.GetPos();
m_nDefaultBlendAmount = m_BlendAmountControl.GetPos();
m_nDefaultColorBlendAmount = m_ColorBlendAmountControl.GetPos();
m_nDefaultAlphaBlendAmount = m_AlphaBlendAmountControl.GetPos();
APP()->ClearCustomAccelerator();
return;
}
// Get the displacement manager from the active map document.
IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
if( pDispMgr )
{
int nDispCount = pDispMgr->SelectCount();
for ( int iDisp = 0; iDisp < nDispCount; iDisp++ )
{
CMapDisp *pDisp = pDispMgr->GetFromSelect( iDisp );
if ( pDisp )
{
CMapFace *pFace = static_cast< CMapFace * >( pDisp->GetParent() );
IMaterial *pMaterial = pFace->GetTexture()->GetMaterial();
if ( strcmpi( pMaterial->GetShaderName(), "Lightmapped_4WayBlend" ) == 0 )
{
m_b4WayBlendMode = true;
}
else
{
m_b4WayBlendMode = false;
}
for( int i = 1; i <= MAX_MULTIBLEND_CHANNELS; i++ )
{
char temp[ 128 ];
if ( i == 1 )
{
sprintf( temp, "$basetexture" );
}
else
{
sprintf( temp, "$basetexture%d", i );
}
IMaterialVar *pMaterialVar = pMaterial->FindVar( temp, NULL, false );
if ( pMaterialVar != NULL )
{
IEditorTexture *pTexture = g_Textures.FindActiveTexture( pMaterialVar->GetStringValue() );
pTexture->Load();
m_TextureControl[ i - 1 ].SetTexture( pTexture );
m_TextureControl[ i - 1 ].SetSelected( ( m_nSelectedTexture == i - 1 ) );
m_TextureMaskControl[ i - 1 ].SetCheck( BST_CHECKED );
m_ColorMaskControl[ i - 1 ].SetCheck( BST_UNCHECKED );
}
m_ColorMaskControl[ i - 1 ].EnableWindow( !m_b4WayBlendMode );
}
m_AlphaBlendAmountControl.EnableWindow( !m_b4WayBlendMode );
m_AlphaBlendAmountTextControl.EnableWindow( !m_b4WayBlendMode );
m_ColorBlendAmountControl.EnableWindow( !m_b4WayBlendMode );
m_ColorBlendAmountTextControl.EnableWindow( !m_b4WayBlendMode );
m_BlendColorOperationControl.EnableWindow( !m_b4WayBlendMode );
m_ColorStartControl.EnableWindow( !m_b4WayBlendMode );
m_ColorEndControl.EnableWindow( !m_b4WayBlendMode );
break;
}
}
}
m_TextureControl[ m_nSelectedTexture ].SetSelected( true );
SelectTexture( m_nSelectedTexture );
APP()->SetCustomAccelerator( m_hWnd, IDR_BLEND_ACCELERATOR );
}
//-----------------------------------------------------------------------------
// 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 CSculptBlendOptions::BeginPaint( CMapView3D *pView, const Vector2D &vPoint )
{
__super::BeginPaint( pView, vPoint );
if ( m_bCtrlDown )
{
m_Direction = -1.0f;
}
else
{
m_Direction = 1.0f;
}
m_nLastCollideDisplacement = -1;
return true;
}
//-----------------------------------------------------------------------------
// Purpose: draws the tool in the 3d view
// Input : pRender - the 3d renderer
//-----------------------------------------------------------------------------
void CSculptBlendOptions::RenderTool3D( CRender3D *pRender )
{
pRender->PushRenderMode( RENDER_MODE_WIREFRAME );
m_flFalloffSpot = m_FalloffPositionControl.GetPos() / 100.0f;
m_flFalloffEndingValue = m_FalloffFinalControl.GetPos() / 100.0f;
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_Direction < 0.0f )
{ // red for negative blending
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();
}
else
{ // green for positive blending
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();
}
pRender->PopRenderMode();
}
//-----------------------------------------------------------------------------
// 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 CSculptBlendOptions::OnRMouseDown3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
{
CSculptTool::OnRMouseDown3D( pView, nFlags, vPoint );
return true;
}
bool CSculptBlendOptions::DoPaint( CMapView3D *pView, const Vector2D &vPoint )
{
Vector vCollisionPoint, vCollisionNormal;
float flCollisionIntercept;
int nCollideDisplacement, nCollideTri;
if ( FindCollisionIntercept( pView->GetCamera(), vPoint, true, vCollisionPoint, vCollisionNormal, flCollisionIntercept, &nCollideDisplacement, &nCollideTri ) == false )
{
return false;
}
// if ( m_nLastCollideDisplacement != -1 && m_nLastCollideDisplacement == nCollideDisplacement && m_nLastCollideTri == nCollideTri )
// {
// return false;
// }
m_nLastCollideDisplacement = nCollideDisplacement;
m_nLastCollideTri = nCollideTri;
return __super::DoPaint( pView, vPoint );
}
//-----------------------------------------------------------------------------
// 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 CSculptBlendOptions::DoPaintOperation( CMapView3D *pView, const Vector2D &vPoint, CMapDisp *pDisp, CMapDisp *pOrigDisp )
{
Vector4D vBlend, vPaintBlend;
Vector4D vAlphaBlend, vPaintAlphaBlend;
Vector vColor[ MAX_MULTIBLEND_CHANNELS ], vPaintColor[ MAX_MULTIBLEND_CHANNELS ];
float flDistance;
float flLengthPercent;
int nIndex = m_nSelectedTexture;
float flTextureBlendAmount = ( float )m_BlendAmountControl.GetPos() / 2000.0f;
float flColorBlendAmount = ( float )m_ColorBlendAmountControl.GetPos() / 2000.0f;
float flAlphaBlendAmount = ( float )m_AlphaBlendAmountControl.GetPos() / 1000.0f;
bool bDrawTexture = ( m_BlendAmountControl.GetPos() > 0 );
bool bDrawAlpha = ( m_AlphaBlendAmountControl.GetPos() > 0 );
bool bDrawColor = ( m_ColorBlendAmountControl.GetPos() > 0 );
bool bDrawTextureChannel[ MAX_MULTIBLEND_CHANNELS ], bDrawColorChannel[ MAX_MULTIBLEND_CHANNELS ];
m_flFalloffSpot = m_FalloffPositionControl.GetPos() / 100.0f;
m_flFalloffEndingValue = m_FalloffFinalControl.GetPos() / 100.0f;
if ( nIndex < 0 )
{
return;
}
flAlphaBlendAmount *= m_Direction;
if ( WinTab_Opened() == true )
{
flTextureBlendAmount *= WinTab_GetPressure();
flColorBlendAmount *= WinTab_GetPressure();
flAlphaBlendAmount *= WinTab_GetPressure();
}
for( int i = 0; i < MAX_MULTIBLEND_CHANNELS; i++ )
{
bDrawTextureChannel[ i ] = ( bDrawTexture == true && m_TextureMaskControl[ i ].GetCheck() == BST_CHECKED );
bDrawColorChannel[ i ] = ( bDrawColor == true && m_ColorMaskControl[ i ].GetCheck() == BST_CHECKED );
}
AddToUndo( &pDisp );
int nVertCount = pDisp->GetSize();
for ( int iVert = 0; iVert < nVertCount; iVert++ )
{
if ( IsPointInScreenCircle( pView, pDisp, pOrigDisp, iVert, true, false, &flLengthPercent ) )
{
pDisp->GetMultiBlend( iVert, vBlend, vAlphaBlend, vColor[ 0 ], vColor[ 1 ], vColor[ 2 ], vColor[ 3 ] );
if ( flLengthPercent > m_flFalloffSpot )
{
flLengthPercent = ( flLengthPercent - m_flFalloffSpot ) / ( 1.0f - m_flFalloffSpot );
flLengthPercent = 1.0 - flLengthPercent;
flDistance = ( ( 1.0f - m_flFalloffEndingValue ) * flLengthPercent ) + ( m_flFalloffEndingValue );
}
else
{
flDistance = 1.0f;
}
if ( flDistance == 0.0f )
{
continue;
}
float flTextureAmount = flTextureBlendAmount * flDistance;
float flColorAmount = flColorBlendAmount * flDistance;
float flAlphaAmount = flAlphaBlendAmount * flDistance;
vPaintBlend = vBlend;
vPaintAlphaBlend = vAlphaBlend;
vPaintColor[ 0 ] = vColor[ 0 ];
vPaintColor[ 1 ] = vColor[ 1 ];
vPaintColor[ 2 ] = vColor[ 2 ];
vPaintColor[ 3 ] = vColor[ 3 ];
Assert( MAX_MULTIBLEND_CHANNELS == 4 );
if ( bDrawTexture == true )
{
if ( m_Direction > 0.0f )
{
if ( nIndex == 4 )
{
float flRemainder = flTextureAmount;
#if 1
// for( int i = 1; i < MAX_MULTIBLEND_CHANNELS; i++ )
for( int i = MAX_MULTIBLEND_CHANNELS - 1; i > 0; i-- )
{
if ( bDrawTextureChannel[ i ] == false )
{
continue;
}
if ( vPaintBlend[ i ] > flRemainder )
{
vPaintBlend[ i ] -= flRemainder;
flRemainder = 0.0f;
break;
}
else
{
flRemainder -= vPaintBlend[ i ];
vPaintBlend[ i ] = 0.0f;
}
}
#else
for( int i = MAX_MULTIBLEND_CHANNELS - 1; i > 0; i-- )
{
if ( m_TextureMaskControl[ i ].GetCheck() != BST_CHECKED )
{
continue;
}
if ( vPaintBlend[ i ] > flRemainder )
{
vPaintBlend[ i ] -= flRemainder;
}
else
{
vPaintBlend[ i ] = 0.0f;
}
}
#endif
}
else
{
if ( m_b4WayBlendMode )
{
vPaintBlend[ nIndex ] += flTextureAmount;
for ( int i = nIndex + 1; i < MAX_MULTIBLEND_CHANNELS; i++)
{
if ( bDrawTextureChannel[ i ] == false )
{
continue;
}
if ( vPaintBlend[ i ] > flTextureAmount )
{
vPaintBlend[ i ] -= flTextureAmount;
}
else
{
vPaintBlend[ i ] = 0.0f;
}
}
}
else // multiblend
{
for( int i = nIndex; i >= 0; i-- )
// for( int i = MAX_MULTIBLEND_CHANNELS - 1; i > 0; i-- )
{
if ( i == nIndex )
{
vPaintBlend[ i ] += flTextureAmount;
}
else
{
if ( bDrawTextureChannel[ i ] == false )
{
continue;
}
if ( vPaintBlend[ i ] > flTextureAmount )
{
vPaintBlend[ i ] -= flTextureAmount;
flTextureAmount = 0.0f;
}
else
{
flTextureAmount -= vPaintBlend[ i ];
vPaintBlend[ i ] = 0.0f;
}
}
}
}
}
}
else
{
vPaintBlend[ nIndex ] -= flTextureAmount;
}
vPaintBlend.x = clamp( vPaintBlend.x, 0.0f, 1.0f );
vPaintBlend.y = clamp( vPaintBlend.y, 0.0f, 1.0f );
vPaintBlend.z = clamp( vPaintBlend.z, 0.0f, 1.0f );
vPaintBlend.w = clamp( vPaintBlend.w, 0.0f, 1.0f );
}
if ( bDrawColor == true )
{
Vector vResultColor;
switch( m_ColorMode[ nIndex ] )
{
case COLOR_MODE_SINGLE:
vResultColor = m_vStartDrawColor[ nIndex ];
break;
case COLOR_MODE_RANGE:
{
float flRange = RandomFloat( 0.0f, 1.0f );
vResultColor.x = m_vStartDrawColor[ nIndex ].x + ( ( m_vEndDrawColor[ nIndex ].x - m_vStartDrawColor[ nIndex ].x ) * flRange );
vResultColor.y = m_vStartDrawColor[ nIndex ].y + ( ( m_vEndDrawColor[ nIndex ].y - m_vStartDrawColor[ nIndex ].y ) * flRange );
vResultColor.z = m_vStartDrawColor[ nIndex ].z + ( ( m_vEndDrawColor[ nIndex ].z - m_vStartDrawColor[ nIndex ].z ) * flRange );
}
break;
case COLOR_MODE_OR:
if ( RandomInt( 1, 100 ) > 50 )
{
vResultColor = m_vStartDrawColor[ nIndex ];
}
else
{
vResultColor = m_vEndDrawColor[ nIndex ];
}
break;
}
if ( m_Direction < 0.0f )
{
vResultColor.Init( 1.0f, 1.0f, 1.0f );
}
for( int i = 0; i < MAX_MULTIBLEND_CHANNELS; i++ )
{
if ( bDrawColorChannel[ i ] == true )
{
vPaintColor[ i ] = ( vPaintColor[ i ] * ( 1.0f - flColorAmount ) ) + ( vResultColor * flColorAmount );
}
}
}
if ( bDrawAlpha == true )
{
vPaintAlphaBlend[ nIndex ] = clamp( vPaintAlphaBlend[ nIndex ] + flAlphaAmount, 0.0f, 2.0f );
}
pDisp->SetMultiBlend( iVert, vPaintBlend, vPaintAlphaBlend, vPaintColor[ 0 ], vPaintColor[ 1 ], vPaintColor[ 2 ], vPaintColor[ 3 ] );
}
}
}
void CSculptBlendOptions::OnNMCustomdrawBlendAmount(NMHDR *pNMHDR, LRESULT *pResult)
{
// LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
// TODO: Add your control notification handler code here
*pResult = 0;
if ( m_BlendAmountControl.GetPos() == 0 )
{
m_BlendAmountTextControl.SetWindowText( "Off" );
}
else
{
char temp[ 128 ];
sprintf( temp, "%d%%", m_BlendAmountControl.GetPos() );
m_BlendAmountTextControl.SetWindowText( temp );
}
}
void CSculptBlendOptions::OnBnClickedTextureButton1()
{
m_TextureControl[ m_nSelectedTexture ].SetSelected( false );
SelectTexture( 0 );
m_TextureControl[ m_nSelectedTexture ].SetSelected( true );
}
void CSculptBlendOptions::OnBnClickedTextureButton2()
{
m_TextureControl[ m_nSelectedTexture ].SetSelected( false );
SelectTexture( 1 );
m_TextureControl[ m_nSelectedTexture ].SetSelected( true );
}
void CSculptBlendOptions::OnBnClickedTextureButton3()
{
m_TextureControl[ m_nSelectedTexture ].SetSelected( false );
SelectTexture( 2 );
m_TextureControl[ m_nSelectedTexture ].SetSelected( true );
}
void CSculptBlendOptions::OnBnClickedTextureButton4()
{
m_TextureControl[ m_nSelectedTexture ].SetSelected( false );
SelectTexture( 3 );
m_TextureControl[ m_nSelectedTexture ].SetSelected( true );
}
#define BRUSH_CHANGE_AMOUNT 4
void CSculptBlendOptions::ShrinkBrush()
{
if ( m_BrushSize > BRUSH_CHANGE_AMOUNT + 1 )
{
m_BrushSize -= BRUSH_CHANGE_AMOUNT;
}
}
void CSculptBlendOptions::EnlargeBrush()
{
m_BrushSize += BRUSH_CHANGE_AMOUNT;
}
#include <tier0/memdbgoff.h>
void CSculptBlendOptions::OnBnClickedSetColor()
{
CColorDialog dlg( RGB( m_vStartDrawColor[ m_nSelectedTexture ].x * 255, m_vStartDrawColor[ m_nSelectedTexture ].y * 255, m_vStartDrawColor[ m_nSelectedTexture ].z * 255 ), CC_FULLOPEN );
if ( dlg.DoModal() == IDOK )
{
m_vStartDrawColor[ m_nSelectedTexture ].x = GetRValue( dlg.m_cc.rgbResult ) / 255.0f;
m_vStartDrawColor[ m_nSelectedTexture ].y = GetGValue( dlg.m_cc.rgbResult ) / 255.0f;
m_vStartDrawColor[ m_nSelectedTexture ].z = GetBValue( dlg.m_cc.rgbResult ) / 255.0f;
m_ColorStartControl.SetColor( m_vStartDrawColor[ m_nSelectedTexture ].x, m_vStartDrawColor[ m_nSelectedTexture ].y, m_vStartDrawColor[ m_nSelectedTexture ].z );
}
}
void CSculptBlendOptions::OnBnClickedSetColor2()
{
CColorDialog dlg( RGB( m_vEndDrawColor[ m_nSelectedTexture ].x * 255, m_vEndDrawColor[ m_nSelectedTexture ].y * 255, m_vEndDrawColor[ m_nSelectedTexture ].z * 255 ), CC_FULLOPEN );
if ( dlg.DoModal() == IDOK )
{
m_vEndDrawColor[ m_nSelectedTexture ].x = GetRValue( dlg.m_cc.rgbResult ) / 255.0f;
m_vEndDrawColor[ m_nSelectedTexture ].y = GetGValue( dlg.m_cc.rgbResult ) / 255.0f;
m_vEndDrawColor[ m_nSelectedTexture ].z = GetBValue( dlg.m_cc.rgbResult ) / 255.0f;
m_ColorEndControl.SetColor( m_vEndDrawColor[ m_nSelectedTexture ].x, m_vEndDrawColor[ m_nSelectedTexture ].y, m_vEndDrawColor[ m_nSelectedTexture ].z );
}
}
void CSculptBlendOptions::OnNMCustomdrawColorBlendAmount(NMHDR *pNMHDR, LRESULT *pResult)
{
*pResult = 0;
if ( m_ColorBlendAmountControl.GetPos() == 0 )
{
m_ColorBlendAmountTextControl.SetWindowText( "Off" );
}
else
{
char temp[ 128 ];
sprintf( temp, "%d%%", m_ColorBlendAmountControl.GetPos() );
m_ColorBlendAmountTextControl.SetWindowText( temp );
}
}
void CSculptBlendOptions::OnCbnSelchangeBlendColorOperation()
{
SetColorMode( ( ColorMode )m_BlendColorOperationControl.GetCurSel(), false );
}
void CSculptBlendOptions::OnNMCustomdrawAlphaBlendAmount(NMHDR *pNMHDR, LRESULT *pResult)
{
// LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
*pResult = 0;
if ( m_AlphaBlendAmountControl.GetPos() == 0 )
{
m_AlphaBlendAmountTextControl.SetWindowText( "Off" );
}
else
{
char temp[ 128 ];
sprintf( temp, "%d%%", m_AlphaBlendAmountControl.GetPos() );
m_AlphaBlendAmountTextControl.SetWindowText( temp );
}
}
void CSculptBlendOptions::OnRButtonDblClk(UINT nFlags, CPoint point)
{
__super::OnRButtonDblClk(nFlags, point);
// Get the displacement manager from the active map document.
IWorldEditDispMgr *pDispMgr = GetActiveWorldEditDispManager();
if( !pDispMgr )
{
return;
}
bool bDrawTexture = ( m_BlendAmountControl.GetPos() > 0 );
bool bDrawAlpha = ( m_AlphaBlendAmountControl.GetPos() > 0 );
bool bDrawColor = ( m_ColorBlendAmountControl.GetPos() > 0 );
bool bDrawTextureChannel[ MAX_MULTIBLEND_CHANNELS ], bDrawColorChannel[ MAX_MULTIBLEND_CHANNELS ];
Vector4D vBlend, vPaintBlend, vAlphaBlend, vPaintAlphaBlend;
Vector vColor[ MAX_MULTIBLEND_CHANNELS ], vPaintColor[ MAX_MULTIBLEND_CHANNELS ];
vPaintBlend.Init( 1.0f, 0.0f, 0.0f, 0.0f );
vPaintAlphaBlend.Init();
for( int i = 0; i < MAX_MULTIBLEND_CHANNELS; i++ )
{
vPaintColor[ i ] = Vector( 1.0f, 1.0f, 1.0f );
bDrawTextureChannel[ i ] = ( bDrawTexture == true && m_TextureMaskControl[ i ].GetCheck() == BST_CHECKED );
bDrawColorChannel[ i ] = ( bDrawColor == true && m_ColorMaskControl[ i ].GetCheck() == BST_CHECKED );
}
// 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 )
{
AddToUndo( &pDisp );
int nVertCount = pDisp->GetSize();
for ( int iVert = 0; iVert < nVertCount; iVert++ )
{
pDisp->GetMultiBlend( iVert, vBlend, vAlphaBlend, vColor[ 0 ], vColor[ 1 ], vColor[ 2 ], vColor[ 3 ] );
if ( bDrawAlpha == true )
{
vAlphaBlend = vPaintAlphaBlend;
}
for( int i = 0; i < MAX_MULTIBLEND_CHANNELS; i++ )
{
if ( bDrawTextureChannel[ i ] == true )
{
vBlend[ i ] = vPaintBlend[ i ];
}
if ( bDrawColorChannel[ i ] == true )
{
vColor[ i ] = vPaintColor[ i ];
}
}
pDisp->SetMultiBlend( iVert, vBlend, vAlphaBlend, vColor[ 0 ], vColor[ 1 ], vColor[ 2 ], vColor[ 3 ] );
}
}
}
pDispMgr->PostUndo();
}