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.

3417 lines
94 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "stdafx.h"
  8. #include <math.h>
  9. #include <mmsystem.h>
  10. #include "Camera.h"
  11. #include "CullTreeNode.h"
  12. #include "MapDefs.h"
  13. #include "MapDoc.h"
  14. #include "MapEntity.h"
  15. #include "MapInstance.h"
  16. #include "MapWorld.h"
  17. #include "Render3DMS.h"
  18. #include "SSolid.h"
  19. #include "MapStudioModel.h"
  20. #include "Material.h"
  21. #include "materialsystem/IMaterialSystem.h"
  22. #include "materialsystem/IMesh.h"
  23. #include "TextureSystem.h"
  24. #include "ToolInterface.h"
  25. #include "StudioModel.h"
  26. #include "ibsplighting.h"
  27. #include "MapDisp.h"
  28. #include "ToolManager.h"
  29. #include "mapview.h"
  30. #include "hammer.h"
  31. #include "IStudioRender.h"
  32. #include <renderparm.h>
  33. #include "materialsystem/itexture.h"
  34. #include "maplightcone.h"
  35. #include "map_utils.h"
  36. #include "bitmap/floatbitmap.h"
  37. #include "lpreview_thread.h"
  38. #include "hammer.h"
  39. #include "mainfrm.h"
  40. #include "mathlib/halton.h"
  41. #include "Manifest.h"
  42. #include "toolutils/enginetools_int.h"
  43. #include "toolframework/ienginetool.h"
  44. #include "..\FoW\FoW.h"
  45. #include "..\fow\fow_trisoup.h"
  46. #include "..\fow\fow_lineoccluder.h"
  47. #include "gridnav.h"
  48. // memdbgon must be the last include file in a .cpp file!!!
  49. #include <tier0/memdbgon.h>
  50. #define NUM_MIPLEVELS 4
  51. #define CROSSHAIR_DIST_HORIZONTAL 5
  52. #define CROSSHAIR_DIST_VERTICAL 6
  53. #define TEXTURE_AXIS_LENGTH 10 // Texture axis length in world units
  54. // dvs: experiment!
  55. //extern int g_nClipPoints;
  56. //extern Vector g_ClipPoints[4];
  57. //
  58. // Debugging / diagnostic stuff.
  59. //
  60. static bool g_bDrawWireFrameSelection = true;
  61. static bool g_bShowStatistics = false;
  62. static bool g_bUseCullTree = true;
  63. static bool g_bRenderCullBoxes = false;
  64. int g_nBitmapGenerationCounter = 1;
  65. //-----------------------------------------------------------------------------
  66. // Purpose: Callback comparison function for sorting objects clicked on while
  67. // in selection mode.
  68. // Input : pHit1 - First hit to compare.
  69. // pHit2 - Second hit to compare.
  70. // Output : Sorts by increasing depth value. Returns -1, 0, or 1 per qsort spec.
  71. //-----------------------------------------------------------------------------
  72. static int _CompareHits(const void *pHit1, const void *pHit2)
  73. {
  74. if (((HitInfo_t *)pHit1)->nDepth < ((HitInfo_t *)pHit2)->nDepth)
  75. {
  76. return(-1);
  77. }
  78. if (((HitInfo_t *)pHit1)->nDepth > ((HitInfo_t *)pHit2)->nDepth)
  79. {
  80. return(1);
  81. }
  82. return(0);
  83. }
  84. //-----------------------------------------------------------------------------
  85. // Purpose: Callback comparison function for sorting objects clicked on while
  86. // in selection mode. The reverse sort is used for cards that return
  87. // depth values in reverse (larger numbers are closer to the camera).
  88. // Input : pHit1 - First hit to compare.
  89. // pHit2 - Second hit to compare.
  90. // Output : Sorts by decreasing depth value. Returns -1, 0, or 1 per qsort spec.
  91. //-----------------------------------------------------------------------------
  92. static int _CompareHitsReverse(const void *pHit1, const void *pHit2)
  93. {
  94. if (((HitInfo_t *)pHit1)->nDepth > ((HitInfo_t *)pHit2)->nDepth)
  95. {
  96. return(-1);
  97. }
  98. if (((HitInfo_t *)pHit1)->nDepth < ((HitInfo_t *)pHit2)->nDepth)
  99. {
  100. return(1);
  101. }
  102. return(0);
  103. }
  104. static bool TranslucentObjectsLessFunc( TranslucentObjects_t const&a, TranslucentObjects_t const&b )
  105. {
  106. return (a.depth < b.depth);
  107. }
  108. bool GetRequiredMaterial( const char *pName, IMaterial* &pMaterial )
  109. {
  110. pMaterial = NULL;
  111. IEditorTexture *pTex = g_Textures.FindActiveTexture( pName );
  112. if ( pTex )
  113. pMaterial = pTex->GetMaterial();
  114. if ( pMaterial )
  115. {
  116. return true;
  117. }
  118. else
  119. {
  120. char str[512];
  121. Q_snprintf( str, sizeof( str ), "Missing material '%s'. Go to Tools | Options | Game Configurations and verify that your game directory is correct.", pName );
  122. MessageBox( NULL, str, "FATAL ERROR", MB_OK );
  123. return false;
  124. }
  125. }
  126. //-----------------------------------------------------------------------------
  127. // Purpose: Calculates lighting for a given face.
  128. // Input : Normal - vector that is normal to the face being lit.
  129. // Output : Returns a number from [0.2, 1.0]
  130. //-----------------------------------------------------------------------------
  131. float CRender3D::LightPlane(Vector& Normal)
  132. {
  133. static Vector Light( 1.0f, 2.0f, 3.0f );
  134. static bool bFirst = true;
  135. if (bFirst)
  136. {
  137. VectorNormalize(Light);
  138. bFirst = false;
  139. }
  140. float fShade = 0.65f + (0.35f * DotProduct(Normal, Light));
  141. return(fShade);
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Purpose:
  145. //-----------------------------------------------------------------------------
  146. CRender3D::CRender3D(void) :
  147. CRender()
  148. {
  149. memset(&m_WinData, 0, sizeof(m_WinData));
  150. m_WinData.bAllowSoft = true;
  151. memset(m_FrustumPlanes, 0, sizeof(m_FrustumPlanes));
  152. m_pDropCamera = new CCamera;
  153. m_bDroppedCamera = false;
  154. m_DeferRendering = false;
  155. m_TranslucentSortRendering = false;
  156. m_fFrameRate = 0;
  157. m_nFramesThisSample = 0;
  158. m_dwTimeLastSample = 0;
  159. m_dwTimeLastFrame = 0;
  160. m_fTimeElapsed = 0;
  161. m_LastLPreviewCameraPos = Vector(1.0e22,1.0e22,1.0e22);
  162. m_nLastLPreviewWidth = -1;
  163. m_nLastLPreviewHeight = -1;
  164. memset(&m_Pick, 0, sizeof(m_Pick));
  165. m_Pick.bPicking = false;
  166. memset(&m_RenderState, 0, sizeof(m_RenderState));
  167. for (int i = 0; i < 2; ++i)
  168. {
  169. m_pVertexColor[i] = 0;
  170. }
  171. m_bLightingPreview = false;
  172. m_TranslucentRenderObjects.SetLessFunc( TranslucentObjectsLessFunc );
  173. #ifdef _DEBUG
  174. m_bRenderFrustum = false;
  175. m_bRecomputeFrustumRenderGeometry = false;
  176. #endif
  177. }
  178. //-----------------------------------------------------------------------------
  179. // Purpose:
  180. //-----------------------------------------------------------------------------
  181. CRender3D::~CRender3D(void)
  182. {
  183. if (m_pDropCamera != NULL)
  184. {
  185. delete m_pDropCamera;
  186. }
  187. }
  188. //-----------------------------------------------------------------------------
  189. // Purpose: Called before rendering an object that should be hit tested when
  190. // rendering in selection mode.
  191. // Input : pObject - Map atom pointer that will be returned from the ObjectsAt
  192. // routine if this rendered object is positively hit tested.
  193. //-----------------------------------------------------------------------------
  194. void CRender3D::BeginRenderHitTarget(CMapAtom *pObject, unsigned int uHandle)
  195. {
  196. if ( m_Pick.bPicking == false )
  197. {
  198. return;
  199. }
  200. if ( ( m_Pick.m_nFlags & FLAG_OBJECTS_AT_RESOLVE_INSTANCES ) == 0 && m_bInstanceRendering && !GetInstanceClass()->IsEditable() )
  201. {
  202. pObject = m_CurrentInstanceState.m_pTopInstanceClass; // GetInstanceClass();
  203. uHandle = 0;
  204. }
  205. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  206. pRenderContext->PushSelectionName((unsigned int)pObject);
  207. pRenderContext->PushSelectionName(uHandle);
  208. }
  209. //-----------------------------------------------------------------------------
  210. // Purpose: Called after rendering an object that should be hit tested when
  211. // rendering in selection mode.
  212. // Input : pObject - Map atom pointer that will be returned from the ObjectsAt
  213. // routine if this rendered object is positively hit tested.
  214. // Input : pObject -
  215. //-----------------------------------------------------------------------------
  216. void CRender3D::EndRenderHitTarget(void)
  217. {
  218. if ( m_Pick.bPicking )
  219. {
  220. //
  221. // Pop the name and the handle from the stack.
  222. //
  223. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  224. pRenderContext->PopSelectionName();
  225. pRenderContext->PopSelectionName();
  226. if ((pRenderContext->SelectionMode(true) != 0) && (m_Pick.nNumHits < MAX_PICK_HITS))
  227. {
  228. if (m_Pick.uSelectionBuffer[0] == 2)
  229. {
  230. m_Pick.Hits[m_Pick.nNumHits].pObject = (CMapClass *)m_Pick.uSelectionBuffer[3];
  231. m_Pick.Hits[m_Pick.nNumHits].uData = m_Pick.uSelectionBuffer[4];
  232. m_Pick.Hits[m_Pick.nNumHits].nDepth = m_Pick.uSelectionBuffer[1];
  233. m_Pick.Hits[m_Pick.nNumHits].m_LocalMatrix = m_LocalMatrix.Head();
  234. m_Pick.nNumHits++;
  235. }
  236. }
  237. }
  238. }
  239. //-----------------------------------------------------------------------------
  240. // Purpose:
  241. // Output :
  242. //-----------------------------------------------------------------------------
  243. void CRender3D::AddTranslucentDeferredRendering( CMapPoint *pMapPoint )
  244. {
  245. // object is translucent, render in 2nd batch
  246. Vector direction = m_pView->GetViewAxis();
  247. Vector center;
  248. pMapPoint->GetOrigin(center);
  249. TranslucentObjects_t entry;
  250. if ( m_bInstanceRendering )
  251. {
  252. center += GetInstanceOrigin();
  253. entry.m_InstanceState = m_CurrentInstanceState;
  254. entry.m_bInstanceSelected = ( m_InstanceSelectionDepth != 0 );
  255. }
  256. else
  257. {
  258. entry.m_InstanceState.m_pInstanceClass = NULL;
  259. }
  260. entry.object = pMapPoint;
  261. entry.depth = center.Dot( direction );
  262. m_TranslucentRenderObjects.Insert(entry);
  263. }
  264. //-----------------------------------------------------------------------------
  265. // Purpose:
  266. // Output :
  267. //-----------------------------------------------------------------------------
  268. float CRender3D::GetElapsedTime(void)
  269. {
  270. return(m_fTimeElapsed);
  271. }
  272. //-----------------------------------------------------------------------------
  273. // Computes us some geometry to render the frustum planes
  274. //-----------------------------------------------------------------------------
  275. void CRender3D::ComputeFrustumRenderGeometry(CCamera *pCamera)
  276. {
  277. #ifdef _DEBUG
  278. Vector viewPoint;
  279. pCamera->GetViewPoint(viewPoint);
  280. // Find lines along each of the plane intersections.
  281. // We know these lines are perpendicular to both plane normals,
  282. // so we can take the cross product to find them.
  283. static int edgeIdx[4][2] =
  284. {
  285. { 0, 2 }, { 0, 3 }, { 1, 3 }, { 1, 2 }
  286. };
  287. int i;
  288. Vector edges[4];
  289. for ( i = 0; i < 4; ++i)
  290. {
  291. CrossProduct( m_FrustumPlanes[edgeIdx[i][0]].AsVector3D(),
  292. m_FrustumPlanes[edgeIdx[i][1]].AsVector3D(), edges[i] );
  293. VectorNormalize( edges[i] );
  294. }
  295. // Figure out four near points by intersection lines with the near plane
  296. // Figure out four far points by intersection with lines against far plane
  297. for (i = 0; i < 4; ++i)
  298. {
  299. float t = (m_FrustumPlanes[4][3] - DotProduct(m_FrustumPlanes[4].AsVector3D(), viewPoint)) /
  300. DotProduct(m_FrustumPlanes[4].AsVector3D(), edges[i]);
  301. VectorMA( viewPoint, t, edges[i], m_FrustumRenderPoint[i] );
  302. /*
  303. t = (m_FrustumPlanes[5][3] - DotProduct(m_FrustumPlanes[5], viewPoint)) /
  304. DotProduct(m_FrustumPlanes[5], edges[i]);
  305. VectorMA( viewPoint, t, edges[i], m_FrustumRenderPoint[i + 4] );
  306. */
  307. if (t < 0)
  308. {
  309. edges[i] *= -1;
  310. }
  311. VectorMA( m_FrustumRenderPoint[i], 200.0, edges[i], m_FrustumRenderPoint[i + 4] );
  312. }
  313. #endif
  314. }
  315. //-----------------------------------------------------------------------------
  316. // renders the frustum
  317. //-----------------------------------------------------------------------------
  318. void CRender3D::RenderFrustum( )
  319. {
  320. #ifdef _DEBUG
  321. static int indices[] =
  322. {
  323. 0, 1, 1, 2, 2, 3, 3, 0, // near square
  324. 4, 5, 5, 6, 6, 7, 7, 4, // far square
  325. 0, 4, 1, 5, 2, 6, 3, 7 // connections between them
  326. };
  327. PushRenderMode( RENDER_MODE_WIREFRAME );
  328. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  329. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  330. int numIndices = sizeof(indices) / sizeof(int);
  331. CMeshBuilder meshBuilder;
  332. meshBuilder.Begin( pMesh, MATERIAL_LINES, 8, numIndices );
  333. int i;
  334. for ( i = 0; i < 8; ++i )
  335. {
  336. meshBuilder.Position3fv( m_FrustumRenderPoint[i].Base() );
  337. meshBuilder.Color4ub( 255, 255, 255, 255 );
  338. meshBuilder.AdvanceVertex();
  339. }
  340. for ( i = 0; i < numIndices; ++i )
  341. {
  342. meshBuilder.Index( indices[i] );
  343. meshBuilder.AdvanceIndex();
  344. }
  345. meshBuilder.End();
  346. pMesh->Draw();
  347. PopRenderMode();
  348. #endif
  349. }
  350. //-----------------------------------------------------------------------------
  351. // Purpose: Returns the 3D grid spacing, in world units.
  352. //-----------------------------------------------------------------------------
  353. float CRender3D::GetGridDistance(void)
  354. {
  355. return(m_RenderState.fGridDistance);
  356. }
  357. //-----------------------------------------------------------------------------
  358. // Purpose: Returns the 3D grid spacing, in world units.
  359. //-----------------------------------------------------------------------------
  360. float CRender3D::GetGridSize(void)
  361. {
  362. return(m_RenderState.fGridSpacing);
  363. }
  364. //-----------------------------------------------------------------------------
  365. // Purpose:
  366. // Input : hwnd -
  367. // Output : Returns true on success, false on failure.
  368. //-----------------------------------------------------------------------------
  369. bool CRender3D::SetView( CMapView *pView )
  370. {
  371. if ( !CRender::SetView( pView ) )
  372. return false;
  373. HWND hwnd = pView->GetViewWnd()->GetSafeHwnd();
  374. CMapDoc *pDoc = pView->GetMapDoc();
  375. Assert(hwnd != NULL);
  376. Assert(pDoc != NULL);
  377. Assert(pDoc->GetMapWorld() != NULL);
  378. if (!MaterialSystemInterface()->AddView( hwnd ))
  379. {
  380. return false;
  381. }
  382. MaterialSystemInterface()->SetView( hwnd );
  383. m_WinData.hWnd = hwnd;
  384. if ((m_WinData.hDC = GetDCEx(m_WinData.hWnd, NULL, DCX_CACHE | DCX_CLIPSIBLINGS)) == NULL)
  385. {
  386. ChangeDisplaySettings(NULL, 0);
  387. MessageBox(NULL, "GetDC on main window failed", "FATAL ERROR", MB_OK);
  388. return(false);
  389. }
  390. // Preload all our stuff (textures, etc) for rendering.
  391. Preload( pDoc->GetMapWorld() );
  392. // Store off the three materials we use most often...
  393. if ( !GetRequiredMaterial( "editor/vertexcolor", m_pVertexColor[0] ) )
  394. {
  395. return false;
  396. }
  397. m_pVertexColor[1] = m_pVertexColor[0];
  398. return(true);
  399. }
  400. //-----------------------------------------------------------------------------
  401. // Purpose: Determines the visibility of the given axis-aligned bounding box.
  402. // Input : pBox - Bounding box to evaluate.
  403. // Output : VIS_TOTAL if the box is entirely within the view frustum.
  404. // VIS_PARTIAL if the box is partially within the view frustum.
  405. // VIS_NONE if the box is entirely outside the view frustum.
  406. //-----------------------------------------------------------------------------
  407. Visibility_t CRender3D::IsBoxVisible(Vector const &BoxMins, Vector const &BoxMaxs)
  408. {
  409. Vector NearVertex;
  410. Vector FarVertex;
  411. //
  412. // Build the near and far vertices based on the octant of the plane normal.
  413. //
  414. int nInPlanes = 0;
  415. for ( int i = 0; i < 6; i++ )
  416. {
  417. if (m_FrustumPlanes[i][0] > 0)
  418. {
  419. NearVertex[0] = BoxMins[0];
  420. FarVertex[0] = BoxMaxs[0];
  421. }
  422. else
  423. {
  424. NearVertex[0] = BoxMaxs[0];
  425. FarVertex[0] = BoxMins[0];
  426. }
  427. if (m_FrustumPlanes[i][1] > 0)
  428. {
  429. NearVertex[1] = BoxMins[1];
  430. FarVertex[1] = BoxMaxs[1];
  431. }
  432. else
  433. {
  434. NearVertex[1] = BoxMaxs[1];
  435. FarVertex[1] = BoxMins[1];
  436. }
  437. if (m_FrustumPlanes[i][2] > 0)
  438. {
  439. NearVertex[2] = BoxMins[2];
  440. FarVertex[2] = BoxMaxs[2];
  441. }
  442. else
  443. {
  444. NearVertex[2] = BoxMaxs[2];
  445. FarVertex[2] = BoxMins[2];
  446. }
  447. if (DotProduct(m_FrustumPlanes[i].AsVector3D(), NearVertex) >= m_FrustumPlanes[i][3])
  448. {
  449. return(VIS_NONE);
  450. }
  451. if (DotProduct(m_FrustumPlanes[i].AsVector3D(), FarVertex) < m_FrustumPlanes[i][3])
  452. {
  453. nInPlanes++;
  454. }
  455. }
  456. if (nInPlanes == 6)
  457. {
  458. return(VIS_TOTAL);
  459. }
  460. return(VIS_PARTIAL);
  461. }
  462. //-----------------------------------------------------------------------------
  463. // Purpose:
  464. // Input : eRenderState -
  465. // Output : Returns true if the render state is enabled, false if it is disabled.
  466. //-----------------------------------------------------------------------------
  467. bool CRender3D::IsEnabled(RenderState_t eRenderState)
  468. {
  469. switch (eRenderState)
  470. {
  471. case RENDER_CENTER_CROSSHAIR:
  472. {
  473. return(m_RenderState.bCenterCrosshair);
  474. }
  475. case RENDER_GRID:
  476. {
  477. return(m_RenderState.bDrawGrid);
  478. }
  479. case RENDER_REVERSE_SELECTION:
  480. {
  481. return(m_RenderState.bReverseSelection);
  482. }
  483. }
  484. return(false);
  485. }
  486. //-----------------------------------------------------------------------------
  487. // Purpose: Determines whether we are rendering for for selection or not.
  488. // Output : Returns true if we are rendering for selection, false if rendering normally.
  489. //-----------------------------------------------------------------------------
  490. bool CRender3D::IsPicking(void)
  491. {
  492. return(m_Pick.bPicking);
  493. }
  494. //-----------------------------------------------------------------------------
  495. // Purpose: Returns the map objects within the rectangle whose upper left corner
  496. // is at the client coordinates (x, y) and whose width and height are
  497. // fWidth and fHeight.
  498. // Input : x - Leftmost point in the rectangle, in client coordinates.
  499. // y - Topmost point in the rectangle, in client coordinates.
  500. // fWidth - Width of rectangle, in client coordinates.
  501. // fHeight - Height of rectangle, in client coordinates.
  502. // pObjects - Pointer to buffer to receive objects intersecting the rectangle.
  503. // nMaxObjects - Maximum number of object pointers to place in the buffer.
  504. // Output : Returns the number of object pointers placed in the buffer pointed to
  505. // by 'pObjects'.
  506. //-----------------------------------------------------------------------------
  507. int CRender3D::ObjectsAt( float x, float y, float fWidth, float fHeight, HitInfo_t *pObjects, int nMaxObjects, unsigned int nFlags )
  508. {
  509. int width, height;
  510. GetCamera()->GetViewPort(width,height);
  511. m_Pick.fX = x;
  512. m_Pick.fY = height - (y + 1);
  513. m_Pick.fWidth = fWidth;
  514. m_Pick.fHeight = fHeight;
  515. m_Pick.pHitsDest = pObjects;
  516. m_Pick.nMaxHits = min(nMaxObjects, MAX_PICK_HITS);
  517. m_Pick.nNumHits = 0;
  518. if (!m_RenderState.bReverseSelection)
  519. {
  520. m_Pick.uLastZ = 0xFFFFFFFF;
  521. }
  522. else
  523. {
  524. m_Pick.uLastZ = 0;
  525. }
  526. m_Pick.m_nFlags = nFlags;
  527. m_Pick.bPicking = true;
  528. EditorRenderMode_t eOldMode = GetDefaultRenderMode();
  529. SetDefaultRenderMode( RENDER_MODE_TEXTURED );
  530. bool bOldLightPreview = IsInLightingPreview();
  531. SetInLightingPreview( false );
  532. Render( false );
  533. SetDefaultRenderMode( eOldMode );
  534. SetInLightingPreview( bOldLightPreview );
  535. m_Pick.bPicking = false;
  536. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  537. pRenderContext->SelectionMode(false);
  538. return(m_Pick.nNumHits);
  539. }
  540. static ITexture *SetRenderTargetNamed(int nWhichTarget, char const *pRtName)
  541. {
  542. CMatRenderContextPtr pRenderContext( materials );
  543. ITexture *dest_rt=materials->FindTexture(pRtName, TEXTURE_GROUP_RENDER_TARGET );
  544. pRenderContext->SetRenderTargetEx(nWhichTarget,dest_rt);
  545. return dest_rt;
  546. }
  547. //-----------------------------------------------------------------------------
  548. // Purpose:
  549. //-----------------------------------------------------------------------------
  550. void CRender3D::StartRenderFrame( bool bRenderingOverEngine )
  551. {
  552. CRender::StartRenderFrame( bRenderingOverEngine );
  553. CCamera *pCamera = GetCamera();
  554. //
  555. // Determine the elapsed time since the last frame was rendered.
  556. //
  557. DWORD dwTimeNow = timeGetTime();
  558. if (m_dwTimeLastFrame == 0)
  559. {
  560. m_dwTimeLastFrame = dwTimeNow;
  561. }
  562. DWORD dwTimeElapsed = dwTimeNow - m_dwTimeLastFrame;
  563. m_fTimeElapsed = (float)dwTimeElapsed / 1000.0;
  564. m_dwTimeLastFrame = dwTimeNow;
  565. //
  566. // Animate the models based on elapsed time.
  567. //
  568. CMapStudioModel::AdvanceAnimation( GetElapsedTime() );
  569. // view materialsystem viewport
  570. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  571. // We're drawing to this view now
  572. if ( !m_bRenderingOverEngine )
  573. {
  574. MaterialSystemInterface()->SetView( m_WinData.hWnd );
  575. int width, height;
  576. pCamera->GetViewPort( width, height );
  577. if (
  578. (m_eCurrentRenderMode == RENDER_MODE_LIGHT_PREVIEW2) ||
  579. (m_eCurrentRenderMode == RENDER_MODE_LIGHT_PREVIEW_RAYTRACED)
  580. )
  581. {
  582. AllocateLightingPreviewtextures();
  583. ITexture *first_rt=SetRenderTargetNamed(0,"_rt_albedo");
  584. SetRenderTargetNamed(1,"_rt_normal");
  585. SetRenderTargetNamed(2,"_rt_position");
  586. int nTargetWidth = max( 32, min( width, first_rt->GetActualWidth() ) );
  587. int nTargetHeight = max( 32, min( height, first_rt->GetActualHeight() ) );
  588. pRenderContext->
  589. Viewport(0, 0, nTargetWidth, nTargetHeight );
  590. pRenderContext->ClearColor3ub(0,1,0);
  591. pRenderContext->ClearBuffers( true, true );
  592. }
  593. else
  594. pRenderContext->Viewport(0, 0, width, height);
  595. //
  596. // Setup the camera position, orientation, and FOV.
  597. //
  598. //
  599. // Set up our perspective transformation.
  600. //
  601. // if picking, setup extra perspective matrix
  602. if ( m_Pick.bPicking )
  603. {
  604. pRenderContext->MatrixMode(MATERIAL_PROJECTION);
  605. pRenderContext->LoadIdentity();
  606. pRenderContext->PickMatrix(m_Pick.fX, m_Pick.fY, m_Pick.fWidth, m_Pick.fHeight);
  607. pRenderContext->SelectionBuffer(m_Pick.uSelectionBuffer, ARRAYSIZE(m_Pick.uSelectionBuffer));
  608. pRenderContext->SelectionMode(true);
  609. pRenderContext->ClearSelectionNames();
  610. float aspect = (float)width / (float)height;
  611. pRenderContext->PerspectiveX( pCamera->GetFOV(),
  612. aspect, pCamera->GetNearClip(), pCamera->GetFarClip() );
  613. }
  614. else
  615. {
  616. //
  617. // Clear the frame buffer and Z buffer.
  618. //
  619. pRenderContext->ClearColor3ub( 0,0,0 );
  620. pRenderContext->ClearBuffers( true, true, true );
  621. }
  622. }
  623. //
  624. // Build the frustum planes for view volume culling.
  625. //
  626. CCamera *pTempCamera = NULL;
  627. if (m_bDroppedCamera)
  628. {
  629. pTempCamera = pCamera;
  630. pCamera = m_pDropCamera;
  631. }
  632. pCamera->GetFrustumPlanes( m_FrustumPlanes);
  633. // For debugging frustum planes
  634. #ifdef _DEBUG
  635. if (m_bRecomputeFrustumRenderGeometry)
  636. {
  637. ComputeFrustumRenderGeometry( pCamera );
  638. m_bRecomputeFrustumRenderGeometry = false;
  639. }
  640. #endif
  641. if (m_bDroppedCamera)
  642. {
  643. pCamera = pTempCamera;
  644. }
  645. //
  646. // Cache per-frame information from the doc.
  647. //
  648. m_RenderState.fGridSpacing = m_pView->GetMapDoc()->GetGridSpacing();
  649. m_RenderState.fGridDistance = m_RenderState.fGridSpacing * 10;
  650. if (m_RenderState.fGridDistance > 2048)
  651. {
  652. m_RenderState.fGridDistance = 2048;
  653. }
  654. else if (m_RenderState.fGridDistance < 64)
  655. {
  656. m_RenderState.fGridDistance = 64;
  657. }
  658. // We do bizarro reverse culling in WC
  659. pRenderContext->CullMode( MATERIAL_CULLMODE_CCW );
  660. Assert( m_TranslucentRenderObjects.Count() == 0 );
  661. }
  662. static void SetNamedMaterialVar(IMaterial *pMat, char const *pVName, float fValue)
  663. {
  664. IMaterialVar *pVar = pMat->FindVar( pVName, NULL );
  665. pVar->SetFloatValue( fValue );
  666. }
  667. bool CompareLightPreview_Lights(CLightPreview_Light const &a, CLightPreview_Light const &b)
  668. {
  669. return (a.m_flDistanceToEye > b.m_flDistanceToEye);
  670. }
  671. #define MAX_PREVIEW_LIGHTS 20 // max # of lights to process.
  672. void CRender3D::SendShadowTriangles( void )
  673. {
  674. static int LastSendTimeStamp=-1;
  675. if ( GetUpdateCounter( EVTYPE_FACE_CHANGED ) != LastSendTimeStamp )
  676. {
  677. LastSendTimeStamp = GetUpdateCounter( EVTYPE_FACE_CHANGED );
  678. CUtlVector<Vector> *tri_list=new CUtlVector<Vector>;
  679. CMapDoc *pDoc = m_pView->GetMapDoc();
  680. CMapWorld *pWorld = pDoc->GetMapWorld();
  681. if ( !pWorld )
  682. return;
  683. if (g_pLPreviewOutputBitmap)
  684. delete g_pLPreviewOutputBitmap;
  685. g_pLPreviewOutputBitmap = NULL;
  686. EnumChildrenPos_t pos;
  687. CMapClass *pChild = pWorld->GetFirstDescendent( pos );
  688. while ( pChild )
  689. {
  690. if (pChild->IsVisible())
  691. pChild->AddShadowingTriangles( *tri_list );
  692. pChild = pWorld->GetNextDescendent( pos );
  693. }
  694. if ( tri_list->Count() )
  695. {
  696. MessageToLPreview msg( LPREVIEW_MSG_GEOM_DATA );
  697. msg.m_pShadowTriangleList = tri_list;
  698. g_HammerToLPreviewMsgQueue.QueueMessage( msg );
  699. }
  700. else
  701. delete tri_list;
  702. }
  703. }
  704. static bool LightForString( char const *pLight, Vector& intensity )
  705. {
  706. double r, g, b, scaler;
  707. VectorFill( intensity, 0 );
  708. // scanf into doubles, then assign, so it is vec_t size independent
  709. r = g = b = scaler = 0;
  710. double r_hdr,g_hdr,b_hdr,scaler_hdr;
  711. int argCnt = sscanf ( pLight, "%lf %lf %lf %lf %lf %lf %lf %lf",
  712. &r, &g, &b, &scaler, &r_hdr,&g_hdr,&b_hdr,&scaler_hdr );
  713. // This is a special case for HDR lights. If we have a vector of [-1, -1, -1, 1], then we
  714. // need to fall back to the non-HDR lighting since the HDR lighting hasn't been defined
  715. // for this light source.
  716. if( ( argCnt == 3 && r == -1.0f && g == -1.0f && b == -1.0f ) ||
  717. ( argCnt == 4 && r == -1.0f && g == -1.0f && b == -1.0f && scaler == 1.0f ) )
  718. {
  719. intensity.Init( -1.0f, -1.0f, -1.0f );
  720. return true;
  721. }
  722. if (argCnt==8) // 2 4-tuples
  723. {
  724. if (g_bHDR)
  725. {
  726. r=r_hdr;
  727. g=g_hdr;
  728. b=b_hdr;
  729. scaler=scaler_hdr;
  730. }
  731. argCnt=4;
  732. }
  733. intensity[0] = pow( r / 255.0, 2.2 ) * 255; // convert to linear
  734. switch( argCnt)
  735. {
  736. case 1:
  737. // The R,G,B values are all equal.
  738. intensity[1] = intensity[2] = intensity[0];
  739. break;
  740. case 3:
  741. case 4:
  742. // Save the other two G,B values.
  743. intensity[1] = pow( g / 255.0, 2.2 ) * 255;
  744. intensity[2] = pow( b / 255.0, 2.2 ) * 255;
  745. // Did we also get an "intensity" scaler value too?
  746. if ( argCnt == 4 )
  747. {
  748. // Scale the normalized 0-255 R,G,B values by the intensity scaler
  749. VectorScale( intensity, scaler / 255.0, intensity );
  750. }
  751. break;
  752. default:
  753. printf("unknown light specifier type - %s\n",pLight);
  754. return false;
  755. }
  756. // change light to 0..1
  757. intensity *= (1.0/255);
  758. return true;
  759. }
  760. // ugly code copied from vrad and munged. Should move into a lib
  761. static bool LightForKey (CMapEntity *ent, char *key, Vector& intensity )
  762. {
  763. char const *pLight = ent->GetKeyValue( key );
  764. return LightForString( pLight, intensity );
  765. }
  766. static void GetVectorForKey( CMapEntity *e, char const *kname, Vector *out )
  767. {
  768. Vector ret(-1,-1,-1);
  769. char const *pk = e->GetKeyValue( kname );
  770. if ( pk )
  771. {
  772. sscanf( pk, "%f %f %f", &(ret.x), &(ret.y), &(ret.z) );
  773. }
  774. *out=ret;
  775. }
  776. static float GetFloatForKey( CMapEntity *e, char const *kname)
  777. {
  778. char const *pk = e->GetKeyValue( kname );
  779. if ( pk )
  780. return atof( pk );
  781. else
  782. return 0.0;
  783. }
  784. static void SetLightFalloffParams( CMapEntity *e, CLightingPreviewLightDescription &l)
  785. {
  786. float d50=GetFloatForKey(e,"_fifty_percent_distance");
  787. if (d50)
  788. {
  789. float d0=GetFloatForKey(e,"_zero_percent_distance");
  790. l.SetupNewStyleAttenuation( d50, d0 );
  791. }
  792. else
  793. {
  794. float c = GetFloatForKey (e, "_constant_attn");
  795. float b = GetFloatForKey (e, "_linear_attn");
  796. float a = GetFloatForKey (e, "_quadratic_attn");
  797. l.SetupOldStyleAttenuation( a, b, c );
  798. }
  799. }
  800. static bool ParseLightAmbient( CMapEntity *e, CLightingPreviewLightDescription &out )
  801. {
  802. if( LightForKey( e, "_ambient", out.m_Color ) == 0 )
  803. return false;
  804. return true;
  805. }
  806. static bool ParseLightGeneric( CMapEntity *e, CLightingPreviewLightDescription &out )
  807. {
  808. // returns false if it doesn't like the light
  809. // get intensity
  810. if( g_bHDR )
  811. {
  812. if( LightForKey( e, "_lightHDR", out.m_Color ) == 0 ||
  813. ( out.m_Color.x == -1.0f &&
  814. out.m_Color.y == -1.0f &&
  815. out.m_Color.z == -1.0f ) )
  816. {
  817. LightForKey( e, "_light", out.m_Color );
  818. }
  819. }
  820. else
  821. {
  822. LightForKey( e, "_light", out.m_Color );
  823. }
  824. // handle spot falloffs
  825. if ( out.m_Type == MATERIAL_LIGHT_SPOT )
  826. {
  827. out.m_Theta=GetFloatForKey(e, "_inner_cone");
  828. out.m_Theta *= (M_PI/180.0);
  829. out.m_Phi=GetFloatForKey(e,"_cone");
  830. out.m_Phi *= (M_PI/180.0);
  831. out.m_Falloff=GetFloatForKey(e,"_exponent");
  832. }
  833. // check angle, targets
  834. #if 0 // !!bug!!
  835. target = e->m_KeyValues.GetValue( "target");
  836. if (target[0])
  837. { // point towards target
  838. entity_t *e2;
  839. char *target;
  840. e2 = FindTargetEntity (target);
  841. if (!e2)
  842. Warning("WARNING: light at (%i %i %i) has missing target\n",
  843. (int)dl->light.origin[0], (int)dl->light.origin[1], (int)dl->light.origin[2]);
  844. else
  845. {
  846. Vector dest;
  847. GetVectorForKey (e2, "origin", &dest);
  848. VectorSubtract (dest, dl->light.origin, dl->light.normal);
  849. VectorNormalize (dl->light.normal);
  850. }
  851. }
  852. else
  853. #endif
  854. {
  855. // point down angle
  856. Vector angles;
  857. GetVectorForKey( e, "angles", &angles );
  858. float pitch = GetFloatForKey( e,"pitch");
  859. float angle = GetFloatForKey( e,"angle" );
  860. SetupLightNormalFromProps( QAngle( angles.x, angles.y, angles.z ), angle, pitch,
  861. out.m_Direction );
  862. }
  863. if ( out.m_Type == MATERIAL_LIGHT_DIRECTIONAL )
  864. {
  865. out.m_Range = 0;
  866. out.m_Attenuation2 = out.m_Attenuation1 = out.m_Attenuation0 = 0;
  867. out.m_Direction *= -1;
  868. }
  869. else
  870. SetLightFalloffParams( e, out );
  871. return true;
  872. }
  873. // when there are multiple lighting environments, we are supposed to ignore but the first
  874. static bool s_bAddedLightEnvironmentAlready;
  875. static void AddEntityLightToLightList(
  876. CMapEntity *e,
  877. CUtlIntrusiveList<CLightingPreviewLightDescription> &listout )
  878. {
  879. char const *pszClassName=e->GetClassName();
  880. if (pszClassName)
  881. {
  882. CLightingPreviewLightDescription new_l;
  883. new_l.Init( e->m_nObjectID );
  884. e->GetOrigin( new_l.m_Position );
  885. new_l.m_Range = 0;
  886. if ( (! s_bAddedLightEnvironmentAlready ) &&
  887. (! stricmp( pszClassName, "light_environment" ) ))
  888. {
  889. const int N_FAKE_LIGHTS_FOR_AMBIENT = 100.0;
  890. const float AMBIENT_LIGHT_DISTANCE = 100000;
  891. const float AMBIENT_LIGHT_JITTER = 2.0 *
  892. sqrt( AMBIENT_LIGHT_DISTANCE * AMBIENT_LIGHT_DISTANCE * 2 * M_PI / N_FAKE_LIGHTS_FOR_AMBIENT );
  893. // lets add the sun to the list!
  894. new_l.m_Type = MATERIAL_LIGHT_DIRECTIONAL;
  895. if ( ParseLightGeneric(e,new_l) )
  896. {
  897. new_l.m_Position = new_l.m_Direction * AMBIENT_LIGHT_DISTANCE;
  898. new_l.RecalculateDerivedValues();
  899. CLightingPreviewLightDescription *pNew = new CLightingPreviewLightDescription;
  900. *pNew = new_l;
  901. listout.AddToHead( pNew );
  902. s_bAddedLightEnvironmentAlready = true;
  903. }
  904. // now, add the ambient sphere. We will approximate as "N" directional lights
  905. if ( ParseLightAmbient( e, new_l ) )
  906. {
  907. DirectionalSampler_t sampler;
  908. Vector color = new_l.m_Color;
  909. for( int i = 0; i < N_FAKE_LIGHTS_FOR_AMBIENT; i++)
  910. {
  911. new_l.Init( 0x80000000 | i ); // special id for ambient
  912. new_l.m_Type = MATERIAL_LIGHT_DIRECTIONAL;
  913. Vector dir = sampler.NextValue();
  914. if ( dir.z < 0 )
  915. {
  916. continue;
  917. }
  918. new_l.m_Direction = dir;
  919. new_l.m_Position = new_l.m_Direction * AMBIENT_LIGHT_DISTANCE;
  920. new_l.m_flJitterAmount = AMBIENT_LIGHT_JITTER;
  921. new_l.m_Color = color * ( 1.0 / N_FAKE_LIGHTS_FOR_AMBIENT );
  922. new_l.RecalculateDerivedValues();
  923. CLightingPreviewLightDescription *pNew = new CLightingPreviewLightDescription;
  924. *pNew = new_l;
  925. listout.AddToHead( pNew );
  926. }
  927. }
  928. }
  929. else if ( (! stricmp( pszClassName, "light" ) ))
  930. {
  931. // add point light to list
  932. new_l.m_Type = MATERIAL_LIGHT_POINT;
  933. if ( ParseLightGeneric(e,new_l) )
  934. {
  935. new_l.RecalculateDerivedValues();
  936. CLightingPreviewLightDescription *pNew = new CLightingPreviewLightDescription;
  937. *pNew = new_l;
  938. listout.AddToHead( pNew );
  939. }
  940. }
  941. else if ( (! stricmp( pszClassName, "light_spot" ) ))
  942. {
  943. // add point light to list
  944. new_l.m_Type = MATERIAL_LIGHT_SPOT;
  945. if ( ParseLightGeneric(e,new_l) )
  946. {
  947. new_l.RecalculateDerivedValues();
  948. CLightingPreviewLightDescription *pNew = new CLightingPreviewLightDescription;
  949. *pNew = new_l;
  950. listout.AddToHead( pNew );
  951. }
  952. }
  953. }
  954. }
  955. CUtlIntrusiveList<CLightingPreviewLightDescription> CRender3D::BuildLightList( void ) const
  956. {
  957. CUtlIntrusiveList<CLightingPreviewLightDescription> pRet;
  958. CMapDoc *pDoc = m_pView->GetMapDoc();
  959. CMapWorld *pWorld = pDoc->GetMapWorld();
  960. if ( pWorld )
  961. {
  962. EnumChildrenPos_t pos;
  963. CMapClass *pChild = pWorld->GetFirstDescendent( pos );
  964. while ( pChild )
  965. {
  966. CMapEntity *pLightEntity=dynamic_cast<CMapEntity*>( pChild );
  967. if (pLightEntity && (pLightEntity->m_EntityTypeFlags & ENTITY_FLAG_IS_LIGHT ) &&
  968. (pLightEntity->IsVisible()) )
  969. AddEntityLightToLightList( pLightEntity, pRet );
  970. pChild = pWorld->GetNextDescendent( pos );
  971. }
  972. }
  973. return pRet;
  974. }
  975. void CRender3D::SendLightList( void )
  976. {
  977. // send light list to lighting preview thread in priority order
  978. static int LastSendTimeStamp=-1;
  979. s_bAddedLightEnvironmentAlready = false;
  980. if ( GetUpdateCounter( EVTYPE_LIGHTING_CHANGED ) != LastSendTimeStamp )
  981. {
  982. LastSendTimeStamp = GetUpdateCounter( EVTYPE_LIGHTING_CHANGED );
  983. if (g_pLPreviewOutputBitmap)
  984. delete g_pLPreviewOutputBitmap;
  985. g_pLPreviewOutputBitmap = NULL;
  986. // now, get list of lights
  987. CUtlIntrusiveList<CLightingPreviewLightDescription> pList = BuildLightList( );
  988. MessageToLPreview Msg( LPREVIEW_MSG_LIGHT_DATA );
  989. Msg.m_LightList = pList; // thread deletes
  990. CCamera *pCamera = GetCamera();
  991. pCamera->GetViewPoint( Msg.m_EyePosition );
  992. g_HammerToLPreviewMsgQueue.QueueMessage( Msg );
  993. }
  994. }
  995. void DrawScreenSpaceLightRectangle(
  996. CMeshBuilder &meshBuilder,
  997. int nDestX, int nDestY, int nWidth, int nHeight, // Rect to draw into in screen space
  998. float flSrcTextureX0, float flSrcTextureY0, // which texel you want to appear at destx/y
  999. float flSrcTextureX1, float flSrcTextureY1, // which texel you want to appear at destx+width-1, desty+height-1
  1000. int nSrcTextureWidth, int nSrcTextureHeight, // needed for fixup
  1001. LightDesc_t const &light,
  1002. CMatRenderContextPtr &pRenderContext )
  1003. {
  1004. int nScreenWidth, nScreenHeight;
  1005. pRenderContext->GetRenderTargetDimensions( nScreenWidth, nScreenHeight );
  1006. float flLeftX = nDestX - 0.5f;
  1007. float flRightX = nDestX + nWidth - 0.5f;
  1008. float flTopY = nDestY - 0.5f;
  1009. float flBottomY = nDestY + nHeight - 0.5f;
  1010. float flSubrectWidth = flSrcTextureX1 - flSrcTextureX0;
  1011. float flSubrectHeight = flSrcTextureY1 - flSrcTextureY0;
  1012. float flTexelsPerPixelX = ( nWidth > 1 ) ? flSubrectWidth / ( nWidth - 1 ) : 0.0f;
  1013. float flTexelsPerPixelY = ( nHeight > 1 ) ? flSubrectHeight / ( nHeight - 1 ) : 0.0f;
  1014. float flLeftU = flSrcTextureX0 + 0.5f - ( 0.5f * flTexelsPerPixelX );
  1015. float flRightU = flSrcTextureX1 + 0.5f + ( 0.5f * flTexelsPerPixelX );
  1016. float flTopV = flSrcTextureY0 + 0.5f - ( 0.5f * flTexelsPerPixelY );
  1017. float flBottomV = flSrcTextureY1 + 0.5f + ( 0.5f * flTexelsPerPixelY );
  1018. float flOOTexWidth = 1.0f / nSrcTextureWidth;
  1019. float flOOTexHeight = 1.0f / nSrcTextureHeight;
  1020. flLeftU *= flOOTexWidth;
  1021. flRightU *= flOOTexWidth;
  1022. flTopV *= flOOTexHeight;
  1023. flBottomV *= flOOTexHeight;
  1024. // Get the current viewport size
  1025. int vx, vy, vw, vh;
  1026. pRenderContext->GetViewport( vx, vy, vw, vh );
  1027. // map from screen pixel coords to -1..1
  1028. flRightX = FLerp( -1, 1, 0, vw, flRightX );
  1029. flLeftX = FLerp( -1, 1, 0, vw, flLeftX );
  1030. flTopY = FLerp( 1, -1, 0, vh ,flTopY );
  1031. flBottomY = FLerp( 1, -1, 0, vh, flBottomY );
  1032. Vector color_intens = light.m_Color;
  1033. Vector spot_dir = light.m_Direction;
  1034. for ( int corner = 0; corner < 4; corner++ )
  1035. {
  1036. bool bLeft = (corner==0) || (corner==3);
  1037. meshBuilder.Position3f( (bLeft) ? flLeftX : flRightX, (corner & 2) ? flBottomY : flTopY, 0.0f );
  1038. meshBuilder.TexCoord2f( 0, (bLeft) ? flLeftU : flRightU, (corner & 2) ? flBottomV : flTopV );
  1039. float pdot = light.m_PhiDot;
  1040. float tdot = light.m_ThetaDot;
  1041. if ( light.m_Type == MATERIAL_LIGHT_POINT )
  1042. {
  1043. // model point light as a spot with infinite inner radius
  1044. pdot = 1.0e10;
  1045. tdot = 0.5;
  1046. }
  1047. meshBuilder.TexCoord4f( 1, color_intens.x, color_intens.y, color_intens.z, tdot );
  1048. meshBuilder.TexCoord4f( 2, spot_dir.x, spot_dir.y, spot_dir.z, pdot );
  1049. meshBuilder.TexCoord3fv( 3, light.m_Position.Base() );
  1050. meshBuilder.TexCoord4f( 4, light.m_Attenuation2, light.m_Attenuation1, light.m_Attenuation0, 1.0 );
  1051. meshBuilder.AdvanceVertex();
  1052. }
  1053. }
  1054. #define APPLYSIGN( posneg, incr ) ( ( posneg ) ? ( incr ) : ( - ( incr ) ) )
  1055. static int s_CubeIndices[]={
  1056. 5, 4, 6, // front
  1057. 6, 7, 5,
  1058. 4, 0, 2, // rside
  1059. 2, 6, 4,
  1060. 2, 0, 1, // back
  1061. 1, 3, 2,
  1062. 1, 0, 4, // top
  1063. 4, 5, 1,
  1064. 6, 2, 3, // bot
  1065. 3, 7, 6,
  1066. 5, 7, 3, // lside
  1067. 3, 1, 5
  1068. };
  1069. int DrawWorldSpaceLightCube(
  1070. CMeshBuilder &meshBuilder,
  1071. CMatRenderContextPtr &pRenderContext,
  1072. LightDesc_t const &light,
  1073. int nIndex )
  1074. {
  1075. Vector color_intens = light.m_Color;
  1076. Vector spot_dir = light.m_Direction;
  1077. float rad = light.DistanceAtWhichBrightnessIsLessThan( 1.0/ 255 );
  1078. Vector vecProjectionPlane0 = CrossProduct( spot_dir, Vector( 0, 1, 0 ) ) + CrossProduct( spot_dir, Vector( 1, 0, 0 ) );
  1079. vecProjectionPlane0.NormalizeInPlace();
  1080. Vector vecProjectionPlane1 = CrossProduct( spot_dir, vecProjectionPlane0 );
  1081. Assert( fabs( DotProduct( spot_dir, vecProjectionPlane0 ) ) < 0.01 );
  1082. Assert( fabs( DotProduct( spot_dir, vecProjectionPlane1 ) ) < 0.01 );
  1083. Assert( fabs( DotProduct( vecProjectionPlane0, vecProjectionPlane1 ) ) < 0.01 );
  1084. for ( int corner = 0; corner < 8; corner++ )
  1085. {
  1086. Vector vecPnt = light.m_Position;
  1087. vecPnt.x += APPLYSIGN( corner & 1, rad );
  1088. vecPnt.y += APPLYSIGN( corner & 2, rad );
  1089. vecPnt.z += APPLYSIGN( corner & 4, rad );
  1090. meshBuilder.Position3fv( vecPnt.Base() );
  1091. //meshBuilder.TexCoord2f( 0, (bLeft) ? flLeftU : flRightU, (corner & 2) ? flBottomV : flTopV );
  1092. float pdot = light.m_PhiDot;
  1093. float tdot = light.m_ThetaDot;
  1094. if ( light.m_Type == MATERIAL_LIGHT_POINT )
  1095. {
  1096. // model point light as a spot with infinite inner radius
  1097. pdot = 1.0e10;
  1098. tdot = 0.5;
  1099. }
  1100. meshBuilder.TexCoord4f( 1, color_intens.x, color_intens.y, color_intens.z, tdot );
  1101. meshBuilder.TexCoord4f( 2, spot_dir.x, spot_dir.y, spot_dir.z, pdot );
  1102. meshBuilder.TexCoord3fv( 3, light.m_Position.Base() );
  1103. meshBuilder.TexCoord4f( 4, light.m_Attenuation2, light.m_Attenuation1, light.m_Attenuation0, 1.0 );
  1104. meshBuilder.AdvanceVertex();
  1105. }
  1106. // now, output indices
  1107. for( int i = 0; i < ARRAYSIZE( s_CubeIndices ); i++ )
  1108. {
  1109. meshBuilder.FastIndex( s_CubeIndices[i] + nIndex );
  1110. }
  1111. return 8;
  1112. }
  1113. int DrawWorldSpaceLightPyramid(
  1114. CMeshBuilder &meshBuilder,
  1115. CMatRenderContextPtr &pRenderContext,
  1116. LightDesc_t const &light,
  1117. int nIndex )
  1118. {
  1119. if ( light.m_PhiDot < 0.0001 )
  1120. return DrawWorldSpaceLightCube( meshBuilder, pRenderContext, light, nIndex );
  1121. Vector color_intens = light.m_Color;
  1122. Vector spot_dir = light.m_Direction;
  1123. // now, we need to find two vectors perpendicular to each other and the ray direction
  1124. Vector vecProjectionPlane0 = CrossProduct( spot_dir, Vector( 0, 1, 0 ) ) + CrossProduct( spot_dir, Vector( 1, 0, 0 ) );
  1125. vecProjectionPlane0.NormalizeInPlace();
  1126. Vector vecProjectionPlane1 = CrossProduct( spot_dir, vecProjectionPlane0 );
  1127. Assert( fabs( DotProduct( spot_dir, vecProjectionPlane0 ) ) < 0.01 );
  1128. Assert( fabs( DotProduct( spot_dir, vecProjectionPlane1 ) ) < 0.01 );
  1129. Assert( fabs( DotProduct( vecProjectionPlane0, vecProjectionPlane1 ) ) < 0.01 );
  1130. float dist = light.DistanceAtWhichBrightnessIsLessThan( 1.0/ 255 );
  1131. float flSpreadPerDistance = sqrt( 1.0 / ( light.m_PhiDot * light.m_PhiDot ) -1 );
  1132. float flEndRad = 2.0 * dist * flSpreadPerDistance;
  1133. for ( int corner = 0; corner < 5; corner++ )
  1134. {
  1135. Vector vecPnt = light.m_Position;
  1136. Vector Color(1,1,1);
  1137. switch( corner )
  1138. {
  1139. case 0:
  1140. vecPnt += dist * spot_dir - flEndRad * vecProjectionPlane0 + flEndRad * vecProjectionPlane1;
  1141. Color.Init( 1, 0, 0 );
  1142. break;
  1143. case 1:
  1144. vecPnt += dist * spot_dir + flEndRad * vecProjectionPlane0 + flEndRad * vecProjectionPlane1;
  1145. Color.Init( 0, 1, 0 );
  1146. break;
  1147. case 2:
  1148. vecPnt += dist * spot_dir - flEndRad * vecProjectionPlane0 - flEndRad * vecProjectionPlane1;
  1149. Color.Init( 0, 0, 1 );
  1150. break;
  1151. case 3:
  1152. vecPnt += dist * spot_dir + flEndRad * vecProjectionPlane0 - flEndRad * vecProjectionPlane1;
  1153. Color.Init( 1, 0, 1 );
  1154. break;
  1155. }
  1156. meshBuilder.TexCoord3fv( 5, Color.Base() );
  1157. meshBuilder.Position3fv( vecPnt.Base() );
  1158. //meshBuilder.TexCoord2f( 0, (bLeft) ? flLeftU : flRightU, (corner & 2) ? flBottomV : flTopV );
  1159. float pdot = light.m_PhiDot;
  1160. float tdot = light.m_ThetaDot;
  1161. if ( light.m_Type == MATERIAL_LIGHT_POINT )
  1162. {
  1163. // model point light as a spot with infinite inner radius
  1164. pdot = 1.0e10;
  1165. tdot = 0.5;
  1166. }
  1167. meshBuilder.TexCoord4f( 1, color_intens.x, color_intens.y, color_intens.z, tdot );
  1168. meshBuilder.TexCoord4f( 2, spot_dir.x, spot_dir.y, spot_dir.z, pdot );
  1169. meshBuilder.TexCoord3fv( 3, light.m_Position.Base() );
  1170. meshBuilder.TexCoord4f( 4, light.m_Attenuation2, light.m_Attenuation1, light.m_Attenuation0, 1.0 );
  1171. meshBuilder.AdvanceVertex();
  1172. }
  1173. meshBuilder.FastIndex( nIndex + 1 ); // top
  1174. meshBuilder.FastIndex( nIndex + 0 );
  1175. meshBuilder.FastIndex( nIndex + 4 );
  1176. meshBuilder.FastIndex( nIndex + 2 ); // bottom
  1177. meshBuilder.FastIndex( nIndex + 3 );
  1178. meshBuilder.FastIndex( nIndex + 4 );
  1179. meshBuilder.FastIndex( nIndex + 3 ); // right
  1180. meshBuilder.FastIndex( nIndex + 1 );
  1181. meshBuilder.FastIndex( nIndex + 4 );
  1182. meshBuilder.FastIndex( nIndex + 0 ); // right
  1183. meshBuilder.FastIndex( nIndex + 2 );
  1184. meshBuilder.FastIndex( nIndex + 4 );
  1185. meshBuilder.FastIndex( nIndex + 0 ); // end cap
  1186. meshBuilder.FastIndex( nIndex + 1 );
  1187. meshBuilder.FastIndex( nIndex + 3 );
  1188. meshBuilder.FastIndex( nIndex + 3 );
  1189. meshBuilder.FastIndex( nIndex + 2 );
  1190. meshBuilder.FastIndex( nIndex + 0 );
  1191. return 5;
  1192. }
  1193. static Vector s_pCornerPoints[4]={
  1194. Vector( -1, -1, 0 ),
  1195. Vector( 1, -1, 0 ),
  1196. Vector( 1, 1, 0 ),
  1197. Vector( -1, 1, 0 )
  1198. };
  1199. int DrawWorldSpaceLightFullScreenQuad(
  1200. int nWidth, int nHeight,
  1201. CMeshBuilder &meshBuilder,
  1202. CMatRenderContextPtr &pRenderContext,
  1203. LightDesc_t const &light,
  1204. int nIndex )
  1205. {
  1206. Vector color_intens = light.m_Color;
  1207. Vector spot_dir = light.m_Direction;
  1208. for ( int corner = 0; corner < 4; corner++ )
  1209. {
  1210. Vector vecPnt = s_pCornerPoints[corner];
  1211. meshBuilder.Position3fv( vecPnt.Base() );
  1212. float pdot = light.m_PhiDot;
  1213. float tdot = light.m_ThetaDot;
  1214. if ( light.m_Type == MATERIAL_LIGHT_POINT )
  1215. {
  1216. // model point light as a spot with infinite inner radius
  1217. pdot = 1.0e10;
  1218. tdot = 0.5;
  1219. }
  1220. meshBuilder.TexCoord4f( 1, color_intens.x, color_intens.y, color_intens.z, tdot );
  1221. meshBuilder.TexCoord4f( 2, spot_dir.x, spot_dir.y, spot_dir.z, pdot );
  1222. meshBuilder.TexCoord3fv( 3, light.m_Position.Base() );
  1223. meshBuilder.TexCoord4f( 4, light.m_Attenuation2, light.m_Attenuation1, light.m_Attenuation0, 1.0 );
  1224. meshBuilder.AdvanceVertex();
  1225. }
  1226. // now, output indices
  1227. meshBuilder.FastIndex( 2 + nIndex );
  1228. meshBuilder.FastIndex( 1 + nIndex );
  1229. meshBuilder.FastIndex( 0 + nIndex );
  1230. meshBuilder.FastIndex( 0 + nIndex );
  1231. meshBuilder.FastIndex( 3 + nIndex );
  1232. meshBuilder.FastIndex( 2 + nIndex );
  1233. return 4;
  1234. }
  1235. void CRender3D::AccumulateLights( CUtlPriorityQueue<CLightPreview_Light> &light_queue,
  1236. CMatRenderContextPtr &pRenderContext,
  1237. int nTargetWidth, int nTargetHeight,
  1238. ITexture *dest_rt )
  1239. {
  1240. IMaterial *add_0_to_1=materials->FindMaterial( "editor/addlight0",
  1241. TEXTURE_GROUP_OTHER,true);
  1242. ITexture *dest_rt_current=materials->FindTexture( "_rt_accbuf", TEXTURE_GROUP_RENDER_TARGET );
  1243. pRenderContext->SetRenderTarget( dest_rt_current );
  1244. pRenderContext->ClearColor3ub( 0, 0, 0);
  1245. pRenderContext->ClearBuffers( true, true );
  1246. // pRenderContext->Viewport(0, 0, nTargetWidth, nTargetHeight );
  1247. pRenderContext->Bind( add_0_to_1 );
  1248. int nlights = min( MAX_PREVIEW_LIGHTS, light_queue.Count() );
  1249. // now, lets build up a vertex buffer of lights
  1250. CMeshBuilder meshBuilder;
  1251. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  1252. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 8 * nlights, 6 * 3 * 2 * nlights );
  1253. int nIndex = 0;
  1254. for(int i=0; i < nlights ; i++)
  1255. {
  1256. LightDesc_t light = light_queue.ElementAtHead().m_Light;
  1257. light.RecalculateDerivedValues();
  1258. light_queue.RemoveAtHead();
  1259. nIndex += DrawWorldSpaceLightFullScreenQuad( nTargetWidth, nTargetHeight,
  1260. meshBuilder, pRenderContext, light, nIndex );
  1261. // if ( light.m_Type == MATERIAL_LIGHT_SPOT )
  1262. // nIndex += DrawWorldSpaceLightPyramid( meshBuilder, pRenderContext, light, nIndex );
  1263. // else
  1264. // nIndex += DrawWorldSpaceLightCube( meshBuilder, pRenderContext, light, nIndex );
  1265. // DrawScreenSpaceLightRectangle(
  1266. // meshBuilder,
  1267. // 0, 0, nTargetWidth, nTargetHeight,
  1268. // 0,0,
  1269. // nTargetWidth - 1, nTargetHeight -1,
  1270. // dest_rt->GetActualWidth(),
  1271. // dest_rt->GetActualHeight(),
  1272. // light,
  1273. // pRenderContext
  1274. // );
  1275. }
  1276. meshBuilder.End();
  1277. pMesh->Draw();
  1278. pRenderContext->SetRenderTarget( NULL );
  1279. }
  1280. void CRender3D::SendGBuffersToLightingThread( int nTargetWidth, int nTargetHeight )
  1281. {
  1282. static bool did_dump=false;
  1283. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  1284. static char const *rts_to_transmit[]={"_rt_albedo","_rt_normal","_rt_position",
  1285. "_rt_flags" };
  1286. MessageToLPreview Msg(LPREVIEW_MSG_G_BUFFERS);
  1287. for(int i=0; i < NELEMS( rts_to_transmit ); i++)
  1288. {
  1289. SetRenderTargetNamed(0,rts_to_transmit[i]);
  1290. FloatBitMap_t *fbm = new FloatBitMap_t( nTargetWidth, nTargetHeight );
  1291. Msg.m_pDefferedRenderingBMs[i]=fbm;
  1292. if ( i != 3 )
  1293. {
  1294. // we have to reformat the data for the planar mode used by floatbm now
  1295. float *pTmpData = new float[ nTargetWidth * nTargetHeight * 4 ];
  1296. pRenderContext->ReadPixels( 0, 0, nTargetWidth, nTargetHeight, (uint8 *) pTmpData,
  1297. IMAGE_FORMAT_RGBA32323232F );
  1298. // reformat data
  1299. for( int nY = 0 ; nY < nTargetHeight; nY++ )
  1300. for( int nX = 0; nX < nTargetWidth; nX++ )
  1301. for( int nComp = 0 ; nComp < 4; nComp++ )
  1302. fbm->Pixel( nX, nY, 0, nComp ) = pTmpData[ nComp + 4 * ( nX + nTargetWidth * nY ) ];
  1303. delete[] pTmpData;
  1304. }
  1305. if ( ( i == 0 ) && ( ! did_dump ) )
  1306. {
  1307. fbm->RaiseToPower( 1.0/ 2.2 );
  1308. fbm->WriteTGAFile("albedo.tga");
  1309. fbm->RaiseToPower( 2.2 );
  1310. }
  1311. if ( ( i == 1 ) && ( ! did_dump ) )
  1312. {
  1313. fbm->WriteTGAFile("normal.tga");
  1314. }
  1315. }
  1316. did_dump = true;
  1317. n_gbufs_queued++;
  1318. GetCamera()->GetViewPoint( Msg.m_EyePosition );
  1319. Msg.m_nBitmapGenerationCounter = g_nBitmapGenerationCounter;
  1320. g_HammerToLPreviewMsgQueue.QueueMessage( Msg );
  1321. }
  1322. //-----------------------------------------------------------------------------
  1323. // Purpose:
  1324. //-----------------------------------------------------------------------------
  1325. void CRender3D::EndRenderFrame(void)
  1326. {
  1327. CRender::EndRenderFrame();
  1328. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  1329. if (m_Pick.bPicking)
  1330. {
  1331. pRenderContext->Flush();
  1332. //
  1333. // Some OpenGL drivers, such as the ATI Rage Fury Max, return selection buffer Z values
  1334. // in reverse order. For these cards, we must reverse the selection order.
  1335. //
  1336. if (m_Pick.nNumHits > 1)
  1337. {
  1338. if (!m_RenderState.bReverseSelection)
  1339. {
  1340. qsort(m_Pick.Hits, m_Pick.nNumHits, sizeof(m_Pick.Hits[0]), _CompareHits);
  1341. }
  1342. else
  1343. {
  1344. qsort(m_Pick.Hits, m_Pick.nNumHits, sizeof(m_Pick.Hits[0]), _CompareHitsReverse);
  1345. }
  1346. }
  1347. //
  1348. // Copy the requested number of nearest hits into the destination buffer.
  1349. //
  1350. int nHitsToCopy = min(m_Pick.nNumHits, m_Pick.nMaxHits);
  1351. if (nHitsToCopy != 0)
  1352. {
  1353. memcpy(m_Pick.pHitsDest, m_Pick.Hits, sizeof(m_Pick.Hits[0]) * nHitsToCopy);
  1354. }
  1355. }
  1356. //
  1357. // Copy the GL buffer contents to our window's device context unless we're in pick mode.
  1358. //
  1359. if (!m_Pick.bPicking)
  1360. {
  1361. if (
  1362. (m_eCurrentRenderMode == RENDER_MODE_LIGHT_PREVIEW2) ||
  1363. (m_eCurrentRenderMode == RENDER_MODE_LIGHT_PREVIEW_RAYTRACED)
  1364. )
  1365. {
  1366. pRenderContext->Flush();
  1367. pRenderContext->SetRenderTarget( NULL );
  1368. pRenderContext->SetRenderTargetEx( 1,NULL );
  1369. pRenderContext->SetRenderTargetEx( 2,NULL );
  1370. pRenderContext->SetRenderTargetEx( 3,NULL );
  1371. ITexture *pRT = SetRenderTargetNamed(0,"_rt_accbuf");
  1372. pRenderContext->ClearColor3ub(0,0,0);
  1373. pRenderContext->ClearBuffers( true, true );
  1374. CCamera *pCamera = GetCamera();
  1375. int width, height;
  1376. pCamera->GetViewPort( width, height );
  1377. int nTargetWidth = min( width, pRT->GetActualWidth() );
  1378. int nTargetHeight = min( height, pRT->GetActualHeight() );
  1379. bool view_changed = false;
  1380. Vector new_vp;
  1381. pCamera->GetViewPoint( new_vp );
  1382. if ( (pCamera->GetYaw() != m_fLastLPreviewAngles[0] ) ||
  1383. (pCamera->GetPitch() != m_fLastLPreviewAngles[1] ) ||
  1384. (pCamera->GetRoll() != m_fLastLPreviewAngles[2] ) ||
  1385. (m_nLastLPreviewHeight != height ) ||
  1386. (m_nLastLPreviewWidth != width ) ||
  1387. ( new_vp != m_LastLPreviewCameraPos ) ||
  1388. (pCamera->GetZoom() != m_fLastLPreviewZoom ) )
  1389. view_changed = true;
  1390. if (m_pView->m_bUpdateView && (m_eCurrentRenderMode == RENDER_MODE_LIGHT_PREVIEW_RAYTRACED))
  1391. {
  1392. static float Last_SendTime=0;
  1393. // now, lets create floatbms with the deferred rendering data, so we can pass it to the lpreview thread
  1394. float newtime=Plat_FloatTime();
  1395. if (( n_gbufs_queued < 1 ) && ( newtime-Last_SendTime > 1.0) )
  1396. {
  1397. SendShadowTriangles();
  1398. SendLightList(); // send light list to render thread
  1399. if ( view_changed )
  1400. {
  1401. m_fLastLPreviewAngles[0] = pCamera->GetYaw();
  1402. m_fLastLPreviewAngles[1] = pCamera->GetPitch();
  1403. m_fLastLPreviewAngles[2] = pCamera->GetRoll();
  1404. m_LastLPreviewCameraPos = new_vp;
  1405. m_fLastLPreviewZoom = pCamera->GetZoom();
  1406. m_nLastLPreviewHeight = height;
  1407. m_nLastLPreviewWidth = width;
  1408. g_nBitmapGenerationCounter++;
  1409. Last_SendTime=newtime;
  1410. if (g_pLPreviewOutputBitmap)
  1411. delete g_pLPreviewOutputBitmap;
  1412. g_pLPreviewOutputBitmap = NULL;
  1413. SendGBuffersToLightingThread( nTargetWidth, nTargetHeight );
  1414. pRenderContext->SetRenderTarget( NULL );
  1415. }
  1416. }
  1417. }
  1418. // only update non-ray traced lpreview if we have no ray traced one or if the scene has changed
  1419. if (m_pView->m_bUpdateView || (m_eCurrentRenderMode != RENDER_MODE_LIGHT_PREVIEW_RAYTRACED) ||
  1420. (! g_pLPreviewOutputBitmap) )
  1421. {
  1422. SetRenderTargetNamed(0,"_rt_accbuf");
  1423. pRenderContext->ClearColor3ub( 0, 0, 0 );
  1424. MaterialSystemInterface()->ClearBuffers( true, true );
  1425. pRenderContext->Viewport(0, 0, nTargetWidth, nTargetHeight );
  1426. pRenderContext->ClearColor3ub(0,0,0);
  1427. pRenderContext->ClearBuffers( true, true );
  1428. // now, copy albedo to screen
  1429. ITexture *dest_rt=materials->FindTexture("_rt_albedo", TEXTURE_GROUP_RENDER_TARGET );
  1430. int xl,yl,dest_width,dest_height;
  1431. pRenderContext->GetViewport( xl,yl,dest_width,dest_height);
  1432. CMapDoc *pDoc = m_pView->GetMapDoc();
  1433. CMapWorld *pWorld = pDoc->GetMapWorld();
  1434. if ( !pWorld )
  1435. return;
  1436. // now, get list of lights
  1437. CUtlIntrusiveList<CLightingPreviewLightDescription> lightList = BuildLightList();
  1438. CUtlPriorityQueue<CLightPreview_Light> light_queue( 0, 0, CompareLightPreview_Lights);
  1439. Vector eye_pnt;
  1440. pCamera->GetViewPoint(eye_pnt);
  1441. // now, add lights in priority order
  1442. for( CLightingPreviewLightDescription *pLight = lightList.Head(); pLight; pLight = pLight->m_pNext )
  1443. {
  1444. if (
  1445. ( pLight->m_Type == MATERIAL_LIGHT_SPOT ) ||
  1446. ( pLight->m_Type == MATERIAL_LIGHT_POINT ) )
  1447. {
  1448. Vector lpnt;
  1449. CLightPreview_Light tmplight;
  1450. tmplight.m_Light = *pLight;
  1451. tmplight.m_flDistanceToEye = pLight->m_Position.DistTo( eye_pnt );
  1452. light_queue.Insert(tmplight);
  1453. }
  1454. }
  1455. if ( light_queue.Count() == 0 )
  1456. {
  1457. // no lights for gpu preview? lets add a fake one
  1458. CLightPreview_Light tmplight;
  1459. tmplight.m_Light.m_Type = MATERIAL_LIGHT_POINT;
  1460. tmplight.m_Light.m_Color = Vector( 10, 10, 10 );
  1461. tmplight.m_Light.m_Position = Vector( 0, 0, 30000 );
  1462. tmplight.m_Light.m_Range = 1.0e20;
  1463. tmplight.m_Light.m_Attenuation0 = 1.0;
  1464. tmplight.m_Light.m_Attenuation1 = 0.0;
  1465. tmplight.m_Light.m_Attenuation2 = 0.0;
  1466. tmplight.m_flDistanceToEye = 1;
  1467. light_queue.Insert(tmplight);
  1468. }
  1469. // because of no blend support on ati, we have to ping pong. This needs an nvidia-specifc
  1470. // path for perf
  1471. AccumulateLights( light_queue, pRenderContext, nTargetWidth, nTargetHeight, dest_rt );
  1472. IMaterial *sample_last=materials->FindMaterial("editor/sample_result_1",
  1473. TEXTURE_GROUP_OTHER,true);
  1474. pRenderContext->DrawScreenSpaceRectangle(
  1475. sample_last, xl, yl, dest_width, dest_height,
  1476. 0,0,
  1477. nTargetWidth, nTargetHeight,
  1478. dest_rt->GetActualWidth(),
  1479. dest_rt->GetActualHeight());
  1480. }
  1481. }
  1482. if ( !m_bRenderingOverEngine )
  1483. {
  1484. MaterialSystemInterface()->SwapBuffers();
  1485. }
  1486. if ( (m_eCurrentRenderMode == RENDER_MODE_LIGHT_PREVIEW_RAYTRACED) &&
  1487. g_pLPreviewOutputBitmap )
  1488. {
  1489. // blit it
  1490. BITMAPINFOHEADER mybmh;
  1491. mybmh.biHeight=-g_pLPreviewOutputBitmap->Height();
  1492. mybmh.biSize=sizeof(BITMAPINFOHEADER);
  1493. // now, set up bitmapheader struct for StretchDIB
  1494. mybmh.biWidth=g_pLPreviewOutputBitmap->Width();
  1495. mybmh.biPlanes=1;
  1496. mybmh.biBitCount=32;
  1497. mybmh.biCompression=BI_RGB;
  1498. mybmh.biSizeImage=g_pLPreviewOutputBitmap->Width()*g_pLPreviewOutputBitmap->Height();
  1499. RECT wrect;
  1500. memset(&wrect,0,sizeof(wrect));
  1501. CCamera *pCamera = GetCamera();
  1502. int width, height;
  1503. pCamera->GetViewPort( width, height );
  1504. // StretchDIBits(
  1505. // m_WinData.hDC,0,0,width,height,
  1506. // 0,0,g_pLPreviewOutputBitmap->Width(), g_pLPreviewOutputBitmap->Height(),
  1507. // g_pLPreviewOutputBitmap->m_pBits, (BITMAPINFO *) &mybmh,
  1508. // DIB_RGB_COLORS, SRCCOPY);
  1509. // remember that we blitted it
  1510. m_pView->m_nLastRaytracedBitmapRenderTimeStamp =
  1511. GetUpdateCounter( EVTYPE_BITMAP_RECEIVED_FROM_LPREVIEW );
  1512. }
  1513. if (g_bShowStatistics)
  1514. {
  1515. //
  1516. // Calculate frame rate.
  1517. //
  1518. if (m_dwTimeLastSample != 0)
  1519. {
  1520. DWORD dwTimeNow = timeGetTime();
  1521. DWORD dwTimeElapsed = dwTimeNow - m_dwTimeLastSample;
  1522. if ((dwTimeElapsed > 1000) && (m_nFramesThisSample > 0))
  1523. {
  1524. float fTimeElapsed = (float)dwTimeElapsed / 1000.0;
  1525. m_fFrameRate = m_nFramesThisSample / fTimeElapsed;
  1526. m_nFramesThisSample = 0;
  1527. m_dwTimeLastSample = dwTimeNow;
  1528. }
  1529. }
  1530. else
  1531. {
  1532. m_dwTimeLastSample = timeGetTime();
  1533. }
  1534. m_nFramesThisSample++;
  1535. //
  1536. // Display the frame rate and camera position.
  1537. //
  1538. char szText[100];
  1539. Vector ViewPoint;
  1540. GetCamera()->GetViewPoint(ViewPoint);
  1541. int nLen = sprintf(szText, "FPS=%3.2f Pos=[%.f %.f %.f]", m_fFrameRate, ViewPoint[0], ViewPoint[1], ViewPoint[2]);
  1542. TextOut(m_WinData.hDC, 2, 18, szText, nLen);
  1543. }
  1544. }
  1545. if ( enginetools )
  1546. MaterialSystemInterface()->SetView( enginetools->GetEngineHwnd() );
  1547. }
  1548. void CRender3D::PushInstanceData( CMapInstance *pInstanceClass, Vector &InstanceOrigin, QAngle &InstanceAngles )
  1549. {
  1550. __super::PushInstanceData( pInstanceClass, InstanceOrigin, InstanceAngles );
  1551. if ( m_bInstanceRendering )
  1552. {
  1553. CMapFace::PushFaceQueue();
  1554. }
  1555. }
  1556. void CRender3D::PopInstanceData( void )
  1557. {
  1558. if ( m_bInstanceRendering )
  1559. {
  1560. CMapFace::PopFaceQueue();
  1561. }
  1562. __super::PopInstanceData();
  1563. }
  1564. //-----------------------------------------------------------------------------
  1565. // Renders the world axes
  1566. //-----------------------------------------------------------------------------
  1567. void CRender3D::RenderWorldAxes()
  1568. {
  1569. // Render the world axes.
  1570. PushRenderMode( RENDER_MODE_WIREFRAME );
  1571. CMeshBuilder meshBuilder;
  1572. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  1573. IMesh* pMesh = pRenderContext->GetDynamicMesh( );
  1574. meshBuilder.Begin( pMesh, MATERIAL_LINES, 3 );
  1575. meshBuilder.Color3ub(255, 0, 0);
  1576. meshBuilder.Position3f(0, 0, 0);
  1577. meshBuilder.AdvanceVertex();
  1578. meshBuilder.Color3ub(255, 0, 0);
  1579. meshBuilder.Position3f(100, 0, 0);
  1580. meshBuilder.AdvanceVertex();
  1581. meshBuilder.Color3ub(0, 255, 0);
  1582. meshBuilder.Position3f(0, 0, 0);
  1583. meshBuilder.AdvanceVertex();
  1584. meshBuilder.Color3ub(0, 255, 0);
  1585. meshBuilder.Position3f(0, 100, 0);
  1586. meshBuilder.AdvanceVertex();
  1587. meshBuilder.Color3ub(0, 0, 255);
  1588. meshBuilder.Position3f(0, 0, 0);
  1589. meshBuilder.AdvanceVertex();
  1590. meshBuilder.Color3ub(0, 0, 255);
  1591. meshBuilder.Position3f(0, 0, 100);
  1592. meshBuilder.AdvanceVertex();
  1593. meshBuilder.End();
  1594. pMesh->Draw();
  1595. PopRenderMode();
  1596. }
  1597. //-----------------------------------------------------------------------------
  1598. // Purpose: this will handle all translucent rendering, including local transforms for instance items
  1599. // Input : none
  1600. // Output : none
  1601. //-----------------------------------------------------------------------------
  1602. void CRender3D::RenderTranslucentObjects( void )
  1603. {
  1604. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  1605. bool bAddedTransform = false;
  1606. CMapInstance *pInstanceClass = NULL;
  1607. TInstanceState SaveInstanceState = m_CurrentInstanceState;
  1608. m_bInstanceRendering = false;
  1609. // render translucent objects after all opaque objects
  1610. while ( m_TranslucentRenderObjects.Count() > 0 )
  1611. {
  1612. TranslucentObjects_t current = m_TranslucentRenderObjects.ElementAtHead();
  1613. m_TranslucentRenderObjects.RemoveAtHead();
  1614. if ( current.m_InstanceState.m_pInstanceClass )
  1615. {
  1616. if ( pInstanceClass != current.m_InstanceState.m_pInstanceClass || !m_bInstanceRendering || current.m_InstanceState.m_InstanceMatrix != m_CurrentInstanceState.m_InstanceMatrix )
  1617. {
  1618. if ( bAddedTransform )
  1619. {
  1620. EndLocalTransfrom();
  1621. }
  1622. bAddedTransform = true;
  1623. BeginLocalTransfrom( current.m_InstanceState.m_InstanceRenderMatrix, false );
  1624. m_CurrentInstanceState = current.m_InstanceState;
  1625. pInstanceClass = m_CurrentInstanceState.m_pInstanceClass;
  1626. m_bInstanceRendering = true;
  1627. if ( pInstanceClass->IsEditable() )
  1628. {
  1629. SetInstanceRendering( INSTANCE_STATE_OFF );
  1630. }
  1631. else
  1632. {
  1633. SetInstanceRendering( current.m_bInstanceSelected ? INSTANCE_STACE_SELECTED : INSTANCE_STATE_ON );
  1634. }
  1635. }
  1636. }
  1637. else
  1638. {
  1639. if ( m_bInstanceRendering )
  1640. {
  1641. if ( bAddedTransform )
  1642. {
  1643. EndLocalTransfrom();
  1644. bAddedTransform = false;
  1645. }
  1646. SetInstanceRendering( INSTANCE_STATE_OFF );
  1647. m_bInstanceRendering = false;
  1648. }
  1649. }
  1650. current.object->Render3D( this );
  1651. }
  1652. m_bInstanceRendering = false;
  1653. if ( bAddedTransform )
  1654. {
  1655. EndLocalTransfrom();
  1656. }
  1657. m_CurrentInstanceState = SaveInstanceState;
  1658. }
  1659. #define MAX_SLICE_COLORS 5
  1660. static unsigned char nVerticalColors[ MAX_SLICE_COLORS ][ 3 ] =
  1661. {
  1662. { 127, 127, 127 },
  1663. { 255, 255, 255 },
  1664. { 255, 0, 0 },
  1665. { 0, 255, 0 },
  1666. { 255, 255, 0 }
  1667. };
  1668. //-----------------------------------------------------------------------------
  1669. // Purpose: horribly inefficient rendering mechanism for FoW. Demonstration purposes only!
  1670. //-----------------------------------------------------------------------------
  1671. void CRender3D::RenderFoW( void )
  1672. {
  1673. CFoW *pFoW = m_pView->GetMapDoc()->GetFoW();
  1674. PushRenderMode( RENDER_MODE_FLAT_NOZ );
  1675. for( int i = 0; i < pFoW->GetNumTriSoups(); i++ )
  1676. {
  1677. CFoW_TriSoupCollection *pSoup = pFoW->GetTriSoup( i );
  1678. if ( pSoup == NULL )
  1679. {
  1680. continue;
  1681. }
  1682. for( int j = 0; j < pSoup->GetNumOccluders(); j++ )
  1683. {
  1684. CFoW_LineOccluder *pOccluder = pSoup->GetOccluder( j );
  1685. if ( pOccluder )
  1686. {
  1687. float flZPos;
  1688. Vector2D vStart, vEnd;
  1689. int nSliceNum = pOccluder->GetSliceNum();
  1690. flZPos = pFoW->GetSliceZPosition( nSliceNum ) + 16.0f;
  1691. if ( nSliceNum != 1 && 0 )
  1692. {
  1693. continue;
  1694. }
  1695. if ( nSliceNum < MAX_SLICE_COLORS )
  1696. {
  1697. SetDrawColor( nVerticalColors[ nSliceNum ][ 0 ], nVerticalColors[ nSliceNum ][ 1 ], nVerticalColors[ nSliceNum ][ 2 ] );
  1698. }
  1699. else
  1700. {
  1701. SetDrawColor( 255, 255, 255 );
  1702. }
  1703. vStart = pOccluder->GetStart();
  1704. vEnd = pOccluder->GetEnd();
  1705. Vector vRealStart( vStart.x, vStart.y, flZPos );
  1706. Vector vRealEnd( vEnd.x, vEnd.y, flZPos );
  1707. DrawLine( vRealStart, vRealEnd );
  1708. }
  1709. }
  1710. }
  1711. PopRenderMode();
  1712. }
  1713. //-----------------------------------------------------------------------------
  1714. // Purpose:
  1715. //-----------------------------------------------------------------------------
  1716. void CRender3D::Render( bool bRenderingOverEngine )
  1717. {
  1718. CMapDoc *pDoc = m_pView->GetMapDoc();
  1719. CMapWorld *pMapWorld = pDoc->GetMapWorld();
  1720. CManifest *pManifest = pDoc->GetManifest();
  1721. bool view_changed = false;
  1722. CCamera *pCamera = GetCamera();
  1723. Vector new_vp;
  1724. pCamera->GetViewPoint( new_vp );
  1725. int width, height;
  1726. pCamera->GetViewPort( width, height );
  1727. if ( GetMainWnd()->m_pLightingPreviewOutputWindow)
  1728. {
  1729. SendLightList(); // nop if nothing changed
  1730. SendShadowTriangles(); // nop if nothing changed
  1731. }
  1732. if ( (pCamera->GetYaw() != m_fLastLPreviewAngles[0] ) ||
  1733. (pCamera->GetPitch() != m_fLastLPreviewAngles[1] ) ||
  1734. (pCamera->GetRoll() != m_fLastLPreviewAngles[2] ) ||
  1735. (m_nLastLPreviewHeight != height ) ||
  1736. (m_nLastLPreviewWidth != width ) ||
  1737. ( new_vp != m_LastLPreviewCameraPos ) ||
  1738. (pCamera->GetZoom() != m_fLastLPreviewZoom ) )
  1739. view_changed = true;
  1740. if ( (m_eCurrentRenderMode == RENDER_MODE_LIGHT_PREVIEW_RAYTRACED) &&
  1741. g_pLPreviewOutputBitmap &&
  1742. (! view_changed ) )
  1743. {
  1744. // blit it
  1745. BITMAPINFOHEADER mybmh;
  1746. mybmh.biHeight=-g_pLPreviewOutputBitmap->Height();
  1747. mybmh.biSize=sizeof(BITMAPINFOHEADER);
  1748. // now, set up bitmapheader struct for StretchDIB
  1749. mybmh.biWidth=g_pLPreviewOutputBitmap->Width();
  1750. mybmh.biPlanes=1;
  1751. mybmh.biBitCount=32;
  1752. mybmh.biCompression=BI_RGB;
  1753. mybmh.biSizeImage=g_pLPreviewOutputBitmap->Width()*g_pLPreviewOutputBitmap->Height();
  1754. RECT wrect;
  1755. memset(&wrect,0,sizeof(wrect));
  1756. int width, height;
  1757. pCamera->GetViewPort( width, height );
  1758. // StretchDIBits(
  1759. // m_WinData.hDC,0,0,width,height,
  1760. // 0,0,g_pLPreviewOutputBitmap->Width(), g_pLPreviewOutputBitmap->Height(),
  1761. // g_pLPreviewOutputBitmap->m_pBits, (BITMAPINFO *) &mybmh,
  1762. // DIB_RGB_COLORS, SRCCOPY);
  1763. m_pView->m_nLastRaytracedBitmapRenderTimeStamp =
  1764. GetUpdateCounter( EVTYPE_BITMAP_RECEIVED_FROM_LPREVIEW );
  1765. // return;
  1766. }
  1767. StartRenderFrame( bRenderingOverEngine );
  1768. if (
  1769. ( m_eCurrentRenderMode != RENDER_MODE_LIGHT_PREVIEW2 ) &&
  1770. ( m_eCurrentRenderMode != RENDER_MODE_LIGHT_PREVIEW_RAYTRACED )
  1771. )
  1772. RenderWorldAxes();
  1773. //
  1774. // Deferred rendering lets us sort everything here by material.
  1775. //
  1776. if (!IsPicking())
  1777. {
  1778. m_DeferRendering = true;
  1779. }
  1780. m_TranslucentSortRendering = true;
  1781. // if (IsInLightingPreview())
  1782. // {
  1783. // // Lighting preview?
  1784. // IBSPLighting *pBSPLighting = pDoc->GetBSPLighting();
  1785. // if (pBSPLighting)
  1786. // {
  1787. // pBSPLighting->Draw();
  1788. // }
  1789. // }
  1790. //
  1791. // Render the world using octree culling.
  1792. //
  1793. PrepareInstanceStencil();
  1794. if ( pManifest )
  1795. {
  1796. pMapWorld = pManifest->GetManifestWorld();
  1797. }
  1798. if (g_bUseCullTree)
  1799. {
  1800. RenderTree( pMapWorld );
  1801. }
  1802. //
  1803. // Render the world without octree culling.
  1804. //
  1805. else
  1806. {
  1807. RenderMapClass( pMapWorld );
  1808. }
  1809. if ( m_DeferRendering )
  1810. {
  1811. m_DeferRendering = false;
  1812. // An optimization... render tree doesn't actually render anythung
  1813. // This here will do the rendering, sorted by material by pass
  1814. CMapFace::RenderOpaqueFaces(this);
  1815. }
  1816. RenderTranslucentObjects();
  1817. DrawInstanceStencil();
  1818. if ( pDoc->GetFoW() )
  1819. {
  1820. RenderFoW();
  1821. }
  1822. CGridNav *pGridNav = pDoc->GetGridNav();
  1823. if ( pGridNav && pGridNav->IsEnabled() && pGridNav->IsPreviewActive() )
  1824. {
  1825. Vector vViewForward;
  1826. pCamera->GetViewForward( vViewForward );
  1827. pGridNav->Render( this, new_vp, vViewForward );
  1828. }
  1829. m_TranslucentSortRendering = false;
  1830. pDoc->RenderDocument( this );
  1831. RenderTool();
  1832. RenderPointsAndPortals();
  1833. #ifdef _DEBUG
  1834. if (m_bRenderFrustum)
  1835. {
  1836. RenderFrustum();
  1837. }
  1838. #endif
  1839. //
  1840. // Render any 2D elements that overlay the 3D view, like a center crosshair.
  1841. //
  1842. RenderOverlayElements();
  1843. EndRenderFrame();
  1844. // Purge any translucent detail objects that were added AFTER the translucent rendering loop
  1845. if ( m_TranslucentRenderObjects.Count() )
  1846. m_TranslucentRenderObjects.Purge();
  1847. }
  1848. //-----------------------------------------------------------------------------
  1849. // Purpose: render an arrow of a given color at a given position (start and end)
  1850. // in world space
  1851. // Input : vStartPt - the arrow starting point
  1852. // vEndPt - the arrow ending point (the head of the arrow)
  1853. // chRed, chGree, chBlue - the arrow color
  1854. //-----------------------------------------------------------------------------
  1855. void CRender3D::RenderArrow( Vector const &vStartPt, Vector const &vEndPt,
  1856. unsigned char chRed, unsigned char chGreen, unsigned char chBlue )
  1857. {
  1858. //
  1859. // render the stick portion of the arrow
  1860. //
  1861. // set to a flat shaded render mode
  1862. PushRenderMode( RENDER_MODE_FLAT );
  1863. SetDrawColor( chRed, chGreen, chBlue );
  1864. DrawLine( vStartPt, vEndPt );
  1865. PopRenderMode();
  1866. //
  1867. // render the tip of the arrow
  1868. //
  1869. Vector coneAxis = vEndPt - vStartPt;
  1870. float length = VectorNormalize( coneAxis );
  1871. float length8 = length * 0.125;
  1872. length -= length8;
  1873. Vector vBasePt;
  1874. vBasePt = vStartPt + coneAxis * length;
  1875. RenderCone( vBasePt, vEndPt, ( length8 * 0.333 ), 6, chRed, chGreen, chBlue );
  1876. }
  1877. //-----------------------------------------------------------------------------
  1878. // Purpose: Renders a box in flat shaded or wireframe depending on our render mode.
  1879. // Input : chRed -
  1880. // chGreen -
  1881. // chBlue -
  1882. //-----------------------------------------------------------------------------
  1883. void CRender3D::RenderBox(const Vector &Mins, const Vector &Maxs,
  1884. unsigned char chRed, unsigned char chGreen, unsigned char chBlue, SelectionState_t eBoxSelectionState)
  1885. {
  1886. Vector FacePoints[8];
  1887. PointsFromBox( Mins, Maxs, FacePoints );
  1888. int nFaces[6][4] =
  1889. {
  1890. { 0, 2, 3, 1 },
  1891. { 0, 1, 5, 4 },
  1892. { 4, 5, 7, 6 },
  1893. { 2, 6, 7, 3 },
  1894. { 1, 3, 7, 5 },
  1895. { 0, 4, 6, 2 }
  1896. };
  1897. EditorRenderMode_t eRenderModeThisPass;
  1898. int nPasses;
  1899. if ((eBoxSelectionState != SELECT_NONE) && (GetDefaultRenderMode() != RENDER_MODE_WIREFRAME))
  1900. {
  1901. nPasses = 2;
  1902. }
  1903. else
  1904. {
  1905. nPasses = 1;
  1906. }
  1907. for (int nPass = 1; nPass <= nPasses; nPass++)
  1908. {
  1909. if (nPass == 1)
  1910. {
  1911. eRenderModeThisPass = GetDefaultRenderMode();
  1912. // There's no texture for a bounding box.
  1913. if ((eRenderModeThisPass == RENDER_MODE_TEXTURED) ||
  1914. (eRenderModeThisPass == RENDER_MODE_TEXTURED_SHADED) ||
  1915. (eRenderModeThisPass == RENDER_MODE_LIGHT_PREVIEW2) ||
  1916. (eRenderModeThisPass == RENDER_MODE_LIGHT_PREVIEW_RAYTRACED) ||
  1917. (eRenderModeThisPass == RENDER_MODE_LIGHTMAP_GRID))
  1918. {
  1919. eRenderModeThisPass = RENDER_MODE_FLAT;
  1920. }
  1921. PushRenderMode(eRenderModeThisPass);
  1922. }
  1923. else
  1924. {
  1925. eRenderModeThisPass = RENDER_MODE_WIREFRAME;
  1926. PushRenderMode(eRenderModeThisPass);
  1927. }
  1928. for (int nFace = 0; nFace < 6; nFace++)
  1929. {
  1930. Vector Edge1, Edge2, Normal;
  1931. int nP1, nP2, nP3, nP4;
  1932. nP1 = nFaces[nFace][0];
  1933. nP2 = nFaces[nFace][1];
  1934. nP3 = nFaces[nFace][2];
  1935. nP4 = nFaces[nFace][3];
  1936. VectorSubtract(FacePoints[nP4], FacePoints[nP1], Edge1);
  1937. VectorSubtract(FacePoints[nP2], FacePoints[nP1], Edge2);
  1938. CrossProduct(Edge1, Edge2, Normal);
  1939. VectorNormalize(Normal);
  1940. //
  1941. // If we are rendering using one of the lit modes, calculate lighting.
  1942. //
  1943. unsigned char color[3];
  1944. assert( (eRenderModeThisPass != RENDER_MODE_TEXTURED) &&
  1945. (eRenderModeThisPass != RENDER_MODE_TEXTURED_SHADED) &&
  1946. (eRenderModeThisPass != RENDER_MODE_LIGHT_PREVIEW2) &&
  1947. (eRenderModeThisPass != RENDER_MODE_LIGHT_PREVIEW_RAYTRACED) &&
  1948. (eRenderModeThisPass != RENDER_MODE_LIGHTMAP_GRID) );
  1949. if ((eRenderModeThisPass == RENDER_MODE_FLAT))
  1950. {
  1951. float fShade = LightPlane(Normal);
  1952. //
  1953. // For flat and textured mode use the face color with lighting.
  1954. //
  1955. if (eBoxSelectionState != SELECT_NONE)
  1956. {
  1957. color[0] = SELECT_FACE_RED * fShade;
  1958. color[1] = SELECT_FACE_GREEN * fShade;
  1959. color[2] = SELECT_FACE_BLUE * fShade;
  1960. }
  1961. else
  1962. {
  1963. color[0] = chRed * fShade;
  1964. color[1] = chGreen * fShade;
  1965. color[2] = chBlue * fShade;
  1966. }
  1967. }
  1968. //
  1969. // For wireframe mode use the face color without lighting.
  1970. //
  1971. else
  1972. {
  1973. if (eBoxSelectionState != SELECT_NONE)
  1974. {
  1975. color[0] = SELECT_FACE_RED;
  1976. color[1] = SELECT_FACE_GREEN;
  1977. color[2] = SELECT_FACE_BLUE;
  1978. }
  1979. else
  1980. {
  1981. color[0] = chRed;
  1982. color[1] = chGreen;
  1983. color[2] = chBlue;
  1984. }
  1985. }
  1986. //
  1987. // Draw the face.
  1988. //
  1989. bool wireframe = (eRenderModeThisPass == RENDER_MODE_WIREFRAME);
  1990. CMeshBuilder meshBuilder;
  1991. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  1992. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  1993. meshBuilder.DrawQuad( pMesh, FacePoints[nP1].Base(), FacePoints[nP2].Base(),
  1994. FacePoints[nP3].Base(), FacePoints[nP4].Base(), color, wireframe );
  1995. }
  1996. PopRenderMode();
  1997. }
  1998. }
  1999. //-----------------------------------------------------------------------------
  2000. // Purpose: render a cone of a given color at a given position in world space
  2001. // Intput : vBasePt - the start point of the cone (the base point)
  2002. // vTipPt - the end point of the cone (the peak)
  2003. // fRadius - the radius (at the base) of the cone
  2004. // nSlices - the number of slices (segments) making up the cone
  2005. // chRed, chGreen, chBlue - the cone color
  2006. //-----------------------------------------------------------------------------
  2007. void CRender3D::RenderCone( Vector const &vBasePt, Vector const &vTipPt, float fRadius, int nSlices,
  2008. unsigned char chRed, unsigned char chGreen, unsigned char chBlue )
  2009. {
  2010. // get the angle between slices (in radians)
  2011. float sliceAngle = ( 2 * M_PI ) / ( float )nSlices;
  2012. //
  2013. // allocate ALIGNED!!!!!!! vectors for cone base
  2014. //
  2015. int size = nSlices * sizeof( Vector );
  2016. size += 16 + sizeof( Vector* );
  2017. byte *ptr = ( byte* )_alloca( size );
  2018. long data = ( long )ptr;
  2019. data += 16 + sizeof( Vector* ) - 1;
  2020. data &= -16;
  2021. (( void** )data)[-1] = ptr;
  2022. Vector *pPts = ( Vector* )data;
  2023. if( !pPts )
  2024. return;
  2025. //
  2026. // calculate the cone's base points in a local space (x,y plane)
  2027. //
  2028. for( int i = 0; i < nSlices; i++ )
  2029. {
  2030. pPts[i].x = fRadius * cos( ( sliceAngle * -i ) );
  2031. pPts[i].y = fRadius * sin( ( sliceAngle * -i ) );
  2032. pPts[i].z = 0.0f;
  2033. }
  2034. //
  2035. // get cone tip in local space
  2036. //
  2037. Vector coneAxis = vTipPt - vBasePt;
  2038. float length = coneAxis.Length();
  2039. Vector tipPt( 0.0f, 0.0f, length );
  2040. //
  2041. // create cone faces
  2042. //
  2043. CMapFaceList m_Faces;
  2044. Vector ptList[3];
  2045. // triangulate the base
  2046. for( int i = 0; i < ( nSlices - 2 ); i++ )
  2047. {
  2048. ptList[0] = pPts[0];
  2049. ptList[1] = pPts[i+1];
  2050. ptList[2] = pPts[i+2];
  2051. // add face to list
  2052. CMapFace *pFace = new CMapFace;
  2053. if( !pFace )
  2054. return;
  2055. pFace->SetRenderColor( chRed, chGreen, chBlue );
  2056. pFace->CreateFace( ptList, 3 );
  2057. pFace->RenderUnlit( true );
  2058. m_Faces.AddToTail( pFace );
  2059. }
  2060. // triangulate the sides
  2061. for( int i = 0; i < nSlices; i++ )
  2062. {
  2063. ptList[0] = pPts[i];
  2064. ptList[1] = tipPt;
  2065. ptList[2] = pPts[(i+1)%nSlices];
  2066. // add face to list
  2067. CMapFace *pFace = new CMapFace;
  2068. if( !pFace )
  2069. return;
  2070. pFace->SetRenderColor( chRed, chGreen, chBlue );
  2071. pFace->CreateFace( ptList, 3 );
  2072. pFace->RenderUnlit( true );
  2073. m_Faces.AddToTail( pFace );
  2074. }
  2075. //
  2076. // rotate base points into world space as they are being rendered
  2077. //
  2078. VectorNormalize( coneAxis );
  2079. QAngle rotAngles;
  2080. VectorAngles( coneAxis, rotAngles );
  2081. rotAngles[PITCH] += 90;
  2082. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  2083. pRenderContext->MatrixMode( MATERIAL_MODEL );
  2084. pRenderContext->PushMatrix();
  2085. pRenderContext->LoadIdentity();
  2086. pRenderContext->Translate( vBasePt.x, vBasePt.y, vBasePt.z );
  2087. pRenderContext->Rotate( rotAngles[YAW], 0, 0, 1 );
  2088. pRenderContext->Rotate( rotAngles[PITCH], 0, 1, 0 );
  2089. pRenderContext->Rotate( rotAngles[ROLL], 1, 0, 0 );
  2090. // set to a flat shaded render mode
  2091. PushRenderMode( RENDER_MODE_FLAT );
  2092. for ( int i = 0; i < m_Faces.Count(); i++ )
  2093. {
  2094. CMapFace *pFace = m_Faces.Element( i );
  2095. if( !pFace )
  2096. continue;
  2097. pFace->Render3D( this );
  2098. }
  2099. pRenderContext->PopMatrix();
  2100. // set back to default render mode
  2101. PopRenderMode();
  2102. //
  2103. // delete the faces in the list
  2104. //
  2105. for ( int i = 0; i < m_Faces.Count(); i++ )
  2106. {
  2107. CMapFace *pFace = m_Faces.Element( i );
  2108. delete pFace;
  2109. }
  2110. }
  2111. //-----------------------------------------------------------------------------
  2112. // Purpose:
  2113. // Input : vCenter -
  2114. // flRadius -
  2115. // nTheta - Number of vertical slices in the sphere.
  2116. // nPhi - Number of horizontal slices in the sphere.
  2117. // chRed -
  2118. // chGreen -
  2119. // chBlue -
  2120. //-----------------------------------------------------------------------------
  2121. void CRender3D::RenderSphere(Vector const &vCenter, float flRadius, int nTheta, int nPhi,
  2122. unsigned char chRed, unsigned char chGreen, unsigned char chBlue )
  2123. {
  2124. PushRenderMode( RENDER_MODE_EXTERN );
  2125. int nTriangles = 2 * nTheta * ( nPhi - 1 ); // Two extra degenerate triangles per row (except the last one)
  2126. int nIndices = 2 * ( nTheta + 1 ) * ( nPhi - 1 );
  2127. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  2128. pRenderContext->Bind( m_pVertexColor[0] );
  2129. CMeshBuilder meshBuilder;
  2130. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  2131. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, nTriangles, nIndices );
  2132. //
  2133. // Build the index buffer.
  2134. //
  2135. int i, j;
  2136. for ( i = 0; i < nPhi; ++i )
  2137. {
  2138. for ( j = 0; j < nTheta; ++j )
  2139. {
  2140. float u = j / ( float )( nTheta - 1 );
  2141. float v = i / ( float )( nPhi - 1 );
  2142. float theta = 2.0f * M_PI * u;
  2143. float phi = M_PI * v;
  2144. Vector vecPos;
  2145. vecPos.x = flRadius * sin(phi) * cos(theta);
  2146. vecPos.y = flRadius * sin(phi) * sin(theta);
  2147. vecPos.z = flRadius * cos(phi);
  2148. Vector vecNormal = vecPos;
  2149. VectorNormalize(vecNormal);
  2150. float flScale = LightPlane(vecNormal);
  2151. unsigned char red = chRed * flScale;
  2152. unsigned char green = chGreen * flScale;
  2153. unsigned char blue = chBlue * flScale;
  2154. vecPos += vCenter;
  2155. meshBuilder.Position3f( vecPos.x, vecPos.y, vecPos.z );
  2156. meshBuilder.Color3ub( red, green, blue );
  2157. meshBuilder.AdvanceVertex();
  2158. }
  2159. }
  2160. //
  2161. // Emit the triangle strips.
  2162. //
  2163. int idx = 0;
  2164. for ( i = 0; i < nPhi - 1; ++i )
  2165. {
  2166. for ( j = 0; j < nTheta; ++j )
  2167. {
  2168. idx = nTheta * i + j;
  2169. meshBuilder.Index( idx + nTheta );
  2170. meshBuilder.AdvanceIndex();
  2171. meshBuilder.Index( idx );
  2172. meshBuilder.AdvanceIndex();
  2173. }
  2174. //
  2175. // Emit a degenerate triangle to skip to the next row without
  2176. // a connecting triangle.
  2177. //
  2178. if ( i < nPhi - 2 )
  2179. {
  2180. meshBuilder.Index( idx );
  2181. meshBuilder.AdvanceIndex();
  2182. meshBuilder.Index( idx + nTheta + 1 );
  2183. meshBuilder.AdvanceIndex();
  2184. }
  2185. }
  2186. meshBuilder.End();
  2187. pMesh->Draw();
  2188. PopRenderMode();
  2189. }
  2190. //-----------------------------------------------------------------------------
  2191. // Purpose:
  2192. //-----------------------------------------------------------------------------
  2193. void CRender3D::RenderWireframeSphere(Vector const &vCenter, float flRadius, int nTheta, int nPhi,
  2194. unsigned char chRed, unsigned char chGreen, unsigned char chBlue )
  2195. {
  2196. PushRenderMode(RENDER_MODE_WIREFRAME);
  2197. // Make one more coordinate because (u,v) is discontinuous.
  2198. ++nTheta;
  2199. int nVertices = nPhi * nTheta;
  2200. int nIndices = ( nTheta - 1 ) * 4 * ( nPhi - 1 );
  2201. CMeshBuilder meshBuilder;
  2202. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  2203. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  2204. meshBuilder.Begin( pMesh, MATERIAL_LINES, nVertices, nIndices );
  2205. int i, j;
  2206. for ( i = 0; i < nPhi; ++i )
  2207. {
  2208. for ( j = 0; j < nTheta; ++j )
  2209. {
  2210. float u = j / ( float )( nTheta - 1 );
  2211. float v = i / ( float )( nPhi - 1 );
  2212. float theta = 2.0f * M_PI * u;
  2213. float phi = M_PI * v;
  2214. meshBuilder.Position3f( vCenter.x + ( flRadius * sin(phi) * cos(theta) ),
  2215. vCenter.y + ( flRadius * sin(phi) * sin(theta) ),
  2216. vCenter.z + ( flRadius * cos(phi) ) );
  2217. meshBuilder.Color3ub( chRed, chGreen, chBlue );
  2218. meshBuilder.AdvanceVertex();
  2219. }
  2220. }
  2221. for ( i = 0; i < nPhi - 1; ++i )
  2222. {
  2223. for ( j = 0; j < nTheta - 1; ++j )
  2224. {
  2225. int idx = nTheta * i + j;
  2226. meshBuilder.Index( idx );
  2227. meshBuilder.AdvanceIndex();
  2228. meshBuilder.Index( idx + nTheta );
  2229. meshBuilder.AdvanceIndex();
  2230. meshBuilder.Index( idx );
  2231. meshBuilder.AdvanceIndex();
  2232. meshBuilder.Index( idx + 1 );
  2233. meshBuilder.AdvanceIndex();
  2234. }
  2235. }
  2236. meshBuilder.End();
  2237. pMesh->Draw();
  2238. PopRenderMode();
  2239. }
  2240. //-----------------------------------------------------------------------------
  2241. // Purpose:
  2242. // Input : *pDrawDC -
  2243. //-----------------------------------------------------------------------------
  2244. void CRender3D::RenderPointsAndPortals(void)
  2245. {
  2246. CMapDoc *pDoc = m_pView->GetMapDoc();
  2247. if ( pDoc->m_PFPoints.Count() )
  2248. {
  2249. PushRenderMode(RENDER_MODE_WIREFRAME);
  2250. int nPFPoints = pDoc->m_PFPoints.Count();
  2251. Vector* pPFPoints = pDoc->m_PFPoints.Base();
  2252. CMeshBuilder meshBuilder;
  2253. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  2254. IMesh* pMesh = pRenderContext->GetDynamicMesh( );
  2255. meshBuilder.Begin( pMesh, MATERIAL_LINE_STRIP, nPFPoints - 1 );
  2256. for (int i = 0; i < nPFPoints; i++)
  2257. {
  2258. meshBuilder.Position3f(pPFPoints[i][0], pPFPoints[i][1], pPFPoints[i][2]);
  2259. meshBuilder.Color3ub(255, 0, 0);
  2260. meshBuilder.AdvanceVertex();
  2261. }
  2262. meshBuilder.End();
  2263. pMesh->Draw();
  2264. PopRenderMode();
  2265. }
  2266. // draw any portal file that was loaded
  2267. if ( pDoc->m_pPortalFile )
  2268. {
  2269. PushRenderMode(RENDER_MODE_FLAT_NOCULL);
  2270. // each vert makes and edge and thus a quad
  2271. int totalQuads = pDoc->m_pPortalFile->totalVerts;
  2272. int nMaxVerts;
  2273. int nMaxIndices;
  2274. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  2275. pRenderContext->GetMaxToRender( pRenderContext->GetDynamicMesh( ), false, &nMaxVerts, &nMaxIndices );
  2276. int portalIndex = 0;
  2277. int baseVert = 0;
  2278. while ( totalQuads > 0 )
  2279. {
  2280. int quadLimit = totalQuads;
  2281. int quadOut = 0;
  2282. IMesh* pMesh = pRenderContext->GetDynamicMesh( );
  2283. if ( (quadLimit * 4) > nMaxVerts )
  2284. {
  2285. quadLimit = nMaxVerts / 4;
  2286. }
  2287. if ( (quadLimit * 6) > nMaxIndices )
  2288. {
  2289. quadLimit = nMaxIndices / 6;
  2290. }
  2291. CMeshBuilder meshBuilder;
  2292. meshBuilder.Begin( pMesh, MATERIAL_QUADS, quadLimit );
  2293. const float edgeWidth = 2.0f;
  2294. for (; portalIndex < pDoc->m_pPortalFile->vertCount.Count(); portalIndex++)
  2295. {
  2296. int vertCount = pDoc->m_pPortalFile->vertCount[portalIndex];
  2297. if ( (quadOut + vertCount) > quadLimit )
  2298. break;
  2299. quadOut += vertCount;
  2300. // compute a face normal
  2301. Vector e0 = pDoc->m_pPortalFile->verts[baseVert+1] - pDoc->m_pPortalFile->verts[baseVert];
  2302. Vector e1 = pDoc->m_pPortalFile->verts[baseVert+2] - pDoc->m_pPortalFile->verts[baseVert];
  2303. Vector normal = CrossProduct( e1, e0 );
  2304. VectorNormalize(normal);
  2305. for ( int j = 0; j < vertCount; j++ )
  2306. {
  2307. int v0 = baseVert + j;
  2308. int v1 = baseVert + ((j+1) % vertCount);
  2309. // compute the direction in the plane of the face to extrude the edge toward the
  2310. // face interior, use that to make a wide line with a quad
  2311. Vector e0 = pDoc->m_pPortalFile->verts[v1] - pDoc->m_pPortalFile->verts[v0];
  2312. Vector dir = CrossProduct( e0, normal );
  2313. VectorNormalize(dir);
  2314. dir *= edgeWidth;
  2315. meshBuilder.Position3fv( pDoc->m_pPortalFile->verts[v0].Base() );
  2316. meshBuilder.Color3ub(0, 0, 255);
  2317. meshBuilder.AdvanceVertex();
  2318. meshBuilder.Position3fv( pDoc->m_pPortalFile->verts[v1].Base() );
  2319. meshBuilder.Color3ub(0, 0, 255);
  2320. meshBuilder.AdvanceVertex();
  2321. meshBuilder.Position3fv( (pDoc->m_pPortalFile->verts[v1] + dir).Base() );
  2322. meshBuilder.Color3ub(0, 0, 255);
  2323. meshBuilder.AdvanceVertex();
  2324. meshBuilder.Position3fv( (pDoc->m_pPortalFile->verts[v0] + dir).Base() );
  2325. meshBuilder.Color3ub(0, 0, 255);
  2326. meshBuilder.AdvanceVertex();
  2327. }
  2328. baseVert += vertCount;
  2329. }
  2330. meshBuilder.End();
  2331. pMesh->Draw();
  2332. totalQuads -= quadOut;
  2333. }
  2334. PopRenderMode();
  2335. }
  2336. }
  2337. //-----------------------------------------------------------------------------
  2338. // Purpose: Draws a wireframe box using the given color.
  2339. // Input : pfMins - Pointer to the box minima in all 3 dimensions.
  2340. // pfMins - Pointer to the box maxima in all 3 dimensions.
  2341. // chRed, chGreen, chBlue - Red, green, and blue color compnents for the box.
  2342. //-----------------------------------------------------------------------------
  2343. void CRender3D::RenderWireframeBox(const Vector &Mins, const Vector &Maxs,
  2344. unsigned char chRed, unsigned char chGreen, unsigned char chBlue)
  2345. {
  2346. //
  2347. // Draw the box bottom, top, and one corner edge.
  2348. //
  2349. PushRenderMode( RENDER_MODE_WIREFRAME );
  2350. SetDrawColor( chRed, chGreen, chBlue );
  2351. DrawBox( Mins, Maxs );
  2352. PopRenderMode();
  2353. }
  2354. //-----------------------------------------------------------------------------
  2355. // Purpose: Renders this object (and all of its children) if it is visible and
  2356. // has not already been rendered this frame.
  2357. // Input : pMapClass - Pointer to the object to be rendered.
  2358. //-----------------------------------------------------------------------------
  2359. void CRender3D::RenderMapClass(CMapClass *pMapClass)
  2360. {
  2361. Assert(pMapClass != NULL);
  2362. if ((pMapClass != NULL) && (pMapClass->GetRenderFrame() != m_nFrameCount))
  2363. {
  2364. if (pMapClass->IsVisible())
  2365. {
  2366. //
  2367. // Render this object's culling box if it is enabled.
  2368. //
  2369. if (g_bRenderCullBoxes)
  2370. {
  2371. Vector mins,maxs;
  2372. pMapClass->GetCullBox(mins, maxs);
  2373. RenderWireframeBox(mins, maxs, 255, 0, 0);
  2374. }
  2375. bool should_appear=true;
  2376. if (m_eCurrentRenderMode == RENDER_MODE_LIGHT_PREVIEW2)
  2377. {
  2378. should_appear &= pMapClass->ShouldAppearInLightingPreview();
  2379. }
  2380. if (m_eCurrentRenderMode == RENDER_MODE_LIGHT_PREVIEW_RAYTRACED)
  2381. {
  2382. should_appear &= pMapClass->ShouldAppearInLightingPreview();
  2383. // should_appear &= pMapClass->ShouldAppearInRaytracedLightingPreview();
  2384. }
  2385. if ( m_bRenderingOverEngine )
  2386. {
  2387. should_appear &= pMapClass->ShouldAppearOverEngine();
  2388. }
  2389. if ( should_appear == true && m_Pick.bPicking == true && ( m_Pick.m_nFlags & FLAG_OBJECTS_AT_ONLY_SOLIDS ) != 0 )
  2390. {
  2391. if ( pMapClass->IsSolid() == false )
  2392. {
  2393. should_appear = false;
  2394. }
  2395. }
  2396. if ( should_appear )
  2397. {
  2398. //
  2399. // If we should render this object after all the other objects,
  2400. // just add it to a list of objects to render last. Otherwise, render it now.
  2401. //
  2402. if (!pMapClass->ShouldRenderLast())
  2403. {
  2404. pMapClass->Render3D(this);
  2405. }
  2406. else
  2407. {
  2408. if (
  2409. (m_eCurrentRenderMode != RENDER_MODE_LIGHT_PREVIEW2) &&
  2410. (m_eCurrentRenderMode != RENDER_MODE_LIGHT_PREVIEW_RAYTRACED) )
  2411. {
  2412. AddTranslucentDeferredRendering( pMapClass );
  2413. }
  2414. }
  2415. }
  2416. //
  2417. // Render this object's children.
  2418. //
  2419. const CMapObjectList *pChildren = pMapClass->GetChildren();
  2420. FOR_EACH_OBJ( *pChildren, pos )
  2421. {
  2422. Vector vecMins,vecMaxs;
  2423. CMapClass *pChild = (CUtlReference< CMapClass >)pChildren->Element(pos);
  2424. pChild->GetCullBox(vecMins, vecMaxs);
  2425. if (IsBoxVisible(vecMins, vecMaxs) != VIS_NONE )
  2426. {
  2427. RenderMapClass(pChild);
  2428. }
  2429. }
  2430. }
  2431. //
  2432. // Consider this object as handled for this frame.
  2433. //
  2434. pMapClass->SetRenderFrame(m_nFrameCount);
  2435. }
  2436. }
  2437. //-----------------------------------------------------------------------------
  2438. // Purpose: this function will render an instance map at the specific offset and rotation
  2439. // Input : pInstanceClass - the map class of the func_instance
  2440. // pMapClass - the map class of the world spawn of the instance
  2441. // InstanceOrigin - the translation offset
  2442. // InstanceAngles - the axis rotation
  2443. // Output : none
  2444. //-----------------------------------------------------------------------------
  2445. void CRender3D::RenderInstanceMapClass( CMapInstance *pInstanceClass, CMapClass *pMapClass, Vector &InstanceOrigin, QAngle &InstanceAngles )
  2446. {
  2447. if ( !pInstanceClass->IsInstanceVisible() )
  2448. {
  2449. return;
  2450. }
  2451. PushInstanceData( pInstanceClass, InstanceOrigin, InstanceAngles );
  2452. m_nInstanceCount++;
  2453. RenderInstanceMapClass_r( pMapClass );
  2454. if ( m_DeferRendering )
  2455. {
  2456. CMapFace::RenderOpaqueFaces(this);
  2457. }
  2458. if ( m_TranslucentSortRendering == false )
  2459. { // translucent objects will do their own transforms
  2460. RenderTranslucentObjects();
  2461. }
  2462. PopInstanceData();
  2463. }
  2464. //-----------------------------------------------------------------------------
  2465. // Purpose: this function will recursively render an instance and all of its children
  2466. // Input : pObject - the object to be rendered
  2467. // Output : none
  2468. //-----------------------------------------------------------------------------
  2469. void CRender3D::RenderInstanceMapClass_r(CMapClass *pMapClass)
  2470. {
  2471. Assert(pMapClass != NULL);
  2472. if ( ( pMapClass != NULL ) && ( pMapClass->GetRenderFrame() != m_nInstanceCount ) )
  2473. {
  2474. if (pMapClass->IsVisible())
  2475. {
  2476. //
  2477. // Render this object's culling box if it is enabled.
  2478. //
  2479. if (g_bRenderCullBoxes)
  2480. {
  2481. Vector vecMins, vecMaxs, vecExpandedMins, vecExpandedMaxs;
  2482. pMapClass->GetCullBox( vecMins, vecMaxs );
  2483. RenderWireframeBox( vecMins, vecMaxs, 255, 0, 0 );
  2484. }
  2485. bool should_appear=true;
  2486. if (m_eCurrentRenderMode == RENDER_MODE_LIGHT_PREVIEW2)
  2487. should_appear &= pMapClass->ShouldAppearInLightingPreview();
  2488. if (m_eCurrentRenderMode == RENDER_MODE_LIGHT_PREVIEW_RAYTRACED)
  2489. should_appear &= pMapClass->ShouldAppearInLightingPreview();
  2490. // should_appear &= pMapClass->ShouldAppearInRaytracedLightingPreview();
  2491. if ( should_appear )
  2492. {
  2493. //
  2494. // If we should render this object after all the other objects,
  2495. // just add it to a list of objects to render last. Otherwise, render it now.
  2496. //
  2497. if (!pMapClass->ShouldRenderLast())
  2498. {
  2499. pMapClass->Render3D(this);
  2500. }
  2501. else
  2502. {
  2503. if (
  2504. (m_eCurrentRenderMode != RENDER_MODE_LIGHT_PREVIEW2) &&
  2505. (m_eCurrentRenderMode != RENDER_MODE_LIGHT_PREVIEW_RAYTRACED) )
  2506. {
  2507. AddTranslucentDeferredRendering( pMapClass );
  2508. }
  2509. }
  2510. }
  2511. //
  2512. // Render this object's children.
  2513. //
  2514. const CMapObjectList *pChildren = pMapClass->GetChildren();
  2515. FOR_EACH_OBJ( *pChildren, pos )
  2516. {
  2517. Vector vecMins, vecMaxs, vecExpandedMins, vecExpandedMaxs;
  2518. CMapClass *pChild = (CUtlReference< CMapClass >)pChildren->Element( pos );
  2519. pChild->GetCullBox( vecMins, vecMaxs );
  2520. TransformInstanceAABB( vecMins, vecMaxs, vecExpandedMins, vecExpandedMaxs );
  2521. if (IsBoxVisible( vecExpandedMins, vecExpandedMaxs ) != VIS_NONE )
  2522. {
  2523. RenderInstanceMapClass_r( pChild );
  2524. }
  2525. }
  2526. }
  2527. //
  2528. // Consider this object as handled for this instance frame.
  2529. //
  2530. pMapClass->SetRenderFrame( m_nInstanceCount );
  2531. }
  2532. }
  2533. //-----------------------------------------------------------------------------
  2534. // Purpose: Prepares all objects in this node for rendering.
  2535. // Input : pParent -
  2536. //-----------------------------------------------------------------------------
  2537. void CRender3D::Preload(CMapClass *pParent)
  2538. {
  2539. Assert(pParent != NULL);
  2540. if (pParent != NULL)
  2541. {
  2542. //
  2543. // Preload this object's children.
  2544. //
  2545. const CMapObjectList *pChildren = pParent->GetChildren();
  2546. FOR_EACH_OBJ( *pChildren, pos )
  2547. {
  2548. ((CUtlReference< CMapClass >)pChildren->Element(pos))->RenderPreload(this, true);
  2549. }
  2550. }
  2551. }
  2552. //-----------------------------------------------------------------------------
  2553. // Purpose: Renders all objects in this node if this node is visible.
  2554. // Input : pNode - The node to render.
  2555. // bForce - If true, don't check for visibility, just render the node
  2556. // and all of its children.
  2557. //-----------------------------------------------------------------------------
  2558. void CRender3D::RenderNode(CCullTreeNode *pNode, bool bForce )
  2559. {
  2560. //
  2561. // Render all child nodes first.
  2562. //
  2563. CCullTreeNode *pChild;
  2564. int nChildren = pNode->GetChildCount();
  2565. if (nChildren != 0)
  2566. {
  2567. for (int nChild = 0; nChild < nChildren; nChild++)
  2568. {
  2569. pChild = pNode->GetCullTreeChild(nChild);
  2570. Assert(pChild != NULL);
  2571. if (pChild != NULL)
  2572. {
  2573. //
  2574. // Only bother checking nodes with children or objects.
  2575. //
  2576. if ((pChild->GetChildCount() != 0) || (pChild->GetObjectCount() != 0))
  2577. {
  2578. bool bForceThisChild = bForce;
  2579. Visibility_t eVis = VIS_NONE;
  2580. if (!bForceThisChild)
  2581. {
  2582. Vector vecMins;
  2583. Vector vecMaxs;
  2584. pChild->GetBounds(vecMins, vecMaxs);
  2585. eVis = IsBoxVisible(vecMins, vecMaxs);
  2586. if (eVis == VIS_TOTAL)
  2587. {
  2588. bForceThisChild = true;
  2589. }
  2590. }
  2591. if ((bForceThisChild) || (eVis != VIS_NONE))
  2592. {
  2593. RenderNode(pChild, bForceThisChild);
  2594. }
  2595. }
  2596. }
  2597. }
  2598. }
  2599. else
  2600. {
  2601. //
  2602. // Now render the contents of this node.
  2603. //
  2604. CMapClass *pObject;
  2605. int nObjects = pNode->GetObjectCount();
  2606. for (int nObject = 0; nObject < nObjects; nObject++)
  2607. {
  2608. pObject = pNode->GetCullTreeObject(nObject);
  2609. Assert(pObject != NULL);
  2610. Vector vecMins;
  2611. Vector vecMaxs;
  2612. pObject->GetCullBox(vecMins, vecMaxs);
  2613. if (IsBoxVisible(vecMins, vecMaxs) != VIS_NONE)
  2614. {
  2615. RenderMapClass(pObject);
  2616. }
  2617. }
  2618. }
  2619. }
  2620. void CRender3D::RenderCrossHair()
  2621. {
  2622. int width, height;
  2623. GetCamera()->GetViewPort( width, height );
  2624. int nCenterX = width / 2;
  2625. int nCenterY = height / 2;
  2626. Assert( IsInClientSpace() );
  2627. // Render the world axes
  2628. PushRenderMode( RENDER_MODE_FLAT_NOZ );
  2629. SetDrawColor(0,0,0);
  2630. DrawLine( Vector(nCenterX - CROSSHAIR_DIST_HORIZONTAL, nCenterY - 1, 0),
  2631. Vector(nCenterX + CROSSHAIR_DIST_HORIZONTAL + 1, nCenterY - 1, 0) );
  2632. DrawLine( Vector(nCenterX - CROSSHAIR_DIST_HORIZONTAL, nCenterY + 1, 0),
  2633. Vector(nCenterX + CROSSHAIR_DIST_HORIZONTAL + 1, nCenterY + 1, 0) );
  2634. DrawLine( Vector(nCenterX - 1, nCenterY - CROSSHAIR_DIST_VERTICAL, 0),
  2635. Vector(nCenterX - 1, nCenterY + CROSSHAIR_DIST_VERTICAL, 0) );
  2636. DrawLine( Vector(nCenterX + 1, nCenterY - CROSSHAIR_DIST_VERTICAL, 0),
  2637. Vector(nCenterX + 1, nCenterY + CROSSHAIR_DIST_VERTICAL, 0) );
  2638. SetDrawColor(255,255,255);
  2639. DrawLine( Vector(nCenterX - CROSSHAIR_DIST_HORIZONTAL, nCenterY, 0),
  2640. Vector(nCenterX + CROSSHAIR_DIST_HORIZONTAL + 1, nCenterY, 0) );
  2641. DrawLine( Vector(nCenterX, nCenterY - CROSSHAIR_DIST_VERTICAL, 0),
  2642. Vector(nCenterX, nCenterY + CROSSHAIR_DIST_VERTICAL, 0) );
  2643. PopRenderMode();
  2644. }
  2645. //-----------------------------------------------------------------------------
  2646. // Purpose: Renders 2D elements that overlay the 3D objects.
  2647. //-----------------------------------------------------------------------------
  2648. void CRender3D::RenderOverlayElements(void)
  2649. {
  2650. bool bPopMode = BeginClientSpace();
  2651. if (m_RenderState.bCenterCrosshair && !m_bRenderingOverEngine)
  2652. RenderCrossHair();
  2653. if ( bPopMode )
  2654. EndClientSpace();
  2655. }
  2656. //-----------------------------------------------------------------------------
  2657. // Purpose: Gives all the tools a chance to render themselves.
  2658. //-----------------------------------------------------------------------------
  2659. void CRender3D::RenderTool(void)
  2660. {
  2661. CMapDoc *pDoc = m_pView->GetMapDoc();
  2662. CBaseTool *pTool = pDoc->GetTools()->GetActiveTool();
  2663. if ( pTool )
  2664. {
  2665. pTool->RenderTool3D(this);
  2666. }
  2667. }
  2668. //-----------------------------------------------------------------------------
  2669. // Purpose:
  2670. //-----------------------------------------------------------------------------
  2671. void CRender3D::RenderTree( CMapWorld *pWorld )
  2672. {
  2673. if (pWorld == NULL)
  2674. {
  2675. return;
  2676. }
  2677. //
  2678. // Recursively traverse the culling tree, rendering visible nodes.
  2679. //
  2680. CCullTreeNode *pTree = pWorld->CullTree_GetCullTree();
  2681. if (pTree != NULL)
  2682. {
  2683. Vector vecMins;
  2684. Vector vecMaxs;
  2685. pTree->GetBounds(vecMins, vecMaxs);
  2686. Visibility_t eVis = IsBoxVisible(vecMins, vecMaxs);
  2687. if (eVis != VIS_NONE)
  2688. {
  2689. RenderNode(pTree, eVis == VIS_TOTAL);
  2690. }
  2691. }
  2692. }
  2693. //-----------------------------------------------------------------------------
  2694. // Purpose: Returns whether we are in lighting preview mode or not.
  2695. //-----------------------------------------------------------------------------
  2696. bool CRender3D::IsInLightingPreview()
  2697. {
  2698. return false; //m_bLightingPreview;
  2699. }
  2700. //-----------------------------------------------------------------------------
  2701. // Purpose: Enables/disables lighting preview mode.
  2702. //-----------------------------------------------------------------------------
  2703. void CRender3D::SetInLightingPreview( bool bLightingPreview )
  2704. {
  2705. m_bLightingPreview = false; //bLightingPreview;
  2706. }
  2707. void CRender3D::ResetFocus()
  2708. {
  2709. // A bizarre workaround; the drop-down menu somehow
  2710. // sets some wierd state that causes the whole screen to not be updated
  2711. InvalidateRect( m_WinData.hWnd, 0, false );
  2712. }
  2713. //-----------------------------------------------------------------------------
  2714. // indicates we need to render an overlay pass...
  2715. //-----------------------------------------------------------------------------
  2716. bool CRender3D::NeedsOverlay() const
  2717. {
  2718. return (m_eCurrentRenderMode == RENDER_MODE_LIGHTMAP_GRID) ||
  2719. (m_eCurrentRenderMode == RENDER_MODE_TEXTURED_SHADED) ||
  2720. (m_eCurrentRenderMode == RENDER_MODE_LIGHT_PREVIEW2) ||
  2721. (m_eCurrentRenderMode == RENDER_MODE_LIGHT_PREVIEW_RAYTRACED) ||
  2722. (m_eCurrentRenderMode == RENDER_MODE_TEXTURED);
  2723. }
  2724. //-----------------------------------------------------------------------------
  2725. // Purpose:
  2726. //-----------------------------------------------------------------------------
  2727. void CRender3D::ShutDown(void)
  2728. {
  2729. MaterialSystemInterface()->RemoveView( m_WinData.hWnd );
  2730. if (m_WinData.hDC)
  2731. {
  2732. m_WinData.hDC = NULL;
  2733. }
  2734. if (m_WinData.bFullScreen)
  2735. {
  2736. ChangeDisplaySettings(NULL, 0);
  2737. }
  2738. }
  2739. //-----------------------------------------------------------------------------
  2740. // Purpose: Uncaches all cached textures
  2741. //-----------------------------------------------------------------------------
  2742. void CRender3D::UncacheAllTextures()
  2743. {
  2744. }
  2745. //-----------------------------------------------------------------------------
  2746. // Purpose: Enables and disables various rendering parameters.
  2747. // Input : eRenderState - Parameter to enable or disable. See RenderState_t.
  2748. // bEnable - true to enable, false to disable the specified render state.
  2749. //-----------------------------------------------------------------------------
  2750. void CRender3D::RenderEnable(RenderState_t eRenderState, bool bEnable)
  2751. {
  2752. switch (eRenderState)
  2753. {
  2754. case RENDER_POLYGON_OFFSET_FILL:
  2755. {
  2756. m_nDecalMode = bEnable?1:0;
  2757. SetRenderMode( RENDER_MODE_CURRENT, true );
  2758. }
  2759. break;
  2760. case RENDER_POLYGON_OFFSET_LINE:
  2761. {
  2762. assert(0);
  2763. /* FIXME:
  2764. Think we'll need to have two versions of the wireframe material
  2765. one which ztests with offset + culling, the other which doesn't
  2766. ztest, doesn't offect, and doesn't cull??!?
  2767. m_pWireframeIgnoreZ->SetIntValue( bEnable );
  2768. m_pWireframe->GetMaterial()->InitializeStateSnapshots();
  2769. /*
  2770. if (bEnable)
  2771. {
  2772. glEnable(GL_POLYGON_OFFSET_LINE);
  2773. glPolygonOffset(-1, -1);
  2774. }
  2775. else
  2776. {
  2777. glDisable(GL_POLYGON_OFFSET_LINE);
  2778. }
  2779. */
  2780. break;
  2781. }
  2782. case RENDER_CENTER_CROSSHAIR:
  2783. {
  2784. m_RenderState.bCenterCrosshair = bEnable;
  2785. break;
  2786. }
  2787. case RENDER_GRID:
  2788. {
  2789. m_RenderState.bDrawGrid = bEnable;
  2790. break;
  2791. }
  2792. case RENDER_FILTER_TEXTURES:
  2793. {
  2794. m_RenderState.bFilterTextures = bEnable;
  2795. break;
  2796. }
  2797. case RENDER_REVERSE_SELECTION:
  2798. {
  2799. m_RenderState.bReverseSelection = bEnable;
  2800. break;
  2801. }
  2802. }
  2803. }
  2804. //-----------------------------------------------------------------------------
  2805. // Purpose: Groovy little debug hook; can be whatever I want or need.
  2806. // Input : pData -
  2807. //-----------------------------------------------------------------------------
  2808. void CRender3D::DebugHook1(void *pData)
  2809. {
  2810. g_bShowStatistics = !g_bShowStatistics;
  2811. #ifdef _DEBUG
  2812. m_bRecomputeFrustumRenderGeometry = true;
  2813. m_bRenderFrustum = true;
  2814. #endif
  2815. //if (!m_bDroppedCamera)
  2816. //{
  2817. // *m_pDropCamera = *m_pCamera;
  2818. // m_bDroppedCamera = true;
  2819. //}
  2820. //else
  2821. //{
  2822. // m_bDroppedCamera = false;
  2823. //}
  2824. }
  2825. //-----------------------------------------------------------------------------
  2826. // Purpose: Another groovy little debug hook; can be whatever I want or need.
  2827. // Input : pData -
  2828. //-----------------------------------------------------------------------------
  2829. void CRender3D::DebugHook2(void *pData)
  2830. {
  2831. g_bRenderCullBoxes = !g_bRenderCullBoxes;
  2832. }
  2833. //-----------------------------------------------------------------------------
  2834. // Purpose:
  2835. //-----------------------------------------------------------------------------
  2836. float CRender3D::ComputePixelWidthOfSphere( const Vector &vecOrigin, float flRadius )
  2837. {
  2838. return ComputePixelDiameterOfSphere( vecOrigin, flRadius ) * 2.0f;
  2839. }
  2840. //-----------------------------------------------------------------------------
  2841. // This returns the diameter of the sphere in pixels based on
  2842. // the current model, view, + projection matrices and viewport.
  2843. //-----------------------------------------------------------------------------
  2844. float CRender3D::ComputePixelDiameterOfSphere( const Vector &vecOrigin, float flRadius )
  2845. {
  2846. // Get the current camera.
  2847. CCamera *pCamera = GetCamera();
  2848. if ( !pCamera )
  2849. return 0.0f;
  2850. // Get the up vector.
  2851. Vector vecViewUp;
  2852. pCamera->GetViewUp( vecViewUp );
  2853. Vector4D testPoint1, testPoint2;
  2854. VectorMA( vecOrigin, flRadius, vecViewUp, testPoint1.AsVector3D() );
  2855. VectorMA( vecOrigin, -flRadius, vecViewUp, testPoint2.AsVector3D() );
  2856. testPoint1.w = testPoint2.w = 1.0f;
  2857. // Get the projection matrix.
  2858. VMatrix matProj;
  2859. pCamera->GetViewProjMatrix( matProj );
  2860. Vector4D clipPos1, clipPos2;
  2861. Vector4DMultiply( matProj, testPoint1, clipPos1 );
  2862. Vector4DMultiply( matProj, testPoint2, clipPos2 );
  2863. if (clipPos1.w >= 0.001f)
  2864. {
  2865. clipPos1.y /= clipPos1.w;
  2866. }
  2867. else
  2868. {
  2869. clipPos1.y *= 1000;
  2870. }
  2871. if (clipPos2.w >= 0.001f)
  2872. {
  2873. clipPos2.y /= clipPos2.w;
  2874. }
  2875. else
  2876. {
  2877. clipPos2.y *= 1000;
  2878. }
  2879. // Scale by viewport.
  2880. int nWidth, nHeight;
  2881. pCamera->GetViewPort( nWidth, nHeight );
  2882. // The divide-by-two here is because y goes from -1 to 1 in projection space
  2883. return nHeight * fabs( clipPos2.y - clipPos1.y ) / 2.0f;
  2884. }