Team Fortress 2 Source Code as on 22/4/2020
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.

2950 lines
80 KiB

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