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.

403 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Renders a cone for spotlight entities. Only renders when the parent
  4. // entity is selected.
  5. //
  6. //=============================================================================//
  7. #include "stdafx.h"
  8. #include "Box3D.h"
  9. #include "fgdlib/HelperInfo.h"
  10. #include "MapDefs.h" // dvs: For COORD_NOTINIT
  11. #include "MapEntity.h"
  12. #include "MapFrustum.h"
  13. #include "Render3D.h"
  14. #include "Material.h"
  15. #include "materialsystem/imaterialsystem.h"
  16. #include "TextureSystem.h"
  17. #include "hammer.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include <tier0/memdbgon.h>
  20. IMPLEMENT_MAPCLASS(CMapFrustum)
  21. //-----------------------------------------------------------------------------
  22. // Purpose: Factory function. Used for creating a CMapFrustum helper from a
  23. // set of string parameters from the FGD file.
  24. // Input : *pInfo - Pointer to helper info class which gives us information
  25. // about how to create the helper.
  26. // Output : Returns a pointer to the helper, NULL if an error occurs.
  27. //-----------------------------------------------------------------------------
  28. CMapClass *CMapFrustum::Create(CHelperInfo *pHelperInfo, CMapEntity *pParent)
  29. {
  30. CMapFrustum *new1 = new CMapFrustum;
  31. if( new1 != NULL )
  32. {
  33. const char *pszKeyName;
  34. // The first parameter should be the fov key name.
  35. pszKeyName = pHelperInfo->GetParameter(0);
  36. if ( pszKeyName )
  37. V_strncpy( new1->m_szFOVKeyName, pszKeyName, sizeof( new1->m_szFOVKeyName ) );
  38. // Second parameter should be the near plane name.
  39. pszKeyName = pHelperInfo->GetParameter(1);
  40. if ( pszKeyName )
  41. V_strncpy( new1->m_szNearPlaneKeyName, pszKeyName, sizeof( new1->m_szNearPlaneKeyName ) );
  42. // Third parameter should be the far plane name.
  43. pszKeyName = pHelperInfo->GetParameter(2);
  44. if ( pszKeyName )
  45. V_strncpy( new1->m_szFarPlaneKeyName, pszKeyName, sizeof( new1->m_szFarPlaneKeyName ) );
  46. pszKeyName = pHelperInfo->GetParameter(3);
  47. if (pszKeyName != NULL)
  48. {
  49. V_strncpy( new1->m_szColorKeyName, pszKeyName, sizeof( new1->m_szColorKeyName ) );
  50. }
  51. pszKeyName = pHelperInfo->GetParameter(4);
  52. if (pszKeyName != NULL)
  53. {
  54. new1->m_flPitchScale = Q_atof( pszKeyName );
  55. }
  56. else
  57. {
  58. new1->m_flPitchScale = 1.0f;
  59. }
  60. }
  61. return new1;
  62. }
  63. //-----------------------------------------------------------------------------
  64. // Purpose:
  65. //-----------------------------------------------------------------------------
  66. CMapFrustum::CMapFrustum(void)
  67. {
  68. // Set default parameter names.
  69. V_strncpy( m_szFOVKeyName, "_fov", sizeof( m_szFOVKeyName ) );
  70. V_strncpy( m_szNearPlaneKeyName, "_NearPlane", sizeof( m_szNearPlaneKeyName ) );
  71. V_strncpy( m_szFarPlaneKeyName, "_FarPlane", sizeof( m_szFarPlaneKeyName ) );
  72. V_strncpy( m_szColorKeyName, "_light", sizeof( m_szColorKeyName ) );
  73. m_flFOV = 90;
  74. m_flNearPlane = 10;
  75. m_flFarPlane = 200;
  76. m_flPitchScale = -1;
  77. }
  78. //-----------------------------------------------------------------------------
  79. // Purpose: Destructor. Deletes faces allocated by BuildCone.
  80. //-----------------------------------------------------------------------------
  81. CMapFrustum::~CMapFrustum(void)
  82. {
  83. for (int i = 0; i < m_Faces.Count(); i++)
  84. {
  85. CMapFace *pFace = m_Faces.Element(i);
  86. delete pFace;
  87. }
  88. }
  89. CMapFace* CMapFrustum::CreateMapFace( const Vector &v1, const Vector &v2, const Vector &v3, const Vector &v4, float flAlpha )
  90. {
  91. Assert( IsFinite(v1.x) && IsFinite(v1.y) && IsFinite(v1.z) );
  92. Vector points[4] = {v1,v2,v3,v4};
  93. CMapFace *pFace = new CMapFace;
  94. pFace->SetRenderColor( r, g, b );
  95. pFace->SetRenderAlpha( flAlpha );
  96. pFace->CreateFace( points, 4 );
  97. pFace->RenderUnlit(true);
  98. return pFace;
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Purpose: Builds the light cone faces in local space. Does NOT call CalcBounds,
  102. // because that CalcBounds updates the parent, which causes problems
  103. // in the undo system.
  104. //-----------------------------------------------------------------------------
  105. void CMapFrustum::BuildFrustumFaces(void)
  106. {
  107. //
  108. // Delete the current face list.
  109. //
  110. for (int i = 0; i < m_Faces.Count(); i++)
  111. {
  112. CMapFace *pFace = m_Faces.Element(i);
  113. delete pFace;
  114. }
  115. m_Faces.RemoveAll();
  116. // 6 total faces. 4 on the sides and 2 caps.
  117. Vector vNearFace[4], vFarFace[4];
  118. float flHalfFOV = m_flFOV / 2.0f;
  119. flHalfFOV = clamp( flHalfFOV, 0.01f, 89.0f );
  120. float flScaleFactor = tan( DEG2RAD( flHalfFOV ) );
  121. float flBaseAlpha = 180;
  122. vNearFace[0].Init( m_flNearPlane, -flScaleFactor*m_flNearPlane, -flScaleFactor*m_flNearPlane );
  123. vNearFace[1].Init( m_flNearPlane, +flScaleFactor*m_flNearPlane, -flScaleFactor*m_flNearPlane );
  124. vNearFace[2].Init( m_flNearPlane, +flScaleFactor*m_flNearPlane, +flScaleFactor*m_flNearPlane );
  125. vNearFace[3].Init( m_flNearPlane, -flScaleFactor*m_flNearPlane, +flScaleFactor*m_flNearPlane );
  126. vFarFace[0].Init( m_flFarPlane, -flScaleFactor*m_flFarPlane, -flScaleFactor*m_flFarPlane );
  127. vFarFace[1].Init( m_flFarPlane, +flScaleFactor*m_flFarPlane, -flScaleFactor*m_flFarPlane );
  128. vFarFace[2].Init( m_flFarPlane, +flScaleFactor*m_flFarPlane, +flScaleFactor*m_flFarPlane );
  129. vFarFace[3].Init( m_flFarPlane, -flScaleFactor*m_flFarPlane, +flScaleFactor*m_flFarPlane );
  130. // Build the near and far faces.
  131. m_Faces.AddToTail( CreateMapFace( vNearFace[0], vNearFace[1], vNearFace[2], vNearFace[3], flBaseAlpha ) );
  132. m_Faces.AddToTail( CreateMapFace( vFarFace[3], vFarFace[2], vFarFace[1], vFarFace[0], flBaseAlpha ) );
  133. // Build the 4 cap faces.
  134. for ( int i=0; i < 4; i++ )
  135. {
  136. m_Faces.AddToTail( CreateMapFace( vNearFace[i], vFarFace[i], vFarFace[(i+1)%4], vNearFace[(i+1)%4], flBaseAlpha ) );
  137. }
  138. // Also build some really translucent faces from the origin to the near plane.
  139. float flOriginFacesAlpha = 40.0f;
  140. for ( int i=0; i < 4; i++ )
  141. {
  142. m_Faces.AddToTail( CreateMapFace( Vector(0,0,0), vNearFace[i], vNearFace[(i+1)%4], Vector(0,0,0), flOriginFacesAlpha ) );
  143. }
  144. }
  145. //-----------------------------------------------------------------------------
  146. // Purpose:
  147. // Input : bFullUpdate -
  148. //-----------------------------------------------------------------------------
  149. void CMapFrustum::CalcBounds(BOOL bFullUpdate)
  150. {
  151. CMapClass::CalcBounds(bFullUpdate);
  152. //
  153. // HACK: Update our origin to stick to our parent.
  154. //
  155. if (m_pParent != NULL)
  156. {
  157. GetParent()->GetOrigin(m_Origin);
  158. }
  159. //
  160. // Pretend to be very small for the 2D view. Won't be necessary when 2D
  161. // rendering is done in the map classes.
  162. //
  163. m_Render2DBox.ResetBounds();
  164. m_Render2DBox.UpdateBounds(m_Origin);
  165. SetCullBoxFromFaceList( &m_Faces );
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Purpose:
  169. // Output : CMapClass
  170. //-----------------------------------------------------------------------------
  171. CMapClass *CMapFrustum::Copy(bool bUpdateDependencies)
  172. {
  173. CMapFrustum *pCopy = new CMapFrustum;
  174. if (pCopy != NULL)
  175. {
  176. pCopy->CopyFrom(this, bUpdateDependencies);
  177. }
  178. return(pCopy);
  179. }
  180. //-----------------------------------------------------------------------------
  181. // Purpose:
  182. // Input : pObject -
  183. // Output : CMapClass
  184. //-----------------------------------------------------------------------------
  185. CMapClass *CMapFrustum::CopyFrom(CMapClass *pObject, bool bUpdateDependencies)
  186. {
  187. Assert(pObject->IsMapClass(MAPCLASS_TYPE(CMapFrustum)));
  188. CMapFrustum *pFrom = (CMapFrustum *)pObject;
  189. CMapClass::CopyFrom(pObject, bUpdateDependencies);
  190. m_flFOV = pFrom->m_flFOV;
  191. m_flNearPlane = pFrom->m_flNearPlane;
  192. m_flFarPlane = pFrom->m_flFarPlane;
  193. m_Angles = pFrom->m_Angles;
  194. m_flPitchScale = pFrom->m_flPitchScale;
  195. V_strncpy( m_szFOVKeyName, pFrom->m_szFOVKeyName, sizeof( m_szFOVKeyName ) );
  196. V_strncpy( m_szNearPlaneKeyName, pFrom->m_szNearPlaneKeyName, sizeof( m_szNearPlaneKeyName ) );
  197. V_strncpy( m_szFarPlaneKeyName, pFrom->m_szFarPlaneKeyName, sizeof( m_szFarPlaneKeyName ) );
  198. V_strncpy( m_szColorKeyName, pFrom->m_szColorKeyName, sizeof( m_szColorKeyName ) );
  199. BuildFrustumFaces();
  200. return(this);
  201. }
  202. //-----------------------------------------------------------------------------
  203. // Purpose: Notifies that this object's parent entity has had a key value change.
  204. // Input : szKey - The key that changed.
  205. // szValue - The new value of the key.
  206. //-----------------------------------------------------------------------------
  207. void CMapFrustum::OnParentKeyChanged(const char *szKey, const char *szValue)
  208. {
  209. bool bRebuild = true;
  210. if (!stricmp(szKey, "angles"))
  211. {
  212. sscanf(szValue, "%f %f %f", &m_Angles[PITCH], &m_Angles[YAW], &m_Angles[ROLL]);
  213. }
  214. else if (!stricmp(szKey, m_szColorKeyName))
  215. {
  216. int nRed;
  217. int nGreen;
  218. int nBlue;
  219. sscanf(szValue, "%d %d %d", &nRed, &nGreen, &nBlue);
  220. r = nRed;
  221. g = nGreen;
  222. b = nBlue;
  223. }
  224. else if (!stricmp(szKey, m_szFOVKeyName))
  225. {
  226. m_flFOV = atof(szValue);
  227. }
  228. else if (!stricmp(szKey, m_szNearPlaneKeyName))
  229. {
  230. m_flNearPlane = atof(szValue);
  231. }
  232. else if (!stricmp(szKey, m_szFarPlaneKeyName))
  233. {
  234. m_flFarPlane = atof(szValue);
  235. }
  236. else
  237. {
  238. bRebuild = false;
  239. }
  240. if (bRebuild)
  241. {
  242. BuildFrustumFaces();
  243. PostUpdate(Notify_Changed);
  244. }
  245. }
  246. //-----------------------------------------------------------------------------
  247. // Purpose: Called after the entire map has been loaded. This allows the object
  248. // to perform any linking with other map objects or to do other operations
  249. // that require all world objects to be present.
  250. // Input : pWorld - The world that we are in.
  251. //-----------------------------------------------------------------------------
  252. void CMapFrustum::PostloadWorld(CMapWorld *pWorld)
  253. {
  254. CMapClass::PostloadWorld(pWorld);
  255. BuildFrustumFaces();
  256. CalcBounds();
  257. }
  258. //-----------------------------------------------------------------------------
  259. // Purpose:
  260. // Input : pRender -
  261. //-----------------------------------------------------------------------------
  262. void CMapFrustum::Render3D(CRender3D *pRender)
  263. {
  264. if (m_pParent->IsSelected())
  265. {
  266. CMatRenderContextPtr pRenderContext( MaterialSystemInterface() );
  267. pRenderContext->MatrixMode(MATERIAL_MODEL);
  268. pRenderContext->PushMatrix();
  269. pRenderContext->Translate(m_Origin[0], m_Origin[1], m_Origin[2]);
  270. QAngle Angles;
  271. GetAngles(Angles);
  272. pRenderContext->Rotate(Angles[YAW], 0, 0, 1);
  273. pRenderContext->Rotate(m_flPitchScale * Angles[PITCH], 0, -1, 0);
  274. pRenderContext->Rotate(Angles[ROLL], 1, 0, 0);
  275. if (
  276. (pRender->GetCurrentRenderMode() != RENDER_MODE_LIGHT_PREVIEW2) &&
  277. (pRender->GetCurrentRenderMode() != RENDER_MODE_LIGHT_PREVIEW_RAYTRACED) &&
  278. (GetSelectionState() != SELECT_MODIFY )
  279. )
  280. {
  281. // Render the cone faces flatshaded.
  282. pRender->PushRenderMode( RENDER_MODE_TRANSLUCENT_FLAT );
  283. for (int i = 0; i < m_Faces.Count(); i++)
  284. {
  285. CMapFace *pFace = m_Faces.Element(i);
  286. pFace->Render3D(pRender);
  287. }
  288. pRender->PopRenderMode();
  289. }
  290. //
  291. // Render the cone faces in yellow wireframe (on top)
  292. //
  293. pRender->PushRenderMode( RENDER_MODE_WIREFRAME );
  294. for (int i = 0; i < m_Faces.Count(); i++)
  295. {
  296. CMapFace *pFace = m_Faces.Element(i);
  297. pFace->Render3D(pRender);
  298. }
  299. //
  300. // Restore the default rendering mode.
  301. //
  302. pRender->PopRenderMode();
  303. pRenderContext->PopMatrix();
  304. }
  305. }
  306. //-----------------------------------------------------------------------------
  307. // Purpose:
  308. // Input : File -
  309. // bRMF -
  310. // Output : int
  311. //-----------------------------------------------------------------------------
  312. int CMapFrustum::SerializeRMF(std::fstream &File, BOOL bRMF)
  313. {
  314. return(0);
  315. }
  316. //-----------------------------------------------------------------------------
  317. // Purpose:
  318. // Input : File -
  319. // bRMF -
  320. // Output : int
  321. //-----------------------------------------------------------------------------
  322. int CMapFrustum::SerializeMAP(std::fstream &File, BOOL bRMF)
  323. {
  324. return(0);
  325. }
  326. void CMapFrustum::GetAngles(QAngle& Angles)
  327. {
  328. Angles = m_Angles;
  329. }