`//////////////////////////////////////////////////////////////////////////// // // Crytek Engine Source File. // Copyright (C), Crytek Studios, 2001. // ------------------------------------------------------------------------- // File name: BrushTool.cpp // Version: v1.00 // Created: 11/1/2002 by Timur. // Compilers: Visual C++ 6.0 // Description: Terrain Modification Tool implementation. // ------------------------------------------------------------------------- // History: // //////////////////////////////////////////////////////////////////////////// #include "StdAfx.h" #include "BrushTool.h" #include "..\Viewport.h" #include "Brush.h" #include "..\Objects\ObjectManager.h" #include "..\Objects\BrushObject.h" ////////////////////////////////////////////////////////////////////////// IMPLEMENT_DYNCREATE(CBrushTool,CEditTool) ////////////////////////////////////////////////////////////////////////// CBrushTool::CBrushTool() { m_IEditor = 0; m_mode = BrushNoMode; m_bMouseCaptured = false; m_lastBrushBounds = BBox( Vec3(-32,-32,-32),Vec3(32,32,32) ); } ////////////////////////////////////////////////////////////////////////// CBrushTool::~CBrushTool() { } ////////////////////////////////////////////////////////////////////////// void CBrushTool::BeginEditParams( IEditor *ie,int flags ) { m_IEditor = ie; } ////////////////////////////////////////////////////////////////////////// void CBrushTool::EndEditParams() { } void::CBrushTool::Display( DisplayContext &dc ) { CalcLastBrushSize(); } bool CBrushTool::OnLButtonDown( CViewport *view,UINT nFlags,CPoint point ) { m_mode = BrushNoMode; m_mouseDownPos = point; if (nFlags & MK_SHIFT) { // Enable Create or sheer mode. if (GetIEditor()->GetSelection()->IsEmpty()) { // Create new brush. m_mode = BrushCreateMode; view->BeginUndo(); view->CaptureMouse(); m_bMouseCaptured = true; return true; } } bool bMouseClickedSelected = false; // If clicked within selected brush. move this brush. ObjectHitInfo hitInfo(view,point); if (view->HitTest( point,hitInfo )) { if (hitInfo.object->GetType() == OBJTYPE_BRUSH && hitInfo.object->IsSelected()) { bMouseClickedSelected = true; // Only Left buttons should be pressed (no combinations) if (nFlags == MK_LBUTTON) { m_mode = BrushMoveMode; view->BeginUndo(); view->CaptureMouse(); m_bMouseCaptured = true; return true; } } } if (nFlags & MK_SHIFT) { if (!bMouseClickedSelected) { // Clicked outside of selected objects. // So start streching brushes. //GetIEditor()->ClearSelection(); bool bShear = (nFlags & MK_CONTROL) != 0; m_mode = BrushStretchMode; view->BeginUndo(); view->CaptureMouse(); m_bMouseCaptured = true; // Select brush drag sides. CSelectionGroup *selection = GetIEditor()->GetSelection(); for (int i = 0; i < selection->GetCount(); i++) { if (!selection->GetObject(i)->IsKindOf(RUNTIME_CLASS(CBrushObject))) continue; CBrushObject *brushObj = (CBrushObject*)selection->GetObject(i); Vec3 raySrc,rayDir; view->ViewToWorldRay( point,raySrc,rayDir ); brushObj->SelectBrushSide( raySrc,rayDir,bShear ); } m_IEditor->UpdateViews(eUpdateObjects); return true; } } return false; } ////////////////////////////////////////////////////////////////////////// bool CBrushTool::OnLButtonUp( CViewport *view,UINT nFlags,CPoint point ) { bool bResult = false; if (m_mode == BrushMoveMode) { view->AcceptUndo( "Move Brush" ); bResult = true; } else if (m_mode == BrushCreateMode) { view->AcceptUndo( "Create Brush" ); bResult = true; } else if (m_mode == BrushStretchMode) { view->AcceptUndo( "Sheer Brush(s)" ); bResult = true; } if (m_bMouseCaptured) { view->ReleaseMouse(); } m_mode = BrushNoMode; return bResult; } ////////////////////////////////////////////////////////////////////////// bool CBrushTool::OnMouseMove( CViewport *view,UINT nFlags, CPoint point ) { if (m_mode == BrushMoveMode) { // Move brush. GetIEditor()->RestoreUndo(); Vec3 p1 = view->MapViewToCP(m_mouseDownPos); Vec3 p2 = view->MapViewToCP(point); Vec3 v = view->GetCPVector(p1,p2); int coordSys = GetIEditor()->GetReferenceCoordSys(); GetIEditor()->GetSelection()->Move( v,false, coordSys==COORDS_WORLD ); return true; } if (m_mode == BrushCreateMode) { NewBrush( view,point ); return true; } else if (m_mode == BrushStretchMode) { StretchBrush( view,point ); return true; } return false; } ////////////////////////////////////////////////////////////////////////// bool CBrushTool::MouseCallback( CViewport *view,EMouseEvent event,CPoint &point,int flags ) { bool bProcessed = false; if (event == eMouseLDown) { bProcessed = OnLButtonDown( view,flags,point ); } else if (event == eMouseLUp) { bProcessed = OnLButtonUp( view,flags,point ); } else if (event == eMouseMove) { bProcessed = OnMouseMove( view,flags,point ); } // Not processed. return bProcessed; } ////////////////////////////////////////////////////////////////////////// bool CBrushTool::OnKeyDown( CViewport *view,uint nChar,uint nRepCnt,uint nFlags ) { if (nChar == VK_ESCAPE) { // Escape clears selection. GetIEditor()->ClearSelection(); return true; } // Not processed. return false; } ////////////////////////////////////////////////////////////////////////// bool CBrushTool::OnKeyUp( CViewport *view,uint nChar,uint nRepCnt,uint nFlags ) { // Not processed. return false; } ////////////////////////////////////////////////////////////////////////// void CBrushTool::NewBrush( CViewport *view,CPoint point ) { CRect rc( m_mouseDownPos,point ); rc.NormalizeRect(); BBox brushBox; brushBox.Reset(); brushBox.Add( view->MapViewToCP( CPoint(rc.left,rc.top) ) ); brushBox.Add( view->MapViewToCP( CPoint(rc.right,rc.bottom) ) ); switch (view->GetType()) { case ET_ViewportXY: brushBox.min.z = m_lastBrushBounds.min.z; brushBox.max.z = m_lastBrushBounds.max.z; break; case ET_ViewportXZ: brushBox.min.y = m_lastBrushBounds.min.y; brushBox.max.y = m_lastBrushBounds.max.y; break; case ET_ViewportYZ: brushBox.min.x = m_lastBrushBounds.min.x; brushBox.max.x = m_lastBrushBounds.max.x; break; default: brushBox.min.z = m_lastBrushBounds.min.z; brushBox.max.z = m_lastBrushBounds.max.z; } if (IsVectorsEqual(brushBox.min,brushBox.max)) return; // If width or height or depth are zero. if (fabs(brushBox.min.x-brushBox.max.x) < 0.01 || fabs(brushBox.min.y-brushBox.max.y) < 0.01 || fabs(brushBox.min.z-brushBox.max.z) < 0.01) return; if (IsEquivalent(m_lastBrushBounds.min,brushBox.min,0) && IsEquivalent(m_lastBrushBounds.max,brushBox.max,0)) return; m_lastBrushBounds = brushBox; Vec3 center = (brushBox.min + brushBox.max)/2.0f; brushBox.min -= center; brushBox.max -= center; SBrush *brush = new SBrush; SMapTexInfo ti; brush->Create( brushBox.min,brushBox.max,&ti ); bool bSolidValid = brush->BuildSolid(); CBrushObject *brushObj; CBaseObject *obj = m_IEditor->GetSelectedObject(); if (obj && obj->IsKindOf(RUNTIME_CLASS(CBrushObject))) { brushObj = (CBrushObject*)obj; } else { m_IEditor->ClearSelection(); brushObj = (CBrushObject*)m_IEditor->NewObject( "Brush" ); m_IEditor->SelectObject( brushObj ); } brushObj->SetPos( center ); brushObj->SetBrush( brush ); } ////////////////////////////////////////////////////////////////////////// void CBrushTool::StretchBrush( CViewport* view,CPoint point ) { Vec3 src = view->MapViewToCP(m_mouseDownPos); Vec3 trg = view->MapViewToCP(point); Vec3 delta = trg - src; if (IsEquivalent(delta,Vec3(0,0,0),0)) return; m_mouseDownPos = point; Vec3 raySrc,rayDir; view->ViewToWorldRay( point,raySrc,rayDir ); CSelectionGroup *selection = GetIEditor()->GetSelection(); for (int i = 0; i < selection->GetCount(); i++) { if (!selection->GetObject(i)->IsKindOf(RUNTIME_CLASS(CBrushObject))) continue; CBrushObject *brushObj = (CBrushObject*)selection->GetObject(i); brushObj->MoveSelectedPoints( delta ); //SBrush *brush = brushObj->GetBrush(); //brush->SideSelect( } view->Invalidate(FALSE); } ////////////////////////////////////////////////////////////////////////// void CBrushTool::CalcLastBrushSize() { bool bSelected = false; BBox box; box.Reset(); CSelectionGroup *sel = m_IEditor->GetSelection(); for (int i = 0; i < sel->GetCount(); i++) { if (sel->GetObject(i)->GetType() == OBJTYPE_BRUSH) { BBox local; sel->GetObject(i)->GetBoundBox(local); box.Add( local.min ); box.Add( local.max ); bSelected = true; } } BBox empty; empty.Reset(); if (bSelected) { if (!IsEquivalent(box.min,empty.min,0) && !IsEquivalent(box.max,empty.max,0)) { m_lastBrushBounds = box; } } }