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.

1032 lines
25 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Implements the entity/prefab placement tool.
  4. //
  5. //=============================================================================//
  6. #include "stdafx.h"
  7. #include "History.h"
  8. #include "MainFrm.h"
  9. #include "MapDefs.h"
  10. #include "MapSolid.h"
  11. #include "MapDoc.h"
  12. #include "MapWorld.h"
  13. #include "MapView2D.h"
  14. #include "MapView3D.h"
  15. #include "Material.h"
  16. #include "materialsystem/IMesh.h"
  17. #include "Render2D.h"
  18. #include "Render3D.h"
  19. #include "StatusBarIDs.h"
  20. #include "TextureSystem.h"
  21. #include "toolsprinkle.h"
  22. #include "ToolManager.h"
  23. #include "hammer.h"
  24. #include "vgui/Cursor.h"
  25. #include "Selection.h"
  26. #include "vstdlib/random.h"
  27. #include "KeyValues.h"
  28. #include "entitysprinkledlg.h"
  29. // memdbgon must be the last include file in a .cpp file!!!
  30. #include <tier0/memdbgon.h>
  31. #define SPRINKLE_PATH "scripts/hammer/sprinkle/"
  32. //#pragma warning(disable:4244)
  33. //-----------------------------------------------------------------------------
  34. // Purpose:
  35. //-----------------------------------------------------------------------------
  36. CToolEntitySprinkle::CToolEntitySprinkle(void)
  37. {
  38. SetEmpty();
  39. m_vecPos.Init();
  40. pSprinkleDlg = NULL;
  41. m_pSprinkleInfo = NULL;
  42. m_OrigBrushSize = m_BrushSize = 256;
  43. m_vMousePoint.Init();
  44. m_bWorldValid = false;
  45. m_vWorldMousePoint.Init();
  46. m_InSizingMode = false;
  47. m_InDrawMode = false;
  48. m_bCtrlDown = false;
  49. }
  50. //-----------------------------------------------------------------------------
  51. // Purpose:
  52. //-----------------------------------------------------------------------------
  53. CToolEntitySprinkle::~CToolEntitySprinkle(void)
  54. {
  55. }
  56. // memdbgon must be the last include file in a .cpp file!!!
  57. #include <tier0/memdbgoff.h>
  58. //-----------------------------------------------------------------------------
  59. // Purpose:
  60. // Input :
  61. // Output :
  62. //-----------------------------------------------------------------------------
  63. void CToolEntitySprinkle::OnActivate()
  64. {
  65. if ( pSprinkleDlg == NULL )
  66. {
  67. pSprinkleDlg = new CEntitySprinkleDlg();
  68. pSprinkleDlg->Create( CEntitySprinkleDlg::IDD, NULL );
  69. }
  70. if ( m_pSprinkleInfo != NULL )
  71. {
  72. m_pSprinkleInfo->deleteThis();
  73. m_pSprinkleInfo = NULL;
  74. }
  75. m_pSprinkleInfo = new KeyValues( "Sprinkles" );
  76. FileFindHandle_t findHandle;
  77. const char *pFileName = g_pFullFileSystem->FindFirstEx( SPRINKLE_PATH "*.txt", "GAME", &findHandle );
  78. while( pFileName )
  79. {
  80. CString FullPath = SPRINKLE_PATH;
  81. FullPath += pFileName;
  82. KeyValues *pLocalInfo = new KeyValues( "loading" );
  83. if ( !pLocalInfo->LoadFromFile( g_pFileSystem, FullPath, "GAME" ) )
  84. {
  85. pLocalInfo->deleteThis();
  86. }
  87. m_pSprinkleInfo->AddSubKey( pLocalInfo );
  88. pFileName = g_pFullFileSystem->FindNext( findHandle );
  89. }
  90. g_pFullFileSystem->FindClose( findHandle );
  91. pSprinkleDlg->SetSprinkleTypes( m_pSprinkleInfo );
  92. pSprinkleDlg->ShowWindow( SW_SHOW );
  93. }
  94. void CToolEntitySprinkle::OnDeactivate()
  95. {
  96. pSprinkleDlg->ShowWindow( SW_HIDE );
  97. }
  98. //-----------------------------------------------------------------------------
  99. // Purpose:
  100. // Input : pt -
  101. // BOOL -
  102. // Output :
  103. //-----------------------------------------------------------------------------
  104. int CToolEntitySprinkle::HitTest(CMapView *pView, const Vector2D &ptClient, bool bTestHandles)
  105. {
  106. return HitRect( pView, ptClient, m_vecPos, 8 )?TRUE:FALSE;
  107. }
  108. //-----------------------------------------------------------------------------
  109. // Purpose:
  110. // Input : bSave -
  111. //-----------------------------------------------------------------------------
  112. void CToolEntitySprinkle::FinishTranslation(bool bSave)
  113. {
  114. Tool3D::FinishTranslation(bSave);
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Purpose:
  118. // Input : pt -
  119. // uFlags -
  120. // size -
  121. // Output : Returns true if the translation delta was nonzero.
  122. //-----------------------------------------------------------------------------
  123. bool CToolEntitySprinkle::UpdateTranslation( const Vector &vUpdate, UINT uFlags)
  124. {
  125. return true;
  126. }
  127. //-----------------------------------------------------------------------------
  128. // Purpose: determines if any of the special keys ( control, shift, alt ) are pressed
  129. //-----------------------------------------------------------------------------
  130. void CToolEntitySprinkle::DetermineKeysDown( )
  131. {
  132. m_bCtrlDown = ( ( GetAsyncKeyState( VK_CONTROL ) & 0x8000 ) != 0 );
  133. // m_bShiftDown = ( ( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) != 0 );
  134. // m_bAltDown = ( ( GetAsyncKeyState( VK_MENU ) & 0x8000 ) != 0 );
  135. }
  136. //-----------------------------------------------------------------------------
  137. // Purpose:
  138. // Input : pRender -
  139. //-----------------------------------------------------------------------------
  140. void CToolEntitySprinkle::RenderTool2D(CRender2D *pRender)
  141. {
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Purpose:
  145. // Input : pView -
  146. // point -
  147. // Output :
  148. //-----------------------------------------------------------------------------
  149. bool CToolEntitySprinkle::OnContextMenu2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
  150. {
  151. return true;
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Purpose:
  155. // Input : *pView -
  156. // nChar -
  157. // nRepCnt -
  158. // nFlags -
  159. // Output : Returns true on success, false on failure.
  160. //-----------------------------------------------------------------------------
  161. bool CToolEntitySprinkle::OnKeyDown2D(CMapView2D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
  162. {
  163. switch (nChar)
  164. {
  165. case VK_RETURN:
  166. {
  167. return true;
  168. }
  169. case VK_ESCAPE:
  170. {
  171. OnEscape();
  172. return true;
  173. }
  174. }
  175. return false;
  176. }
  177. //-----------------------------------------------------------------------------
  178. // Purpose:
  179. // Input : pView -
  180. // nFlags -
  181. // point -
  182. // Output : Returns true on success, false on failure.
  183. //-----------------------------------------------------------------------------
  184. bool CToolEntitySprinkle::OnLMouseDown2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
  185. {
  186. Tool3D::OnLMouseDown2D(pView, nFlags, vPoint);
  187. return true;
  188. }
  189. //-----------------------------------------------------------------------------
  190. // Purpose:
  191. // Input : Pre CWnd::OnLButtonUp.
  192. // Output : Returns true on success, false on failure.
  193. //-----------------------------------------------------------------------------
  194. bool CToolEntitySprinkle::OnLMouseUp2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
  195. {
  196. Tool3D::OnLMouseUp2D(pView, nFlags, vPoint);
  197. return true;
  198. }
  199. //-----------------------------------------------------------------------------
  200. // Returns true if the message was handled, false otherwise.
  201. //-----------------------------------------------------------------------------
  202. bool CToolEntitySprinkle::OnMouseMove2D(CMapView2D *pView, UINT nFlags, const Vector2D &vPoint)
  203. {
  204. Tool3D::OnMouseMove2D(pView, nFlags, vPoint);
  205. return true;
  206. }
  207. //-----------------------------------------------------------------------------
  208. // Returns true if the message was handled, false otherwise.
  209. //-----------------------------------------------------------------------------
  210. bool CToolEntitySprinkle::OnMouseMove3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  211. {
  212. DetermineKeysDown();
  213. #if 0
  214. Vector vecWorld;
  215. pView->ClientToWorld( vecWorld, vPoint );
  216. m_MousePoint.x = vecWorld.x;
  217. m_MousePoint.y = vecWorld.y;
  218. #else
  219. if ( m_InSizingMode == true )
  220. {
  221. DoSizing( vPoint );
  222. }
  223. else
  224. {
  225. if ( FindWorldMousePoint( pView, vPoint ) == true )
  226. {
  227. if ( m_InDrawMode == true )
  228. {
  229. PerformSprinkle( false );
  230. }
  231. }
  232. }
  233. #endif
  234. return true;
  235. }
  236. //-----------------------------------------------------------------------------
  237. // Returns true if the message was handled, false otherwise.
  238. //-----------------------------------------------------------------------------
  239. bool CToolEntitySprinkle::OnKeyDown3D(CMapView3D *pView, UINT nChar, UINT nRepCnt, UINT nFlags)
  240. {
  241. CMapDoc *pDoc = pView->GetMapDoc();
  242. if (pDoc == NULL)
  243. {
  244. return false;
  245. }
  246. switch (nChar)
  247. {
  248. case VK_RETURN:
  249. {
  250. return true;
  251. }
  252. case VK_ESCAPE:
  253. {
  254. OnEscape();
  255. return true;
  256. }
  257. }
  258. return false;
  259. }
  260. //-----------------------------------------------------------------------------
  261. // Purpose: Handles the escape key in the 2D or 3D views.
  262. //-----------------------------------------------------------------------------
  263. void CToolEntitySprinkle::OnEscape(void)
  264. {
  265. ToolManager()->SetTool( TOOL_PICK_ENTITY );
  266. }
  267. //-----------------------------------------------------------------------------
  268. // Purpose:
  269. // Input : *pView -
  270. // nFlags -
  271. // point -
  272. // Output : Returns true on success, false on failure.
  273. //-----------------------------------------------------------------------------
  274. bool CToolEntitySprinkle::OnLMouseDown3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  275. {
  276. DetermineKeysDown();
  277. if ( FindWorldMousePoint( pView, vPoint ) == true && m_InSizingMode == false )
  278. {
  279. m_InDrawMode = true;
  280. PerformSprinkle( true );
  281. }
  282. return true;
  283. }
  284. //-----------------------------------------------------------------------------
  285. // Purpose:
  286. // Input : *pView -
  287. // nFlags -
  288. // point -
  289. // Output : Returns true on success, false on failure.
  290. //-----------------------------------------------------------------------------
  291. bool CToolEntitySprinkle::OnLMouseUp3D(CMapView3D *pView, UINT nFlags, const Vector2D &vPoint)
  292. {
  293. DetermineKeysDown();
  294. m_InDrawMode = false;
  295. return true;
  296. }
  297. //-----------------------------------------------------------------------------
  298. // Purpose:
  299. // Input :
  300. // Output :
  301. //-----------------------------------------------------------------------------
  302. bool CToolEntitySprinkle::OnRMouseDown3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
  303. {
  304. DetermineKeysDown();
  305. if ( FindWorldMousePoint( pView, vPoint ) == true )
  306. {
  307. m_InDrawMode = false;
  308. DoSizing( vPoint );
  309. }
  310. return true;
  311. }
  312. //-----------------------------------------------------------------------------
  313. // Purpose:
  314. // Input :
  315. // Output :
  316. //-----------------------------------------------------------------------------
  317. bool CToolEntitySprinkle::OnRMouseUp3D( CMapView3D *pView, UINT nFlags, const Vector2D &vPoint )
  318. {
  319. DetermineKeysDown();
  320. m_InSizingMode = false;
  321. return true;
  322. }
  323. //-----------------------------------------------------------------------------
  324. // Purpose: Renders a selection gizmo at our bounds center.
  325. // Input : pRender - Rendering interface.
  326. //-----------------------------------------------------------------------------
  327. void CToolEntitySprinkle::RenderTool3D(CRender3D *pRender)
  328. {
  329. if ( m_bWorldValid == true )
  330. {
  331. pRender->PushRenderMode( RENDER_MODE_WIREFRAME );
  332. if ( m_InSizingMode )
  333. { // yellow for sizing mode
  334. pRender->RenderWireframeSphere( m_vWorldMousePoint, m_BrushSize, 12, 12, 255, 255, 0 );
  335. }
  336. else
  337. {
  338. if ( m_bCtrlDown == true )
  339. {
  340. pRender->RenderWireframeSphere( m_vWorldMousePoint, m_BrushSize, 12, 12, 255, 0, 0 );
  341. }
  342. else
  343. {
  344. pRender->RenderWireframeSphere( m_vWorldMousePoint, m_BrushSize, 12, 12, 0, 255, 0 );
  345. }
  346. KeyValues *pSprinkleType = pSprinkleDlg->GetSprinkleType( );
  347. if ( pSprinkleType != NULL )
  348. {
  349. float flGridXSize, flGridYSize;
  350. float flXSize, flYSize;
  351. Vector vCenter;
  352. float flBrushSizeSq = m_BrushSize * m_BrushSize;
  353. Vector vOffset = Vector( 0.0f, 0.0f, 64.0f );
  354. CalcGridInfo( pSprinkleType, flGridXSize, flGridYSize, flXSize, flYSize, vCenter );
  355. pRender->SetDrawColor( 255, 255, 0 );
  356. for( float x = -flXSize; x <= flXSize; x += flGridXSize )
  357. {
  358. for( float y = -flYSize; y <= flYSize; y += flGridYSize )
  359. {
  360. #if 0
  361. if ( ( ( x * x ) + ( y * y ) ) > flBrushSizeSq )
  362. {
  363. continue;
  364. }
  365. #endif
  366. Vector vOrigin = vCenter + Vector( x, y, 0.0f );
  367. if ( CToolEntitySprinkle::FindWorldSpot( vOrigin ) == true )
  368. {
  369. Vector vDelta = vOrigin - m_vWorldMousePoint;
  370. if ( vDelta.LengthSqr() > flBrushSizeSq )
  371. {
  372. continue;
  373. }
  374. Vector vEnd = vOrigin + vOffset;
  375. pRender->DrawLine( vOrigin, vEnd );
  376. }
  377. }
  378. }
  379. }
  380. }
  381. pRender->PopRenderMode();
  382. }
  383. }
  384. //-----------------------------------------------------------------------------
  385. // Purpose:
  386. // Input :
  387. // Output :
  388. //-----------------------------------------------------------------------------
  389. void CToolEntitySprinkle::RemoveMapObjects( Vector &vOrigin, KeyValues *pSprinkleType, int nMode, int nDensity, CUtlVector< CMapEntity * > *pRemovedEntities, CMapEntity *pTouchedEntity )
  390. {
  391. float flCheckSizeSq;
  392. KeyValues *pBaseInfo = pSprinkleType->FindKey( "base" );
  393. KeyValues *pBaseClass = NULL;
  394. CMapDoc *pDoc = CMapDoc::GetActiveMapDoc();
  395. CMapWorld *pWorld = pDoc->GetMapWorld();
  396. const CMapEntityList *pEntityList = pWorld->EntityList_GetList();
  397. CUtlVector< CMapEntity *> RemoveList;
  398. Vector m_CheckOrigin;
  399. if ( pTouchedEntity != NULL )
  400. {
  401. pTouchedEntity->GetOrigin( m_CheckOrigin );
  402. flCheckSizeSq = 32 * 32;
  403. }
  404. else
  405. {
  406. m_CheckOrigin = m_vWorldMousePoint;
  407. flCheckSizeSq = m_BrushSize * m_BrushSize;
  408. }
  409. if ( pBaseInfo != NULL )
  410. {
  411. pBaseClass = pBaseInfo->FindKey( "classname" );
  412. }
  413. FOR_EACH_OBJ( *pEntityList, pos )
  414. {
  415. CMapEntity *pEntity = ( CUtlReference< CMapEntity > )pEntityList->Element( pos );
  416. if ( pEntity == NULL || pEntity == pTouchedEntity )
  417. {
  418. continue;
  419. }
  420. if ( pEntity->IsVisible() == false )
  421. {
  422. continue;
  423. }
  424. Vector vOrigin;
  425. pEntity->GetOrigin( vOrigin );
  426. Vector vDelta = vOrigin - m_CheckOrigin;
  427. if ( vDelta.LengthSqr() > flCheckSizeSq )
  428. {
  429. continue;
  430. }
  431. if ( IsInSprinkle( pSprinkleType, pEntity->GetClassName() ) == false )
  432. {
  433. continue;
  434. }
  435. bool bRemove = false;
  436. if ( pBaseClass != NULL && pEntity->ClassNameMatches( pBaseClass->GetString() )== true )
  437. {
  438. bRemove = true;
  439. }
  440. else
  441. {
  442. for ( KeyValues *pSub = pSprinkleType->GetFirstSubKey() ; pSub != NULL; pSub = pSub->GetNextKey() )
  443. {
  444. KeyValues *pClass = pSub->FindKey( "classname" );
  445. if ( pClass != NULL && pEntity->ClassNameMatches( pClass->GetString() )== true )
  446. {
  447. bRemove = true;
  448. break;
  449. }
  450. }
  451. }
  452. if ( nMode == SPRINKLE_MODE_SUBTRACTIVE && pTouchedEntity == NULL )
  453. {
  454. if ( RandomInt( 1, 100 ) > nDensity )
  455. {
  456. continue;
  457. }
  458. }
  459. if ( bRemove == true )
  460. {
  461. RemoveList.AddToTail( pEntity );
  462. if ( pRemovedEntities != NULL )
  463. {
  464. pRemovedEntities->AddToTail( pEntity );
  465. }
  466. }
  467. }
  468. if ( nMode != SPRINKLE_MODE_OVERWRITE )
  469. {
  470. for( int i = 0; i < RemoveList.Count(); i++ )
  471. {
  472. GetHistory()->KeepForDestruction( RemoveList[ i ] );
  473. pDoc->RemoveObjectFromWorld( RemoveList[ i ], true );
  474. }
  475. }
  476. }
  477. static const char *pszReserved[ ] =
  478. {
  479. "classname",
  480. "grid",
  481. NULL
  482. };
  483. //-----------------------------------------------------------------------------
  484. // Purpose:
  485. // Input :
  486. // Output :
  487. //-----------------------------------------------------------------------------
  488. void CToolEntitySprinkle::PopulateEntity( CMapEntity *pEntity, KeyValues *pFields )
  489. {
  490. if ( pFields != NULL )
  491. {
  492. for ( KeyValues *pSub = pFields->GetFirstSubKey() ; pSub != NULL; pSub = pSub->GetNextKey() )
  493. {
  494. int i;
  495. for( i = 0; pszReserved[ i ] != NULL; i++ )
  496. {
  497. if ( strcmpi( pSub->GetName(), pszReserved[ i ] ) == 0 )
  498. {
  499. break;
  500. }
  501. }
  502. if ( pszReserved[ i ] == NULL )
  503. {
  504. pEntity->SetKeyValue( pSub->GetName(), pSub->GetString() );
  505. }
  506. }
  507. }
  508. }
  509. //-----------------------------------------------------------------------------
  510. // Purpose:
  511. // Input :
  512. // Output :
  513. //-----------------------------------------------------------------------------
  514. void CToolEntitySprinkle::CreateMapObject( Vector &vOrigin, KeyValues *pSprinkleType, int nMode, bool bRandomYaw, CMapEntity *pExisting )
  515. {
  516. int nTotal = 0;
  517. KeyValues *pUseInfo = NULL;
  518. for ( KeyValues *pSub = pSprinkleType->GetFirstSubKey() ; pSub != NULL; pSub = pSub->GetNextKey() )
  519. {
  520. nTotal += atoi( pSub->GetName() );
  521. }
  522. int nPick = RandomInt( 1, nTotal );
  523. nTotal = 0;
  524. for ( KeyValues *pSub = pSprinkleType->GetFirstSubKey() ; pSub != NULL; pSub = pSub->GetNextKey() )
  525. {
  526. nTotal += atoi( pSub->GetName() );
  527. if ( nPick <= nTotal )
  528. {
  529. pUseInfo = pSub;
  530. break;
  531. }
  532. }
  533. if ( pUseInfo == NULL )
  534. {
  535. return;
  536. }
  537. KeyValues *pBaseInfo = pSprinkleType->FindKey( "base" );
  538. KeyValues *pClass = pUseInfo->FindKey( "classname" );
  539. if ( pClass == NULL )
  540. {
  541. if ( pBaseInfo != NULL )
  542. {
  543. pClass = pBaseInfo->FindKey( "classname" );
  544. }
  545. }
  546. if ( pClass == NULL )
  547. {
  548. return;
  549. }
  550. CMapEntity *pEntity;
  551. if ( pExisting != NULL )
  552. {
  553. pEntity = pExisting;
  554. }
  555. else
  556. {
  557. pEntity = new CMapEntity;
  558. }
  559. pEntity->SetOrigin( vOrigin );
  560. pEntity->SetClass( pClass->GetString() );
  561. PopulateEntity( pEntity, pBaseInfo );
  562. PopulateEntity( pEntity, pUseInfo );
  563. if ( bRandomYaw == true )
  564. {
  565. QAngle vAngles;
  566. pEntity->GetAngles( vAngles );
  567. vAngles[ YAW ] = ( float )RandomInt( 0.0f, 360.0f );
  568. pEntity->SetAngles( vAngles );
  569. }
  570. if ( pExisting == NULL )
  571. {
  572. m_pDocument->AddObjectToWorld( pEntity );
  573. GetHistory()->KeepNew( pEntity );
  574. RemoveMapObjects( vOrigin, pSprinkleType, nMode, 0, NULL, pEntity );
  575. }
  576. }
  577. //-----------------------------------------------------------------------------
  578. // Purpose:
  579. // Input :
  580. // Output :
  581. //-----------------------------------------------------------------------------
  582. bool CToolEntitySprinkle::FindWorldMousePoint( CMapView3D *pView, const Vector2D &vPoint )
  583. {
  584. m_vMousePoint = vPoint;
  585. ULONG ulFace;
  586. CMapClass *pObject = pView->NearestObjectAt( m_vMousePoint, ulFace, FLAG_OBJECTS_AT_RESOLVE_INSTANCES | FLAG_OBJECTS_AT_ONLY_SOLIDS, &m_LocalMatrix );
  587. m_bWorldValid = false;
  588. if (pObject != NULL)
  589. {
  590. CMapSolid *pSolid = dynamic_cast <CMapSolid *> ( pObject );
  591. if ( pSolid == NULL )
  592. { // Clicked on a point entity - do nothing.
  593. return false;
  594. }
  595. m_LocalMatrix.InverseTR( m_LocalMatrixNeg );
  596. // Build a ray to trace against the face that they clicked on to
  597. // find the point of intersection.
  598. Vector Start, End;
  599. pView->GetCamera()->BuildRay( vPoint, Start, End);
  600. Vector HitPos, HitNormal;
  601. m_pHitFace = pSolid->GetFace( ulFace );
  602. Vector vFinalStart, vFinalEnd;
  603. m_LocalMatrixNeg.V3Mul( Start, vFinalStart );
  604. m_LocalMatrixNeg.V3Mul( End, vFinalEnd );
  605. if ( m_pHitFace->TraceLineInside( HitPos, HitNormal, vFinalStart, vFinalEnd ) )
  606. {
  607. Vector vFinalHitPos, vFinalHitNormal;
  608. m_LocalMatrix.V3Mul( HitPos, vFinalHitPos );
  609. vFinalHitNormal = m_LocalMatrix.ApplyRotation( HitNormal );
  610. m_vWorldMousePoint = vFinalHitPos;
  611. m_bWorldValid = true;
  612. //CMapClass *pNewObject = NULL;
  613. return true;
  614. }
  615. }
  616. return false;
  617. }
  618. //-----------------------------------------------------------------------------
  619. // Purpose:
  620. // Input :
  621. // Output :
  622. //-----------------------------------------------------------------------------
  623. bool CToolEntitySprinkle::FindWorldSpot( Vector &vOrigin )
  624. {
  625. Vector vStart, vEnd;
  626. Vector vFinalStart, vFinalEnd;
  627. Vector vHitPos, vHitNormal;
  628. vStart = vOrigin - Vector( 0.0f, 0.0f, 600.0f );
  629. vEnd = vOrigin + Vector( 0.0f, 0.0f, 600.0f );
  630. m_LocalMatrixNeg.V3Mul( vStart, vFinalStart );
  631. m_LocalMatrixNeg.V3Mul( vEnd, vFinalEnd );
  632. if ( m_pHitFace->TraceLineInside( vHitPos, vHitNormal, vFinalStart, vFinalEnd ) )
  633. {
  634. Vector vFinalHitPos, vFinalHitNormal;
  635. m_LocalMatrix.V3Mul( vHitPos, vFinalHitPos );
  636. vFinalHitNormal = m_LocalMatrix.ApplyRotation( vHitNormal );
  637. vOrigin = vFinalHitPos;
  638. return true;
  639. }
  640. return false;
  641. }
  642. //-----------------------------------------------------------------------------
  643. // Purpose:
  644. // Input :
  645. // Output :
  646. //-----------------------------------------------------------------------------
  647. bool CToolEntitySprinkle::IsInSprinkle( KeyValues *pSprinkleType, const char *pszClassname )
  648. {
  649. KeyValues *pBaseInfo = pSprinkleType->FindKey( "base" );
  650. if ( pBaseInfo != NULL )
  651. {
  652. KeyValues *pClass = pBaseInfo->FindKey( "classname" );
  653. if ( pClass != NULL && strcmpi( pClass->GetString(), pszClassname ) == 0 )
  654. {
  655. return true;
  656. }
  657. }
  658. for ( KeyValues *pSub = pSprinkleType->GetFirstSubKey() ; pSub != NULL; pSub = pSub->GetNextKey() )
  659. {
  660. KeyValues *pClass = pSub->FindKey( "classname" );
  661. if ( pClass != NULL && strcmpi( pClass->GetString(), pszClassname ) == 0 )
  662. {
  663. return true;
  664. }
  665. }
  666. return false;
  667. }
  668. //-----------------------------------------------------------------------------
  669. // Purpose:
  670. // Input :
  671. // Output :
  672. //-----------------------------------------------------------------------------
  673. const char *CToolEntitySprinkle::FindField( KeyValues *pSprinkleType, const char *pszClassname, const char *pszFieldName )
  674. {
  675. KeyValues *pFoundClass = NULL;
  676. for ( KeyValues *pSub = pSprinkleType->GetFirstSubKey() ; pSub != NULL; pSub = pSub->GetNextKey() )
  677. {
  678. KeyValues *pClass = pSub->FindKey( "classname" );
  679. if ( pClass != NULL && strcmpi( pClass->GetString(), pszClassname ) == 0 )
  680. {
  681. pFoundClass = pClass;
  682. break;
  683. }
  684. }
  685. if ( pFoundClass != NULL )
  686. {
  687. pFoundClass = pFoundClass->FindKey( pszFieldName, false );
  688. if ( pFoundClass != NULL )
  689. {
  690. return pFoundClass->GetString();
  691. }
  692. }
  693. KeyValues *pBaseInfo = pSprinkleType->FindKey( "base" );
  694. if ( pBaseInfo != NULL )
  695. {
  696. pFoundClass = pBaseInfo->FindKey( pszFieldName, false );
  697. if ( pFoundClass != NULL )
  698. {
  699. return pFoundClass->GetString();
  700. }
  701. }
  702. return "";
  703. }
  704. //-----------------------------------------------------------------------------
  705. // Purpose: toggles the sizing mode
  706. // Input : vPoint - the mouse point
  707. // Output : returns true if successful
  708. //-----------------------------------------------------------------------------
  709. bool CToolEntitySprinkle::DoSizing( const Vector2D &vPoint )
  710. {
  711. if ( !m_InSizingMode )
  712. {
  713. m_InSizingMode = true;
  714. m_StartSizingPoint = vPoint;
  715. m_OrigBrushSize = m_BrushSize;
  716. }
  717. else
  718. {
  719. m_BrushSize = m_OrigBrushSize + ( vPoint.x - m_StartSizingPoint.x );
  720. if ( m_BrushSize < 1.0f )
  721. {
  722. m_BrushSize = 1.0f;
  723. }
  724. }
  725. return true;
  726. }
  727. //-----------------------------------------------------------------------------
  728. // Purpose:
  729. // Input :
  730. // Output :
  731. //-----------------------------------------------------------------------------
  732. void CToolEntitySprinkle::CalcGridInfo( KeyValues *pSprinkleType, float &flGridXSize, float &flGridYSize, float &flXSize, float &flYSize, Vector &vCenter )
  733. {
  734. flGridXSize = 64;
  735. flGridYSize = 64;
  736. if ( pSprinkleDlg->UseDefinitionGridSize() )
  737. {
  738. KeyValues *pBaseInfo = pSprinkleType->FindKey( "base" );
  739. if ( pBaseInfo != NULL )
  740. {
  741. KeyValues *pGridInfo = pBaseInfo->FindKey( "grid" );
  742. if ( pGridInfo != NULL )
  743. {
  744. sscanf( pGridInfo->GetString(), "%g %g", &flGridXSize, &flGridYSize );
  745. }
  746. }
  747. }
  748. else
  749. {
  750. pSprinkleDlg->GetGridSize( flGridXSize, flGridYSize );
  751. }
  752. flXSize = ceil( m_BrushSize / flGridXSize ) * flGridXSize;
  753. flYSize = ceil( m_BrushSize / flGridYSize ) * flGridXSize;
  754. vCenter = m_vWorldMousePoint;
  755. vCenter.x -= fmod( vCenter.x, flGridXSize );
  756. vCenter.y -= fmod( vCenter.y, flGridYSize );
  757. }
  758. //-----------------------------------------------------------------------------
  759. // Purpose:
  760. // Input :
  761. // Output :
  762. //-----------------------------------------------------------------------------
  763. void CToolEntitySprinkle::PerformSprinkle( bool bInitial )
  764. {
  765. if ( m_bWorldValid == false )
  766. {
  767. return;
  768. }
  769. KeyValues *pSprinkleType = pSprinkleDlg->GetSprinkleType( );
  770. if ( pSprinkleType == NULL )
  771. {
  772. return;
  773. }
  774. int nDensity = pSprinkleDlg->GetSprinkleDensity();
  775. int nMode = pSprinkleDlg->GetSprinkleMode();
  776. bool bRandomYaw = pSprinkleDlg->UseRandomYaw();
  777. float flGridXSize, flGridYSize;
  778. float flXSize, flYSize;
  779. float flBrushSizeSq = m_BrushSize * m_BrushSize;
  780. Vector vCenter = m_vWorldMousePoint;
  781. CUtlVector< CMapEntity * > ReplacedEntities;
  782. if ( bInitial == true )
  783. {
  784. GetHistory()->MarkUndoPosition( m_pDocument->GetSelection()->GetList(), "Sprinkle" );
  785. }
  786. else if ( m_vLastDrawPoint.x == vCenter.x && m_vLastDrawPoint.y == vCenter.y )
  787. {
  788. return;
  789. }
  790. CalcGridInfo( pSprinkleType, flGridXSize, flGridYSize, flXSize, flYSize, vCenter );
  791. if ( m_bCtrlDown == true )
  792. {
  793. nMode = SPRINKLE_MODE_SUBTRACTIVE;
  794. }
  795. m_vLastDrawPoint = vCenter;
  796. if ( nMode == SPRINKLE_MODE_REPLACE || nMode == SPRINKLE_MODE_OVERWRITE )
  797. {
  798. RemoveMapObjects( m_vWorldMousePoint, pSprinkleType, nMode, nDensity, &ReplacedEntities );
  799. }
  800. switch( nMode )
  801. {
  802. case SPRINKLE_MODE_OVERWRITE:
  803. for( int i = 0; i < ReplacedEntities.Count(); i++ )
  804. {
  805. Vector vOrigin;
  806. ReplacedEntities[ i ]->GetOrigin( vOrigin );
  807. CreateMapObject( vOrigin, pSprinkleType, nMode, bRandomYaw, ReplacedEntities[ i ] );
  808. }
  809. break;
  810. case SPRINKLE_MODE_SUBTRACTIVE:
  811. break;
  812. default:
  813. for( float x = -flXSize; x <= flXSize; x += flGridXSize )
  814. {
  815. for( float y = -flYSize; y <= flYSize; y += flGridYSize )
  816. {
  817. #if 0
  818. if ( ( ( x * x ) + ( y * y ) ) > flBrushSizeSq )
  819. {
  820. continue;
  821. }
  822. #endif
  823. int nValue = RandomInt( 1, 100 );
  824. if ( nValue > nDensity )
  825. {
  826. continue;
  827. }
  828. Vector vOrigin = vCenter + Vector( x, y, 0.0f );
  829. if ( CToolEntitySprinkle::FindWorldSpot( vOrigin ) == true )
  830. {
  831. Vector vDelta = vOrigin - m_vWorldMousePoint;
  832. if ( vDelta.LengthSqr() > flBrushSizeSq )
  833. {
  834. continue;
  835. }
  836. CreateMapObject( vOrigin, pSprinkleType, nMode, bRandomYaw );
  837. }
  838. }
  839. }
  840. break;
  841. }
  842. if ( nMode == SPRINKLE_MODE_SUBTRACTIVE )
  843. {
  844. RemoveMapObjects( m_vWorldMousePoint, pSprinkleType, nMode, nDensity );
  845. }
  846. m_pDocument->SetModifiedFlag();
  847. }