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.

392 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // r_studio.cpp: routines for setting up to draw 3DStudio models
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //===========================================================================//
  9. #include "studio.h"
  10. #include "studiorender.h"
  11. #include "studiorendercontext.h"
  12. #include "materialsystem/imaterial.h"
  13. #include "materialsystem/imaterialvar.h"
  14. #include "tier0/vprof.h"
  15. #include "tier3/tier3.h"
  16. #include "datacache/imdlcache.h"
  17. // memdbgon must be the last include file in a .cpp file!!!
  18. #include "tier0/memdbgon.h"
  19. //-----------------------------------------------------------------------------
  20. // Figures out what kind of lighting we're gonna want
  21. //-----------------------------------------------------------------------------
  22. FORCEINLINE StudioModelLighting_t CStudioRender::R_StudioComputeLighting( IMaterial *pMaterial, int materialFlags, ColorMeshInfo_t *pColorMeshes )
  23. {
  24. // Here, we only do software lighting when the following conditions are met.
  25. // 1) The material is vertex lit and we don't have hardware lighting
  26. // 2) We're drawing an eyeball
  27. // 3) We're drawing mouth-lit stuff
  28. // FIXME: When we move software lighting into the material system, only need to
  29. // test if it's vertex lit
  30. Assert( pMaterial );
  31. bool doMouthLighting = materialFlags && (m_pStudioHdr->nummouths >= 1);
  32. if ( IsX360() )
  33. {
  34. // 360 does not do software lighting
  35. return doMouthLighting ? LIGHTING_MOUTH : LIGHTING_HARDWARE;
  36. }
  37. bool doSoftwareLighting = doMouthLighting ||
  38. (pMaterial->IsVertexLit() && pMaterial->NeedsSoftwareLighting() );
  39. if ( !m_pRC->m_Config.m_bSupportsVertexAndPixelShaders )
  40. {
  41. if ( !doSoftwareLighting && pColorMeshes )
  42. {
  43. pMaterial->SetUseFixedFunctionBakedLighting( true );
  44. }
  45. else
  46. {
  47. doSoftwareLighting = true;
  48. pMaterial->SetUseFixedFunctionBakedLighting( false );
  49. }
  50. }
  51. StudioModelLighting_t lighting = LIGHTING_HARDWARE;
  52. if ( doMouthLighting )
  53. lighting = LIGHTING_MOUTH;
  54. else if ( doSoftwareLighting )
  55. lighting = LIGHTING_SOFTWARE;
  56. return lighting;
  57. }
  58. IMaterial* CStudioRender::R_StudioSetupSkinAndLighting( IMatRenderContext *pRenderContext, int index, IMaterial **ppMaterials, int materialFlags,
  59. void /*IClientRenderable*/ *pClientRenderable, ColorMeshInfo_t *pColorMeshes, StudioModelLighting_t &lighting )
  60. {
  61. VPROF( "R_StudioSetupSkin" );
  62. IMaterial *pMaterial = NULL;
  63. bool bCheckForConVarDrawTranslucentSubModels = false;
  64. if( m_pRC->m_Config.bWireframe && !m_pRC->m_pForcedMaterial )
  65. {
  66. if ( m_pRC->m_Config.bDrawZBufferedWireframe )
  67. pMaterial = m_pMaterialMRMWireframeZBuffer;
  68. else
  69. pMaterial = m_pMaterialMRMWireframe;
  70. }
  71. else if( m_pRC->m_Config.bShowEnvCubemapOnly )
  72. {
  73. pMaterial = m_pMaterialModelEnvCubemap;
  74. }
  75. else
  76. {
  77. if ( !m_pRC->m_pForcedMaterial && ( m_pRC->m_nForcedMaterialType != OVERRIDE_DEPTH_WRITE && m_pRC->m_nForcedMaterialType != OVERRIDE_SSAO_DEPTH_WRITE ) )
  78. {
  79. pMaterial = ppMaterials[index];
  80. if ( !pMaterial )
  81. {
  82. Assert( 0 );
  83. return 0;
  84. }
  85. }
  86. else
  87. {
  88. materialFlags = 0;
  89. pMaterial = m_pRC->m_pForcedMaterial;
  90. if (m_pRC->m_nForcedMaterialType == OVERRIDE_BUILD_SHADOWS)
  91. {
  92. // Connect the original material up to the shadow building material
  93. // Also bind the original material so its proxies are in the correct state
  94. static unsigned int translucentCache = 0;
  95. IMaterialVar* pOriginalMaterialVar = pMaterial->FindVarFast( "$translucent_material", &translucentCache );
  96. Assert( pOriginalMaterialVar );
  97. IMaterial *pOriginalMaterial = ppMaterials[index];
  98. if ( pOriginalMaterial )
  99. {
  100. // Disable any alpha modulation on the original material that was left over from when it was last rendered
  101. pOriginalMaterial->AlphaModulate( 1.0f );
  102. pRenderContext->Bind( pOriginalMaterial, pClientRenderable );
  103. if ( pOriginalMaterial->IsTranslucent() || pOriginalMaterial->IsAlphaTested() )
  104. {
  105. if ( pOriginalMaterialVar )
  106. pOriginalMaterialVar->SetMaterialValue( pOriginalMaterial );
  107. }
  108. else
  109. {
  110. if ( pOriginalMaterialVar )
  111. pOriginalMaterialVar->SetMaterialValue( NULL );
  112. }
  113. }
  114. else
  115. {
  116. if ( pOriginalMaterialVar )
  117. pOriginalMaterialVar->SetMaterialValue( NULL );
  118. }
  119. }
  120. else if ( m_pRC->m_nForcedMaterialType == OVERRIDE_DEPTH_WRITE || m_pRC->m_nForcedMaterialType == OVERRIDE_SSAO_DEPTH_WRITE )
  121. {
  122. // Disable any alpha modulation on the original material that was left over from when it was last rendered
  123. ppMaterials[index]->AlphaModulate( 1.0f );
  124. // Bail if the material is still considered translucent after setting the AlphaModulate to 1.0
  125. if ( ppMaterials[index]->IsTranslucent() )
  126. {
  127. return NULL;
  128. }
  129. static unsigned int originalTextureVarCache = 0;
  130. IMaterialVar *pOriginalTextureVar = ppMaterials[index]->FindVarFast( "$basetexture", &originalTextureVarCache );
  131. // Select proper override material
  132. int nAlphaTest = (int) ( ppMaterials[index]->IsAlphaTested() && pOriginalTextureVar->IsTexture() ); // alpha tested base texture
  133. int nNoCull = (int) ppMaterials[index]->IsTwoSided();
  134. if ( m_pRC->m_nForcedMaterialType == OVERRIDE_SSAO_DEPTH_WRITE )
  135. {
  136. pMaterial = m_pSSAODepthWrite[nAlphaTest][nNoCull];
  137. }
  138. else
  139. {
  140. pMaterial = m_pDepthWrite[nAlphaTest][nNoCull];
  141. }
  142. // If we're alpha tested, we should set up the texture variables from the original material
  143. if ( nAlphaTest != 0 )
  144. {
  145. static unsigned int originalTextureFrameVarCache = 0;
  146. IMaterialVar *pOriginalTextureFrameVar = ppMaterials[index]->FindVarFast( "$frame", &originalTextureFrameVarCache );
  147. static unsigned int originalAlphaRefCache = 0;
  148. IMaterialVar *pOriginalAlphaRefVar = ppMaterials[index]->FindVarFast( "$AlphaTestReference", &originalAlphaRefCache );
  149. static unsigned int textureVarCache = 0;
  150. IMaterialVar *pTextureVar = pMaterial->FindVarFast( "$basetexture", &textureVarCache );
  151. static unsigned int textureFrameVarCache = 0;
  152. IMaterialVar *pTextureFrameVar = pMaterial->FindVarFast( "$frame", &textureFrameVarCache );
  153. static unsigned int alphaRefCache = 0;
  154. IMaterialVar *pAlphaRefVar = pMaterial->FindVarFast( "$AlphaTestReference", &alphaRefCache );
  155. if ( pOriginalTextureVar->IsTexture() ) // If $basetexture is defined
  156. {
  157. if( pTextureVar && pOriginalTextureVar )
  158. {
  159. pTextureVar->SetTextureValue( pOriginalTextureVar->GetTextureValue() );
  160. }
  161. if( pTextureFrameVar && pOriginalTextureFrameVar )
  162. {
  163. pTextureFrameVar->SetIntValue( pOriginalTextureFrameVar->GetIntValue() );
  164. }
  165. if( pAlphaRefVar && pOriginalAlphaRefVar )
  166. {
  167. pAlphaRefVar->SetFloatValue( pOriginalAlphaRefVar->GetFloatValue() );
  168. }
  169. }
  170. }
  171. }
  172. }
  173. // Set this bool to check after the bind below
  174. bCheckForConVarDrawTranslucentSubModels = true;
  175. if ( m_pRC->m_nForcedMaterialType != OVERRIDE_DEPTH_WRITE && m_pRC->m_nForcedMaterialType != OVERRIDE_SSAO_DEPTH_WRITE)
  176. {
  177. // Try to set the alpha based on the blend
  178. pMaterial->AlphaModulate( m_pRC->m_AlphaMod );
  179. // Try to set the color based on the colormod
  180. pMaterial->ColorModulate( m_pRC->m_ColorMod[0], m_pRC->m_ColorMod[1], m_pRC->m_ColorMod[2] );
  181. }
  182. }
  183. lighting = R_StudioComputeLighting( pMaterial, materialFlags, pColorMeshes );
  184. if ( lighting == LIGHTING_MOUTH )
  185. {
  186. if ( !m_pRC->m_Config.bTeeth || !R_TeethAreVisible() )
  187. return NULL;
  188. // skin it and light it, but only if we need to.
  189. if ( m_pRC->m_Config.m_bSupportsVertexAndPixelShaders )
  190. {
  191. R_MouthSetupVertexShader( pMaterial );
  192. }
  193. }
  194. // TODO: It's possible we don't want to use the color texels--for example because of a convar.
  195. // We should check that here in addition to whether or not we have the data available.
  196. static unsigned int lightmapVarCache = 0;
  197. IMaterialVar *pLightmapVar = pMaterial->FindVarFast( "$lightmap", &lightmapVarCache );
  198. if ( pLightmapVar )
  199. {
  200. ITexture* newTex = pColorMeshes ? pColorMeshes->m_pLightmap : NULL;
  201. if (newTex)
  202. pLightmapVar->SetTextureValue(newTex);
  203. else
  204. pLightmapVar->SetUndefined();
  205. }
  206. pRenderContext->Bind( pMaterial, pClientRenderable );
  207. if ( bCheckForConVarDrawTranslucentSubModels )
  208. {
  209. bool translucent = pMaterial->IsTranslucent();
  210. if (( m_bDrawTranslucentSubModels && !translucent ) ||
  211. ( !m_bDrawTranslucentSubModels && translucent ))
  212. {
  213. m_bSkippedMeshes = true;
  214. return NULL;
  215. }
  216. }
  217. return pMaterial;
  218. }
  219. //=============================================================================
  220. /*
  221. =================
  222. R_StudioSetupModel
  223. based on the body part, figure out which mesh it should be using.
  224. inputs:
  225. outputs:
  226. pstudiomesh
  227. pmdl
  228. =================
  229. */
  230. int R_StudioSetupModel( int bodypart, int entity_body, mstudiomodel_t **ppSubModel,
  231. const studiohdr_t *pStudioHdr )
  232. {
  233. int index;
  234. mstudiobodyparts_t *pbodypart;
  235. if (bodypart > pStudioHdr->numbodyparts)
  236. {
  237. ConDMsg ("R_StudioSetupModel: no such bodypart %d\n", bodypart);
  238. bodypart = 0;
  239. }
  240. pbodypart = pStudioHdr->pBodypart( bodypart );
  241. if ( pbodypart->base == 0 )
  242. {
  243. Warning( "Model has missing body part: %s\n", pStudioHdr->pszName() );
  244. Assert( 0 );
  245. }
  246. index = entity_body / pbodypart->base;
  247. index = index % pbodypart->nummodels;
  248. Assert( ppSubModel );
  249. *ppSubModel = pbodypart->pModel( index );
  250. return index;
  251. }
  252. //-----------------------------------------------------------------------------
  253. // Generates the PoseToBone Matrix nessecary to align the given bone with the
  254. // world.
  255. //-----------------------------------------------------------------------------
  256. static void ScreenAlignBone( matrix3x4_t *pPoseToWorld, mstudiobone_t *pCurBone,
  257. const Vector& vecViewOrigin, const matrix3x4_t &boneToWorld )
  258. {
  259. // Grab the world translation:
  260. Vector vT( boneToWorld[0][3], boneToWorld[1][3], boneToWorld[2][3] );
  261. // Construct the coordinate frame:
  262. // Initialized to get rid of compiler
  263. Vector vX, vY, vZ;
  264. if( pCurBone->flags & BONE_SCREEN_ALIGN_SPHERE )
  265. {
  266. vX = vecViewOrigin - vT;
  267. VectorNormalize(vX);
  268. vZ = Vector(0,0,1);
  269. vY = vZ.Cross(vX);
  270. VectorNormalize(vY);
  271. vZ = vX.Cross(vY);
  272. VectorNormalize(vZ);
  273. }
  274. else
  275. {
  276. Assert( pCurBone->flags & BONE_SCREEN_ALIGN_CYLINDER );
  277. vX.Init( boneToWorld[0][0], boneToWorld[1][0], boneToWorld[2][0] );
  278. vZ = vecViewOrigin - vT;
  279. VectorNormalize(vZ);
  280. vY = vZ.Cross(vX);
  281. VectorNormalize(vY);
  282. vZ = vX.Cross(vY);
  283. VectorNormalize(vZ);
  284. }
  285. matrix3x4_t matBoneBillboard(
  286. vX.x, vY.x, vZ.x, vT.x,
  287. vX.y, vY.y, vZ.y, vT.y,
  288. vX.z, vY.z, vZ.z, vT.z );
  289. ConcatTransforms( matBoneBillboard, pCurBone->poseToBone, *pPoseToWorld );
  290. }
  291. //-----------------------------------------------------------------------------
  292. // Computes PoseToWorld from BoneToWorld
  293. //-----------------------------------------------------------------------------
  294. void ComputePoseToWorld( matrix3x4_t *pPoseToWorld, studiohdr_t *pStudioHdr, int boneMask, const Vector& vecViewOrigin, const matrix3x4_t *pBoneToWorld )
  295. {
  296. if ( pStudioHdr->flags & STUDIOHDR_FLAGS_STATIC_PROP )
  297. {
  298. // by definition, these always have an identity poseToBone transform
  299. MatrixCopy( pBoneToWorld[ 0 ], pPoseToWorld[ 0 ] );
  300. return;
  301. }
  302. if ( !pStudioHdr->pLinearBones() )
  303. {
  304. // convert bone to world transformations into pose to world transformations
  305. for (int i = 0; i < pStudioHdr->numbones; i++)
  306. {
  307. mstudiobone_t *pCurBone = pStudioHdr->pBone( i );
  308. if ( !(pCurBone->flags & boneMask) )
  309. continue;
  310. ConcatTransforms( pBoneToWorld[ i ], pCurBone->poseToBone, pPoseToWorld[ i ] );
  311. }
  312. }
  313. else
  314. {
  315. mstudiolinearbone_t *pLinearBones = pStudioHdr->pLinearBones();
  316. // convert bone to world transformations into pose to world transformations
  317. for (int i = 0; i < pStudioHdr->numbones; i++)
  318. {
  319. if ( !(pLinearBones->flags(i) & boneMask) )
  320. continue;
  321. ConcatTransforms( pBoneToWorld[ i ], pLinearBones->poseToBone(i), pPoseToWorld[ i ] );
  322. }
  323. }
  324. #if 0
  325. // These don't seem to be used in any existing QC file, re-enable in a future project?
  326. // Pretransform
  327. if( !( pCurBone->flags & ( BONE_SCREEN_ALIGN_SPHERE | BONE_SCREEN_ALIGN_CYLINDER )))
  328. {
  329. ConcatTransforms( pBoneToWorld[ i ], pCurBone->poseToBone, pPoseToWorld[ i ] );
  330. }
  331. else
  332. {
  333. // If this bone is screen aligned, then generate a PoseToWorld matrix that billboards the bone
  334. ScreenAlignBone( &pPoseToWorld[i], pCurBone, vecViewOrigin, pBoneToWorld[i] );
  335. }
  336. #endif
  337. }