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.

397 lines
11 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #include "matsys_controls/vtfpreviewpanel.h"
  7. #include "matsys_controls/matsyscontrols.h"
  8. #include "VGuiMatSurface/IMatSystemSurface.h"
  9. #include "materialsystem/MaterialSystemUtil.h"
  10. #include "materialsystem/imaterialsystem.h"
  11. #include "materialsystem/itexture.h"
  12. #include "materialsystem/imesh.h"
  13. #include "tier1/KeyValues.h"
  14. using namespace vgui;
  15. #define FOV 90.0f
  16. #define ZNEAR 0.1f
  17. #define ZFAR 2000.0f
  18. #define ROTATION_SPEED 120.0f // degrees/sec
  19. //-----------------------------------------------------------------------------
  20. //
  21. // VTF Preview panel
  22. //
  23. //-----------------------------------------------------------------------------
  24. //-----------------------------------------------------------------------------
  25. // constructor
  26. //-----------------------------------------------------------------------------
  27. CVTFPreviewPanel::CVTFPreviewPanel( vgui::Panel *pParent, const char *pName ) :
  28. BaseClass( pParent, pName )
  29. {
  30. SetVTF( "//platform/materials/vgui/vtfnotloaded", true );
  31. m_nTextureID = MatSystemSurface()->CreateNewTextureID( false );
  32. }
  33. CVTFPreviewPanel::~CVTFPreviewPanel()
  34. {
  35. if ( vgui::surface() && m_nTextureID != -1 )
  36. {
  37. vgui::surface()->DestroyTextureID( m_nTextureID );
  38. m_nTextureID = -1;
  39. }
  40. }
  41. //-----------------------------------------------------------------------------
  42. // Sets the current VTF
  43. //-----------------------------------------------------------------------------
  44. void CVTFPreviewPanel::SetVTF( const char *pFullPath, bool bLoadImmediately )
  45. {
  46. m_PreviewTexture.Init( pFullPath, "editor texture" );
  47. m_VTFName = pFullPath;
  48. KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
  49. if ( m_PreviewTexture->IsCubeMap() )
  50. {
  51. pVMTKeyValues->SetString( "$envmap", pFullPath );
  52. }
  53. else if ( m_PreviewTexture->IsNormalMap() )
  54. {
  55. pVMTKeyValues->SetString( "$bumpmap", pFullPath );
  56. }
  57. else
  58. {
  59. pVMTKeyValues->SetString( "$basetexture", pFullPath );
  60. }
  61. pVMTKeyValues->SetInt( "$nocull", 1 );
  62. pVMTKeyValues->SetInt( "$nodebug", 1 );
  63. m_PreviewMaterial.Init( MaterialSystem()->CreateMaterial( pFullPath, pVMTKeyValues ));
  64. MatSystemSurface()->DrawSetTextureMaterial( m_nTextureID, m_PreviewMaterial );
  65. // Reset the camera direction
  66. m_vecCameraDirection.Init( 1.0f, 0.0f, 0.0f );
  67. m_flLastRotationTime = Plat_FloatTime();
  68. }
  69. //-----------------------------------------------------------------------------
  70. // Gets the current VTF
  71. //-----------------------------------------------------------------------------
  72. const char *CVTFPreviewPanel::GetVTF() const
  73. {
  74. return m_VTFName;
  75. }
  76. //-----------------------------------------------------------------------------
  77. // Draw a sphere
  78. //-----------------------------------------------------------------------------
  79. void CVTFPreviewPanel::RenderSphere( const Vector &vCenter, float flRadius, int nTheta, int nPhi )
  80. {
  81. CMatRenderContextPtr pRenderContext( MaterialSystem() );
  82. int nVertices = nTheta * nPhi;
  83. int nIndices = 2 * ( nTheta + 1 ) * ( nPhi - 1 );
  84. pRenderContext->FogMode( MATERIAL_FOG_NONE );
  85. pRenderContext->SetNumBoneWeights( 0 );
  86. pRenderContext->Bind( m_PreviewMaterial );
  87. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  88. CMeshBuilder meshBuilder;
  89. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, nVertices, nIndices );
  90. //
  91. // Build the index buffer.
  92. //
  93. int i, j;
  94. for ( i = 0; i < nPhi; ++i )
  95. {
  96. for ( j = 0; j < nTheta; ++j )
  97. {
  98. float u = j / ( float )(nTheta - 1);
  99. float v = i / ( float )(nPhi - 1);
  100. float theta = ( j != nTheta-1 ) ? 2.0f * M_PI * u : 0.0f;
  101. float phi = M_PI * v;
  102. Vector vecPos;
  103. vecPos.x = flRadius * sin(phi) * cos(theta);
  104. vecPos.y = flRadius * cos(phi);
  105. vecPos.z = -flRadius * sin(phi) * sin(theta);
  106. Vector vecNormal = vecPos;
  107. VectorNormalize( vecNormal );
  108. Vector4D vecTangentS;
  109. Vector vecTangentT;
  110. vecTangentS.Init( vecPos.z, -vecPos.x, 0.0f, 1.0f );
  111. if ( VectorNormalize( vecTangentS.AsVector3D() ) == 0.0f )
  112. {
  113. vecTangentS.Init( 1.0f, 0.0f, 0.0f, 1.0f );
  114. }
  115. CrossProduct( vecNormal, vecTangentS.AsVector3D(), vecTangentT );
  116. unsigned char red = (int)( u * 255.0f );
  117. unsigned char green = (int)( v * 255.0f );
  118. unsigned char blue = (int)( v * 255.0f );
  119. unsigned char alpha = (int)( v * 255.0f );
  120. vecPos += vCenter;
  121. float u1, u2, v1, v2;
  122. u1 = u2 = u;
  123. v1 = v2 = v;
  124. meshBuilder.Position3fv( vecPos.Base() );
  125. meshBuilder.Normal3fv( vecNormal.Base() );
  126. meshBuilder.Color4ub( red, green, blue, alpha );
  127. meshBuilder.TexCoord2f( 0, u, v );
  128. meshBuilder.TexCoord2f( 1, u1, v1 );
  129. meshBuilder.TexCoord2f( 2, u2, v2 );
  130. meshBuilder.TangentS3fv( vecTangentS.Base() );
  131. meshBuilder.TangentT3fv( vecTangentT.Base() );
  132. meshBuilder.BoneWeight( 0, 1.0f );
  133. meshBuilder.BoneMatrix( 0, 0 );
  134. meshBuilder.UserData( vecTangentS.Base() );
  135. meshBuilder.AdvanceVertex();
  136. }
  137. }
  138. //
  139. // Emit the triangle strips.
  140. //
  141. int idx = 0;
  142. for ( i = 0; i < nPhi - 1; ++i )
  143. {
  144. for ( j = 0; j < nTheta; ++j )
  145. {
  146. idx = nTheta * i + j;
  147. meshBuilder.FastIndex( idx );
  148. meshBuilder.FastIndex( idx + nTheta );
  149. }
  150. //
  151. // Emit a degenerate triangle to skip to the next row without
  152. // a connecting triangle.
  153. //
  154. if ( i < nPhi - 2 )
  155. {
  156. meshBuilder.FastIndex( idx + 1 );
  157. meshBuilder.FastIndex( idx + 1 + nTheta );
  158. }
  159. }
  160. meshBuilder.End();
  161. pMesh->Draw();
  162. }
  163. //-----------------------------------------------------------------------------
  164. // Paints a regular texture
  165. //-----------------------------------------------------------------------------
  166. void CVTFPreviewPanel::PaintStandardTexture( void )
  167. {
  168. int x, y, w, h;
  169. x = y = 0;
  170. GetSize( w, h );
  171. vgui::surface()->DrawSetTexture( m_nTextureID );
  172. vgui::surface()->DrawSetColor( 255, 255, 255, 255 );
  173. // Get the aspect ratio of the texture
  174. int tw = m_PreviewTexture->GetActualWidth();
  175. int th = m_PreviewTexture->GetActualHeight();
  176. if ( th > 0 && h > 0 )
  177. {
  178. float screenaspect = (float)tw / (float)th;
  179. float aspect = (float)w / (float)h;
  180. float ratio = screenaspect / aspect;
  181. // Screen is wider, need bars at top and bottom
  182. if ( ratio > 1.0f )
  183. {
  184. int usetall = (float)w / screenaspect;
  185. y = ( h - usetall ) / 2;
  186. h = usetall;
  187. }
  188. // Screen is narrower, need bars at left/right
  189. else
  190. {
  191. int usewide = (float)h * screenaspect;
  192. x = ( w - usewide ) / 2;
  193. w = usewide;
  194. }
  195. }
  196. vgui::surface()->DrawTexturedRect( x, y, x+w, y+h );
  197. }
  198. //-----------------------------------------------------------------------------
  199. // Paints a normalmap texture
  200. //-----------------------------------------------------------------------------
  201. void CVTFPreviewPanel::PaintNormalMapTexture( void )
  202. {
  203. }
  204. //-----------------------------------------------------------------------------
  205. // Paints a volume texture
  206. //-----------------------------------------------------------------------------
  207. void CVTFPreviewPanel::PaintVolumeTexture( void )
  208. {
  209. }
  210. //-----------------------------------------------------------------------------
  211. // Paints a cubemap texture
  212. //-----------------------------------------------------------------------------
  213. void CVTFPreviewPanel::PaintCubeTexture( void )
  214. {
  215. float flNewTime = Plat_FloatTime();
  216. // Circle the camera around the origin
  217. VMatrix rot;
  218. MatrixBuildRotateZ( rot, ROTATION_SPEED * (flNewTime - m_flLastRotationTime ) );
  219. Vector vecTemp;
  220. Vector3DMultiply( rot, m_vecCameraDirection, vecTemp );
  221. m_vecCameraDirection = vecTemp;
  222. m_flLastRotationTime = flNewTime;
  223. LookAt( vec3_origin, 12.0f );
  224. // Draw a sphere at the origin
  225. RenderSphere( vec3_origin, 10.0f, 20, 20 );
  226. }
  227. //-----------------------------------------------------------------------------
  228. // Sets the camera to look at the the thing we're spinning around
  229. //-----------------------------------------------------------------------------
  230. void CVTFPreviewPanel::LookAt( const Vector &vecLookAt, float flRadius )
  231. {
  232. // Compute the distance to the camera for the object based on its
  233. // radius and fov.
  234. // since tan( fov/2 ) = f/d
  235. // cos( fov/2 ) = r / r' where r = sphere radius, r' = perp distance from sphere center to max extent of camera
  236. // d/f = r'/d' where d' is distance of camera to sphere
  237. // d' = r' / tan( fov/2 ) * r' = r / ( cos (fov/2) * tan( fov/2 ) ) = r / sin( fov/2 )
  238. float flFOVx = FOV;
  239. // Compute fov/2 in radians
  240. flFOVx *= M_PI / 360.0f;
  241. // Compute an effective fov based on the aspect ratio
  242. // if the height is smaller than the width
  243. int w, h;
  244. GetSize( w, h );
  245. if ( h < w )
  246. {
  247. flFOVx = atan( h * tan( flFOVx ) / w );
  248. }
  249. float flDistance = flRadius / sin( flFOVx );
  250. Vector vecMDLOrigin = vecLookAt;
  251. Vector vecCameraOrigin;
  252. VectorMA( vecMDLOrigin, -flDistance, m_vecCameraDirection, vecCameraOrigin );
  253. CMatRenderContextPtr pRenderContext( MaterialSystem() );
  254. QAngle angles;
  255. VectorAngles( m_vecCameraDirection, angles );
  256. pRenderContext->MatrixMode( MATERIAL_VIEW );
  257. pRenderContext->LoadIdentity();
  258. // convert from a right handed system to a left handed system
  259. // since dx for wants it that way.
  260. // pRenderContext->Scale( 1.0f, 1.0f, -1.0f );
  261. pRenderContext->Rotate( -90, 1, 0, 0 ); // put Z going up
  262. pRenderContext->Rotate( 90, 0, 0, 1 ); // put Z going up
  263. pRenderContext->Rotate( -angles[2], 1, 0, 0 );
  264. pRenderContext->Rotate( -angles[0], 0, 1, 0 );
  265. pRenderContext->Rotate( -angles[1], 0, 0, 1 );
  266. pRenderContext->Translate( -vecCameraOrigin[0], -vecCameraOrigin[1], -vecCameraOrigin[2] );
  267. }
  268. //-----------------------------------------------------------------------------
  269. // Set up a projection matrix for a 90 degree fov
  270. //-----------------------------------------------------------------------------
  271. void CVTFPreviewPanel::SetupProjectionMatrix( int nWidth, int nHeight )
  272. {
  273. CMatRenderContextPtr pRenderContext( MaterialSystem() );
  274. VMatrix proj;
  275. float flFOV = FOV;
  276. float flZNear = ZNEAR;
  277. float flZFar = ZFAR;
  278. float flApsectRatio = (nHeight != 0.0f) ? (float)nWidth / (float)nHeight : 100.0f;
  279. #if 1
  280. float halfWidth = tan( flFOV * M_PI / 360.0 );
  281. float halfHeight = halfWidth / flApsectRatio;
  282. #else
  283. float halfHeight = tan( flFOV * M_PI / 360.0 );
  284. float halfWidth = flApsectRatio * halfHeight;
  285. #endif
  286. memset( proj.Base(), 0, sizeof( proj ) );
  287. proj[0][0] = 1.0f / halfWidth;
  288. proj[1][1] = 1.0f / halfHeight;
  289. proj[2][2] = flZFar / ( flZNear - flZFar );
  290. proj[3][2] = -1.0f;
  291. proj[2][3] = flZNear * flZFar / ( flZNear - flZFar );
  292. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  293. pRenderContext->LoadMatrix( proj );
  294. }
  295. //-----------------------------------------------------------------------------
  296. // Paints the texture
  297. //-----------------------------------------------------------------------------
  298. void CVTFPreviewPanel::Paint( void )
  299. {
  300. if ( !m_PreviewTexture->IsCubeMap() && /*!m_PreviewTexture->IsNormalMap() &&*/ !m_PreviewTexture->IsVolumeTexture() )
  301. {
  302. PaintStandardTexture();
  303. return;
  304. }
  305. CMatRenderContextPtr pRenderContext( MaterialSystem() );
  306. int w, h;
  307. GetSize( w, h );
  308. vgui::MatSystemSurface()->Begin3DPaint( 0, 0, w, h );
  309. pRenderContext->ClearColor4ub( 76, 88, 68, 255 );
  310. pRenderContext->ClearBuffers( true, true );
  311. SetupProjectionMatrix( w, h );
  312. if ( m_PreviewTexture->IsCubeMap() )
  313. {
  314. PaintCubeTexture();
  315. }
  316. else if ( m_PreviewTexture->IsNormalMap() )
  317. {
  318. PaintNormalMapTexture();
  319. }
  320. else if ( m_PreviewTexture->IsVolumeTexture() )
  321. {
  322. PaintVolumeTexture();
  323. }
  324. vgui::MatSystemSurface()->End3DPaint( );
  325. }