Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

294 lines
9.6 KiB

  1. //===== Copyright � 2013-2013, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: Class to help with rendering CMDLs & CMergedMDLs to textures.
  4. //
  5. //===========================================================================//
  6. #include "render_to_rt_helper.h"
  7. #include "istudiorender.h"
  8. #include "tier2/renderutils.h"
  9. #include "materialsystem/MaterialSystemUtil.h"
  10. #include "renderparm.h"
  11. // NOTE: This has to be the last file included!
  12. #include "tier0/memdbgon.h"
  13. // uncomment these to write out VTFs of the inventory icons with no lighting to be used for the "default icon images"
  14. //#define WRITE_OUT_VTF
  15. //#define ICON_VTF_BASE_PATH "d:/temp"
  16. //-----------------------------------------------------------------------------
  17. // Singleton
  18. //-----------------------------------------------------------------------------
  19. static CRenderToRTHelper s_RenderToRTHelper;
  20. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CRenderToRTHelper, IRenderToRTHelper, RENDER_TO_RT_HELPER_INTERFACE_VERSION, s_RenderToRTHelper );
  21. CRenderToRTHelper::CRenderToRTHelper()
  22. : m_pCurrentObjectToRender( NULL )
  23. , m_pPixelsReadEvent( NULL )
  24. , m_pRenderTarget( NULL )
  25. {
  26. }
  27. CRenderToRTHelper::~CRenderToRTHelper()
  28. {
  29. }
  30. bool ProcessRenderToRTHelper()
  31. {
  32. return ( g_pRenderToRTHelper != NULL ) ? g_pRenderToRTHelper->Process() : false;
  33. }
  34. bool CRenderToRTHelper::Init()
  35. {
  36. if ( !g_pMaterialSystem )
  37. return false;
  38. memset( &m_LightingState, 0, sizeof(MaterialLightingState_t) );
  39. for ( int i = 0; i < 6; ++i )
  40. {
  41. #ifdef WRITE_OUT_ICON_VTFS
  42. m_LightingState.m_vecAmbientCube[i].Init( 0.f, 0.f, 0.f );
  43. #else
  44. m_LightingState.m_vecAmbientCube[i].Init( 0.15f, 0.15f, 0.15f );
  45. #endif
  46. }
  47. //the default light is a blueish rim
  48. m_LightingState.m_pLocalLightDesc[0].InitDirectional( Vector( -1.0f, 0.3f, 1.0f ), Vector( 1.5f, 1.8f, 2.0f ) );
  49. m_LightingState.m_nLocalLightCount = 1;
  50. m_pRenderTarget = g_pMaterialSystem->FindTexture( "render_to_rt_helper", TEXTURE_GROUP_RENDER_TARGET );
  51. Assert( m_pRenderTarget );
  52. m_pRenderTarget->AddRef();
  53. g_pMaterialSystem->AddEndFramePriorToNextContextFunc( ::ProcessRenderToRTHelper );
  54. return true;
  55. }
  56. void CRenderToRTHelper::Shutdown( void )
  57. {
  58. g_pMaterialSystem->RemoveEndFramePriorToNextContextFunc( ::ProcessRenderToRTHelper );
  59. if ( m_pRenderTarget )
  60. {
  61. m_pRenderTarget->Release();
  62. m_pRenderTarget = NULL;
  63. }
  64. }
  65. void CRenderToRTHelper::LookAt( Camera_t& camera, const Vector &vecCenter, float flRadius, QAngle cameraAngles, Vector cameraOffset )
  66. {
  67. // Compute the distance to the camera for the object based on its
  68. // radius and fov.
  69. // clamp to a reasonable range
  70. flRadius = clamp(flRadius, 6.0f, 20.0f);
  71. // since tan( fov/2 ) = f/d
  72. // cos( fov/2 ) = r / r' where r = sphere radius, r' = perp distance from sphere center to max extent of camera
  73. // d/f = r'/d' where d' is distance of camera to sphere
  74. // d' = r' / tan( fov/2 ) * r' = r / ( cos (fov/2) * tan( fov/2 ) ) = r / sin( fov/2 )
  75. float flFOVx = camera.m_flFOVX;
  76. flFOVx *= M_PI / 360.0f;
  77. Vector vecCameraOffset( cameraOffset );
  78. vecCameraOffset.x -= ( flRadius / sin( flFOVx ) );
  79. // now setup the camera's origin and angles
  80. matrix3x4_t matCameraPivot;
  81. matrix3x4_t offset;
  82. matrix3x4_t worldToCamera;
  83. AngleMatrix( cameraAngles, vecCenter, matCameraPivot );
  84. SetIdentityMatrix( offset );
  85. MatrixSetColumn( vecCameraOffset, 3, offset );
  86. ConcatTransforms( matCameraPivot, offset, worldToCamera );
  87. MatrixAngles( worldToCamera, camera.m_angles, camera.m_origin );
  88. }
  89. RenderToRTData_t *CRenderToRTHelper::CreateRenderToRTData( IRenderToRTHelperObject *pObject, IVTFTexture *pResultVTF )
  90. {
  91. RenderToRTData_t *pRenderToRTData = new RenderToRTData_t;
  92. pRenderToRTData->m_pObject = pObject;
  93. pRenderToRTData->m_pResultVTF = pResultVTF;
  94. pRenderToRTData->m_LightingState = m_LightingState;
  95. pRenderToRTData->m_cameraAngles = QAngle( 0.0f, -150.0f, 0.0f );
  96. pRenderToRTData->m_cameraOffset = Vector( 0.0f, 1.0f, -1.0f );
  97. pRenderToRTData->m_cameraFOV = 20.0f;
  98. pRenderToRTData->m_bUsingExplicitModelCameraPosAnglesFromAttachment = false;
  99. SetIdentityMatrix( pRenderToRTData->m_rootToWorld );
  100. pRenderToRTData->m_stage = RENDER_TO_RT_STAGE_CREATED;
  101. m_objectsToRender.AddToTail( pRenderToRTData );
  102. return pRenderToRTData;
  103. }
  104. void CRenderToRTHelper::DestroyRenderToRTData( RenderToRTData_t *pRenderToRTData )
  105. {
  106. if ( pRenderToRTData->m_stage == RENDER_TO_RT_STAGE_WAITING_FOR_READ_BACK && m_pPixelsReadEvent )
  107. {
  108. m_pPixelsReadEvent->Wait();
  109. delete m_pPixelsReadEvent;
  110. m_pPixelsReadEvent = NULL;
  111. }
  112. if ( m_pCurrentObjectToRender == pRenderToRTData )
  113. {
  114. m_pCurrentObjectToRender = NULL;
  115. }
  116. pRenderToRTData->m_stage = RENDER_TO_RT_STAGE_UNDEFINED;
  117. m_objectsToRender.FindAndRemove( pRenderToRTData );
  118. delete pRenderToRTData;
  119. }
  120. void CRenderToRTHelper::StartRenderToRT( RenderToRTData_t *pRenderToRTData )
  121. {
  122. if ( pRenderToRTData->m_stage == RENDER_TO_RT_STAGE_CREATED )
  123. {
  124. // update camera here, because m_cameraAngles may have been changed
  125. pRenderToRTData->m_Camera.Init( Vector( 0, 0, 0 ), QAngle( 0, 0, 0 ), 1.0f, 1000.0f, pRenderToRTData->m_cameraFOV, 1.0f );
  126. if ( !pRenderToRTData->m_bUsingExplicitModelCameraPosAnglesFromAttachment )
  127. {
  128. float flRadius;
  129. Vector vecCenter;
  130. pRenderToRTData->m_pObject->GetBoundingSphere( vecCenter, flRadius );
  131. LookAt( pRenderToRTData->m_Camera, vecCenter, flRadius, pRenderToRTData->m_cameraAngles, pRenderToRTData->m_cameraOffset );
  132. }
  133. else
  134. {
  135. pRenderToRTData->m_Camera.InitViewParameters( pRenderToRTData->m_cameraOffset, pRenderToRTData->m_cameraAngles );
  136. }
  137. #ifdef WRITE_OUT_ICON_VTFS
  138. pRenderToRTData->m_LightingState.m_pLocalLightDesc[0].InitDirectional( Vector( 0.0f, 0.0f, 0.0f ), Vector( 0.0f, 0.0f, 0.0f ) );
  139. pRenderToRTData->m_LightingState.m_nLocalLightCount = 1;
  140. #endif
  141. pRenderToRTData->m_stage = RENDER_TO_RT_STAGE_STARTED;
  142. }
  143. }
  144. bool CRenderToRTHelper::Process()
  145. {
  146. bool bDidWork = false;
  147. if ( !m_pCurrentObjectToRender && m_objectsToRender.Count() > 0 )
  148. {
  149. int nIndex = m_objectsToRender.Head();
  150. while ( m_objectsToRender.IsValidIndex( nIndex ) )
  151. {
  152. if ( m_objectsToRender.Element( nIndex )->m_stage == RENDER_TO_RT_STAGE_STARTED )
  153. {
  154. m_pCurrentObjectToRender = m_objectsToRender.Element( nIndex );
  155. break;
  156. }
  157. nIndex = m_objectsToRender.Next( nIndex );
  158. }
  159. }
  160. if ( m_pCurrentObjectToRender )
  161. {
  162. if ( m_pCurrentObjectToRender->m_stage == RENDER_TO_RT_STAGE_STARTED && m_pRenderTarget != NULL && materials->CanDownloadTextures() )
  163. {
  164. // render it and save
  165. m_pCurrentObjectToRender->m_pResultVTF->Init( m_pRenderTarget->GetActualWidth(), m_pRenderTarget->GetActualHeight(), m_pRenderTarget->GetActualDepth(), IMAGE_FORMAT_BGRA8888, 0, 1 );
  166. int resolutionX = m_pRenderTarget->GetActualWidth();
  167. int resolutionY = m_pRenderTarget->GetActualHeight();
  168. unsigned char *pDestImage = m_pCurrentObjectToRender->m_pResultVTF->ImageData( 0, 0, 0 );
  169. StudioRenderConfig_t oldStudioRenderConfig;
  170. g_pStudioRender->GetCurrentConfig( oldStudioRenderConfig );
  171. MaterialLock_t hLock = materials->Lock();
  172. //init render context and set the the custom weapon RT as the current target
  173. CMatRenderContextPtr pRenderContext( materials );
  174. pRenderContext->PushRenderTargetAndViewport( m_pRenderTarget, 0, 0, resolutionX, resolutionY );
  175. VMatrix view, projection;
  176. ComputeViewMatrix( &view, m_pCurrentObjectToRender->m_Camera );
  177. ComputeProjectionMatrix( &projection, m_pCurrentObjectToRender->m_Camera, resolutionX, resolutionY );
  178. pRenderContext->MatrixMode( MATERIAL_MODEL );
  179. pRenderContext->PushMatrix();
  180. pRenderContext->LoadIdentity( );
  181. pRenderContext->MatrixMode( MATERIAL_VIEW );
  182. pRenderContext->PushMatrix();
  183. pRenderContext->LoadMatrix( view );
  184. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  185. pRenderContext->PushMatrix();
  186. pRenderContext->LoadMatrix( projection );
  187. pRenderContext->SetLightingState( m_pCurrentObjectToRender->m_LightingState );
  188. pRenderContext->ClearColor4ub( 128, 128, 128, 0 );
  189. //pRenderContext->ClearBuffersObeyStencilEx( true, true, true );
  190. pRenderContext->ClearBuffers( true, true, true );
  191. // We want the models to use their natural alpha, not depth in alpha
  192. pRenderContext->SetIntRenderingParameter( INT_RENDERPARM_WRITE_DEPTH_TO_DESTALPHA, 0 );
  193. // flashlights can't work in the model panel under queued mode (the state isn't ready yet, so causes a crash)
  194. pRenderContext->SetFlashlightMode( false );
  195. pRenderContext->BindLocalCubemap( m_pCurrentObjectToRender->m_pObject->GetEnvCubeMap() );
  196. m_pCurrentObjectToRender->m_pObject->Draw( m_pCurrentObjectToRender->m_rootToWorld );
  197. pRenderContext->ReadPixels( 0, 0, resolutionX, resolutionY, pDestImage, IMAGE_FORMAT_RGBA8888, m_pRenderTarget );
  198. pRenderContext->PopRenderTargetAndViewport();
  199. pRenderContext->MatrixMode( MATERIAL_MODEL );
  200. pRenderContext->PopMatrix();
  201. pRenderContext->MatrixMode( MATERIAL_VIEW );
  202. pRenderContext->PopMatrix();
  203. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  204. pRenderContext->PopMatrix();
  205. pRenderContext->Flush();
  206. materials->Unlock( hLock );
  207. g_pStudioRender->UpdateConfig( oldStudioRenderConfig );
  208. m_pCurrentObjectToRender->m_stage = RENDER_TO_RT_STAGE_DONE;
  209. bDidWork = true;
  210. #ifdef WRITE_OUT_ICON_VTFS
  211. static int s_nIconNumber = 0;
  212. CUtlBuffer buf;
  213. m_pCurrentObjectToRender->m_pResultVTF->Serialize(buf);
  214. char szTextureName[MAX_PATH];
  215. V_snprintf(szTextureName, MAX_PATH, "%s/inventory_icon_%s.vtf", ICON_VTF_BASE_PATH, m_pCurrentObjectToRender->m_pszIconNameSuffix );
  216. FileHandle_t f = g_pFullFileSystem->Open(szTextureName, "wb", NULL);
  217. if ( f != FILESYSTEM_INVALID_HANDLE )
  218. {
  219. g_pFullFileSystem->Write( buf.Base(), buf.TellMaxPut(), f );
  220. g_pFullFileSystem->Close(f);
  221. }
  222. #endif
  223. m_pCurrentObjectToRender = NULL;
  224. }
  225. }
  226. return bDidWork;
  227. }