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.

352 lines
8.2 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. // gl_warp.c -- sky and water polygons
  9. #include "render_pch.h"
  10. #include "gl_water.h"
  11. #include "zone.h"
  12. #include "gl_model_private.h"
  13. #include "gl_matsysiface.h"
  14. #include "utlvector.h"
  15. #include "materialsystem/imesh.h"
  16. #include "materialsystem/imaterial.h"
  17. #include "tier2/tier2.h"
  18. #include "materialsystem/imaterialsystemhardwareconfig.h"
  19. #include "tier0/vprof.h"
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22. #define SQRT3INV (0.57735f) // a little less than 1 / sqrt(3)
  23. static ConVar r_drawskybox( "r_drawskybox", "1", FCVAR_CHEAT );
  24. extern ConVar mat_loadtextures;
  25. static IMaterial *skyboxMaterials[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
  26. // 1 = s, 2 = t, 3 = 2048
  27. int st_to_vec[6][3] =
  28. {
  29. {3,-1,2},
  30. {-3,1,2},
  31. {1,3,2},
  32. {-1,-3,2},
  33. {-2,-1,3}, // 0 degrees yaw, look straight up
  34. {2,-1,-3} // look straight down
  35. };
  36. // s = [0]/[2], t = [1]/[2]
  37. int skytexorder[6] = {0,2,1,3,4,5};
  38. #define SIGN(d) ((d)<0?-1:1)
  39. static int gFakePlaneType[6] = {1,-1,2,-2,3,-3};
  40. // (This is pasted from vtf.cpp - just for reference. It shows how the faces
  41. // of the engine's skybox are oriented and mapped).
  42. //
  43. // The vert ordering is lower-left, top-left, top-right, bottom-right.
  44. //
  45. // These were constructed for the engine skybox, which looks like this
  46. // (assuming X goes forward, Y goes left, and Z goes up).
  47. //
  48. // 6 ------------- 5
  49. // / /
  50. // / | / |
  51. // / | / |
  52. // 2 ------------- 1 |
  53. // | |
  54. // | |
  55. // | 7 ------|------ 4
  56. // | / | /
  57. // | / | /
  58. // / /
  59. // 3 ------------- 0
  60. //
  61. //int g_skybox_rightFaceVerts[4] = { 7, 6, 5, 4 };
  62. //int g_skybox_leftFaceVerts[4] = { 0, 1, 2, 3 };
  63. //int g_skybox_backFaceVerts[4] = { 3, 2, 6, 7 };
  64. //int g_skybox_frontFaceVerts[4] = { 4, 5, 1, 0 };
  65. //int g_skybox_upFaceVerts[4] = { 6, 2, 1, 5 };
  66. //int g_skybox_downFaceVerts[4] = { 3, 7, 4, 0 };
  67. //-----------------------------------------------------------------------------
  68. // Purpose:
  69. //-----------------------------------------------------------------------------
  70. void R_UnloadSkys( void )
  71. {
  72. int i;
  73. for ( i = 0; i < 6; i++ )
  74. {
  75. if( skyboxMaterials[i] )
  76. {
  77. skyboxMaterials[ i ]->DecrementReferenceCount();
  78. skyboxMaterials[ i ] = NULL;
  79. }
  80. }
  81. }
  82. //-----------------------------------------------------------------------------
  83. // Purpose:
  84. // Input : *name -
  85. // Output : Returns true on success, false on failure.
  86. //-----------------------------------------------------------------------------
  87. bool R_LoadNamedSkys( const char *skyname )
  88. {
  89. char name[ MAX_OSPATH ];
  90. IMaterial *skies[ 6 ];
  91. bool success = true;
  92. const char *skyboxsuffix[ 6 ] = { "rt", "bk", "lf", "ft", "up", "dn" };
  93. bool bUseDx8Skyboxes = ( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 90 );
  94. for ( int i = 0; i < 6; i++ )
  95. {
  96. skies[i] = NULL;
  97. if ( bUseDx8Skyboxes )
  98. {
  99. Q_snprintf( name, sizeof( name ), "skybox/%s_dx80%s", skyname, skyboxsuffix[i] );
  100. skies[i] = materials->FindMaterial( name, TEXTURE_GROUP_SKYBOX, false );
  101. if( IsErrorMaterial( skies[i] ) )
  102. {
  103. skies[i] = NULL;
  104. }
  105. }
  106. if ( skies[i] == NULL )
  107. {
  108. Q_snprintf( name, sizeof( name ), "skybox/%s%s", skyname, skyboxsuffix[i] );
  109. skies[i] = materials->FindMaterial( name, TEXTURE_GROUP_SKYBOX );
  110. }
  111. if( !IsErrorMaterial( skies[i] ) )
  112. continue;
  113. success = false;
  114. break;
  115. }
  116. if ( !success )
  117. {
  118. return false;
  119. }
  120. // Increment references
  121. for ( int i = 0; i < 6; i++ )
  122. {
  123. // Unload any old skybox
  124. if ( skyboxMaterials[ i ] )
  125. {
  126. skyboxMaterials[ i ]->DecrementReferenceCount();
  127. skyboxMaterials[ i ] = NULL;
  128. }
  129. // Use the new one
  130. assert( skies[ i ] );
  131. skyboxMaterials[i] = skies[ i ];
  132. skyboxMaterials[i]->IncrementReferenceCount();
  133. }
  134. return true;
  135. }
  136. //-----------------------------------------------------------------------------
  137. // Purpose:
  138. //-----------------------------------------------------------------------------
  139. void R_LoadSkys( void )
  140. {
  141. bool success = true;
  142. char requestedsky[ 128 ];
  143. ConVarRef skyname( "sv_skyname" );
  144. if ( skyname.IsValid() )
  145. {
  146. Q_strncpy( requestedsky, skyname.GetString(), sizeof( requestedsky ) );
  147. }
  148. else
  149. {
  150. ConDMsg( "Unable to find skyname ConVar!!!\n" );
  151. return;
  152. }
  153. // See if user's sky will work
  154. if ( !R_LoadNamedSkys( requestedsky ) )
  155. {
  156. // Assume failure
  157. success = false;
  158. // See if user requested other than the default
  159. if ( Q_stricmp( requestedsky, "sky_urb01" ) )
  160. {
  161. // Try the default
  162. skyname.SetValue( "sky_urb01" );
  163. // See if we could load that one now
  164. if ( R_LoadNamedSkys( skyname.GetString() ) )
  165. {
  166. ConDMsg( "Unable to load sky %s, but successfully loaded %s\n", requestedsky, skyname.GetString() );
  167. success = true;
  168. }
  169. }
  170. }
  171. if ( !success )
  172. {
  173. ConDMsg( "Unable to load sky %s\n", requestedsky );
  174. }
  175. }
  176. //-----------------------------------------------------------------------------
  177. // Purpose:
  178. //-----------------------------------------------------------------------------
  179. #pragma warning (disable : 4701)
  180. void MakeSkyVec( float s, float t, int axis, float zFar, Vector& position, Vector2D &texCoord )
  181. {
  182. Vector v, b;
  183. int j, k;
  184. float width;
  185. width = zFar * SQRT3INV;
  186. if ( s < -1 )
  187. s = -1;
  188. else if ( s > 1 )
  189. s = 1;
  190. if ( t < -1 )
  191. t = -1;
  192. else if ( t > 1 )
  193. t = 1;
  194. b[0] = s*width;
  195. b[1] = t*width;
  196. b[2] = width;
  197. for (j=0 ; j<3 ; j++)
  198. {
  199. k = st_to_vec[axis][j];
  200. if (k < 0)
  201. v[j] = -b[-k - 1];
  202. else
  203. v[j] = b[k - 1];
  204. v[j] += CurrentViewOrigin()[j];
  205. }
  206. // avoid bilerp seam
  207. s = (s+1)*0.5;
  208. t = (t+1)*0.5;
  209. if (s < 1.0/512)
  210. s = 1.0/512;
  211. else if (s > 511.0/512)
  212. s = 511.0/512;
  213. if (t < 1.0/512)
  214. t = 1.0/512;
  215. else if (t > 511.0/512)
  216. t = 511.0/512;
  217. t = 1.0 - t;
  218. VectorCopy( v, position );
  219. texCoord[0] = s;
  220. texCoord[1] = t;
  221. }
  222. #pragma warning (default : 4701)
  223. //-----------------------------------------------------------------------------
  224. // Purpose:
  225. //-----------------------------------------------------------------------------
  226. void R_DrawSkyBox( float zFar, int nDrawFlags /*= 0x3F*/ )
  227. {
  228. VPROF("R_DrawSkyBox");
  229. tmZoneFiltered( TELEMETRY_LEVEL0, 50, TMZF_NONE, "%s %x", __FUNCTION__, nDrawFlags );
  230. int i;
  231. Vector normal;
  232. if ( !r_drawskybox.GetInt() || !mat_loadtextures.GetInt() )
  233. {
  234. return;
  235. }
  236. CMatRenderContextPtr pRenderContext( materials );
  237. for (i=0 ; i<6 ; i++, nDrawFlags >>= 1 )
  238. {
  239. // Don't draw this panel of the skybox if the flag isn't set:
  240. if ( !(nDrawFlags & 1) )
  241. continue;
  242. VectorCopy( vec3_origin, normal );
  243. switch( gFakePlaneType[i] )
  244. {
  245. case 1:
  246. normal[0] = 1;
  247. break;
  248. case -1:
  249. normal[0] = -1;
  250. break;
  251. case 2:
  252. normal[1] = 1;
  253. break;
  254. case -2:
  255. normal[1] = -1;
  256. break;
  257. case 3:
  258. normal[2] = 1;
  259. break;
  260. case -3:
  261. normal[2] = -1;
  262. break;
  263. }
  264. // Normals are reversed so looking at face dots to 1.0, looking away from is -1.0
  265. // Reject backfacing surfaces on the inside of the cube to avoid binding their texture
  266. // Assuming a 90 fov looking at face is 0 degrees, so reject at 107
  267. if ( DotProduct( CurrentViewForward(), normal ) < -0.29289f )
  268. continue;
  269. Vector positionArray[4];
  270. Vector2D texCoordArray[4];
  271. if (skyboxMaterials[skytexorder[i]])
  272. {
  273. pRenderContext->Bind( skyboxMaterials[skytexorder[i]] );
  274. MakeSkyVec( -1.0f, -1.0f, i, zFar, positionArray[0], texCoordArray[0] );
  275. MakeSkyVec( -1.0f, 1.0f, i, zFar, positionArray[1], texCoordArray[1] );
  276. MakeSkyVec( 1.0f, 1.0f, i, zFar, positionArray[2], texCoordArray[2] );
  277. MakeSkyVec( 1.0f, -1.0f, i, zFar, positionArray[3], texCoordArray[3] );
  278. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  279. CMeshBuilder meshBuilder;
  280. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, 4, 6 );
  281. // meshbuilder Begin can fail if dynamic mesh is not available (eg, alt-tabbed away)
  282. if ( meshBuilder.BaseVertexData() == NULL )
  283. continue;
  284. for (int j = 0; j < 4; ++j)
  285. {
  286. meshBuilder.Position3fv( positionArray[j].Base() );
  287. meshBuilder.TexCoord2fv( 0, texCoordArray[j].Base() );
  288. meshBuilder.AdvanceVertex();
  289. }
  290. CIndexBuilder &indexBuilder = meshBuilder;
  291. indexBuilder.FastQuad( 0 );
  292. meshBuilder.End();
  293. pMesh->Draw();
  294. }
  295. }
  296. }