Counter Strike : Global Offensive Source Code
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.

353 lines
11 KiB

  1. //===== Copyright (c) 1996-2005, 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 "optimize.h"
  13. #include "materialsystem/imaterial.h"
  14. #include "materialsystem/imaterialvar.h"
  15. #include "tier0/vprof.h"
  16. #include "tier3/tier3.h"
  17. #include "datacache/imdlcache.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. //-----------------------------------------------------------------------------
  21. // Figures out what kind of lighting we're gonna want
  22. //-----------------------------------------------------------------------------
  23. FORCEINLINE StudioModelLighting_t CStudioRender::R_StudioComputeLighting( IMaterial *pMaterial, int materialFlags, ColorMeshInfo_t *pColorMeshes )
  24. {
  25. // Here, we only do software lighting when the following conditions are met.
  26. // 1) The material is vertex lit and we don't have hardware lighting
  27. // 2) We're drawing an eyeball
  28. // 3) We're drawing mouth-lit stuff
  29. // FIXME: When we move software lighting into the material system, only need to
  30. // test if it's vertex lit
  31. Assert( pMaterial );
  32. bool doMouthLighting = materialFlags && (m_pStudioHdr->nummouths >= 1);
  33. if ( IsGameConsole() )
  34. {
  35. // Console does not do software lighting
  36. return doMouthLighting ? LIGHTING_MOUTH : LIGHTING_HARDWARE;
  37. }
  38. bool doSoftwareLighting = doMouthLighting ||
  39. (pMaterial && pMaterial->IsVertexLit() && pMaterial->NeedsSoftwareLighting() );
  40. StudioModelLighting_t lighting = LIGHTING_HARDWARE;
  41. if ( doMouthLighting )
  42. lighting = LIGHTING_MOUTH;
  43. else if ( doSoftwareLighting )
  44. lighting = LIGHTING_SOFTWARE;
  45. return lighting;
  46. }
  47. IMaterial* CStudioRender::R_StudioSetupSkinAndLighting( IMatRenderContext *pRenderContext, int index, IMaterial **ppMaterials, int materialFlags,
  48. void /*IClientRenderable*/ *pClientRenderable, ColorMeshInfo_t *pColorMeshes, StudioModelLighting_t &lighting )
  49. {
  50. VPROF( "R_StudioSetupSkin" );
  51. IMaterial *pMaterial = NULL;
  52. bool bCheckForConVarDrawTranslucentSubModels = false;
  53. bool translucent;
  54. if( m_pRC->m_Config.bWireframe && !m_pRC->m_pForcedMaterial[ 0 ] )
  55. {
  56. // Initially, assume no displacement mapping
  57. pMaterial = m_pMaterialWireframe[m_pRC->m_Config.bDrawZBufferedWireframe?1:0][0];
  58. translucent = false;
  59. // Look to see if the original material is displacement mapped
  60. IMaterial *pOriginalMaterial = ppMaterials[index];
  61. static unsigned int originalDisplacementMap = 0;
  62. IMaterialVar* pOriginalMaterialVar = pOriginalMaterial->FindVarFast( "$displacementmap", &originalDisplacementMap );
  63. // If we are displacement mapped
  64. if ( pOriginalMaterialVar && pOriginalMaterialVar->IsTexture() )
  65. {
  66. // Switch to displacement mapped wireframe material
  67. pMaterial = m_pMaterialWireframe[m_pRC->m_Config.bDrawZBufferedWireframe?1:0][1];
  68. static unsigned int newDisplacementMap = 0;
  69. IMaterialVar* pNewMaterialVar = pMaterial->FindVarFast( "$displacementmap", &newDisplacementMap );
  70. if ( pNewMaterialVar )
  71. {
  72. pNewMaterialVar->SetTextureValue( pOriginalMaterialVar->GetTextureValue() );
  73. }
  74. }
  75. }
  76. else if( m_pRC->m_Config.bShowEnvCubemapOnly )
  77. {
  78. pMaterial = m_pMaterialModelEnvCubemap;
  79. translucent = false;
  80. }
  81. else
  82. {
  83. if ( ( !m_pRC->m_pForcedMaterial[ 0 ] && ( m_pRC->m_nForcedMaterialType != OVERRIDE_DEPTH_WRITE && m_pRC->m_nForcedMaterialType != OVERRIDE_SSAO_DEPTH_WRITE ) )
  84. || m_pRC->m_nForcedMaterialType == OVERRIDE_SELECTIVE )
  85. {
  86. int nOverrideIndex = GetForcedMaterialOverrideIndex( index );
  87. if ( m_pRC->m_nForcedMaterialType == OVERRIDE_SELECTIVE && nOverrideIndex != -1 )
  88. {
  89. pMaterial = m_pRC->m_pForcedMaterial[ nOverrideIndex ];
  90. }
  91. else
  92. {
  93. pMaterial = ppMaterials[index];
  94. }
  95. if ( !pMaterial )
  96. {
  97. Assert( 0 );
  98. return 0;
  99. }
  100. translucent = pMaterial->IsTranslucentUnderModulation( m_pRC->m_AlphaMod );
  101. }
  102. else
  103. {
  104. materialFlags = 0;
  105. pMaterial = m_pRC->m_pForcedMaterial[ 0 ];
  106. if (m_pRC->m_nForcedMaterialType == OVERRIDE_BUILD_SHADOWS)
  107. {
  108. // Connect the original material up to the shadow building material
  109. // Also bind the original material so its proxies are in the correct state
  110. static unsigned int translucentCache = 0;
  111. IMaterialVar* pOriginalMaterialVar = pMaterial->FindVarFast( "$translucent_material", &translucentCache );
  112. Assert( pOriginalMaterialVar );
  113. IMaterial *pOriginalMaterial = ppMaterials[index];
  114. if ( pOriginalMaterial )
  115. {
  116. pRenderContext->Bind( pOriginalMaterial, pClientRenderable );
  117. if ( pOriginalMaterial->IsTranslucentUnderModulation() || pOriginalMaterial->IsAlphaTested() )
  118. {
  119. pOriginalMaterialVar->SetMaterialValue( pOriginalMaterial );
  120. }
  121. else
  122. {
  123. pOriginalMaterialVar->SetMaterialValue( NULL );
  124. }
  125. }
  126. else
  127. {
  128. pOriginalMaterialVar->SetMaterialValue( NULL );
  129. }
  130. translucent = pMaterial->IsTranslucentUnderModulation( m_pRC->m_AlphaMod );
  131. }
  132. else if ( m_pRC->m_nForcedMaterialType == OVERRIDE_DEPTH_WRITE || m_pRC->m_nForcedMaterialType == OVERRIDE_SSAO_DEPTH_WRITE )
  133. {
  134. // Bail if the material is still considered translucent after setting the AlphaModulate to 1.0
  135. if ( ppMaterials[index]->IsTranslucentUnderModulation() )
  136. return NULL;
  137. bool bIsAlphaTested = false;
  138. bool bUsesTreeSway = false;
  139. GetDepthWriteMaterial( &pMaterial, &bIsAlphaTested, &bUsesTreeSway, ppMaterials[ index ], false, ( m_pRC->m_nForcedMaterialType == OVERRIDE_SSAO_DEPTH_WRITE) );
  140. if ( bIsAlphaTested )
  141. {
  142. SetupAlphaTestedDepthWrite( pMaterial, ppMaterials[index] );
  143. }
  144. if ( bUsesTreeSway )
  145. {
  146. SetupTreeSwayDepthWrite( pMaterial, ppMaterials[index] );
  147. }
  148. translucent = false;
  149. }
  150. else
  151. {
  152. translucent = pMaterial->IsTranslucentUnderModulation( m_pRC->m_AlphaMod );
  153. }
  154. }
  155. // Set this bool to check after the bind below
  156. bCheckForConVarDrawTranslucentSubModels = true;
  157. }
  158. lighting = R_StudioComputeLighting( pMaterial, materialFlags, pColorMeshes );
  159. if ( lighting == LIGHTING_MOUTH )
  160. {
  161. if ( !m_pRC->m_Config.bTeeth || !R_TeethAreVisible() )
  162. return NULL;
  163. // skin it and light it, but only if we need to.
  164. if ( m_pRC->m_Config.m_bSupportsVertexAndPixelShaders )
  165. {
  166. R_MouthSetupVertexShader( pMaterial );
  167. }
  168. }
  169. pRenderContext->Bind( pMaterial, pClientRenderable );
  170. if ( bCheckForConVarDrawTranslucentSubModels )
  171. {
  172. if (( m_bDrawTranslucentSubModels && !translucent ) ||
  173. ( !m_bDrawTranslucentSubModels && translucent ))
  174. {
  175. m_bSkippedMeshes = true;
  176. return NULL;
  177. }
  178. }
  179. return pMaterial;
  180. }
  181. //=============================================================================
  182. /*
  183. =================
  184. R_StudioSetupModel
  185. based on the body part, figure out which mesh it should be using.
  186. inputs:
  187. outputs:
  188. pstudiomesh
  189. pmdl
  190. =================
  191. */
  192. int R_StudioSetupModel( int bodypart, int entity_body, mstudiomodel_t **ppSubModel,
  193. const studiohdr_t *pStudioHdr )
  194. {
  195. int index;
  196. mstudiobodyparts_t *pbodypart;
  197. if (bodypart > pStudioHdr->numbodyparts)
  198. {
  199. ConDMsg ("R_StudioSetupModel: no such bodypart %d\n", bodypart);
  200. bodypart = 0;
  201. }
  202. pbodypart = pStudioHdr->pBodypart( bodypart );
  203. index = entity_body / pbodypart->base;
  204. index = index % pbodypart->nummodels;
  205. Assert( ppSubModel );
  206. *ppSubModel = pbodypart->pModel( index );
  207. return index;
  208. }
  209. //-----------------------------------------------------------------------------
  210. // Generates the PoseToBone Matrix nessecary to align the given bone with the
  211. // world.
  212. //-----------------------------------------------------------------------------
  213. static void ScreenAlignBone( matrix3x4_t *pPoseToWorld, mstudiobone_t *pCurBone,
  214. const Vector& vecViewOrigin, const matrix3x4_t &boneToWorld )
  215. {
  216. // Grab the world translation:
  217. Vector vT( boneToWorld[0][3], boneToWorld[1][3], boneToWorld[2][3] );
  218. // Construct the coordinate frame:
  219. // Initialized to get rid of compiler
  220. Vector vX, vY, vZ;
  221. if( pCurBone->flags & BONE_SCREEN_ALIGN_SPHERE )
  222. {
  223. vX = vecViewOrigin - vT;
  224. VectorNormalize(vX);
  225. vZ = Vector(0,0,1);
  226. vY = vZ.Cross(vX);
  227. VectorNormalize(vY);
  228. vZ = vX.Cross(vY);
  229. VectorNormalize(vZ);
  230. }
  231. else
  232. {
  233. Assert( pCurBone->flags & BONE_SCREEN_ALIGN_CYLINDER );
  234. vX.Init( boneToWorld[0][0], boneToWorld[1][0], boneToWorld[2][0] );
  235. vZ = vecViewOrigin - vT;
  236. VectorNormalize(vZ);
  237. vY = vZ.Cross(vX);
  238. VectorNormalize(vY);
  239. vZ = vX.Cross(vY);
  240. VectorNormalize(vZ);
  241. }
  242. matrix3x4_t matBoneBillboard(
  243. vX.x, vY.x, vZ.x, vT.x,
  244. vX.y, vY.y, vZ.y, vT.y,
  245. vX.z, vY.z, vZ.z, vT.z );
  246. ConcatTransforms( matBoneBillboard, pCurBone->poseToBone, *pPoseToWorld );
  247. }
  248. //-----------------------------------------------------------------------------
  249. // Computes PoseToWorld from BoneToWorld
  250. //-----------------------------------------------------------------------------
  251. void ComputePoseToWorld( matrix3x4_t *pPoseToWorld, studiohdr_t *pStudioHdr, int boneMask, const Vector& vecViewOrigin, const matrix3x4_t *pBoneToWorld )
  252. {
  253. if ( pStudioHdr->flags & STUDIOHDR_FLAGS_STATIC_PROP )
  254. {
  255. // by definition, these always have an identity poseToBone transform
  256. MatrixCopy( pBoneToWorld[ 0 ], pPoseToWorld[ 0 ] );
  257. return;
  258. }
  259. if ( !pStudioHdr->pLinearBones() )
  260. {
  261. // convert bone to world transformations into pose to world transformations
  262. for (int i = 0; i < pStudioHdr->numbones; i++)
  263. {
  264. const mstudiobone_t *pCurBone = pStudioHdr->pBone( i );
  265. if ( !(pCurBone->flags & boneMask) )
  266. continue;
  267. ConcatTransforms( pBoneToWorld[ i ], pCurBone->poseToBone, pPoseToWorld[ i ] );
  268. }
  269. }
  270. else
  271. {
  272. mstudiolinearbone_t *pLinearBones = pStudioHdr->pLinearBones();
  273. // convert bone to world transformations into pose to world transformations
  274. for (int i = 0; i < pStudioHdr->numbones; i++)
  275. {
  276. if ( !(pLinearBones->flags(i) & boneMask) )
  277. continue;
  278. ConcatTransforms( pBoneToWorld[ i ], pLinearBones->poseToBone(i), pPoseToWorld[ i ] );
  279. }
  280. }
  281. #if 0
  282. // These don't seem to be used in any existing QC file, re-enable in a future project?
  283. // Pretransform
  284. if( !( pCurBone->flags & ( BONE_SCREEN_ALIGN_SPHERE | BONE_SCREEN_ALIGN_CYLINDER )))
  285. {
  286. ConcatTransforms( pBoneToWorld[ i ], pCurBone->poseToBone, pPoseToWorld[ i ] );
  287. }
  288. else
  289. {
  290. // If this bone is screen aligned, then generate a PoseToWorld matrix that billboards the bone
  291. ScreenAlignBone( &pPoseToWorld[i], pCurBone, vecViewOrigin, pBoneToWorld[i] );
  292. }
  293. #endif
  294. }
  295. //-----------------------------------------------------------------------------
  296. // Helper to determine which material type to use depending on what strip
  297. // header flags are set.
  298. //-----------------------------------------------------------------------------
  299. MaterialPrimitiveType_t GetPrimitiveTypeForStripHeaderFlags( unsigned char Flags )
  300. {
  301. if ( Flags & OptimizedModel::STRIP_IS_QUADLIST_EXTRA )
  302. return MATERIAL_SUBD_QUADS_EXTRA;
  303. else if( Flags & OptimizedModel::STRIP_IS_QUADLIST_REG )
  304. return MATERIAL_SUBD_QUADS_REG;
  305. return MATERIAL_TRIANGLES;
  306. }