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.

2986 lines
97 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=====================================================================================//
  6. #include "studiorender.h"
  7. #include "studio.h"
  8. #include "materialsystem/imesh.h"
  9. #include "materialsystem/imaterialsystemhardwareconfig.h"
  10. #include "materialsystem/imaterialvar.h"
  11. #include "materialsystem/imorph.h"
  12. #include "materialsystem/itexture.h"
  13. #include "materialsystem/imaterial.h"
  14. #include "optimize.h"
  15. #include "mathlib/mathlib.h"
  16. #include "mathlib/vector.h"
  17. #include <malloc.h>
  18. #include "mathlib/vmatrix.h"
  19. #include "studiorendercontext.h"
  20. #include "tier2/tier2.h"
  21. #include "tier0/vprof.h"
  22. //#define PROFILE_STUDIO VPROF
  23. #define PROFILE_STUDIO
  24. // memdbgon must be the last include file in a .cpp file!!!
  25. #include "tier0/memdbgon.h"
  26. typedef void (*SoftwareProcessMeshFunc_t)( const mstudio_meshvertexdata_t *, matrix3x4_t *pPoseToWorld,
  27. CCachedRenderData &vertexCache, CMeshBuilder& meshBuilder, int numVertices, unsigned short* pGroupToMesh, unsigned int nAlphaMask,
  28. IMaterial *pMaterial);
  29. //-----------------------------------------------------------------------------
  30. // Forward declarations
  31. //-----------------------------------------------------------------------------
  32. class IClientEntity;
  33. static int boxpnt[6][4] =
  34. {
  35. { 0, 4, 6, 2 }, // +X
  36. { 0, 1, 5, 4 }, // +Y
  37. { 0, 2, 3, 1 }, // +Z
  38. { 7, 5, 1, 3 }, // -X
  39. { 7, 3, 2, 6 }, // -Y
  40. { 7, 6, 4, 5 }, // -Z
  41. };
  42. static TableVector hullcolor[8] =
  43. {
  44. { 1.0, 1.0, 1.0 },
  45. { 1.0, 0.5, 0.5 },
  46. { 0.5, 1.0, 0.5 },
  47. { 1.0, 1.0, 0.5 },
  48. { 0.5, 0.5, 1.0 },
  49. { 1.0, 0.5, 1.0 },
  50. { 0.5, 1.0, 1.0 },
  51. { 1.0, 1.0, 1.0 }
  52. };
  53. //-----------------------------------------------------------------------------
  54. //
  55. //-----------------------------------------------------------------------------
  56. static unsigned int s_nTranslucentModelHullCache = 0;
  57. static unsigned int s_nSolidModelHullCache = 0;
  58. void CStudioRender::R_StudioDrawHulls( int hitboxset, bool translucent )
  59. {
  60. int i, j;
  61. // float lv;
  62. Vector tmp;
  63. Vector p[8];
  64. mstudiobbox_t *pbbox;
  65. IMaterialVar *colorVar;
  66. mstudiohitboxset_t *s = m_pStudioHdr->pHitboxSet( hitboxset );
  67. if ( !s )
  68. return;
  69. pbbox = s->pHitbox( 0 );
  70. if ( !pbbox )
  71. return;
  72. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  73. if( translucent )
  74. {
  75. pRenderContext->Bind( m_pMaterialTranslucentModelHulls );
  76. colorVar = m_pMaterialTranslucentModelHulls->FindVarFast( "$color", &s_nTranslucentModelHullCache );
  77. }
  78. else
  79. {
  80. pRenderContext->Bind( m_pMaterialSolidModelHulls );
  81. colorVar = m_pMaterialSolidModelHulls->FindVarFast( "$color", &s_nSolidModelHullCache );
  82. }
  83. for (i = 0; i < s->numhitboxes; i++)
  84. {
  85. for (j = 0; j < 8; j++)
  86. {
  87. tmp[0] = (j & 1) ? pbbox[i].bbmin[0] : pbbox[i].bbmax[0];
  88. tmp[1] = (j & 2) ? pbbox[i].bbmin[1] : pbbox[i].bbmax[1];
  89. tmp[2] = (j & 4) ? pbbox[i].bbmin[2] : pbbox[i].bbmax[2];
  90. VectorTransform( tmp, m_pBoneToWorld[pbbox[i].bone], p[j] );
  91. }
  92. j = (pbbox[i].group % 8);
  93. g_pMaterialSystem->Flush();
  94. if( colorVar )
  95. {
  96. if( translucent )
  97. {
  98. colorVar->SetVecValue( 0.2f * hullcolor[j].x, 0.2f * hullcolor[j].y, 0.2f * hullcolor[j].z );
  99. }
  100. else
  101. {
  102. colorVar->SetVecValue( hullcolor[j].x, hullcolor[j].y, hullcolor[j].z );
  103. }
  104. }
  105. for (j = 0; j < 6; j++)
  106. {
  107. #if 0
  108. tmp[0] = tmp[1] = tmp[2] = 0;
  109. tmp[j % 3] = (j < 3) ? 1.0 : -1.0;
  110. // R_StudioLighting( &lv, pbbox[i].bone, 0, tmp ); // BUG: not updated
  111. #endif
  112. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  113. CMeshBuilder meshBuilder;
  114. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  115. for (int k = 0; k < 4; ++k)
  116. {
  117. meshBuilder.Position3fv( p[boxpnt[j][k]].Base() );
  118. meshBuilder.AdvanceVertex();
  119. }
  120. meshBuilder.End();
  121. pMesh->Draw();
  122. }
  123. }
  124. }
  125. void CStudioRender::R_StudioDrawBones (void)
  126. {
  127. int i, j, k;
  128. // float lv;
  129. Vector tmp;
  130. Vector p[8];
  131. Vector up, right, forward;
  132. Vector a1;
  133. mstudiobone_t *pbones;
  134. Vector positionArray[4];
  135. pbones = m_pStudioHdr->pBone( 0 );
  136. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  137. for (i = 0; i < m_pStudioHdr->numbones; i++)
  138. {
  139. if (pbones[i].parent == -1)
  140. continue;
  141. k = pbones[i].parent;
  142. a1[0] = a1[1] = a1[2] = 1.0;
  143. up[0] = m_pBoneToWorld[i][0][3] - m_pBoneToWorld[k][0][3];
  144. up[1] = m_pBoneToWorld[i][1][3] - m_pBoneToWorld[k][1][3];
  145. up[2] = m_pBoneToWorld[i][2][3] - m_pBoneToWorld[k][2][3];
  146. if (up[0] > up[1])
  147. if (up[0] > up[2])
  148. a1[0] = 0.0;
  149. else
  150. a1[2] = 0.0;
  151. else
  152. if (up[1] > up[2])
  153. a1[1] = 0.0;
  154. else
  155. a1[2] = 0.0;
  156. CrossProduct( up, a1, right );
  157. VectorNormalize( right );
  158. CrossProduct( up, right, forward );
  159. VectorNormalize( forward );
  160. VectorScale( right, 2.0, right );
  161. VectorScale( forward, 2.0, forward );
  162. for (j = 0; j < 8; j++)
  163. {
  164. p[j][0] = m_pBoneToWorld[k][0][3];
  165. p[j][1] = m_pBoneToWorld[k][1][3];
  166. p[j][2] = m_pBoneToWorld[k][2][3];
  167. if (j & 1)
  168. {
  169. VectorSubtract( p[j], right, p[j] );
  170. }
  171. else
  172. {
  173. VectorAdd( p[j], right, p[j] );
  174. }
  175. if (j & 2)
  176. {
  177. VectorSubtract( p[j], forward, p[j] );
  178. }
  179. else
  180. {
  181. VectorAdd( p[j], forward, p[j] );
  182. }
  183. if (j & 4)
  184. {
  185. }
  186. else
  187. {
  188. VectorAdd( p[j], up, p[j] );
  189. }
  190. }
  191. VectorNormalize( up );
  192. VectorNormalize( right );
  193. VectorNormalize( forward );
  194. pRenderContext->Bind( m_pMaterialModelBones );
  195. for (j = 0; j < 6; j++)
  196. {
  197. switch( j)
  198. {
  199. case 0: VectorCopy( right, tmp ); break;
  200. case 1: VectorCopy( forward, tmp ); break;
  201. case 2: VectorCopy( up, tmp ); break;
  202. case 3: VectorScale( right, -1, tmp ); break;
  203. case 4: VectorScale( forward, -1, tmp ); break;
  204. case 5: VectorScale( up, -1, tmp ); break;
  205. }
  206. // R_StudioLighting( &lv, -1, 0, tmp ); // BUG: not updated
  207. IMesh* pMesh = pRenderContext->GetDynamicMesh();
  208. CMeshBuilder meshBuilder;
  209. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  210. for (int k = 0; k < 4; ++k)
  211. {
  212. meshBuilder.Position3fv( p[boxpnt[j][k]].Base() );
  213. meshBuilder.AdvanceVertex();
  214. }
  215. meshBuilder.End();
  216. pMesh->Draw();
  217. }
  218. }
  219. }
  220. int CStudioRender::R_StudioRenderModel( IMatRenderContext *pRenderContext, int skin,
  221. int body, int hitboxset, void /*IClientEntity*/ *pEntity,
  222. IMaterial **ppMaterials, int *pMaterialFlags, int flags, int boneMask, int lod, ColorMeshInfo_t *pColorMeshes )
  223. {
  224. VPROF("CStudioRender::R_StudioRenderModel");
  225. int nDrawGroup = flags & STUDIORENDER_DRAW_GROUP_MASK;
  226. if ( m_pRC->m_Config.drawEntities == 2 )
  227. {
  228. if ( nDrawGroup != STUDIORENDER_DRAW_TRANSLUCENT_ONLY )
  229. {
  230. R_StudioDrawBones( );
  231. }
  232. return 0;
  233. }
  234. if ( m_pRC->m_Config.drawEntities == 3 )
  235. {
  236. if ( nDrawGroup != STUDIORENDER_DRAW_TRANSLUCENT_ONLY )
  237. {
  238. R_StudioDrawHulls( hitboxset, false );
  239. }
  240. return 0;
  241. }
  242. // BUG: This method is crap, though less crap than before. It should just sort
  243. // the materials though it'll need to sort at render time as "skin"
  244. // can change what materials a given mesh may use
  245. int numTrianglesRendered = 0;
  246. // don't try to use these if not supported
  247. if ( IsPC() && !g_pMaterialSystemHardwareConfig->SupportsColorOnSecondStream() )
  248. {
  249. pColorMeshes = NULL;
  250. }
  251. // Build list of submodels
  252. BodyPartInfo_t *pBodyPartInfo = (BodyPartInfo_t*)_alloca( m_pStudioHdr->numbodyparts * sizeof(BodyPartInfo_t) );
  253. for ( int i=0 ; i < m_pStudioHdr->numbodyparts; ++i )
  254. {
  255. pBodyPartInfo[i].m_nSubModelIndex = R_StudioSetupModel( i, body, &pBodyPartInfo[i].m_pSubModel, m_pStudioHdr );
  256. }
  257. // mark possible translucent meshes
  258. if ( nDrawGroup != STUDIORENDER_DRAW_TRANSLUCENT_ONLY )
  259. {
  260. // we're going to render the opaque meshes, so these will get counted in that pass
  261. m_bSkippedMeshes = false;
  262. m_bDrawTranslucentSubModels = false;
  263. numTrianglesRendered += R_StudioRenderFinal( pRenderContext, skin, m_pStudioHdr->numbodyparts, pBodyPartInfo,
  264. pEntity, ppMaterials, pMaterialFlags, boneMask, lod, pColorMeshes );
  265. }
  266. else
  267. {
  268. m_bSkippedMeshes = true;
  269. }
  270. if ( m_bSkippedMeshes && nDrawGroup != STUDIORENDER_DRAW_OPAQUE_ONLY )
  271. {
  272. m_bDrawTranslucentSubModels = true;
  273. numTrianglesRendered += R_StudioRenderFinal( pRenderContext, skin, m_pStudioHdr->numbodyparts, pBodyPartInfo,
  274. pEntity, ppMaterials, pMaterialFlags, boneMask, lod, pColorMeshes );
  275. }
  276. return numTrianglesRendered;
  277. }
  278. //-----------------------------------------------------------------------------
  279. // Generate morph accumulator
  280. //-----------------------------------------------------------------------------
  281. void CStudioRender::GenerateMorphAccumulator( mstudiomodel_t *pSubModel )
  282. {
  283. // Deal with all flexes
  284. // FIXME: HW Morphing doesn't work with translucent models yet
  285. if ( !m_pRC->m_Config.m_bEnableHWMorph || !m_pRC->m_Config.bFlex || m_bDrawTranslucentSubModels ||
  286. !g_pMaterialSystemHardwareConfig->HasFastVertexTextures() )
  287. return;
  288. int nActiveMeshCount = 0;
  289. mstudiomesh_t *ppMeshes[512];
  290. // First, build the list of meshes that need morphing
  291. for ( int i = 0; i < pSubModel->nummeshes; ++i )
  292. {
  293. mstudiomesh_t *pMesh = pSubModel->pMesh(i);
  294. studiomeshdata_t *pMeshData = &m_pStudioMeshes[pMesh->meshid];
  295. Assert( pMeshData );
  296. int nFlexCount = pMesh->numflexes;
  297. if ( !nFlexCount )
  298. continue;
  299. for ( int j = 0; j < pMeshData->m_NumGroup; ++j )
  300. {
  301. studiomeshgroup_t* pGroup = &pMeshData->m_pMeshGroup[j];
  302. bool bIsDeltaFlexed = (pGroup->m_Flags & MESHGROUP_IS_DELTA_FLEXED) != 0;
  303. if ( !bIsDeltaFlexed )
  304. continue;
  305. ppMeshes[nActiveMeshCount++] = pMesh;
  306. Assert( nActiveMeshCount < 512 );
  307. break;
  308. }
  309. }
  310. if ( nActiveMeshCount == 0 )
  311. return;
  312. // HACK - Just turn off scissor for this model if it is doing morph accumulation
  313. DisableScissor();
  314. // Next, accumulate morphs for appropriate meshes
  315. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  316. pRenderContext->BeginMorphAccumulation();
  317. for ( int i = 0; i < nActiveMeshCount; ++i )
  318. {
  319. mstudiomesh_t *pMesh = ppMeshes[i];
  320. studiomeshdata_t *pMeshData = &m_pStudioMeshes[pMesh->meshid];
  321. int nFlexCount = pMesh->numflexes;
  322. MorphWeight_t *pWeights = (MorphWeight_t*)_alloca( nFlexCount * sizeof(MorphWeight_t) );
  323. ComputeFlexWeights( nFlexCount, pMesh->pFlex(0), pWeights );
  324. for ( int j = 0; j < pMeshData->m_NumGroup; ++j )
  325. {
  326. studiomeshgroup_t* pGroup = &pMeshData->m_pMeshGroup[j];
  327. if ( !pGroup->m_pMorph )
  328. continue;
  329. pRenderContext->AccumulateMorph( pGroup->m_pMorph, nFlexCount, pWeights );
  330. }
  331. }
  332. pRenderContext->EndMorphAccumulation();
  333. }
  334. //-----------------------------------------------------------------------------
  335. // Computes eyeball state
  336. //-----------------------------------------------------------------------------
  337. void CStudioRender::ComputeEyelidStateFACS( mstudiomodel_t *pSubModel )
  338. {
  339. for ( int j = 0; j < pSubModel->numeyeballs; j++ )
  340. {
  341. // FIXME: This might not be necessary...
  342. R_StudioEyeballPosition( pSubModel->pEyeball( j ), &m_pEyeballState[ j ] );
  343. R_StudioEyelidFACS( pSubModel->pEyeball(j), &m_pEyeballState[j] );
  344. }
  345. }
  346. /*
  347. ================
  348. R_StudioRenderFinal
  349. inputs:
  350. outputs: returns the number of triangles rendered.
  351. ================
  352. */
  353. int CStudioRender::R_StudioRenderFinal( IMatRenderContext *pRenderContext,
  354. int skin, int nBodyPartCount, BodyPartInfo_t *pBodyPartInfo, void /*IClientEntity*/ *pClientEntity,
  355. IMaterial **ppMaterials, int *pMaterialFlags, int boneMask, int lod, ColorMeshInfo_t *pColorMeshes )
  356. {
  357. VPROF("CStudioRender::R_StudioRenderFinal");
  358. int numTrianglesRendered = 0;
  359. for ( int i=0 ; i < nBodyPartCount; i++ )
  360. {
  361. m_pSubModel = pBodyPartInfo[i].m_pSubModel;
  362. // NOTE: This has to run here because it effects flex targets,
  363. // so therefore it must happen prior to GenerateMorphAccumulator.
  364. ComputeEyelidStateFACS( m_pSubModel );
  365. GenerateMorphAccumulator( m_pSubModel );
  366. // Set up SW flex
  367. m_VertexCache.SetBodyPart( i );
  368. m_VertexCache.SetModel( pBodyPartInfo[i].m_nSubModelIndex );
  369. numTrianglesRendered += R_StudioDrawPoints( pRenderContext, skin, pClientEntity,
  370. ppMaterials, pMaterialFlags, boneMask, lod, pColorMeshes );
  371. }
  372. return numTrianglesRendered;
  373. }
  374. static ConVar r_flashlightscissor( "r_flashlightscissor", "1", 0 );
  375. void CStudioRender::EnableScissor( FlashlightState_t *state )
  376. {
  377. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  378. // Only scissor into the backbuffer
  379. if ( r_flashlightscissor.GetBool() && state->DoScissor() && ( pRenderContext->GetRenderTarget() == NULL ) )
  380. {
  381. pRenderContext->SetScissorRect( state->GetLeft(), state->GetTop(), state->GetRight(), state->GetBottom(), true );
  382. }
  383. }
  384. void CStudioRender::DisableScissor()
  385. {
  386. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  387. // Scissor even if we're not shadow depth mapping
  388. if ( r_flashlightscissor.GetBool() )
  389. {
  390. pRenderContext->SetScissorRect( -1, -1, -1, -1, false );
  391. }
  392. }
  393. //-----------------------------------------------------------------------------
  394. // Draw shadows
  395. //-----------------------------------------------------------------------------
  396. void CStudioRender::DrawShadows( const DrawModelInfo_t& info, int flags, int boneMask )
  397. {
  398. if ( !m_ShadowState.Count() )
  399. return;
  400. VPROF("CStudioRender::DrawShadows");
  401. IMaterial* pForcedMat = m_pRC->m_pForcedMaterial;
  402. OverrideType_t nForcedType = m_pRC->m_nForcedMaterialType;
  403. // Here, we have to redraw the model one time for each flashlight
  404. // Having a material of NULL means that we are a light source.
  405. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  406. pRenderContext->SetFlashlightMode( true );
  407. int i;
  408. for (i = 0; i < m_ShadowState.Count(); ++i )
  409. {
  410. if( !m_ShadowState[i].m_pMaterial )
  411. {
  412. Assert( m_ShadowState[i].m_pFlashlightState && m_ShadowState[i].m_pWorldToTexture );
  413. pRenderContext->SetFlashlightStateEx( *m_ShadowState[i].m_pFlashlightState, *m_ShadowState[i].m_pWorldToTexture, m_ShadowState[i].m_pFlashlightDepthTexture );
  414. EnableScissor( m_ShadowState[i].m_pFlashlightState );
  415. R_StudioRenderModel( pRenderContext, info.m_Skin, info.m_Body, info.m_HitboxSet, info.m_pClientEntity,
  416. info.m_pHardwareData->m_pLODs[info.m_Lod].ppMaterials,
  417. info.m_pHardwareData->m_pLODs[info.m_Lod].pMaterialFlags, flags, boneMask, info.m_Lod, info.m_pColorMeshes );
  418. DisableScissor();
  419. }
  420. }
  421. pRenderContext->SetFlashlightMode( false );
  422. // Here, we have to redraw the model one time for each shadow
  423. for (int i = 0; i < m_ShadowState.Count(); ++i )
  424. {
  425. if( m_ShadowState[i].m_pMaterial )
  426. {
  427. m_pRC->m_pForcedMaterial = m_ShadowState[i].m_pMaterial;
  428. m_pRC->m_nForcedMaterialType = OVERRIDE_NORMAL;
  429. R_StudioRenderModel( pRenderContext, 0, info.m_Body, 0, m_ShadowState[i].m_pProxyData,
  430. NULL, NULL, flags, boneMask, info.m_Lod, NULL );
  431. }
  432. }
  433. // Restore the previous forced material
  434. m_pRC->m_pForcedMaterial = pForcedMat;
  435. m_pRC->m_nForcedMaterialType = nForcedType;
  436. }
  437. void CStudioRender::DrawStaticPropShadows( const DrawModelInfo_t &info, const StudioRenderContext_t &rc, const matrix3x4_t& rootToWorld, int flags )
  438. {
  439. memcpy( &m_StaticPropRootToWorld, &rootToWorld, sizeof(matrix3x4_t) );
  440. memcpy( &m_PoseToWorld[0], &rootToWorld, sizeof(matrix3x4_t) );
  441. m_pRC = const_cast< StudioRenderContext_t* >( &rc );
  442. m_pBoneToWorld = &m_StaticPropRootToWorld;
  443. m_pStudioHdr = info.m_pStudioHdr;
  444. m_pStudioMeshes = info.m_pHardwareData->m_pLODs[info.m_Lod].m_pMeshData;
  445. DrawShadows( info, flags, BONE_USED_BY_ANYTHING );
  446. m_pRC = NULL;
  447. m_pBoneToWorld = NULL;
  448. }
  449. // Draw flashlight lighting on decals.
  450. void CStudioRender::DrawFlashlightDecals( const DrawModelInfo_t& info, int lod )
  451. {
  452. if ( !m_ShadowState.Count() )
  453. return;
  454. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  455. pRenderContext->SetFlashlightMode( true );
  456. int i;
  457. for (i = 0; i < m_ShadowState.Count(); ++i )
  458. {
  459. // This isn't clear. This means that this is a flashlight if the material is NULL. FLASHLIGHTFIXME
  460. if( !m_ShadowState[i].m_pMaterial )
  461. {
  462. Assert( m_ShadowState[i].m_pFlashlightState && m_ShadowState[i].m_pWorldToTexture );
  463. pRenderContext->SetFlashlightStateEx( *m_ShadowState[i].m_pFlashlightState, *m_ShadowState[i].m_pWorldToTexture, m_ShadowState[i].m_pFlashlightDepthTexture );
  464. EnableScissor( m_ShadowState[i].m_pFlashlightState );
  465. DrawDecal( info, lod, info.m_Body );
  466. DisableScissor();
  467. }
  468. }
  469. pRenderContext->SetFlashlightMode( false );
  470. }
  471. static matrix3x4_t *ComputeSkinMatrix( mstudioboneweight_t &boneweights, matrix3x4_t *pPoseToWorld, matrix3x4_t &result )
  472. {
  473. float flWeight0, flWeight1, flWeight2;
  474. switch( boneweights.numbones )
  475. {
  476. default:
  477. case 1:
  478. return &pPoseToWorld[(unsigned)boneweights.bone[0]];
  479. case 2:
  480. {
  481. matrix3x4_t &boneMat0 = pPoseToWorld[(unsigned)boneweights.bone[0]];
  482. matrix3x4_t &boneMat1 = pPoseToWorld[(unsigned)boneweights.bone[1]];
  483. flWeight0 = boneweights.weight[0];
  484. flWeight1 = boneweights.weight[1];
  485. // NOTE: Inlining here seems to make a fair amount of difference
  486. result[0][0] = boneMat0[0][0] * flWeight0 + boneMat1[0][0] * flWeight1;
  487. result[0][1] = boneMat0[0][1] * flWeight0 + boneMat1[0][1] * flWeight1;
  488. result[0][2] = boneMat0[0][2] * flWeight0 + boneMat1[0][2] * flWeight1;
  489. result[0][3] = boneMat0[0][3] * flWeight0 + boneMat1[0][3] * flWeight1;
  490. result[1][0] = boneMat0[1][0] * flWeight0 + boneMat1[1][0] * flWeight1;
  491. result[1][1] = boneMat0[1][1] * flWeight0 + boneMat1[1][1] * flWeight1;
  492. result[1][2] = boneMat0[1][2] * flWeight0 + boneMat1[1][2] * flWeight1;
  493. result[1][3] = boneMat0[1][3] * flWeight0 + boneMat1[1][3] * flWeight1;
  494. result[2][0] = boneMat0[2][0] * flWeight0 + boneMat1[2][0] * flWeight1;
  495. result[2][1] = boneMat0[2][1] * flWeight0 + boneMat1[2][1] * flWeight1;
  496. result[2][2] = boneMat0[2][2] * flWeight0 + boneMat1[2][2] * flWeight1;
  497. result[2][3] = boneMat0[2][3] * flWeight0 + boneMat1[2][3] * flWeight1;
  498. }
  499. return &result;
  500. case 3:
  501. {
  502. matrix3x4_t &boneMat0 = pPoseToWorld[(unsigned)boneweights.bone[0]];
  503. matrix3x4_t &boneMat1 = pPoseToWorld[(unsigned)boneweights.bone[1]];
  504. matrix3x4_t &boneMat2 = pPoseToWorld[(unsigned)boneweights.bone[2]];
  505. flWeight0 = boneweights.weight[0];
  506. flWeight1 = boneweights.weight[1];
  507. flWeight2 = boneweights.weight[2];
  508. result[0][0] = boneMat0[0][0] * flWeight0 + boneMat1[0][0] * flWeight1 + boneMat2[0][0] * flWeight2;
  509. result[0][1] = boneMat0[0][1] * flWeight0 + boneMat1[0][1] * flWeight1 + boneMat2[0][1] * flWeight2;
  510. result[0][2] = boneMat0[0][2] * flWeight0 + boneMat1[0][2] * flWeight1 + boneMat2[0][2] * flWeight2;
  511. result[0][3] = boneMat0[0][3] * flWeight0 + boneMat1[0][3] * flWeight1 + boneMat2[0][3] * flWeight2;
  512. result[1][0] = boneMat0[1][0] * flWeight0 + boneMat1[1][0] * flWeight1 + boneMat2[1][0] * flWeight2;
  513. result[1][1] = boneMat0[1][1] * flWeight0 + boneMat1[1][1] * flWeight1 + boneMat2[1][1] * flWeight2;
  514. result[1][2] = boneMat0[1][2] * flWeight0 + boneMat1[1][2] * flWeight1 + boneMat2[1][2] * flWeight2;
  515. result[1][3] = boneMat0[1][3] * flWeight0 + boneMat1[1][3] * flWeight1 + boneMat2[1][3] * flWeight2;
  516. result[2][0] = boneMat0[2][0] * flWeight0 + boneMat1[2][0] * flWeight1 + boneMat2[2][0] * flWeight2;
  517. result[2][1] = boneMat0[2][1] * flWeight0 + boneMat1[2][1] * flWeight1 + boneMat2[2][1] * flWeight2;
  518. result[2][2] = boneMat0[2][2] * flWeight0 + boneMat1[2][2] * flWeight1 + boneMat2[2][2] * flWeight2;
  519. result[2][3] = boneMat0[2][3] * flWeight0 + boneMat1[2][3] * flWeight1 + boneMat2[2][3] * flWeight2;
  520. }
  521. return &result;
  522. case 4:
  523. Assert(0);
  524. #if (MAX_NUM_BONES_PER_VERT > 3)
  525. {
  526. // Don't compile this if MAX_NUM_BONES_PER_VERT is too low
  527. matrix3x4_t &boneMat0 = pPoseToWorld[boneweights.bone[0]];
  528. matrix3x4_t &boneMat1 = pPoseToWorld[boneweights.bone[1]];
  529. matrix3x4_t &boneMat2 = pPoseToWorld[boneweights.bone[2]];
  530. matrix3x4_t &boneMat3 = pPoseToWorld[boneweights.bone[3]];
  531. flWeight0 = boneweights.weight[0];
  532. flWeight1 = boneweights.weight[1];
  533. flWeight2 = boneweights.weight[2];
  534. float flWeight3 = boneweights.weight[3];
  535. result[0][0] = boneMat0[0][0] * flWeight0 + boneMat1[0][0] * flWeight1 + boneMat2[0][0] * flWeight2 + boneMat3[0][0] * flWeight3;
  536. result[0][1] = boneMat0[0][1] * flWeight0 + boneMat1[0][1] * flWeight1 + boneMat2[0][1] * flWeight2 + boneMat3[0][1] * flWeight3;
  537. result[0][2] = boneMat0[0][2] * flWeight0 + boneMat1[0][2] * flWeight1 + boneMat2[0][2] * flWeight2 + boneMat3[0][2] * flWeight3;
  538. result[0][3] = boneMat0[0][3] * flWeight0 + boneMat1[0][3] * flWeight1 + boneMat2[0][3] * flWeight2 + boneMat3[0][3] * flWeight3;
  539. result[1][0] = boneMat0[1][0] * flWeight0 + boneMat1[1][0] * flWeight1 + boneMat2[1][0] * flWeight2 + boneMat3[1][0] * flWeight3;
  540. result[1][1] = boneMat0[1][1] * flWeight0 + boneMat1[1][1] * flWeight1 + boneMat2[1][1] * flWeight2 + boneMat3[1][1] * flWeight3;
  541. result[1][2] = boneMat0[1][2] * flWeight0 + boneMat1[1][2] * flWeight1 + boneMat2[1][2] * flWeight2 + boneMat3[1][2] * flWeight3;
  542. result[1][3] = boneMat0[1][3] * flWeight0 + boneMat1[1][3] * flWeight1 + boneMat2[1][3] * flWeight2 + boneMat3[1][3] * flWeight3;
  543. result[2][0] = boneMat0[2][0] * flWeight0 + boneMat1[2][0] * flWeight1 + boneMat2[2][0] * flWeight2 + boneMat3[2][0] * flWeight3;
  544. result[2][1] = boneMat0[2][1] * flWeight0 + boneMat1[2][1] * flWeight1 + boneMat2[2][1] * flWeight2 + boneMat3[2][1] * flWeight3;
  545. result[2][2] = boneMat0[2][2] * flWeight0 + boneMat1[2][2] * flWeight1 + boneMat2[2][2] * flWeight2 + boneMat3[2][2] * flWeight3;
  546. result[2][3] = boneMat0[2][3] * flWeight0 + boneMat1[2][3] * flWeight1 + boneMat2[2][3] * flWeight2 + boneMat3[2][3] * flWeight3;
  547. }
  548. return &result;
  549. #endif
  550. }
  551. Assert(0);
  552. return NULL;
  553. }
  554. static matrix3x4_t *ComputeSkinMatrixSSE( mstudioboneweight_t &boneweights, matrix3x4_t *pPoseToWorld, matrix3x4_t &result )
  555. {
  556. // NOTE: pPoseToWorld, being cache aligned, doesn't need explicit initialization
  557. #if defined( _WIN32 ) && !defined( _X360 )
  558. switch( boneweights.numbones )
  559. {
  560. default:
  561. case 1:
  562. return &pPoseToWorld[boneweights.bone[0]];
  563. case 2:
  564. {
  565. matrix3x4_t &boneMat0 = pPoseToWorld[boneweights.bone[0]];
  566. matrix3x4_t &boneMat1 = pPoseToWorld[boneweights.bone[1]];
  567. float *pWeights = boneweights.weight;
  568. _asm
  569. {
  570. mov eax, DWORD PTR [pWeights]
  571. movss xmm6, dword ptr[eax] ; boneweights.weight[0]
  572. movss xmm7, dword ptr[eax + 4] ; boneweights.weight[1]
  573. mov eax, DWORD PTR [boneMat0]
  574. mov ecx, DWORD PTR [boneMat1]
  575. mov edi, DWORD PTR [result]
  576. // Fill xmm6, and 7 with all the bone weights
  577. shufps xmm6, xmm6, 0
  578. shufps xmm7, xmm7, 0
  579. // Load up all rows of the three matrices
  580. movaps xmm0, XMMWORD PTR [eax]
  581. movaps xmm1, XMMWORD PTR [ecx]
  582. movaps xmm2, XMMWORD PTR [eax + 16]
  583. movaps xmm3, XMMWORD PTR [ecx + 16]
  584. movaps xmm4, XMMWORD PTR [eax + 32]
  585. movaps xmm5, XMMWORD PTR [ecx + 32]
  586. // Multiply the rows by the weights
  587. mulps xmm0, xmm6
  588. mulps xmm1, xmm7
  589. mulps xmm2, xmm6
  590. mulps xmm3, xmm7
  591. mulps xmm4, xmm6
  592. mulps xmm5, xmm7
  593. addps xmm0, xmm1
  594. addps xmm2, xmm3
  595. addps xmm4, xmm5
  596. movaps XMMWORD PTR [edi], xmm0
  597. movaps XMMWORD PTR [edi + 16], xmm2
  598. movaps XMMWORD PTR [edi + 32], xmm4
  599. }
  600. }
  601. return &result;
  602. case 3:
  603. {
  604. matrix3x4_t &boneMat0 = pPoseToWorld[boneweights.bone[0]];
  605. matrix3x4_t &boneMat1 = pPoseToWorld[boneweights.bone[1]];
  606. matrix3x4_t &boneMat2 = pPoseToWorld[boneweights.bone[2]];
  607. float *pWeights = boneweights.weight;
  608. _asm
  609. {
  610. mov eax, DWORD PTR [pWeights]
  611. movss xmm5, dword ptr[eax] ; boneweights.weight[0]
  612. movss xmm6, dword ptr[eax + 4] ; boneweights.weight[1]
  613. movss xmm7, dword ptr[eax + 8] ; boneweights.weight[2]
  614. mov eax, DWORD PTR [boneMat0]
  615. mov ecx, DWORD PTR [boneMat1]
  616. mov edx, DWORD PTR [boneMat2]
  617. mov edi, DWORD PTR [result]
  618. // Fill xmm5, 6, and 7 with all the bone weights
  619. shufps xmm5, xmm5, 0
  620. shufps xmm6, xmm6, 0
  621. shufps xmm7, xmm7, 0
  622. // Load up the first row of the three matrices
  623. movaps xmm0, XMMWORD PTR [eax]
  624. movaps xmm1, XMMWORD PTR [ecx]
  625. movaps xmm2, XMMWORD PTR [edx]
  626. // Multiply the rows by the weights
  627. mulps xmm0, xmm5
  628. mulps xmm1, xmm6
  629. mulps xmm2, xmm7
  630. addps xmm0, xmm1
  631. addps xmm0, xmm2
  632. movaps XMMWORD PTR [edi], xmm0
  633. // Load up the second row of the three matrices
  634. movaps xmm0, XMMWORD PTR [eax + 16]
  635. movaps xmm1, XMMWORD PTR [ecx + 16]
  636. movaps xmm2, XMMWORD PTR [edx + 16]
  637. // Multiply the rows by the weights
  638. mulps xmm0, xmm5
  639. mulps xmm1, xmm6
  640. mulps xmm2, xmm7
  641. addps xmm0, xmm1
  642. addps xmm0, xmm2
  643. movaps XMMWORD PTR [edi + 16], xmm0
  644. // Load up the third row of the three matrices
  645. movaps xmm0, XMMWORD PTR [eax + 32]
  646. movaps xmm1, XMMWORD PTR [ecx + 32]
  647. movaps xmm2, XMMWORD PTR [edx + 32]
  648. // Multiply the rows by the weights
  649. mulps xmm0, xmm5
  650. mulps xmm1, xmm6
  651. mulps xmm2, xmm7
  652. addps xmm0, xmm1
  653. addps xmm0, xmm2
  654. movaps XMMWORD PTR [edi + 32], xmm0
  655. }
  656. }
  657. return &result;
  658. case 4:
  659. Assert(0);
  660. #if (MAX_NUM_BONES_PER_VERT > 3)
  661. {
  662. // Don't compile this if MAX_NUM_BONES_PER_VERT is too low
  663. matrix3x4_t &boneMat0 = pPoseToWorld[boneweights.bone[0]];
  664. matrix3x4_t &boneMat1 = pPoseToWorld[boneweights.bone[1]];
  665. matrix3x4_t &boneMat2 = pPoseToWorld[boneweights.bone[2]];
  666. matrix3x4_t &boneMat3 = pPoseToWorld[boneweights.bone[3]];
  667. float *pWeights = boneweights.weight;
  668. _asm
  669. {
  670. mov eax, DWORD PTR [pWeights]
  671. movss xmm4, dword ptr[eax] ; boneweights.weight[0]
  672. movss xmm5, dword ptr[eax + 4] ; boneweights.weight[1]
  673. movss xmm6, dword ptr[eax + 8] ; boneweights.weight[2]
  674. movss xmm7, dword ptr[eax + 12] ; boneweights.weight[3]
  675. mov eax, DWORD PTR [boneMat0]
  676. mov ecx, DWORD PTR [boneMat1]
  677. mov edx, DWORD PTR [boneMat2]
  678. mov esi, DWORD PTR [boneMat3]
  679. mov edi, DWORD PTR [result]
  680. // Fill xmm5, 6, and 7 with all the bone weights
  681. shufps xmm4, xmm4, 0
  682. shufps xmm5, xmm5, 0
  683. shufps xmm6, xmm6, 0
  684. shufps xmm7, xmm7, 0
  685. // Load up the first row of the four matrices
  686. movaps xmm0, XMMWORD PTR [eax]
  687. movaps xmm1, XMMWORD PTR [ecx]
  688. movaps xmm2, XMMWORD PTR [edx]
  689. movaps xmm3, XMMWORD PTR [esi]
  690. // Multiply the rows by the weights
  691. mulps xmm0, xmm4
  692. mulps xmm1, xmm5
  693. mulps xmm2, xmm6
  694. mulps xmm3, xmm7
  695. addps xmm0, xmm1
  696. addps xmm2, xmm3
  697. addps xmm0, xmm2
  698. movaps XMMWORD PTR [edi], xmm0
  699. // Load up the second row of the three matrices
  700. movaps xmm0, XMMWORD PTR [eax + 16]
  701. movaps xmm1, XMMWORD PTR [ecx + 16]
  702. movaps xmm2, XMMWORD PTR [edx + 16]
  703. movaps xmm3, XMMWORD PTR [esi + 16]
  704. // Multiply the rows by the weights
  705. mulps xmm0, xmm4
  706. mulps xmm1, xmm5
  707. mulps xmm2, xmm6
  708. mulps xmm3, xmm7
  709. addps xmm0, xmm1
  710. addps xmm2, xmm3
  711. addps xmm0, xmm2
  712. movaps XMMWORD PTR [edi + 16], xmm0
  713. // Load up the third row of the three matrices
  714. movaps xmm0, XMMWORD PTR [eax + 32]
  715. movaps xmm1, XMMWORD PTR [ecx + 32]
  716. movaps xmm2, XMMWORD PTR [edx + 32]
  717. movaps xmm3, XMMWORD PTR [esi + 32]
  718. // Multiply the rows by the weights
  719. mulps xmm0, xmm4
  720. mulps xmm1, xmm5
  721. mulps xmm2, xmm6
  722. mulps xmm3, xmm7
  723. addps xmm0, xmm1
  724. addps xmm2, xmm3
  725. addps xmm0, xmm2
  726. movaps XMMWORD PTR [edi + 32], xmm0
  727. }
  728. }
  729. return &result;
  730. #endif
  731. }
  732. #elif POSIX
  733. #warning "ComputeSkinMatrixSSE C implementation only"
  734. return ComputeSkinMatrix( boneweights, pPoseToWorld, result );
  735. #elif defined( _X360 )
  736. return ComputeSkinMatrix( boneweights, pPoseToWorld, result );
  737. #else
  738. #error
  739. #endif
  740. Assert( 0 );
  741. return NULL;
  742. }
  743. //-----------------------------------------------------------------------------
  744. // Designed for inter-module draw optimized calling, requires R_InitLightEffectWorld3()
  745. // Compute the lighting at a point and normal
  746. // Uses the set function pointer
  747. // Final lighting is in gamma space
  748. //-----------------------------------------------------------------------------
  749. static lightpos_t lightpos[MAXLOCALLIGHTS];
  750. inline void CStudioRender::R_ComputeLightAtPoint3( const Vector &pos, const Vector &normal, Vector &color )
  751. {
  752. if ( m_pRC->m_Config.fullbright )
  753. {
  754. color.Init( 1.0f, 1.0f, 1.0f );
  755. return;
  756. }
  757. // Set up lightpos[i].dot, lightpos[i].falloff, and lightpos[i].delta for all lights
  758. R_LightStrengthWorld( pos, m_pRC->m_NumLocalLights, m_pRC->m_LocalLights, lightpos );
  759. // calculate ambient values from the ambient cube given a normal.
  760. R_LightAmbient_4D( normal, m_pRC->m_LightBoxColors, color );
  761. // Calculate color given lightpos_t lightpos, a normal, and the ambient
  762. // color from the ambient cube calculated above.
  763. Assert(R_LightEffectsWorld3);
  764. R_LightEffectsWorld3( m_pRC->m_LocalLights, lightpos, normal, color );
  765. }
  766. // define SPECIAL_SSE_MESH_PROCESSOR to enable code which contains a special optimized SSE lighting loop, significantly
  767. // improving software vertex processing performace.
  768. #if defined( _WIN32 ) && !defined( _X360 )
  769. #define SPECIAL_SSE_MESH_PROCESSOR
  770. #endif
  771. #ifdef SPECIAL_SSE_MESH_PROCESSOR
  772. //#define VERIFY_SSE_LIGHTING
  773. // false: MAX(0,L*N) true: .5*(L.N)+.5. set based on material
  774. static bool SSELightingHalfLambert;
  775. // These variables are used by the special SSE lighting path. The
  776. // lighting path calculates them everytime it processes a mesh so their
  777. // is no need to keep them in sync with changes to the other light variables
  778. static fltx4 OneOver_ThetaDot_Minus_PhiDot[MAXLOCALLIGHTS]; // 1/(theta-phi)
  779. void CStudioRender::R_MouthLighting( fltx4 fIllum, const FourVectors& normal, const FourVectors& forward, FourVectors &light )
  780. {
  781. fltx4 dot = SubSIMD(Four_Zeros,normal*forward);
  782. dot=MaxSIMD(Four_Zeros,dot);
  783. dot=MulSIMD(fIllum,dot);
  784. light *= dot;
  785. }
  786. inline void CStudioRender::R_ComputeLightAtPoints3( const FourVectors &pos, const FourVectors &normal, FourVectors &color )
  787. {
  788. if ( m_pRC->m_Config.fullbright )
  789. {
  790. color.DuplicateVector( Vector( 1.0f, 1.0f, 1.0f ) );
  791. return;
  792. }
  793. R_LightAmbient_4D( normal, m_pRC->m_LightBoxColors, color );
  794. // now, add in contribution from all lights
  795. for ( int i = 0; i < m_pRC->m_NumLocalLights; i++)
  796. {
  797. FourVectors delta;
  798. LightDesc_t const *wl = m_pRC->m_LocalLights+i;
  799. Assert((wl->m_Type==MATERIAL_LIGHT_POINT) || (wl->m_Type==MATERIAL_LIGHT_SPOT) || (wl->m_Type==MATERIAL_LIGHT_DIRECTIONAL));
  800. switch (wl->m_Type)
  801. {
  802. case MATERIAL_LIGHT_POINT:
  803. case MATERIAL_LIGHT_SPOT:
  804. delta.DuplicateVector(wl->m_Position);
  805. delta-=pos;
  806. break;
  807. case MATERIAL_LIGHT_DIRECTIONAL:
  808. delta.DuplicateVector(wl->m_Direction);
  809. delta*=-1.0;
  810. break;
  811. }
  812. fltx4 falloff = R_WorldLightDistanceFalloff( wl, delta);
  813. delta.VectorNormalizeFast();
  814. fltx4 strength=delta*normal;
  815. if (SSELightingHalfLambert)
  816. {
  817. strength=AddSIMD(MulSIMD(strength,Four_PointFives),Four_PointFives);
  818. }
  819. else
  820. strength=MaxSIMD(Four_Zeros,delta*normal);
  821. switch(wl->m_Type)
  822. {
  823. case MATERIAL_LIGHT_POINT:
  824. // half-lambert
  825. break;
  826. case MATERIAL_LIGHT_SPOT:
  827. {
  828. fltx4 dot2=SubSIMD(Four_Zeros,delta*wl->m_Direction); // dot position with spot light dir for cone falloff
  829. fltx4 cone_falloff_scale=MulSIMD(OneOver_ThetaDot_Minus_PhiDot[i],
  830. SubSIMD(dot2,ReplicateX4(wl->m_PhiDot)));
  831. cone_falloff_scale=MinSIMD(cone_falloff_scale,Four_Ones);
  832. if ((wl->m_Falloff!=0.0) && (wl->m_Falloff!=1.0))
  833. {
  834. // !!speed!! could compute integer exponent needed by powsimd and store in light
  835. cone_falloff_scale=PowSIMD(cone_falloff_scale,wl->m_Falloff);
  836. }
  837. strength=MulSIMD(cone_falloff_scale,strength);
  838. // now, zero out lighting where dot2<phidot. This will mask out any invalid results
  839. // from pow function, etc
  840. fltx4 OutsideMask=CmpGtSIMD(dot2,ReplicateX4(wl->m_PhiDot)); // outside light cone?
  841. strength=AndSIMD(OutsideMask,strength);
  842. }
  843. break;
  844. case MATERIAL_LIGHT_DIRECTIONAL:
  845. break;
  846. }
  847. strength=MulSIMD(strength,falloff);
  848. color.x=AddSIMD(color.x,MulSIMD(strength,ReplicateX4(wl->m_Color.x)));
  849. color.y=AddSIMD(color.y,MulSIMD(strength,ReplicateX4(wl->m_Color.y)));
  850. color.z=AddSIMD(color.z,MulSIMD(strength,ReplicateX4(wl->m_Color.z)));
  851. }
  852. }
  853. #endif // SPECIAL_SSE_MESH_PROCESSOR
  854. //-----------------------------------------------------------------------------
  855. // Optimized for low-end hardware
  856. //-----------------------------------------------------------------------------
  857. #pragma warning (disable:4701)
  858. // NOTE: I'm using this crazy wrapper because using straight template functions
  859. // doesn't appear to work with function tables
  860. template< int nHasTangentSpace, int nDoFlex, int nHasSIMD, int nLighting, int nDX8VertexFormat >
  861. class CProcessMeshWrapper
  862. {
  863. public:
  864. static void R_PerformLighting( const Vector &forward, float fIllum,
  865. const Vector &pos, const Vector &norm, unsigned int nAlphaMask, unsigned int *pColor )
  866. {
  867. if ( nLighting == LIGHTING_SOFTWARE )
  868. {
  869. Vector color;
  870. g_StudioRender.R_ComputeLightAtPoint3( pos, norm, color );
  871. unsigned char r = LinearToLightmap( color.x );
  872. unsigned char g = LinearToLightmap( color.y );
  873. unsigned char b = LinearToLightmap( color.z );
  874. *pColor = b | (g << 8) | (r << 16) | nAlphaMask;
  875. }
  876. else if ( nLighting == LIGHTING_MOUTH )
  877. {
  878. if ( fIllum != 0.0f )
  879. {
  880. Vector color;
  881. g_StudioRender.R_ComputeLightAtPoint3( pos, norm, color );
  882. g_StudioRender.R_MouthLighting( fIllum, norm, forward, color );
  883. unsigned char r = LinearToLightmap( color.x );
  884. unsigned char g = LinearToLightmap( color.y );
  885. unsigned char b = LinearToLightmap( color.z );
  886. *pColor = b | (g << 8) | (r << 16) | nAlphaMask;
  887. }
  888. else
  889. {
  890. *pColor = nAlphaMask;
  891. }
  892. }
  893. }
  894. static void R_TransformVert( const Vector *pSrcPos, const Vector *pSrcNorm, const Vector4D *pSrcTangentS,
  895. matrix3x4_t *pSkinMat, VectorAligned &pos, Vector &norm, Vector4DAligned &tangentS )
  896. {
  897. // NOTE: Could add SSE stuff here, if we knew what SSE stuff could make it faster
  898. pos.x = pSrcPos->x * (*pSkinMat)[0][0] + pSrcPos->y * (*pSkinMat)[0][1] + pSrcPos->z * (*pSkinMat)[0][2] + (*pSkinMat)[0][3];
  899. norm.x = pSrcNorm->x * (*pSkinMat)[0][0] + pSrcNorm->y * (*pSkinMat)[0][1] + pSrcNorm->z * (*pSkinMat)[0][2];
  900. pos.y = pSrcPos->x * (*pSkinMat)[1][0] + pSrcPos->y * (*pSkinMat)[1][1] + pSrcPos->z * (*pSkinMat)[1][2] + (*pSkinMat)[1][3];
  901. norm.y = pSrcNorm->x * (*pSkinMat)[1][0] + pSrcNorm->y * (*pSkinMat)[1][1] + pSrcNorm->z * (*pSkinMat)[1][2];
  902. pos.z = pSrcPos->x * (*pSkinMat)[2][0] + pSrcPos->y * (*pSkinMat)[2][1] + pSrcPos->z * (*pSkinMat)[2][2] + (*pSkinMat)[2][3];
  903. norm.z = pSrcNorm->x * (*pSkinMat)[2][0] + pSrcNorm->y * (*pSkinMat)[2][1] + pSrcNorm->z * (*pSkinMat)[2][2];
  904. if ( nHasTangentSpace )
  905. {
  906. tangentS.x = pSrcTangentS->x * (*pSkinMat)[0][0] + pSrcTangentS->y * (*pSkinMat)[0][1] + pSrcTangentS->z * (*pSkinMat)[0][2];
  907. tangentS.y = pSrcTangentS->x * (*pSkinMat)[1][0] + pSrcTangentS->y * (*pSkinMat)[1][1] + pSrcTangentS->z * (*pSkinMat)[1][2];
  908. tangentS.z = pSrcTangentS->x * (*pSkinMat)[2][0] + pSrcTangentS->y * (*pSkinMat)[2][1] + pSrcTangentS->z * (*pSkinMat)[2][2];
  909. tangentS.w = pSrcTangentS->w;
  910. }
  911. }
  912. static void R_StudioSoftwareProcessMesh( const mstudio_meshvertexdata_t *vertData, matrix3x4_t *pPoseToWorld,
  913. CCachedRenderData &vertexCache, CMeshBuilder& meshBuilder, int numVertices, unsigned short* pGroupToMesh, unsigned int nAlphaMask,
  914. IMaterial* pMaterial)
  915. {
  916. Vector color;
  917. Vector4D *pStudioTangentS;
  918. Vector4DAligned tangentS;
  919. Vector *pSrcPos;
  920. Vector *pSrcNorm;
  921. Vector4D *pSrcTangentS = NULL;
  922. ALIGN16 ModelVertexDX8_t dstVertex ALIGN16_POST;
  923. dstVertex.m_flBoneWeights[0] = 1.0f;
  924. dstVertex.m_flBoneWeights[1] = 0.0f;
  925. dstVertex.m_nBoneIndices = 0;
  926. dstVertex.m_nColor = 0xFFFFFFFF;
  927. dstVertex.m_vecUserData.Init( 1.0f, 0.0f, 0.0f, 1.0f );
  928. ALIGN16 matrix3x4_t temp ALIGN16_POST;
  929. ALIGN16 matrix3x4_t *pSkinMat ALIGN16_POST;
  930. int ntemp[PREFETCH_VERT_COUNT];
  931. Assert( numVertices > 0 );
  932. mstudiovertex_t *pVertices = vertData->Vertex( 0 );
  933. if (nHasTangentSpace)
  934. {
  935. pStudioTangentS = vertData->TangentS( 0 );
  936. Assert( pStudioTangentS->w == -1.0f || pStudioTangentS->w == 1.0f );
  937. }
  938. // Mouth related stuff...
  939. float fIllum = 1.0f;
  940. Vector forward;
  941. if (nLighting == LIGHTING_MOUTH)
  942. {
  943. g_StudioRender.R_MouthComputeLightingValues( fIllum, forward );
  944. }
  945. if ((nLighting == LIGHTING_MOUTH) || (nLighting == LIGHTING_SOFTWARE))
  946. {
  947. g_StudioRender.R_InitLightEffectsWorld3();
  948. }
  949. #ifdef _DEBUG
  950. // In debug, clear it out to ensure we aren't accidentially calling
  951. // the last setup for R_ComputeLightForPoint3.
  952. else
  953. {
  954. g_StudioRender.R_LightEffectsWorld3 = NULL;
  955. }
  956. #endif
  957. #if defined( _WIN32 ) && !defined( _X360 )
  958. if ( nHasSIMD )
  959. {
  960. // Precaches the data
  961. _mm_prefetch( (char*)((int)pGroupToMesh & (~0x1F)), _MM_HINT_NTA );
  962. }
  963. #endif
  964. for ( int i = 0; i < PREFETCH_VERT_COUNT; ++i )
  965. {
  966. ntemp[i] = pGroupToMesh[i];
  967. #if defined( _WIN32 ) && !defined( _X360 )
  968. if ( nHasSIMD )
  969. {
  970. char *pMem = (char*)&pVertices[ntemp[i]];
  971. _mm_prefetch( pMem, _MM_HINT_NTA );
  972. _mm_prefetch( pMem + 32, _MM_HINT_NTA );
  973. if ( nHasTangentSpace )
  974. {
  975. _mm_prefetch( (char*)&pStudioTangentS[ntemp[i]], _MM_HINT_NTA );
  976. }
  977. }
  978. #endif
  979. }
  980. int n, idx;
  981. for ( int j=0; j < numVertices; ++j )
  982. {
  983. #if defined( _WIN32 ) && !defined( _X360 )
  984. if ( nHasSIMD )
  985. {
  986. char *pMem = (char*)&pGroupToMesh[j + PREFETCH_VERT_COUNT + 1];
  987. _mm_prefetch( (char*)((int)pMem & (~0x1F)), _MM_HINT_NTA );
  988. }
  989. #endif
  990. idx = j & (PREFETCH_VERT_COUNT-1);
  991. n = ntemp[idx];
  992. mstudiovertex_t &vert = pVertices[n];
  993. ntemp[idx] = pGroupToMesh[j + PREFETCH_VERT_COUNT];
  994. // Compute the skinning matrix
  995. if ( nHasSIMD )
  996. {
  997. pSkinMat = ComputeSkinMatrixSSE( vert.m_BoneWeights, pPoseToWorld, temp );
  998. }
  999. else
  1000. {
  1001. pSkinMat = ComputeSkinMatrix( vert.m_BoneWeights, pPoseToWorld, temp );
  1002. }
  1003. // transform into world space
  1004. if (nDoFlex && vertexCache.IsVertexFlexed(n))
  1005. {
  1006. CachedPosNormTan_t* pFlexedVertex = vertexCache.GetFlexVertex(n);
  1007. pSrcPos = &pFlexedVertex->m_Position;
  1008. pSrcNorm = &pFlexedVertex->m_Normal;
  1009. if (nHasTangentSpace)
  1010. {
  1011. pSrcTangentS = &pFlexedVertex->m_TangentS;
  1012. Assert( pSrcTangentS->w == -1.0f || pSrcTangentS->w == 1.0f );
  1013. }
  1014. }
  1015. else
  1016. {
  1017. pSrcPos = &vert.m_vecPosition;
  1018. pSrcNorm = &vert.m_vecNormal;
  1019. if (nHasTangentSpace)
  1020. {
  1021. pSrcTangentS = &pStudioTangentS[n];
  1022. Assert( pSrcTangentS->w == -1.0f || pSrcTangentS->w == 1.0f );
  1023. }
  1024. }
  1025. // Transform the vert into world space
  1026. R_TransformVert( pSrcPos, pSrcNorm, pSrcTangentS, pSkinMat,
  1027. *(VectorAligned*)&dstVertex.m_vecPosition, dstVertex.m_vecNormal, *(Vector4DAligned*)&dstVertex.m_vecUserData );
  1028. #if defined( _WIN32 ) && !defined( _X360 )
  1029. if ( nHasSIMD )
  1030. {
  1031. _mm_prefetch( (char*)&pVertices[ntemp[idx]], _MM_HINT_NTA);
  1032. _mm_prefetch( (char*)&pVertices[ntemp[idx]] + 32, _MM_HINT_NTA );
  1033. if ( nHasTangentSpace )
  1034. {
  1035. _mm_prefetch( (char*)&pStudioTangentS[ntemp[idx]], _MM_HINT_NTA );
  1036. }
  1037. }
  1038. #endif
  1039. // Compute lighting
  1040. R_PerformLighting( forward, fIllum, dstVertex.m_vecPosition, dstVertex.m_vecNormal, nAlphaMask, &dstVertex.m_nColor );
  1041. dstVertex.m_vecTexCoord = vert.m_vecTexCoord;
  1042. if ( IsX360() || nDX8VertexFormat )
  1043. {
  1044. #if !defined( _X360 )
  1045. Assert( dstVertex.m_vecUserData.w == -1.0f || dstVertex.m_vecUserData.w == 1.0f );
  1046. if ( nHasSIMD )
  1047. {
  1048. meshBuilder.FastVertexSSE( dstVertex );
  1049. }
  1050. else
  1051. {
  1052. meshBuilder.FastVertex( dstVertex );
  1053. }
  1054. #else
  1055. meshBuilder.VertexDX8ToX360( dstVertex );
  1056. #endif
  1057. }
  1058. else
  1059. {
  1060. if ( nHasSIMD )
  1061. {
  1062. meshBuilder.FastVertexSSE( *(ModelVertexDX7_t*)&dstVertex );
  1063. }
  1064. else
  1065. {
  1066. meshBuilder.FastVertex( *(ModelVertexDX7_t*)&dstVertex );
  1067. }
  1068. }
  1069. }
  1070. meshBuilder.FastAdvanceNVertices( numVertices );
  1071. }
  1072. #ifdef SPECIAL_SSE_MESH_PROCESSOR
  1073. #ifdef VERIFY_SSE_LIGHTING
  1074. static int NotCloseEnough( float a, float b )
  1075. {
  1076. // check if 2 linear lighting values are close enough between the sse and non see lighting model
  1077. // no point being more precise than 1% since it all maps to 8 bit anyway
  1078. float thresh=0.1f*fabs( a );
  1079. if ( thresh < 0.1f )
  1080. thresh = 0.1f;
  1081. return ( fabs( a-b ) > thresh );
  1082. }
  1083. #endif
  1084. // this special version of the vertex processor does 4 vertices at once, so that they can be lit using SSE instructions. This provides
  1085. // a >2x speedup in the lit case
  1086. static void R_PerformVectorizedLightingSSE( const FourVectors &forward, fltx4 fIllum, ModelVertexDX8_t *dst, unsigned int nAlphaMask)
  1087. {
  1088. if ( nLighting == LIGHTING_SOFTWARE )
  1089. {
  1090. #ifdef VERIFY_SSE_LIGHTING
  1091. // if ( (g_StudioRender.m_NumLocalLights==1) &&
  1092. // ( (g_StudioRender.m_LocalLights[0].m_Type==MATERIAL_LIGHT_SPOT)))
  1093. // {
  1094. // // ihvtest doesn't use different exponents for its spots,
  1095. // // so i mess with the exponents when testing
  1096. // static int ctr=0;
  1097. // static float exps[8]={0,1,2,3,4,4.5,5.25,2.5};
  1098. // ctr=(ctr+1)&7;
  1099. // g_StudioRender.m_LocalLights[0].m_Falloff=exps[ctr];
  1100. // }
  1101. #endif
  1102. FourVectors Position;
  1103. Position.LoadAndSwizzleAligned(dst[0].m_vecPosition,dst[1].m_vecPosition,dst[2].m_vecPosition,dst[3].m_vecPosition);
  1104. FourVectors Normal(dst[0].m_vecNormal,dst[1].m_vecNormal,dst[2].m_vecNormal,dst[3].m_vecNormal);
  1105. FourVectors Color;
  1106. g_StudioRender.R_ComputeLightAtPoints3( Position, Normal, Color);
  1107. for (int i=0; i<4; i++)
  1108. {
  1109. Vector color;
  1110. #ifdef VERIFY_SSE_LIGHTING
  1111. // debug - check sse version against "real" version
  1112. g_StudioRender.R_ComputeLightAtPoint3( dst[i].m_vecPosition,dst[i].m_vecNormal, color );
  1113. if ( NotCloseEnough(color.x,Color.X(i)) ||
  1114. NotCloseEnough(color.y,Color.Y(i)) ||
  1115. NotCloseEnough(color.z,Color.Z(i)))
  1116. {
  1117. Assert(0);
  1118. // recompute so can step in debugger
  1119. g_StudioRender.R_ComputeLightAtPoints3( Position,Normal,Color);
  1120. g_StudioRender.R_ComputeLightAtPoint3( dst[i].m_vecPosition,dst[i].m_vecNormal, color );
  1121. }
  1122. #endif
  1123. unsigned char r = LinearToLightmap( Color.X(i) );
  1124. unsigned char g = LinearToLightmap( Color.Y(i) );
  1125. unsigned char b = LinearToLightmap( Color.Z(i) );
  1126. dst[i].m_nColor = b | (g << 8) | (r << 16) | nAlphaMask;
  1127. }
  1128. }
  1129. else if ( nLighting == LIGHTING_MOUTH )
  1130. {
  1131. FourVectors Position;
  1132. Position.LoadAndSwizzleAligned(dst[0].m_vecPosition,dst[1].m_vecPosition,dst[2].m_vecPosition,dst[3].m_vecPosition);
  1133. FourVectors Normal(dst[0].m_vecNormal,dst[1].m_vecNormal,dst[2].m_vecNormal,dst[3].m_vecNormal);
  1134. FourVectors Color;
  1135. g_StudioRender.R_ComputeLightAtPoints3( Position, Normal, Color);
  1136. g_StudioRender.R_MouthLighting( fIllum, Normal, forward, Color );
  1137. for (int i=0; i<4; i++)
  1138. {
  1139. unsigned char r = LinearToLightmap( Color.X(i) );
  1140. unsigned char g = LinearToLightmap( Color.Y(i) );
  1141. unsigned char b = LinearToLightmap( Color.Z(i) );
  1142. dst[i].m_nColor = b | (g << 8) | (r << 16) | nAlphaMask;
  1143. }
  1144. }
  1145. }
  1146. static void R_StudioSoftwareProcessMeshSSE_DX7( const mstudio_meshvertexdata_t *vertData, matrix3x4_t *pPoseToWorld,
  1147. CCachedRenderData &vertexCache, CMeshBuilder& meshBuilder,
  1148. int numVertices, unsigned short* pGroupToMesh, unsigned int nAlphaMask,
  1149. IMaterial* pMaterial)
  1150. {
  1151. Assert( numVertices > 0 );
  1152. mstudiovertex_t *pVertices = vertData->Vertex( 0 );
  1153. #define N_VERTS_TO_DO_AT_ONCE 4 // for SSE processing
  1154. Assert(N_VERTS_TO_DO_AT_ONCE<=PREFETCH_VERT_COUNT);
  1155. SSELightingHalfLambert=(pMaterial && (pMaterial->GetMaterialVarFlag( MATERIAL_VAR_HALFLAMBERT)));
  1156. Vector color;
  1157. Vector *pSrcPos;
  1158. Vector *pSrcNorm;
  1159. ALIGN16 ModelVertexDX8_t dstVertexBuf[N_VERTS_TO_DO_AT_ONCE] ALIGN16_POST;
  1160. for(int i=0;i<N_VERTS_TO_DO_AT_ONCE;i++)
  1161. {
  1162. dstVertexBuf[i].m_flBoneWeights[0] = 1.0f;
  1163. dstVertexBuf[i].m_flBoneWeights[1] = 0.0f;
  1164. dstVertexBuf[i].m_nBoneIndices = 0;
  1165. dstVertexBuf[i].m_nColor = 0xFFFFFFFF;
  1166. dstVertexBuf[i].m_vecUserData.Init( 1.0f, 0.0f, 0.0f, 1.0f );
  1167. }
  1168. // do per-light precalcs. Better than doing them per vertex
  1169. for ( int l = 0; l < g_StudioRender.m_pRC->m_NumLocalLights; l++)
  1170. {
  1171. LightDesc_t *wl=g_StudioRender.m_pRC->m_LocalLights+l;
  1172. if (wl->m_Type==MATERIAL_LIGHT_SPOT)
  1173. {
  1174. float spread=wl->m_ThetaDot-wl->m_PhiDot;
  1175. if (spread>1.0e-10)
  1176. {
  1177. // note - this quantity is very sensitive to round off error. the sse
  1178. // reciprocal approximation won't cut it here.
  1179. OneOver_ThetaDot_Minus_PhiDot[l]=ReplicateX4(1.0/spread);
  1180. }
  1181. else
  1182. {
  1183. // hard falloff instead of divide by zero
  1184. OneOver_ThetaDot_Minus_PhiDot[l]=ReplicateX4(1.0);
  1185. }
  1186. }
  1187. }
  1188. ALIGN16 matrix3x4_t temp ALIGN16_POST;
  1189. ALIGN16 matrix3x4_t *pSkinMat ALIGN16_POST;
  1190. // Mouth related stuff...
  1191. float fIllum = 1.0f;
  1192. fltx4 fIllumReplicated;
  1193. Vector forward;
  1194. FourVectors mouth_forward;
  1195. if (nLighting == LIGHTING_MOUTH)
  1196. {
  1197. g_StudioRender.R_MouthComputeLightingValues( fIllum, forward );
  1198. mouth_forward.DuplicateVector(forward);
  1199. }
  1200. fIllumReplicated=ReplicateX4(fIllum);
  1201. if ((nLighting == LIGHTING_MOUTH) || (nLighting == LIGHTING_SOFTWARE))
  1202. {
  1203. g_StudioRender.R_InitLightEffectsWorld3();
  1204. }
  1205. #ifdef _DEBUG
  1206. // In debug, clear it out to ensure we aren't accidentially calling
  1207. // the last setup for R_ComputeLightForPoint3.
  1208. else
  1209. {
  1210. g_StudioRender.R_LightEffectsWorld3 = NULL;
  1211. }
  1212. #endif
  1213. int n_iters=numVertices;
  1214. ModelVertexDX8_t *dst=dstVertexBuf;
  1215. while(1)
  1216. {
  1217. for(int subc=0;subc<4;subc++)
  1218. {
  1219. int n=*(pGroupToMesh++);
  1220. mstudiovertex_t &vert = pVertices[n];
  1221. // Compute the skinning matrix
  1222. pSkinMat = ComputeSkinMatrixSSE( vert.m_BoneWeights, pPoseToWorld, temp );
  1223. // transform into world space
  1224. if (nDoFlex && vertexCache.IsVertexFlexed(n))
  1225. {
  1226. CachedPosNormTan_t* pFlexedVertex = vertexCache.GetFlexVertex(n);
  1227. pSrcPos = &pFlexedVertex->m_Position;
  1228. pSrcNorm = &pFlexedVertex->m_Normal;
  1229. }
  1230. else
  1231. {
  1232. pSrcPos = &vert.m_vecPosition;
  1233. pSrcNorm = &vert.m_vecNormal;
  1234. }
  1235. // Transform the vert into world space
  1236. R_TransformVert( pSrcPos, pSrcNorm, 0, pSkinMat,
  1237. *(VectorAligned*)&dst->m_vecPosition, dst->m_vecNormal, *(Vector4DAligned*)&dst->m_vecUserData );
  1238. dst->m_vecTexCoord = vert.m_vecTexCoord;
  1239. dst++;
  1240. }
  1241. n_iters-=4;
  1242. dst=dstVertexBuf;
  1243. // Compute lighting
  1244. R_PerformVectorizedLightingSSE( mouth_forward, fIllumReplicated, dst, nAlphaMask);
  1245. if (n_iters<=0) // partial copy back?
  1246. {
  1247. // copy 1..3 verts
  1248. while(n_iters!=-4)
  1249. {
  1250. meshBuilder.FastVertexSSE( *(ModelVertexDX7_t*)dst );
  1251. n_iters--;
  1252. dst++;
  1253. }
  1254. break;
  1255. }
  1256. else
  1257. {
  1258. meshBuilder.Fast4VerticesSSE(
  1259. (ModelVertexDX7_t*)&(dst[0]),
  1260. (ModelVertexDX7_t*)&(dst[1]),
  1261. (ModelVertexDX7_t*)&(dst[2]),
  1262. (ModelVertexDX7_t*)&(dst[3]));
  1263. }
  1264. }
  1265. meshBuilder.FastAdvanceNVertices( numVertices );
  1266. }
  1267. #endif // SPECIAL_SSE_MESH_PROCESSOR
  1268. };
  1269. //-----------------------------------------------------------------------------
  1270. // Draws the mesh as tristrips using software
  1271. //-----------------------------------------------------------------------------
  1272. #if !defined( _X360 )
  1273. typedef CProcessMeshWrapper< false, false, false, LIGHTING_HARDWARE, false > ProcessMesh000H7_t;
  1274. typedef CProcessMeshWrapper< false, false, false, LIGHTING_SOFTWARE, false > ProcessMesh000S7_t;
  1275. typedef CProcessMeshWrapper< false, false, false, LIGHTING_MOUTH, false > ProcessMesh000M7_t;
  1276. #endif
  1277. #if !defined( _X360 )
  1278. typedef CProcessMeshWrapper< false, false, true, LIGHTING_HARDWARE, false > ProcessMesh001H7_t;
  1279. typedef CProcessMeshWrapper< false, false, true, LIGHTING_SOFTWARE, false > ProcessMesh001S7_t;
  1280. typedef CProcessMeshWrapper< false, false, true, LIGHTING_MOUTH, false > ProcessMesh001M7_t;
  1281. #endif
  1282. #if !defined( _X360 )
  1283. typedef CProcessMeshWrapper< false, true, false, LIGHTING_HARDWARE, false > ProcessMesh010H7_t;
  1284. typedef CProcessMeshWrapper< false, true, false, LIGHTING_SOFTWARE, false > ProcessMesh010S7_t;
  1285. typedef CProcessMeshWrapper< false, true, false, LIGHTING_MOUTH, false > ProcessMesh010M7_t;
  1286. #endif
  1287. #if !defined( _X360 )
  1288. typedef CProcessMeshWrapper< false, true, true, LIGHTING_HARDWARE, false > ProcessMesh011H7_t;
  1289. typedef CProcessMeshWrapper< false, true, true, LIGHTING_SOFTWARE, false > ProcessMesh011S7_t;
  1290. typedef CProcessMeshWrapper< false, true, true, LIGHTING_MOUTH, false > ProcessMesh011M7_t;
  1291. #endif
  1292. #if !defined( _X360 )
  1293. typedef CProcessMeshWrapper< true, false, false, LIGHTING_HARDWARE, false > ProcessMesh100H7_t;
  1294. typedef CProcessMeshWrapper< true, false, false, LIGHTING_SOFTWARE, false > ProcessMesh100S7_t;
  1295. typedef CProcessMeshWrapper< true, false, false, LIGHTING_MOUTH, false > ProcessMesh100M7_t;
  1296. #endif
  1297. #if !defined( _X360 )
  1298. typedef CProcessMeshWrapper< true, false, true, LIGHTING_HARDWARE, false > ProcessMesh101H7_t;
  1299. typedef CProcessMeshWrapper< true, false, true, LIGHTING_SOFTWARE, false > ProcessMesh101S7_t;
  1300. typedef CProcessMeshWrapper< true, false, true, LIGHTING_MOUTH, false > ProcessMesh101M7_t;
  1301. #endif
  1302. #if !defined( _X360 )
  1303. typedef CProcessMeshWrapper< true, true, false, LIGHTING_HARDWARE, false > ProcessMesh110H7_t;
  1304. typedef CProcessMeshWrapper< true, true, false, LIGHTING_SOFTWARE, false > ProcessMesh110S7_t;
  1305. typedef CProcessMeshWrapper< true, true, false, LIGHTING_MOUTH, false > ProcessMesh110M7_t;
  1306. #endif
  1307. #if !defined( _X360 )
  1308. typedef CProcessMeshWrapper< true, true, true, LIGHTING_HARDWARE, false > ProcessMesh111H7_t;
  1309. typedef CProcessMeshWrapper< true, true, true, LIGHTING_SOFTWARE, false > ProcessMesh111S7_t;
  1310. typedef CProcessMeshWrapper< true, true, true, LIGHTING_MOUTH, false > ProcessMesh111M7_t;
  1311. #endif
  1312. #if !defined( _X360 )
  1313. typedef CProcessMeshWrapper< false, false, false, LIGHTING_HARDWARE, true > ProcessMesh000H8_t;
  1314. typedef CProcessMeshWrapper< false, false, false, LIGHTING_SOFTWARE, true > ProcessMesh000S8_t;
  1315. typedef CProcessMeshWrapper< false, false, false, LIGHTING_MOUTH, true > ProcessMesh000M8_t;
  1316. #endif
  1317. typedef CProcessMeshWrapper< false, false, true, LIGHTING_HARDWARE, true > ProcessMesh001H8_t;
  1318. typedef CProcessMeshWrapper< false, false, true, LIGHTING_SOFTWARE, true > ProcessMesh001S8_t;
  1319. typedef CProcessMeshWrapper< false, false, true, LIGHTING_MOUTH, true > ProcessMesh001M8_t;
  1320. #if !defined( _X360 )
  1321. typedef CProcessMeshWrapper< false, true, false, LIGHTING_HARDWARE, true > ProcessMesh010H8_t;
  1322. typedef CProcessMeshWrapper< false, true, false, LIGHTING_SOFTWARE, true > ProcessMesh010S8_t;
  1323. typedef CProcessMeshWrapper< false, true, false, LIGHTING_MOUTH, true > ProcessMesh010M8_t;
  1324. #endif
  1325. typedef CProcessMeshWrapper< false, true, true, LIGHTING_HARDWARE, true > ProcessMesh011H8_t;
  1326. typedef CProcessMeshWrapper< false, true, true, LIGHTING_SOFTWARE, true > ProcessMesh011S8_t;
  1327. typedef CProcessMeshWrapper< false, true, true, LIGHTING_MOUTH, true > ProcessMesh011M8_t;
  1328. #if !defined( _X360 )
  1329. typedef CProcessMeshWrapper< true, false, false, LIGHTING_HARDWARE, true > ProcessMesh100H8_t;
  1330. typedef CProcessMeshWrapper< true, false, false, LIGHTING_SOFTWARE, true > ProcessMesh100S8_t;
  1331. typedef CProcessMeshWrapper< true, false, false, LIGHTING_MOUTH, true > ProcessMesh100M8_t;
  1332. #endif
  1333. typedef CProcessMeshWrapper< true, false, true, LIGHTING_HARDWARE, true > ProcessMesh101H8_t;
  1334. typedef CProcessMeshWrapper< true, false, true, LIGHTING_SOFTWARE, true > ProcessMesh101S8_t;
  1335. typedef CProcessMeshWrapper< true, false, true, LIGHTING_MOUTH, true > ProcessMesh101M8_t;
  1336. #if !defined( _X360 )
  1337. typedef CProcessMeshWrapper< true, true, false, LIGHTING_HARDWARE, true > ProcessMesh110H8_t;
  1338. typedef CProcessMeshWrapper< true, true, false, LIGHTING_SOFTWARE, true > ProcessMesh110S8_t;
  1339. typedef CProcessMeshWrapper< true, true, false, LIGHTING_MOUTH, true > ProcessMesh110M8_t;
  1340. #endif
  1341. typedef CProcessMeshWrapper< true, true, true, LIGHTING_HARDWARE, true > ProcessMesh111H8_t;
  1342. typedef CProcessMeshWrapper< true, true, true, LIGHTING_SOFTWARE, true > ProcessMesh111S8_t;
  1343. typedef CProcessMeshWrapper< true, true, true, LIGHTING_MOUTH, true > ProcessMesh111M8_t;
  1344. static SoftwareProcessMeshFunc_t g_SoftwareProcessMeshFunc[] =
  1345. {
  1346. #if !defined( _X360 )
  1347. ProcessMesh000H7_t::R_StudioSoftwareProcessMesh,
  1348. ProcessMesh000S7_t::R_StudioSoftwareProcessMesh,
  1349. ProcessMesh000M7_t::R_StudioSoftwareProcessMesh,
  1350. ProcessMesh001H7_t::R_StudioSoftwareProcessMesh,
  1351. #ifdef SPECIAL_SSE_MESH_PROCESSOR
  1352. ProcessMesh001S7_t::R_StudioSoftwareProcessMeshSSE_DX7,
  1353. ProcessMesh001M7_t::R_StudioSoftwareProcessMeshSSE_DX7,
  1354. #else
  1355. ProcessMesh001S7_t::R_StudioSoftwareProcessMesh,
  1356. ProcessMesh001M7_t::R_StudioSoftwareProcessMesh,
  1357. #endif
  1358. ProcessMesh010H7_t::R_StudioSoftwareProcessMesh,
  1359. ProcessMesh010S7_t::R_StudioSoftwareProcessMesh,
  1360. ProcessMesh010M7_t::R_StudioSoftwareProcessMesh,
  1361. ProcessMesh011H7_t::R_StudioSoftwareProcessMesh,
  1362. #ifdef SPECIAL_SSE_MESH_PROCESSOR
  1363. ProcessMesh011S7_t::R_StudioSoftwareProcessMeshSSE_DX7,
  1364. ProcessMesh011M7_t::R_StudioSoftwareProcessMeshSSE_DX7,
  1365. #else
  1366. ProcessMesh011S7_t::R_StudioSoftwareProcessMesh,
  1367. ProcessMesh011M7_t::R_StudioSoftwareProcessMesh,
  1368. #endif
  1369. ProcessMesh100H7_t::R_StudioSoftwareProcessMesh,
  1370. ProcessMesh100S7_t::R_StudioSoftwareProcessMesh,
  1371. ProcessMesh100M7_t::R_StudioSoftwareProcessMesh,
  1372. ProcessMesh101H7_t::R_StudioSoftwareProcessMesh,
  1373. ProcessMesh101S7_t::R_StudioSoftwareProcessMesh,
  1374. ProcessMesh101M7_t::R_StudioSoftwareProcessMesh,
  1375. ProcessMesh110H7_t::R_StudioSoftwareProcessMesh,
  1376. ProcessMesh110S7_t::R_StudioSoftwareProcessMesh,
  1377. ProcessMesh110M7_t::R_StudioSoftwareProcessMesh,
  1378. ProcessMesh111H7_t::R_StudioSoftwareProcessMesh,
  1379. ProcessMesh111S7_t::R_StudioSoftwareProcessMesh,
  1380. ProcessMesh111M7_t::R_StudioSoftwareProcessMesh,
  1381. #endif
  1382. #if !defined( _X360 )
  1383. ProcessMesh000H8_t::R_StudioSoftwareProcessMesh,
  1384. ProcessMesh000S8_t::R_StudioSoftwareProcessMesh,
  1385. ProcessMesh000M8_t::R_StudioSoftwareProcessMesh,
  1386. #endif
  1387. ProcessMesh001H8_t::R_StudioSoftwareProcessMesh,
  1388. ProcessMesh001S8_t::R_StudioSoftwareProcessMesh,
  1389. ProcessMesh001M8_t::R_StudioSoftwareProcessMesh,
  1390. #if !defined( _X360 )
  1391. ProcessMesh010H8_t::R_StudioSoftwareProcessMesh,
  1392. ProcessMesh010S8_t::R_StudioSoftwareProcessMesh,
  1393. ProcessMesh010M8_t::R_StudioSoftwareProcessMesh,
  1394. #endif
  1395. ProcessMesh011H8_t::R_StudioSoftwareProcessMesh,
  1396. ProcessMesh011S8_t::R_StudioSoftwareProcessMesh,
  1397. ProcessMesh011M8_t::R_StudioSoftwareProcessMesh,
  1398. #if !defined( _X360 )
  1399. ProcessMesh100H8_t::R_StudioSoftwareProcessMesh,
  1400. ProcessMesh100S8_t::R_StudioSoftwareProcessMesh,
  1401. ProcessMesh100M8_t::R_StudioSoftwareProcessMesh,
  1402. #endif
  1403. ProcessMesh101H8_t::R_StudioSoftwareProcessMesh,
  1404. ProcessMesh101S8_t::R_StudioSoftwareProcessMesh,
  1405. ProcessMesh101M8_t::R_StudioSoftwareProcessMesh,
  1406. #if !defined( _X360 )
  1407. ProcessMesh110H8_t::R_StudioSoftwareProcessMesh,
  1408. ProcessMesh110S8_t::R_StudioSoftwareProcessMesh,
  1409. ProcessMesh110M8_t::R_StudioSoftwareProcessMesh,
  1410. #endif
  1411. ProcessMesh111H8_t::R_StudioSoftwareProcessMesh,
  1412. ProcessMesh111S8_t::R_StudioSoftwareProcessMesh,
  1413. ProcessMesh111M8_t::R_StudioSoftwareProcessMesh,
  1414. };
  1415. inline const mstudio_meshvertexdata_t * GetFatVertexData( mstudiomesh_t * pMesh, studiohdr_t * pStudioHdr )
  1416. {
  1417. if ( !pMesh->pModel()->CacheVertexData( pStudioHdr ) )
  1418. {
  1419. // not available yet
  1420. return NULL;
  1421. }
  1422. const mstudio_meshvertexdata_t *pVertData = pMesh->GetVertexData( pStudioHdr );
  1423. Assert( pVertData );
  1424. if ( !pVertData )
  1425. {
  1426. static unsigned int warnCount = 0;
  1427. if ( warnCount++ < 20 )
  1428. Warning( "ERROR: model verts have been compressed, cannot render! (use \"-no_compressed_vvds\")" );
  1429. }
  1430. return pVertData;
  1431. }
  1432. void CStudioRender::R_StudioSoftwareProcessMesh( mstudiomesh_t* pmesh, CMeshBuilder& meshBuilder,
  1433. int numVertices, unsigned short* pGroupToMesh, StudioModelLighting_t lighting, bool doFlex, float r_blend,
  1434. bool bNeedsTangentSpace, bool bDX8Vertex, IMaterial *pMaterial )
  1435. {
  1436. unsigned int nAlphaMask = RoundFloatToInt( r_blend * 255.0f );
  1437. nAlphaMask = clamp( nAlphaMask, 0, 255 );
  1438. nAlphaMask <<= 24;
  1439. // FIXME: Use function pointers to simplify this?!?
  1440. int idx;
  1441. if ( IsPC() )
  1442. {
  1443. idx = bDX8Vertex * 24 + bNeedsTangentSpace * 12 + doFlex * 6 + MathLib_SSEEnabled() * 3 + lighting;
  1444. }
  1445. else
  1446. {
  1447. idx = bNeedsTangentSpace * 6 + doFlex * 3 + lighting;
  1448. }
  1449. const mstudio_meshvertexdata_t *pVertData = GetFatVertexData( pmesh, m_pStudioHdr );
  1450. if ( pVertData )
  1451. {
  1452. // invoke the software mesh processing handler
  1453. g_SoftwareProcessMeshFunc[idx]( pVertData, m_PoseToWorld, m_VertexCache, meshBuilder, numVertices, pGroupToMesh, nAlphaMask, pMaterial );
  1454. }
  1455. }
  1456. static void R_SlowTransformVert( const Vector *pSrcPos, const Vector *pSrcNorm,
  1457. matrix3x4_t *pSkinMat, VectorAligned &pos, VectorAligned &norm )
  1458. {
  1459. pos.x = pSrcPos->x * (*pSkinMat)[0][0] + pSrcPos->y * (*pSkinMat)[0][1] + pSrcPos->z * (*pSkinMat)[0][2] + (*pSkinMat)[0][3];
  1460. norm.x = pSrcNorm->x * (*pSkinMat)[0][0] + pSrcNorm->y * (*pSkinMat)[0][1] + pSrcNorm->z * (*pSkinMat)[0][2];
  1461. pos.y = pSrcPos->x * (*pSkinMat)[1][0] + pSrcPos->y * (*pSkinMat)[1][1] + pSrcPos->z * (*pSkinMat)[1][2] + (*pSkinMat)[1][3];
  1462. norm.y = pSrcNorm->x * (*pSkinMat)[1][0] + pSrcNorm->y * (*pSkinMat)[1][1] + pSrcNorm->z * (*pSkinMat)[1][2];
  1463. pos.z = pSrcPos->x * (*pSkinMat)[2][0] + pSrcPos->y * (*pSkinMat)[2][1] + pSrcPos->z * (*pSkinMat)[2][2] + (*pSkinMat)[2][3];
  1464. norm.z = pSrcNorm->x * (*pSkinMat)[2][0] + pSrcNorm->y * (*pSkinMat)[2][1] + pSrcNorm->z * (*pSkinMat)[2][2];
  1465. }
  1466. static void R_SlowTransformVert( const Vector *pSrcPos, const Vector *pSrcNorm, const Vector4D *pSrcTangentS,
  1467. matrix3x4_t *pSkinMat, VectorAligned &pos, VectorAligned &norm, VectorAligned &tangentS )
  1468. {
  1469. pos.x = pSrcPos->x * (*pSkinMat)[0][0] + pSrcPos->y * (*pSkinMat)[0][1] + pSrcPos->z * (*pSkinMat)[0][2] + (*pSkinMat)[0][3];
  1470. norm.x = pSrcNorm->x * (*pSkinMat)[0][0] + pSrcNorm->y * (*pSkinMat)[0][1] + pSrcNorm->z * (*pSkinMat)[0][2];
  1471. tangentS.x = pSrcTangentS->x * (*pSkinMat)[0][0] + pSrcTangentS->y * (*pSkinMat)[0][1] + pSrcTangentS->z * (*pSkinMat)[0][2];
  1472. pos.y = pSrcPos->x * (*pSkinMat)[1][0] + pSrcPos->y * (*pSkinMat)[1][1] + pSrcPos->z * (*pSkinMat)[1][2] + (*pSkinMat)[1][3];
  1473. norm.y = pSrcNorm->x * (*pSkinMat)[1][0] + pSrcNorm->y * (*pSkinMat)[1][1] + pSrcNorm->z * (*pSkinMat)[1][2];
  1474. tangentS.y = pSrcTangentS->x * (*pSkinMat)[1][0] + pSrcTangentS->y * (*pSkinMat)[1][1] + pSrcTangentS->z * (*pSkinMat)[1][2];
  1475. pos.z = pSrcPos->x * (*pSkinMat)[2][0] + pSrcPos->y * (*pSkinMat)[2][1] + pSrcPos->z * (*pSkinMat)[2][2] + (*pSkinMat)[2][3];
  1476. norm.z = pSrcNorm->x * (*pSkinMat)[2][0] + pSrcNorm->y * (*pSkinMat)[2][1] + pSrcNorm->z * (*pSkinMat)[2][2];
  1477. tangentS.z = pSrcTangentS->x * (*pSkinMat)[2][0] + pSrcTangentS->y * (*pSkinMat)[2][1] + pSrcTangentS->z * (*pSkinMat)[2][2];
  1478. }
  1479. void CStudioRender::R_StudioSoftwareProcessMesh_Normals( mstudiomesh_t* pmesh, CMeshBuilder& meshBuilder,
  1480. int numVertices, unsigned short* pGroupToMesh, StudioModelLighting_t lighting, bool doFlex, float r_blend,
  1481. bool bShowNormals, bool bShowTangentFrame )
  1482. {
  1483. ALIGN16 matrix3x4_t temp ALIGN16_POST;
  1484. ALIGN16 matrix3x4_t *pSkinMat ALIGN16_POST;
  1485. Vector *pSrcPos = NULL;
  1486. Vector *pSrcNorm = NULL;
  1487. Vector4D *pSrcTangentS = NULL;
  1488. VectorAligned norm, pos, tangentS, tangentT;
  1489. // Gets at the vertex data
  1490. const mstudio_meshvertexdata_t *vertData = GetFatVertexData( pmesh, m_pStudioHdr );
  1491. if ( !vertData )
  1492. {
  1493. // not available
  1494. return;
  1495. }
  1496. if ( bShowTangentFrame && !vertData->HasTangentData() )
  1497. return;
  1498. mstudiovertex_t *pVertices = vertData->Vertex( 0 );
  1499. Vector4D *pTangentS = NULL;
  1500. Vector4D tang;
  1501. if ( bShowTangentFrame )
  1502. {
  1503. pTangentS = vertData->TangentS( 0 );
  1504. }
  1505. for ( int j=0; j < numVertices; j++ )
  1506. {
  1507. int n = pGroupToMesh[j];
  1508. mstudiovertex_t &vert = pVertices[n];
  1509. if ( bShowTangentFrame )
  1510. {
  1511. tang = pTangentS[n];
  1512. }
  1513. pSkinMat = ComputeSkinMatrix( vert.m_BoneWeights, m_PoseToWorld, temp );
  1514. // transform into world space
  1515. if ( m_VertexCache.IsVertexFlexed(n) )
  1516. {
  1517. CachedPosNormTan_t* pFlexedVertex = m_VertexCache.GetFlexVertex(n);
  1518. pSrcPos = &pFlexedVertex->m_Position;
  1519. pSrcNorm = &pFlexedVertex->m_Normal;
  1520. if ( bShowTangentFrame )
  1521. {
  1522. pSrcTangentS = &pFlexedVertex->m_TangentS;
  1523. }
  1524. }
  1525. else
  1526. {
  1527. pSrcPos = &vert.m_vecPosition;
  1528. pSrcNorm = &vert.m_vecNormal;
  1529. if ( bShowTangentFrame )
  1530. {
  1531. pSrcTangentS = &tang;
  1532. }
  1533. }
  1534. // Transform the vert into world space
  1535. if ( bShowTangentFrame && ( pSrcTangentS != NULL ) )
  1536. {
  1537. R_SlowTransformVert( pSrcPos, pSrcNorm, pSrcTangentS, pSkinMat, pos, norm, tangentS );
  1538. }
  1539. else
  1540. {
  1541. R_SlowTransformVert( pSrcPos, pSrcNorm, pSkinMat, pos, norm );
  1542. }
  1543. if ( bShowNormals )
  1544. {
  1545. meshBuilder.Position3fv( pos.Base() );
  1546. meshBuilder.Color3f( 0.0f, 0.0f, 1.0f );
  1547. meshBuilder.AdvanceVertex();
  1548. Vector normalPos;
  1549. normalPos = pos + norm * 0.5f;
  1550. meshBuilder.Position3fv( normalPos.Base() );
  1551. meshBuilder.Color3f( 0.0f, 0.0f, 1.0f );
  1552. meshBuilder.AdvanceVertex();
  1553. }
  1554. if ( bShowTangentFrame && ( pSrcTangentS != NULL) )
  1555. {
  1556. // TangentS
  1557. meshBuilder.Position3fv( pos.Base() );
  1558. meshBuilder.Color3f( 1.0f, 0.0f, 0.0f );
  1559. meshBuilder.AdvanceVertex();
  1560. Vector vTangentSPos;
  1561. vTangentSPos = pos + tangentS * 0.5f;
  1562. meshBuilder.Position3fv( vTangentSPos.Base() );
  1563. meshBuilder.Color3f( 1.0f, 0.0f, 0.0f );
  1564. meshBuilder.AdvanceVertex();
  1565. // TangentT
  1566. meshBuilder.Position3fv( pos.Base() );
  1567. meshBuilder.Color3f( 0.0f, 1.0f, 0.0f );
  1568. meshBuilder.AdvanceVertex();
  1569. // Compute tangentT from normal and tangentS
  1570. CrossProduct( norm, tangentS, tangentT );
  1571. Vector vTangentTPos;
  1572. vTangentTPos = pos + tangentT * 0.5f;
  1573. meshBuilder.Position3fv( vTangentTPos.Base() );
  1574. meshBuilder.Color3f( 0.0f, 1.0f, 0.0f );
  1575. meshBuilder.AdvanceVertex();
  1576. } // end tacking on tangentS and tangetT line segments
  1577. }
  1578. }
  1579. #pragma warning (default:4701)
  1580. template
  1581. void CCachedRenderData::ComputeFlexedVertex_StreamOffset<mstudiovertanim_t>( studiohdr_t *pStudioHdr, mstudioflex_t *pflex,
  1582. mstudiovertanim_t *pvanim, int vertCount, float w1, float w2, float w3, float w4 );
  1583. void CStudioRender::R_StudioProcessFlexedMesh_StreamOffset( mstudiomesh_t* pmesh, int lod )
  1584. {
  1585. VPROF_BUDGET( "ProcessFlexedMesh_SO", _T("HW Morphing") );
  1586. if ( m_VertexCache.IsFlexComputationDone() )
  1587. return;
  1588. int vertCount = pmesh->vertexdata.numLODVertexes[lod];
  1589. m_VertexCache.SetupComputation( pmesh, true );
  1590. mstudioflex_t *pflex = pmesh->pFlex( 0 );
  1591. for (int i = 0; i < pmesh->numflexes; i++)
  1592. {
  1593. float w1 = RampFlexWeight( pflex[i], m_pFlexWeights[ pflex[i].flexdesc ] );
  1594. float w2 = RampFlexWeight( pflex[i], m_pFlexDelayedWeights[ pflex[i].flexdesc ] );
  1595. float w3, w4;
  1596. if ( pflex[i].flexpair != 0)
  1597. {
  1598. w3 = RampFlexWeight( pflex[i], m_pFlexWeights[ pflex[i].flexpair ] );
  1599. w4 = RampFlexWeight( pflex[i], m_pFlexDelayedWeights[ pflex[i].flexpair ] );
  1600. }
  1601. else
  1602. {
  1603. w3 = w1;
  1604. w4 = w2;
  1605. }
  1606. // Move on if the weights for this flex are sufficiently small
  1607. if (w1 > -0.001 && w1 < 0.001 && w2 > -0.001 && w2 < 0.001)
  1608. {
  1609. if (w3 > -0.001 && w3 < 0.001 && w4 > -0.001 && w4 < 0.001)
  1610. {
  1611. continue;
  1612. }
  1613. }
  1614. #ifdef PLATFORM_WINDOWS
  1615. if ( pflex[i].vertanimtype == STUDIO_VERT_ANIM_NORMAL )
  1616. {
  1617. mstudiovertanim_t *pvanim = pflex[i].pVertanim( 0 );
  1618. m_VertexCache.ComputeFlexedVertex_StreamOffset_Optimized( m_pStudioHdr, &pflex[i], pvanim, vertCount, w1, w2, w3, w4 );
  1619. }
  1620. else
  1621. {
  1622. mstudiovertanim_wrinkle_t *pvanim = pflex[i].pVertanimWrinkle( 0 );
  1623. m_VertexCache.ComputeFlexedVertexWrinkle_StreamOffset_Optimized( m_pStudioHdr, &pflex[i], pvanim, vertCount, w1, w2, w3, w4 );
  1624. }
  1625. #else // PLATFORM_WINDOWS
  1626. if ( pflex[i].vertanimtype == STUDIO_VERT_ANIM_NORMAL )
  1627. {
  1628. mstudiovertanim_t *pvanim = pflex[i].pVertanim( 0 );
  1629. m_VertexCache.ComputeFlexedVertex_StreamOffset( m_pStudioHdr, &pflex[i], pvanim, vertCount, w1, w2, w3, w4 );
  1630. }
  1631. else
  1632. {
  1633. mstudiovertanim_wrinkle_t *pvanim = pflex[i].pVertanimWrinkle( 0 );
  1634. m_VertexCache.ComputeFlexedVertex_StreamOffset( m_pStudioHdr, &pflex[i], pvanim, vertCount, w1, w2, w3, w4 );
  1635. }
  1636. #endif // PLATFORM_WINDOWS
  1637. }
  1638. }
  1639. //-----------------------------------------------------------------------------
  1640. // Purpose:
  1641. //
  1642. // ** Only execute this function if device supports stream offset **
  1643. //
  1644. // Input : pGroup - pointer to a studio mesh group
  1645. // Output : none
  1646. //-----------------------------------------------------------------------------
  1647. void CStudioRender::R_StudioFlexMeshGroup( studiomeshgroup_t *pGroup )
  1648. {
  1649. VPROF_BUDGET( "R_StudioFlexMeshGroup", VPROF_BUDGETGROUP_MODEL_RENDERING );
  1650. CMeshBuilder meshBuilder;
  1651. int nVertexOffsetInBytes = 0;
  1652. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1653. IMesh *pMesh = pRenderContext->GetFlexMesh();
  1654. meshBuilder.Begin( pMesh, MATERIAL_HETEROGENOUS, pGroup->m_NumVertices, 0, &nVertexOffsetInBytes );
  1655. // Just pos and norm deltas (tangents use same deltas as normals)
  1656. for ( int j=0; j < pGroup->m_NumVertices; j++)
  1657. {
  1658. int n = pGroup->m_pGroupIndexToMeshIndex[j];
  1659. if ( m_VertexCache.IsThinVertexFlexed(n) )
  1660. {
  1661. CachedPosNorm_t *pIn = m_VertexCache.GetThinFlexVertex(n);
  1662. meshBuilder.Position3fv( pIn->m_Position.Base() );
  1663. meshBuilder.NormalDelta3fv( pIn->m_Normal.Base() );
  1664. meshBuilder.Wrinkle1f( pIn->m_Position.w );
  1665. }
  1666. else
  1667. {
  1668. meshBuilder.Position3f( 0.0f, 0.0f, 0.0f );
  1669. meshBuilder.NormalDelta3f( 0.0f, 0.0f, 0.0f );
  1670. meshBuilder.Wrinkle1f( 0.0f );
  1671. }
  1672. meshBuilder.AdvanceVertex();
  1673. }
  1674. meshBuilder.End( false, false );
  1675. pGroup->m_pMesh->SetFlexMesh( pMesh, nVertexOffsetInBytes );
  1676. }
  1677. //-----------------------------------------------------------------------------
  1678. // Processes a flexed mesh to be hw skinned
  1679. //-----------------------------------------------------------------------------
  1680. void CStudioRender::R_StudioProcessFlexedMesh( mstudiomesh_t* pmesh, CMeshBuilder& meshBuilder,
  1681. int numVertices, unsigned short* pGroupToMesh )
  1682. {
  1683. PROFILE_STUDIO("FlexMeshBuilder");
  1684. Vector4D *pStudioTangentS;
  1685. // get the vertex data
  1686. const mstudio_meshvertexdata_t *vertData = GetFatVertexData( pmesh, m_pStudioHdr );
  1687. if ( !vertData )
  1688. {
  1689. // not available
  1690. return;
  1691. }
  1692. mstudiovertex_t *pVertices = vertData->Vertex( 0 );
  1693. if (vertData->HasTangentData())
  1694. {
  1695. pStudioTangentS = vertData->TangentS( 0 );
  1696. Assert( pStudioTangentS->w == -1.0f || pStudioTangentS->w == 1.0f );
  1697. for ( int j=0; j < numVertices ; j++)
  1698. {
  1699. int n = pGroupToMesh[j];
  1700. mstudiovertex_t &vert = pVertices[n];
  1701. // FIXME: For now, flexed hw-skinned meshes can only have one bone
  1702. // The data must exist in the 0th hardware matrix
  1703. // Here, we are doing HW skinning, so we need to simply copy over the flex
  1704. if ( m_VertexCache.IsVertexFlexed(n) )
  1705. {
  1706. CachedPosNormTan_t* pFlexedVertex = m_VertexCache.GetFlexVertex(n);
  1707. meshBuilder.Position3fv( pFlexedVertex->m_Position.Base() );
  1708. meshBuilder.BoneWeight( 0, 1.0f );
  1709. meshBuilder.BoneWeight( 1, 0.0f );
  1710. meshBuilder.BoneWeight( 2, 0.0f );
  1711. meshBuilder.BoneWeight( 3, 0.0f );
  1712. meshBuilder.BoneMatrix( 0, 0 );
  1713. meshBuilder.BoneMatrix( 1, 0 );
  1714. meshBuilder.BoneMatrix( 2, 0 );
  1715. meshBuilder.BoneMatrix( 3, 0 );
  1716. meshBuilder.Normal3fv( pFlexedVertex->m_Normal.Base() );
  1717. meshBuilder.TexCoord2fv( 0, vert.m_vecTexCoord.Base() );
  1718. Assert( pFlexedVertex->m_TangentS.w == -1.0f || pFlexedVertex->m_TangentS.w == 1.0f );
  1719. meshBuilder.UserData( pFlexedVertex->m_TangentS.Base() );
  1720. }
  1721. else
  1722. {
  1723. meshBuilder.Position3fv( vert.m_vecPosition.Base() );
  1724. meshBuilder.BoneWeight( 0, 1.0f );
  1725. meshBuilder.BoneWeight( 1, 0.0f );
  1726. meshBuilder.BoneWeight( 2, 0.0f );
  1727. meshBuilder.BoneWeight( 3, 0.0f );
  1728. meshBuilder.BoneMatrix( 0, 0 );
  1729. meshBuilder.BoneMatrix( 1, 0 );
  1730. meshBuilder.BoneMatrix( 2, 0 );
  1731. meshBuilder.BoneMatrix( 3, 0 );
  1732. meshBuilder.Normal3fv( vert.m_vecNormal.Base() );
  1733. meshBuilder.TexCoord2fv( 0, vert.m_vecTexCoord.Base() );
  1734. Assert( pStudioTangentS[n].w == -1.0f || pStudioTangentS[n].w == 1.0f );
  1735. meshBuilder.UserData( pStudioTangentS[n].Base() );
  1736. }
  1737. meshBuilder.AdvanceVertex();
  1738. }
  1739. }
  1740. else
  1741. {
  1742. // no TangentS, replicated code to save inner conditional
  1743. for ( int j=0; j < numVertices ; j++)
  1744. {
  1745. int n = pGroupToMesh[j];
  1746. mstudiovertex_t &vert = pVertices[n];
  1747. // FIXME: For now, flexed hw-skinned meshes can only have one bone
  1748. // The data must exist in the 0th hardware matrix
  1749. // Here, we are doing HW skinning, so we need to simply copy over the flex
  1750. if ( m_VertexCache.IsVertexFlexed(n) )
  1751. {
  1752. CachedPosNormTan_t* pFlexedVertex = m_VertexCache.GetFlexVertex(n);
  1753. meshBuilder.Position3fv( pFlexedVertex->m_Position.Base() );
  1754. meshBuilder.BoneWeight( 0, 1.0f );
  1755. meshBuilder.BoneWeight( 1, 0.0f );
  1756. meshBuilder.BoneWeight( 2, 0.0f );
  1757. meshBuilder.BoneWeight( 3, 0.0f );
  1758. meshBuilder.BoneMatrix( 0, 0 );
  1759. meshBuilder.BoneMatrix( 1, 0 );
  1760. meshBuilder.BoneMatrix( 2, 0 );
  1761. meshBuilder.BoneMatrix( 3, 0 );
  1762. meshBuilder.Normal3fv( pFlexedVertex->m_Normal.Base() );
  1763. }
  1764. else
  1765. {
  1766. meshBuilder.Position3fv( vert.m_vecPosition.Base() );
  1767. meshBuilder.BoneWeight( 0, 1.0f );
  1768. meshBuilder.BoneWeight( 1, 0.0f );
  1769. meshBuilder.BoneWeight( 2, 0.0f );
  1770. meshBuilder.BoneWeight( 3, 0.0f );
  1771. meshBuilder.BoneMatrix( 0, 0 );
  1772. meshBuilder.BoneMatrix( 1, 0 );
  1773. meshBuilder.BoneMatrix( 2, 0 );
  1774. meshBuilder.BoneMatrix( 3, 0 );
  1775. meshBuilder.Normal3fv( vert.m_vecNormal.Base() );
  1776. }
  1777. meshBuilder.TexCoord2fv( 0, vert.m_vecTexCoord.Base() );
  1778. meshBuilder.AdvanceVertex();
  1779. }
  1780. }
  1781. }
  1782. //-----------------------------------------------------------------------------
  1783. // Restores the static mesh
  1784. //-----------------------------------------------------------------------------
  1785. template<VertexCompressionType_t T> void CStudioRender::R_StudioRestoreMesh( mstudiomesh_t* pmesh, studiomeshgroup_t* pMeshData )
  1786. {
  1787. Vector4D *pStudioTangentS;
  1788. if ( IsX360() )
  1789. return;
  1790. // get at the vertex data
  1791. const mstudio_meshvertexdata_t *vertData = GetFatVertexData( pmesh, m_pStudioHdr );
  1792. if ( !vertData )
  1793. {
  1794. // not available
  1795. return;
  1796. }
  1797. mstudiovertex_t *pVertices = vertData->Vertex( 0 );
  1798. if (vertData->HasTangentData())
  1799. {
  1800. pStudioTangentS = vertData->TangentS( 0 );
  1801. }
  1802. else
  1803. {
  1804. pStudioTangentS = NULL;
  1805. }
  1806. CMeshBuilder meshBuilder;
  1807. meshBuilder.BeginModify( pMeshData->m_pMesh );
  1808. meshBuilder.SetCompressionType( T );
  1809. for ( int j=0; j < meshBuilder.VertexCount() ; j++)
  1810. {
  1811. meshBuilder.SelectVertex(j);
  1812. int n = pMeshData->m_pGroupIndexToMeshIndex[j];
  1813. mstudiovertex_t &vert = pVertices[n];
  1814. meshBuilder.Position3fv( vert.m_vecPosition.Base() );
  1815. meshBuilder.CompressedNormal3fv<T>( vert.m_vecNormal.Base() );
  1816. meshBuilder.TexCoord2fv( 0, vert.m_vecTexCoord.Base() );
  1817. if (pStudioTangentS)
  1818. {
  1819. Assert( pStudioTangentS[n].w == -1.0f || pStudioTangentS[n].w == 1.0f );
  1820. meshBuilder.CompressedUserData<T>( pStudioTangentS[n].Base() );
  1821. }
  1822. meshBuilder.Color4ub( 255, 255, 255, 255 );
  1823. }
  1824. meshBuilder.EndModify();
  1825. }
  1826. //-----------------------------------------------------------------------------
  1827. // Draws a mesh using hardware + software skinning
  1828. //-----------------------------------------------------------------------------
  1829. int CStudioRender::R_StudioDrawGroupHWSkin( IMatRenderContext *pRenderContext, studiomeshgroup_t* pGroup, IMesh* pMesh, ColorMeshInfo_t * pColorMeshInfo )
  1830. {
  1831. PROFILE_STUDIO("HwSkin");
  1832. int numTrianglesRendered = 0;
  1833. #if PIX_ENABLE
  1834. char szPIXEventName[128];
  1835. sprintf( szPIXEventName, "R_StudioDrawGroupHWSkin (%s)", m_pStudioHdr->name ); // PIX
  1836. PIXEVENT( pRenderContext, szPIXEventName );
  1837. #endif
  1838. if ( m_pStudioHdr->numbones == 1 )
  1839. {
  1840. pRenderContext->MatrixMode( MATERIAL_MODEL );
  1841. pRenderContext->LoadMatrix( m_PoseToWorld[0] );
  1842. // a single bone means all verts rigidly assigned
  1843. // any bonestatechange would needlessly re-load the same matrix
  1844. // xbox can skip further hw skinning, seems ok for pc too
  1845. pRenderContext->SetNumBoneWeights( 0 );
  1846. }
  1847. if ( pColorMeshInfo )
  1848. pMesh->SetColorMesh( pColorMeshInfo->m_pMesh, pColorMeshInfo->m_nVertOffsetInBytes );
  1849. else
  1850. pMesh->SetColorMesh( NULL, 0 );
  1851. for (int j = 0; j < pGroup->m_NumStrips; ++j)
  1852. {
  1853. OptimizedModel::StripHeader_t* pStrip = &pGroup->m_pStripData[j];
  1854. if ( m_pStudioHdr->numbones > 1 )
  1855. {
  1856. // Reset bone state if we're hardware skinning
  1857. pRenderContext->SetNumBoneWeights( pStrip->numBones );
  1858. for (int k = 0; k < pStrip->numBoneStateChanges; ++k)
  1859. {
  1860. OptimizedModel::BoneStateChangeHeader_t* pStateChange = pStrip->pBoneStateChange(k);
  1861. if ( pStateChange->newBoneID < 0 )
  1862. break;
  1863. pRenderContext->LoadBoneMatrix( pStateChange->hardwareID, m_PoseToWorld[pStateChange->newBoneID] );
  1864. }
  1865. }
  1866. pMesh->SetPrimitiveType( pStrip->flags & OptimizedModel::STRIP_IS_TRISTRIP ?
  1867. MATERIAL_TRIANGLE_STRIP : MATERIAL_TRIANGLES );
  1868. pMesh->Draw( pStrip->indexOffset, pStrip->numIndices );
  1869. numTrianglesRendered += pGroup->m_pUniqueTris[j];
  1870. }
  1871. pMesh->SetColorMesh( NULL, 0 );
  1872. return numTrianglesRendered;
  1873. }
  1874. int CStudioRender::R_StudioDrawGroupSWSkin( studiomeshgroup_t* pGroup, IMesh* pMesh )
  1875. {
  1876. int numTrianglesRendered = 0;
  1877. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1878. // Disable skinning
  1879. pRenderContext->SetNumBoneWeights( 0 );
  1880. for (int j = 0; j < pGroup->m_NumStrips; ++j)
  1881. {
  1882. OptimizedModel::StripHeader_t* pStrip = &pGroup->m_pStripData[j];
  1883. // Choose our primitive type
  1884. pMesh->SetPrimitiveType( pStrip->flags & OptimizedModel::STRIP_IS_TRISTRIP ?
  1885. MATERIAL_TRIANGLE_STRIP : MATERIAL_TRIANGLES );
  1886. pMesh->Draw( pStrip->indexOffset, pStrip->numIndices );
  1887. numTrianglesRendered += pGroup->m_pUniqueTris[j];
  1888. }
  1889. return numTrianglesRendered;
  1890. }
  1891. //-----------------------------------------------------------------------------
  1892. // Sets up the hw flex mesh
  1893. //-----------------------------------------------------------------------------
  1894. void CStudioRender::ComputeFlexWeights( int nFlexCount, mstudioflex_t *pFlex, MorphWeight_t *pWeights )
  1895. {
  1896. for ( int i = 0; i < nFlexCount; ++i, ++pFlex )
  1897. {
  1898. MorphWeight_t &weight = pWeights[i];
  1899. weight.m_pWeight[MORPH_WEIGHT] = RampFlexWeight( *pFlex, m_pFlexWeights[ pFlex->flexdesc ] );
  1900. weight.m_pWeight[MORPH_WEIGHT_LAGGED] = RampFlexWeight( *pFlex, m_pFlexDelayedWeights[ pFlex->flexdesc ] );
  1901. if ( pFlex->flexpair != 0 )
  1902. {
  1903. weight.m_pWeight[MORPH_WEIGHT_STEREO] = RampFlexWeight( *pFlex, m_pFlexWeights[ pFlex->flexpair ] );
  1904. weight.m_pWeight[MORPH_WEIGHT_STEREO_LAGGED] = RampFlexWeight( *pFlex, m_pFlexDelayedWeights[ pFlex->flexpair ] );
  1905. }
  1906. else
  1907. {
  1908. weight.m_pWeight[MORPH_WEIGHT_STEREO] = weight.m_pWeight[MORPH_WEIGHT];
  1909. weight.m_pWeight[MORPH_WEIGHT_STEREO_LAGGED] = weight.m_pWeight[MORPH_WEIGHT_LAGGED];
  1910. }
  1911. }
  1912. }
  1913. //-----------------------------------------------------------------------------
  1914. // Computes a vertex format to use
  1915. //-----------------------------------------------------------------------------
  1916. inline VertexFormat_t CStudioRender::ComputeSWSkinVertexFormat( IMaterial *pMaterial ) const
  1917. {
  1918. bool bDX8OrHigherVertex = IsX360() || ( UserDataSize( pMaterial->GetVertexFormat() ) != 0 );
  1919. VertexFormat_t fmt = VERTEX_POSITION | VERTEX_NORMAL | VERTEX_COLOR | VERTEX_BONE_INDEX |
  1920. VERTEX_BONEWEIGHT( 2 ) | VERTEX_TEXCOORD_SIZE( 0, 2 );
  1921. if ( bDX8OrHigherVertex )
  1922. {
  1923. fmt |= VERTEX_USERDATA_SIZE( 4 );
  1924. }
  1925. return fmt;
  1926. }
  1927. //-----------------------------------------------------------------------------
  1928. // Draws the mesh as tristrips using hardware
  1929. //-----------------------------------------------------------------------------
  1930. int CStudioRender::R_StudioDrawStaticMesh( IMatRenderContext *pRenderContext, mstudiomesh_t* pmesh,
  1931. studiomeshgroup_t* pGroup, StudioModelLighting_t lighting,
  1932. float r_blend, IMaterial* pMaterial, int lod, ColorMeshInfo_t *pColorMeshes )
  1933. {
  1934. MatSysQueueMark( g_pMaterialSystem, "R_StudioDrawStaticMesh\n" );
  1935. VPROF( "R_StudioDrawStaticMesh" );
  1936. int numTrianglesRendered = 0;
  1937. bool bDoSoftwareLighting = !pColorMeshes &&
  1938. ((m_pRC->m_Config.bSoftwareSkin != 0) || m_pRC->m_Config.bDrawNormals || m_pRC->m_Config.bDrawTangentFrame ||
  1939. (pMaterial ? pMaterial->NeedsSoftwareSkinning() : false) ||
  1940. (m_pRC->m_Config.bSoftwareLighting != 0) ||
  1941. ((lighting != LIGHTING_HARDWARE) && (lighting != LIGHTING_MOUTH) ));
  1942. // software lighting case
  1943. if ( bDoSoftwareLighting || m_pRC->m_Config.m_bStatsMode == true )
  1944. {
  1945. if ( m_pRC->m_Config.bNoSoftware )
  1946. return 0;
  1947. bool bNeedsTangentSpace = pMaterial ? pMaterial->NeedsTangentSpace() : false;
  1948. pRenderContext->MatrixMode( MATERIAL_MODEL );
  1949. pRenderContext->LoadIdentity();
  1950. // Hardcode the vertex format to a well-known format to make sw skin code faster
  1951. VertexFormat_t fmt = ComputeSWSkinVertexFormat( pMaterial );
  1952. bool bDX8Vertex = ( UserDataSize( fmt ) != 0 );
  1953. if ( m_pRC->m_Config.m_bStatsMode == false )
  1954. {
  1955. Assert( ( pGroup->m_Flags & ( MESHGROUP_IS_FLEXED | MESHGROUP_IS_DELTA_FLEXED ) ) == 0 );
  1956. }
  1957. CMeshBuilder meshBuilder;
  1958. IMesh* pMesh = pRenderContext->GetDynamicMeshEx( fmt, false, 0, pGroup->m_pMesh );
  1959. meshBuilder.Begin( pMesh, MATERIAL_HETEROGENOUS, pGroup->m_NumVertices, 0 );
  1960. R_StudioSoftwareProcessMesh( pmesh, meshBuilder,
  1961. pGroup->m_NumVertices, pGroup->m_pGroupIndexToMeshIndex,
  1962. lighting, false, r_blend, bNeedsTangentSpace, bDX8Vertex, pMaterial);
  1963. if ( m_pRC->m_Config.m_bStatsMode == true )
  1964. {
  1965. R_GatherStats( pGroup, meshBuilder, pMesh, pMaterial );
  1966. }
  1967. else
  1968. {
  1969. meshBuilder.End();
  1970. numTrianglesRendered = R_StudioDrawGroupSWSkin( pGroup, pMesh );
  1971. }
  1972. MatSysQueueMark( g_pMaterialSystem, "END R_StudioDrawStaticMesh\n" );
  1973. return numTrianglesRendered;
  1974. }
  1975. // Needed when we switch back and forth between hardware + software lighting
  1976. if ( IsPC() && pGroup->m_MeshNeedsRestore )
  1977. {
  1978. VertexCompressionType_t compressionType = CompressionType( pGroup->m_pMesh->GetVertexFormat() );
  1979. switch ( compressionType )
  1980. {
  1981. case VERTEX_COMPRESSION_ON:
  1982. R_StudioRestoreMesh<VERTEX_COMPRESSION_ON>( pmesh, pGroup );
  1983. case VERTEX_COMPRESSION_NONE:
  1984. default:
  1985. R_StudioRestoreMesh<VERTEX_COMPRESSION_NONE>( pmesh, pGroup );
  1986. break;
  1987. }
  1988. pGroup->m_MeshNeedsRestore = false;
  1989. }
  1990. // Build separate flex stream containing deltas, which will get copied into another vertex stream
  1991. bool bUseHWFlex = m_pRC->m_Config.m_bEnableHWMorph && pGroup->m_pMorph && !m_bDrawTranslucentSubModels;
  1992. bool bUseSOFlex = g_pMaterialSystemHardwareConfig->SupportsStreamOffset() && !bUseHWFlex;
  1993. if ( (pGroup->m_Flags & MESHGROUP_IS_DELTA_FLEXED) && m_pRC->m_Config.bFlex )
  1994. {
  1995. PIXEVENT( pRenderContext, "Delta Flex Processing" );
  1996. if ( bUseHWFlex )
  1997. {
  1998. pRenderContext->BindMorph( pGroup->m_pMorph );
  1999. }
  2000. if ( bUseSOFlex )
  2001. {
  2002. R_StudioProcessFlexedMesh_StreamOffset( pmesh, lod );
  2003. R_StudioFlexMeshGroup( pGroup );
  2004. }
  2005. }
  2006. // Draw it baby
  2007. if ( pColorMeshes && ( pGroup->m_ColorMeshID != -1 ) )
  2008. {
  2009. // draw using specified color mesh
  2010. numTrianglesRendered = R_StudioDrawGroupHWSkin( pRenderContext, pGroup, pGroup->m_pMesh, &(pColorMeshes[pGroup->m_ColorMeshID]) );
  2011. }
  2012. else
  2013. {
  2014. numTrianglesRendered = R_StudioDrawGroupHWSkin( pRenderContext, pGroup, pGroup->m_pMesh, NULL );
  2015. }
  2016. if ( ( pGroup->m_Flags & MESHGROUP_IS_DELTA_FLEXED ) && m_pRC->m_Config.bFlex )
  2017. {
  2018. if ( bUseHWFlex )
  2019. {
  2020. pRenderContext->BindMorph( NULL );
  2021. }
  2022. if ( bUseSOFlex )
  2023. {
  2024. pGroup->m_pMesh->DisableFlexMesh(); // clear flex stream
  2025. }
  2026. }
  2027. MatSysQueueMark( g_pMaterialSystem, "END2 R_StudioDrawStaticMesh\n" );
  2028. return numTrianglesRendered;
  2029. }
  2030. //-----------------------------------------------------------------------------
  2031. // Draws a dynamic mesh
  2032. //-----------------------------------------------------------------------------
  2033. int CStudioRender::R_StudioDrawDynamicMesh( IMatRenderContext *pRenderContext, mstudiomesh_t* pmesh,
  2034. studiomeshgroup_t* pGroup, StudioModelLighting_t lighting,
  2035. float r_blend, IMaterial* pMaterial, int lod )
  2036. {
  2037. VPROF( "R_StudioDrawDynamicMesh" );
  2038. bool doFlex = ((pGroup->m_Flags & MESHGROUP_IS_FLEXED) != 0) && m_pRC->m_Config.bFlex;
  2039. bool doSoftwareLighting = (m_pRC->m_Config.bSoftwareLighting != 0) ||
  2040. ((lighting != LIGHTING_HARDWARE) && (lighting != LIGHTING_MOUTH) );
  2041. bool swSkin = doSoftwareLighting || m_pRC->m_Config.bDrawNormals || m_pRC->m_Config.bDrawTangentFrame ||
  2042. ((pGroup->m_Flags & MESHGROUP_IS_HWSKINNED) == 0) ||
  2043. m_pRC->m_Config.bSoftwareSkin ||
  2044. ( pMaterial ? pMaterial->NeedsSoftwareSkinning() : false );
  2045. if ( !doFlex && !swSkin )
  2046. {
  2047. return R_StudioDrawStaticMesh( pRenderContext, pmesh, pGroup, lighting, r_blend, pMaterial, lod, NULL );
  2048. }
  2049. // drawers before this might not need the vertexes, so don't pay the penalty of getting them
  2050. // everybody else past this point (flex or swskinning) expects to read vertexes
  2051. // get vertex data
  2052. const mstudio_meshvertexdata_t *vertData = GetFatVertexData( pmesh, m_pStudioHdr );
  2053. if ( !vertData )
  2054. {
  2055. // not available
  2056. return 0;
  2057. }
  2058. MatSysQueueMark( g_pMaterialSystem, "R_StudioDrawDynamicMesh\n" );
  2059. int numTrianglesRendered = 0;
  2060. #ifdef _DEBUG
  2061. const char *pDebugMaterialName = NULL;
  2062. if ( pMaterial )
  2063. {
  2064. pDebugMaterialName = pMaterial->GetName();
  2065. }
  2066. #endif
  2067. pRenderContext->MatrixMode( MATERIAL_MODEL );
  2068. pRenderContext->LoadIdentity();
  2069. // Software flex verts (not a delta stream)
  2070. if ( doFlex )
  2071. {
  2072. R_StudioFlexVerts( pmesh, lod );
  2073. }
  2074. IMesh* pMesh;
  2075. bool bNeedsTangentSpace = pMaterial ? pMaterial->NeedsTangentSpace() : false;
  2076. VertexFormat_t fmt = ComputeSWSkinVertexFormat( pMaterial );
  2077. bool bDX8Vertex = ( UserDataSize( fmt ) != 0 );
  2078. CMeshBuilder meshBuilder;
  2079. pMesh = pRenderContext->GetDynamicMeshEx( fmt, false, 0, pGroup->m_pMesh);
  2080. meshBuilder.Begin( pMesh, MATERIAL_HETEROGENOUS, pGroup->m_NumVertices, 0 );
  2081. if ( swSkin )
  2082. {
  2083. R_StudioSoftwareProcessMesh( pmesh, meshBuilder, pGroup->m_NumVertices,
  2084. pGroup->m_pGroupIndexToMeshIndex, lighting, doFlex, r_blend,
  2085. bNeedsTangentSpace, bDX8Vertex, pMaterial );
  2086. }
  2087. else if ( doFlex )
  2088. {
  2089. R_StudioProcessFlexedMesh( pmesh, meshBuilder, pGroup->m_NumVertices,
  2090. pGroup->m_pGroupIndexToMeshIndex );
  2091. }
  2092. meshBuilder.End();
  2093. // Draw it baby
  2094. if ( !swSkin )
  2095. {
  2096. numTrianglesRendered = R_StudioDrawGroupHWSkin( pRenderContext, pGroup, pMesh );
  2097. }
  2098. else
  2099. {
  2100. numTrianglesRendered = R_StudioDrawGroupSWSkin( pGroup, pMesh );
  2101. }
  2102. if ( m_pRC->m_Config.bDrawNormals || m_pRC->m_Config.bDrawTangentFrame )
  2103. {
  2104. pRenderContext->SetNumBoneWeights( 0 );
  2105. pRenderContext->Bind( m_pMaterialTangentFrame );
  2106. CMeshBuilder meshBuilder;
  2107. pMesh = pRenderContext->GetDynamicMesh( false );
  2108. meshBuilder.Begin( pMesh, MATERIAL_LINES, pGroup->m_NumVertices );
  2109. R_StudioSoftwareProcessMesh_Normals( pmesh, meshBuilder, pGroup->m_NumVertices,
  2110. pGroup->m_pGroupIndexToMeshIndex, lighting, doFlex, r_blend, m_pRC->m_Config.bDrawNormals, m_pRC->m_Config.bDrawTangentFrame );
  2111. meshBuilder.End( );
  2112. pMesh->Draw();
  2113. pRenderContext->Bind( pMaterial );
  2114. }
  2115. MatSysQueueMark( g_pMaterialSystem, "END R_StudioDrawDynamicMesh\n" );
  2116. return numTrianglesRendered;
  2117. }
  2118. //-----------------------------------------------------------------------------
  2119. // Sets the material vars for the eye vertex shader
  2120. //-----------------------------------------------------------------------------
  2121. static unsigned int eyeOriginCache = 0;
  2122. static unsigned int eyeUpCache = 0;
  2123. static unsigned int irisUCache = 0;
  2124. static unsigned int irisVCache = 0;
  2125. static unsigned int glintUCache = 0;
  2126. static unsigned int glintVCache = 0;
  2127. void CStudioRender::SetEyeMaterialVars( IMaterial* pMaterial, mstudioeyeball_t* peyeball,
  2128. Vector const& eyeOrigin, const matrix3x4_t& irisTransform, const matrix3x4_t& glintTransform )
  2129. {
  2130. if ( !pMaterial )
  2131. return;
  2132. IMaterialVar* pVar = pMaterial->FindVarFast( "$eyeorigin", &eyeOriginCache );
  2133. if (pVar)
  2134. {
  2135. pVar->SetVecValue( eyeOrigin.Base(), 3 );
  2136. }
  2137. pVar = pMaterial->FindVarFast( "$eyeup", &eyeUpCache );
  2138. if (pVar)
  2139. {
  2140. pVar->SetVecValue( peyeball->up.Base(), 3 );
  2141. }
  2142. pVar = pMaterial->FindVarFast( "$irisu", &irisUCache );
  2143. if (pVar)
  2144. {
  2145. pVar->SetVecValue( irisTransform[0], 4 );
  2146. }
  2147. pVar = pMaterial->FindVarFast( "$irisv", &irisVCache );
  2148. if (pVar)
  2149. {
  2150. pVar->SetVecValue( irisTransform[1], 4 );
  2151. }
  2152. pVar = pMaterial->FindVarFast( "$glintu", &glintUCache );
  2153. if (pVar)
  2154. {
  2155. pVar->SetVecValue( glintTransform[0], 4 );
  2156. }
  2157. pVar = pMaterial->FindVarFast( "$glintv", &glintVCache );
  2158. if (pVar)
  2159. {
  2160. pVar->SetVecValue( glintTransform[1], 4 );
  2161. }
  2162. }
  2163. //-----------------------------------------------------------------------------
  2164. // Specialized routine to draw the eyeball
  2165. //-----------------------------------------------------------------------------
  2166. static unsigned int glintCache = 0;
  2167. int CStudioRender::R_StudioDrawEyeball( IMatRenderContext *pRenderContext, mstudiomesh_t* pmesh, studiomeshdata_t* pMeshData,
  2168. StudioModelLighting_t lighting, IMaterial *pMaterial, int lod )
  2169. {
  2170. if ( !m_pRC->m_Config.bEyes )
  2171. {
  2172. return 0;
  2173. }
  2174. // FIXME: We could compile a static vertex buffer in this case
  2175. // if there's no flexed verts.
  2176. const mstudio_meshvertexdata_t *vertData = GetFatVertexData( pmesh, m_pStudioHdr );
  2177. if ( !vertData )
  2178. {
  2179. // not available
  2180. return 0;
  2181. }
  2182. mstudiovertex_t *pVertices = vertData->Vertex( 0 );
  2183. int j;
  2184. int numTrianglesRendered = 0;
  2185. // See if any meshes in the group want to go down the static path...
  2186. bool bIsDeltaFlexed = false;
  2187. bool bIsHardwareSkinnedData = false;
  2188. bool bIsFlexed = false;
  2189. for (j = 0; j < pMeshData->m_NumGroup; ++j)
  2190. {
  2191. studiomeshgroup_t* pGroup = &pMeshData->m_pMeshGroup[j];
  2192. if ( ( pGroup->m_Flags & MESHGROUP_IS_DELTA_FLEXED ) && g_pMaterialSystemHardwareConfig->SupportsStreamOffset() )
  2193. bIsDeltaFlexed = true;
  2194. if ( pGroup->m_Flags & MESHGROUP_IS_FLEXED )
  2195. bIsFlexed = true;
  2196. if ( pGroup->m_Flags & MESHGROUP_IS_HWSKINNED )
  2197. bIsHardwareSkinnedData = true;
  2198. }
  2199. // Take the static path for new flexed models on DX9 hardware
  2200. bool bFlexStatic = bIsDeltaFlexed && g_pMaterialSystemHardwareConfig->SupportsStreamOffset();
  2201. bool bShouldHardwareSkin = bIsHardwareSkinnedData && ( !bIsFlexed || bFlexStatic ) &&
  2202. ( lighting != LIGHTING_SOFTWARE ) && ( !m_pRC->m_Config.bSoftwareSkin );
  2203. pRenderContext->MatrixMode( MATERIAL_MODEL );
  2204. pRenderContext->LoadIdentity();
  2205. // Software flex eyeball verts (not a delta stream)
  2206. if ( bIsFlexed && ( !bFlexStatic || !bShouldHardwareSkin ) )
  2207. {
  2208. R_StudioFlexVerts( pmesh, lod );
  2209. }
  2210. mstudioeyeball_t *peyeball = m_pSubModel->pEyeball(pmesh->materialparam);
  2211. // We'll need this to compute normals
  2212. Vector org;
  2213. VectorTransform( peyeball->org, m_pBoneToWorld[peyeball->bone], org );
  2214. // Compute the glint projection
  2215. matrix3x4_t glintMat;
  2216. ComputeGlintTextureProjection( &m_pEyeballState[pmesh->materialparam], m_pRC->m_ViewRight, m_pRC->m_ViewUp, glintMat );
  2217. if ( !m_pRC->m_Config.bWireframe )
  2218. {
  2219. // Compute the glint procedural texture
  2220. IMaterialVar* pGlintVar = pMaterial->FindVarFast( "$glint", &glintCache );
  2221. if (pGlintVar)
  2222. {
  2223. R_StudioEyeballGlint( &m_pEyeballState[pmesh->materialparam], pGlintVar, m_pRC->m_ViewRight, m_pRC->m_ViewUp, m_pRC->m_ViewOrigin );
  2224. }
  2225. SetEyeMaterialVars( pMaterial, peyeball, org, m_pEyeballState[pmesh->materialparam].mat, glintMat );
  2226. }
  2227. if ( bShouldHardwareSkin )
  2228. {
  2229. for ( j = 0; j < pMeshData->m_NumGroup; ++j )
  2230. {
  2231. studiomeshgroup_t* pGroup = &pMeshData->m_pMeshGroup[j];
  2232. numTrianglesRendered += R_StudioDrawStaticMesh( pRenderContext, pmesh, pGroup, lighting, m_pRC->m_AlphaMod, pMaterial, lod, NULL );
  2233. }
  2234. return numTrianglesRendered;
  2235. }
  2236. pRenderContext->SetNumBoneWeights( 0 );
  2237. m_VertexCache.SetupComputation( pmesh );
  2238. int nAlpnaInt = RoundFloatToInt( m_pRC->m_AlphaMod * 255 );
  2239. unsigned char a = clamp( nAlpnaInt, 0, 255 );
  2240. Vector position, normal, color;
  2241. // setup the call
  2242. R_InitLightEffectsWorld3();
  2243. // Render the puppy
  2244. CMeshBuilder meshBuilder;
  2245. bool useHWLighting = m_pRC->m_Config.m_bSupportsVertexAndPixelShaders && !m_pRC->m_Config.bSoftwareLighting;
  2246. // Draw all the various mesh groups...
  2247. for ( j = 0; j < pMeshData->m_NumGroup; ++j )
  2248. {
  2249. studiomeshgroup_t* pGroup = &pMeshData->m_pMeshGroup[j];
  2250. IMesh* pMesh = pRenderContext->GetDynamicMesh(false, 0, pGroup->m_pMesh);
  2251. // garymcthack! need to look at the strip flags to figure out what it is.
  2252. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, pmesh->numvertices, 0 );
  2253. // meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, pmesh->numvertices, 0 );
  2254. //VPROF_INCREMENT_COUNTER( "TransformFlexVerts", pGroup->m_NumVertices );
  2255. for ( int i=0; i < pGroup->m_NumVertices; ++i)
  2256. {
  2257. int n = pGroup->m_pGroupIndexToMeshIndex[i];
  2258. mstudiovertex_t &vert = pVertices[n];
  2259. CachedPosNorm_t* pWorldVert = m_VertexCache.CreateWorldVertex(n);
  2260. // transform into world space
  2261. if ( m_VertexCache.IsVertexFlexed(n) )
  2262. {
  2263. CachedPosNormTan_t* pFlexVert = m_VertexCache.GetFlexVertex(n);
  2264. R_StudioTransform( pFlexVert->m_Position, &vert.m_BoneWeights, pWorldVert->m_Position.AsVector3D() );
  2265. R_StudioRotate( pFlexVert->m_Normal, &vert.m_BoneWeights, pWorldVert->m_Normal.AsVector3D() );
  2266. Assert( pWorldVert->m_Normal.x >= -1.05f && pWorldVert->m_Normal.x <= 1.05f );
  2267. Assert( pWorldVert->m_Normal.y >= -1.05f && pWorldVert->m_Normal.y <= 1.05f );
  2268. Assert( pWorldVert->m_Normal.z >= -1.05f && pWorldVert->m_Normal.z <= 1.05f );
  2269. }
  2270. else
  2271. {
  2272. R_StudioTransform( vert.m_vecPosition, &vert.m_BoneWeights, pWorldVert->m_Position.AsVector3D() );
  2273. R_StudioRotate( vert.m_vecNormal, &vert.m_BoneWeights, pWorldVert->m_Normal.AsVector3D() );
  2274. Assert( pWorldVert->m_Normal.x >= -1.05f && pWorldVert->m_Normal.x <= 1.05f );
  2275. Assert( pWorldVert->m_Normal.y >= -1.05f && pWorldVert->m_Normal.y <= 1.05f );
  2276. Assert( pWorldVert->m_Normal.z >= -1.05f && pWorldVert->m_Normal.z <= 1.05f );
  2277. }
  2278. // Don't bother to light in software when we've got vertex + pixel shaders.
  2279. meshBuilder.Position3fv( pWorldVert->m_Position.Base() );
  2280. if (useHWLighting)
  2281. {
  2282. meshBuilder.Normal3fv( pWorldVert->m_Normal.Base() );
  2283. }
  2284. else
  2285. {
  2286. R_StudioEyeballNormal( peyeball, org, pWorldVert->m_Position.AsVector3D(), pWorldVert->m_Normal.AsVector3D() );
  2287. // This isn't really used, but since the meshbuilder checks for messed up
  2288. // normals, let's do this here in debug mode.
  2289. // WRONGO YOU FRIGGIN IDIOT!!!!!!!!!!
  2290. // DX7 needs these for the flashlight.
  2291. meshBuilder.Normal3fv( pWorldVert->m_Normal.Base() );
  2292. R_ComputeLightAtPoint3( pWorldVert->m_Position.AsVector3D(), pWorldVert->m_Normal.AsVector3D(), color );
  2293. unsigned char r = LinearToLightmap( color.x );
  2294. unsigned char g = LinearToLightmap( color.y );
  2295. unsigned char b = LinearToLightmap( color.z );
  2296. meshBuilder.Color4ub( r, g, b, a );
  2297. }
  2298. meshBuilder.TexCoord2fv( 0, vert.m_vecTexCoord.Base() );
  2299. // FIXME: For now, flexed hw-skinned meshes can only have one bone
  2300. // The data must exist in the 0th hardware matrix
  2301. meshBuilder.BoneWeight( 0, 1.0f );
  2302. meshBuilder.BoneWeight( 1, 0.0f );
  2303. meshBuilder.BoneWeight( 2, 0.0f );
  2304. meshBuilder.BoneWeight( 3, 0.0f );
  2305. meshBuilder.BoneMatrix( 0, 0 );
  2306. meshBuilder.BoneMatrix( 1, 0 );
  2307. meshBuilder.BoneMatrix( 2, 0 );
  2308. meshBuilder.BoneMatrix( 3, 0 );
  2309. meshBuilder.AdvanceVertex();
  2310. }
  2311. meshBuilder.End();
  2312. pMesh->Draw();
  2313. for (int k=0; k<pGroup->m_NumStrips; k++)
  2314. {
  2315. numTrianglesRendered += pGroup->m_pUniqueTris[k];
  2316. }
  2317. if ( m_pRC->m_Config.bDrawNormals || m_pRC->m_Config.bDrawTangentFrame )
  2318. {
  2319. pRenderContext->SetNumBoneWeights( 0 );
  2320. pRenderContext->Bind( m_pMaterialTangentFrame );
  2321. CMeshBuilder meshBuilder;
  2322. pMesh = pRenderContext->GetDynamicMesh( false );
  2323. meshBuilder.Begin( pMesh, MATERIAL_LINES, pGroup->m_NumVertices );
  2324. bool doFlex = true;
  2325. bool r_blend = false;
  2326. R_StudioSoftwareProcessMesh_Normals( pmesh, meshBuilder, pGroup->m_NumVertices,
  2327. pGroup->m_pGroupIndexToMeshIndex, lighting, doFlex, r_blend, m_pRC->m_Config.bDrawNormals, m_pRC->m_Config.bDrawTangentFrame );
  2328. meshBuilder.End( );
  2329. pMesh->Draw();
  2330. pRenderContext->Bind( pMaterial );
  2331. }
  2332. }
  2333. return numTrianglesRendered;
  2334. }
  2335. //-----------------------------------------------------------------------------
  2336. // Draws a mesh
  2337. //-----------------------------------------------------------------------------
  2338. int CStudioRender::R_StudioDrawMesh( IMatRenderContext *pRenderContext, mstudiomesh_t* pmesh, studiomeshdata_t* pMeshData,
  2339. StudioModelLighting_t lighting, IMaterial *pMaterial,
  2340. ColorMeshInfo_t *pColorMeshes, int lod )
  2341. {
  2342. VPROF( "R_StudioDrawMesh" );
  2343. int numTrianglesRendered = 0;
  2344. // Draw all the various mesh groups...
  2345. for ( int j = 0; j < pMeshData->m_NumGroup; ++j )
  2346. {
  2347. studiomeshgroup_t* pGroup = &pMeshData->m_pMeshGroup[j];
  2348. // Older models are merely flexed while new ones are also delta flexed
  2349. bool bIsFlexed = (pGroup->m_Flags & MESHGROUP_IS_FLEXED) != 0;
  2350. bool bIsDeltaFlexed = (pGroup->m_Flags & MESHGROUP_IS_DELTA_FLEXED) != 0;
  2351. // Take the static path for new flexed models on DX9 hardware
  2352. bool bFlexStatic = ( bIsDeltaFlexed && g_pMaterialSystemHardwareConfig->SupportsStreamOffset() );
  2353. // Use the hardware if the mesh is hw skinned and we can put flexes on another stream
  2354. // Otherwise, we gotta do some expensive locks
  2355. bool bIsHardwareSkinnedData = ( pGroup->m_Flags & MESHGROUP_IS_HWSKINNED ) != 0;
  2356. bool bShouldHardwareSkin = bIsHardwareSkinnedData && ( !bIsFlexed || bFlexStatic ) &&
  2357. ( lighting != LIGHTING_SOFTWARE );
  2358. if ( bShouldHardwareSkin && !m_pRC->m_Config.bDrawNormals && !m_pRC->m_Config.bDrawTangentFrame && !m_pRC->m_Config.bWireframe )
  2359. {
  2360. if ( !m_pRC->m_Config.bNoHardware )
  2361. {
  2362. numTrianglesRendered += R_StudioDrawStaticMesh( pRenderContext, pmesh, pGroup, lighting, m_pRC->m_AlphaMod, pMaterial, lod, pColorMeshes );
  2363. }
  2364. }
  2365. else
  2366. {
  2367. if ( !m_pRC->m_Config.bNoSoftware )
  2368. {
  2369. numTrianglesRendered += R_StudioDrawDynamicMesh( pRenderContext, pmesh, pGroup, lighting, m_pRC->m_AlphaMod, pMaterial, lod );
  2370. }
  2371. }
  2372. }
  2373. return numTrianglesRendered;
  2374. }
  2375. //-----------------------------------------------------------------------------
  2376. // Inserts translucent mesh into list
  2377. //-----------------------------------------------------------------------------
  2378. template< class T >
  2379. void InsertRenderable( int mesh, T val, int count, int* pIndices, T* pValList )
  2380. {
  2381. // Compute insertion point...
  2382. int i;
  2383. for ( i = count; --i >= 0; )
  2384. {
  2385. if (val < pValList[i])
  2386. break;
  2387. // Shift down
  2388. pIndices[i + 1] = pIndices[i];
  2389. pValList[i+1] = pValList[i];
  2390. }
  2391. // Insert at insertion point
  2392. ++i;
  2393. pValList[i] = val;
  2394. pIndices[i] = mesh;
  2395. }
  2396. //-----------------------------------------------------------------------------
  2397. // Sorts the meshes
  2398. //-----------------------------------------------------------------------------
  2399. int CStudioRender::SortMeshes( int* pIndices, IMaterial **ppMaterials,
  2400. short* pskinref, Vector const& vforward, Vector const& r_origin )
  2401. {
  2402. int numMeshes = 0;
  2403. if (m_bDrawTranslucentSubModels)
  2404. {
  2405. // float* pDist = (float*)_alloca( m_pSubModel->nummeshes * sizeof(float) );
  2406. // Sort each model piece by it's center, if it's translucent
  2407. for (int i = 0; i < m_pSubModel->nummeshes; ++i)
  2408. {
  2409. // Don't add opaque materials
  2410. mstudiomesh_t* pmesh = m_pSubModel->pMesh(i);
  2411. IMaterial *pMaterial = ppMaterials[pskinref[pmesh->material]];
  2412. if( !pMaterial || !pMaterial->IsTranslucent() )
  2413. continue;
  2414. // FIXME: put the "center" of the mesh into delta
  2415. // Vector delta;
  2416. // VectorSubtract( delta, r_origin, delta );
  2417. // float dist = DotProduct( delta, vforward );
  2418. // Add it to our lists
  2419. // InsertRenderable( i, dist, numMeshes, pIndices, pDist );
  2420. // One more mesh
  2421. ++numMeshes;
  2422. }
  2423. }
  2424. else
  2425. {
  2426. IMaterial** ppMat = (IMaterial**)_alloca( m_pSubModel->nummeshes * sizeof(IMaterial*) );
  2427. // Sort by material type
  2428. for (int i = 0; i < m_pSubModel->nummeshes; ++i)
  2429. {
  2430. mstudiomesh_t* pmesh = m_pSubModel->pMesh(i);
  2431. IMaterial *pMaterial = ppMaterials[pskinref[pmesh->material]];
  2432. if( !pMaterial )
  2433. continue;
  2434. // Don't add translucent materials
  2435. if (( !m_pRC->m_Config.bWireframe ) && pMaterial->IsTranslucent() )
  2436. continue;
  2437. // Add it to our lists
  2438. InsertRenderable( i, pMaterial, numMeshes, pIndices, ppMat );
  2439. // One more mesh
  2440. ++numMeshes;
  2441. }
  2442. }
  2443. return numMeshes;
  2444. }
  2445. //-----------------------------------------------------------------------------
  2446. // R_StudioDrawPoints
  2447. //
  2448. // Returns the number of triangles rendered.
  2449. //-----------------------------------------------------------------------------
  2450. #pragma warning (disable:4189)
  2451. int CStudioRender::R_StudioDrawPoints( IMatRenderContext *pRenderContext, int skin, void /*IClientEntity*/ *pClientEntity,
  2452. IMaterial **ppMaterials, int *pMaterialFlags, int boneMask, int lod, ColorMeshInfo_t *pColorMeshes )
  2453. {
  2454. VPROF( "R_StudioDrawPoints" );
  2455. int i;
  2456. int numTrianglesRendered = 0;
  2457. #if 0 // garymcthack
  2458. if ( m_pSubModel->numfaces == 0 )
  2459. return 0;
  2460. #endif
  2461. // happens when there's a model load failure
  2462. if ( m_pStudioMeshes == 0 )
  2463. return 0;
  2464. if ( m_pRC->m_Config.bWireframe && m_bDrawTranslucentSubModels )
  2465. return 0;
  2466. // ConDMsg("%d: %d %d\n", pimesh->numFaces, pimesh->numVertices, pimesh->numNormals );
  2467. if ( m_pRC->m_Config.skin )
  2468. {
  2469. skin = m_pRC->m_Config.skin;
  2470. if ( skin >= m_pStudioHdr->numskinfamilies )
  2471. {
  2472. skin = 0;
  2473. }
  2474. }
  2475. // get skinref array
  2476. short *pskinref = m_pStudioHdr->pSkinref( 0 );
  2477. if ( skin > 0 && skin < m_pStudioHdr->numskinfamilies )
  2478. {
  2479. pskinref += ( skin * m_pStudioHdr->numskinref );
  2480. }
  2481. // FIXME: Activate sorting on a mesh level
  2482. // int* pIndices = (int*)_alloca( m_pSubModel->nummeshes * sizeof(int) );
  2483. // int numMeshes = SortMeshes( pIndices, ppMaterials, pskinref, vforward, r_origin );
  2484. // draw each mesh
  2485. for ( i = 0; i < m_pSubModel->nummeshes; ++i)
  2486. {
  2487. mstudiomesh_t *pmesh = m_pSubModel->pMesh(i);
  2488. studiomeshdata_t *pMeshData = &m_pStudioMeshes[pmesh->meshid];
  2489. Assert( pMeshData );
  2490. if ( !pMeshData->m_NumGroup )
  2491. continue;
  2492. if ( !pMaterialFlags )
  2493. continue;
  2494. StudioModelLighting_t lighting = LIGHTING_HARDWARE;
  2495. int materialFlags = pMaterialFlags[pskinref[pmesh->material]];
  2496. IMaterial* pMaterial = R_StudioSetupSkinAndLighting( pRenderContext, pskinref[ pmesh->material ], ppMaterials, materialFlags, pClientEntity, pColorMeshes, lighting );
  2497. if ( !pMaterial )
  2498. continue;
  2499. #ifdef _DEBUG
  2500. char const *materialName = pMaterial->GetName();
  2501. #endif
  2502. // Set up flex data
  2503. m_VertexCache.SetMesh( i );
  2504. // The following are special cases that can't be covered with
  2505. // the normal static/dynamic methods due to optimization reasons
  2506. switch ( pmesh->materialtype )
  2507. {
  2508. case 1:
  2509. // eyeballs
  2510. numTrianglesRendered += R_StudioDrawEyeball( pRenderContext, pmesh, pMeshData, lighting, pMaterial, lod );
  2511. break;
  2512. default:
  2513. numTrianglesRendered += R_StudioDrawMesh( pRenderContext, pmesh, pMeshData, lighting, pMaterial, pColorMeshes, lod );
  2514. break;
  2515. }
  2516. }
  2517. // Reset this state so it doesn't hose other parts of rendering
  2518. pRenderContext->SetNumBoneWeights( 0 );
  2519. return numTrianglesRendered;
  2520. }
  2521. #pragma warning (default:4189)