|
|
//===== Copyright � 2013-2013, Valve Corporation, All rights reserved. ======//
//
// Purpose: Class to help with rendering CMDLs & CMergedMDLs to textures.
//
//===========================================================================//
#include "render_to_rt_helper.h"
#include "istudiorender.h"
#include "tier2/renderutils.h"
#include "materialsystem/MaterialSystemUtil.h"
#include "renderparm.h"
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
// uncomment these to write out VTFs of the inventory icons with no lighting to be used for the "default icon images"
//#define WRITE_OUT_VTF
//#define ICON_VTF_BASE_PATH "d:/temp"
//-----------------------------------------------------------------------------
// Singleton
//-----------------------------------------------------------------------------
static CRenderToRTHelper s_RenderToRTHelper; EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CRenderToRTHelper, IRenderToRTHelper, RENDER_TO_RT_HELPER_INTERFACE_VERSION, s_RenderToRTHelper );
CRenderToRTHelper::CRenderToRTHelper() : m_pCurrentObjectToRender( NULL ) , m_pPixelsReadEvent( NULL ) , m_pRenderTarget( NULL ) { }
CRenderToRTHelper::~CRenderToRTHelper() { }
bool ProcessRenderToRTHelper() { return ( g_pRenderToRTHelper != NULL ) ? g_pRenderToRTHelper->Process() : false; }
bool CRenderToRTHelper::Init() { if ( !g_pMaterialSystem ) return false;
memset( &m_LightingState, 0, sizeof(MaterialLightingState_t) ); for ( int i = 0; i < 6; ++i ) { #ifdef WRITE_OUT_ICON_VTFS
m_LightingState.m_vecAmbientCube[i].Init( 0.f, 0.f, 0.f ); #else
m_LightingState.m_vecAmbientCube[i].Init( 0.15f, 0.15f, 0.15f ); #endif
}
//the default light is a blueish rim
m_LightingState.m_pLocalLightDesc[0].InitDirectional( Vector( -1.0f, 0.3f, 1.0f ), Vector( 1.5f, 1.8f, 2.0f ) ); m_LightingState.m_nLocalLightCount = 1;
m_pRenderTarget = g_pMaterialSystem->FindTexture( "render_to_rt_helper", TEXTURE_GROUP_RENDER_TARGET ); Assert( m_pRenderTarget ); m_pRenderTarget->AddRef();
g_pMaterialSystem->AddEndFramePriorToNextContextFunc( ::ProcessRenderToRTHelper );
return true; }
void CRenderToRTHelper::Shutdown( void ) { g_pMaterialSystem->RemoveEndFramePriorToNextContextFunc( ::ProcessRenderToRTHelper );
if ( m_pRenderTarget ) { m_pRenderTarget->Release(); m_pRenderTarget = NULL; } }
void CRenderToRTHelper::LookAt( Camera_t& camera, const Vector &vecCenter, float flRadius, QAngle cameraAngles, Vector cameraOffset ) { // Compute the distance to the camera for the object based on its
// radius and fov.
// clamp to a reasonable range
flRadius = clamp(flRadius, 6.0f, 20.0f);
// since tan( fov/2 ) = f/d
// cos( fov/2 ) = r / r' where r = sphere radius, r' = perp distance from sphere center to max extent of camera
// d/f = r'/d' where d' is distance of camera to sphere
// d' = r' / tan( fov/2 ) * r' = r / ( cos (fov/2) * tan( fov/2 ) ) = r / sin( fov/2 )
float flFOVx = camera.m_flFOVX; flFOVx *= M_PI / 360.0f; Vector vecCameraOffset( cameraOffset ); vecCameraOffset.x -= ( flRadius / sin( flFOVx ) );
// now setup the camera's origin and angles
matrix3x4_t matCameraPivot; matrix3x4_t offset; matrix3x4_t worldToCamera; AngleMatrix( cameraAngles, vecCenter, matCameraPivot ); SetIdentityMatrix( offset ); MatrixSetColumn( vecCameraOffset, 3, offset ); ConcatTransforms( matCameraPivot, offset, worldToCamera ); MatrixAngles( worldToCamera, camera.m_angles, camera.m_origin ); }
RenderToRTData_t *CRenderToRTHelper::CreateRenderToRTData( IRenderToRTHelperObject *pObject, IVTFTexture *pResultVTF ) { RenderToRTData_t *pRenderToRTData = new RenderToRTData_t; pRenderToRTData->m_pObject = pObject; pRenderToRTData->m_pResultVTF = pResultVTF; pRenderToRTData->m_LightingState = m_LightingState; pRenderToRTData->m_cameraAngles = QAngle( 0.0f, -150.0f, 0.0f ); pRenderToRTData->m_cameraOffset = Vector( 0.0f, 1.0f, -1.0f ); pRenderToRTData->m_cameraFOV = 20.0f; pRenderToRTData->m_bUsingExplicitModelCameraPosAnglesFromAttachment = false; SetIdentityMatrix( pRenderToRTData->m_rootToWorld ); pRenderToRTData->m_stage = RENDER_TO_RT_STAGE_CREATED;
m_objectsToRender.AddToTail( pRenderToRTData ); return pRenderToRTData; }
void CRenderToRTHelper::DestroyRenderToRTData( RenderToRTData_t *pRenderToRTData ) { if ( pRenderToRTData->m_stage == RENDER_TO_RT_STAGE_WAITING_FOR_READ_BACK && m_pPixelsReadEvent ) { m_pPixelsReadEvent->Wait(); delete m_pPixelsReadEvent; m_pPixelsReadEvent = NULL; }
if ( m_pCurrentObjectToRender == pRenderToRTData ) { m_pCurrentObjectToRender = NULL; }
pRenderToRTData->m_stage = RENDER_TO_RT_STAGE_UNDEFINED;
m_objectsToRender.FindAndRemove( pRenderToRTData ); delete pRenderToRTData; }
void CRenderToRTHelper::StartRenderToRT( RenderToRTData_t *pRenderToRTData ) { if ( pRenderToRTData->m_stage == RENDER_TO_RT_STAGE_CREATED ) { // update camera here, because m_cameraAngles may have been changed
pRenderToRTData->m_Camera.Init( Vector( 0, 0, 0 ), QAngle( 0, 0, 0 ), 1.0f, 1000.0f, pRenderToRTData->m_cameraFOV, 1.0f );
if ( !pRenderToRTData->m_bUsingExplicitModelCameraPosAnglesFromAttachment ) { float flRadius; Vector vecCenter; pRenderToRTData->m_pObject->GetBoundingSphere( vecCenter, flRadius ); LookAt( pRenderToRTData->m_Camera, vecCenter, flRadius, pRenderToRTData->m_cameraAngles, pRenderToRTData->m_cameraOffset ); } else { pRenderToRTData->m_Camera.InitViewParameters( pRenderToRTData->m_cameraOffset, pRenderToRTData->m_cameraAngles ); }
#ifdef WRITE_OUT_ICON_VTFS
pRenderToRTData->m_LightingState.m_pLocalLightDesc[0].InitDirectional( Vector( 0.0f, 0.0f, 0.0f ), Vector( 0.0f, 0.0f, 0.0f ) ); pRenderToRTData->m_LightingState.m_nLocalLightCount = 1; #endif
pRenderToRTData->m_stage = RENDER_TO_RT_STAGE_STARTED; } }
bool CRenderToRTHelper::Process() { bool bDidWork = false;
if ( !m_pCurrentObjectToRender && m_objectsToRender.Count() > 0 ) { int nIndex = m_objectsToRender.Head(); while ( m_objectsToRender.IsValidIndex( nIndex ) ) { if ( m_objectsToRender.Element( nIndex )->m_stage == RENDER_TO_RT_STAGE_STARTED ) { m_pCurrentObjectToRender = m_objectsToRender.Element( nIndex ); break; } nIndex = m_objectsToRender.Next( nIndex ); } }
if ( m_pCurrentObjectToRender ) { if ( m_pCurrentObjectToRender->m_stage == RENDER_TO_RT_STAGE_STARTED && m_pRenderTarget != NULL && materials->CanDownloadTextures() ) { // render it and save
m_pCurrentObjectToRender->m_pResultVTF->Init( m_pRenderTarget->GetActualWidth(), m_pRenderTarget->GetActualHeight(), m_pRenderTarget->GetActualDepth(), IMAGE_FORMAT_BGRA8888, 0, 1 );
int resolutionX = m_pRenderTarget->GetActualWidth(); int resolutionY = m_pRenderTarget->GetActualHeight(); unsigned char *pDestImage = m_pCurrentObjectToRender->m_pResultVTF->ImageData( 0, 0, 0 );
StudioRenderConfig_t oldStudioRenderConfig; g_pStudioRender->GetCurrentConfig( oldStudioRenderConfig );
MaterialLock_t hLock = materials->Lock();
//init render context and set the the custom weapon RT as the current target
CMatRenderContextPtr pRenderContext( materials ); pRenderContext->PushRenderTargetAndViewport( m_pRenderTarget, 0, 0, resolutionX, resolutionY );
VMatrix view, projection; ComputeViewMatrix( &view, m_pCurrentObjectToRender->m_Camera ); ComputeProjectionMatrix( &projection, m_pCurrentObjectToRender->m_Camera, resolutionX, resolutionY );
pRenderContext->MatrixMode( MATERIAL_MODEL ); pRenderContext->PushMatrix(); pRenderContext->LoadIdentity( );
pRenderContext->MatrixMode( MATERIAL_VIEW ); pRenderContext->PushMatrix(); pRenderContext->LoadMatrix( view );
pRenderContext->MatrixMode( MATERIAL_PROJECTION ); pRenderContext->PushMatrix(); pRenderContext->LoadMatrix( projection ); pRenderContext->SetLightingState( m_pCurrentObjectToRender->m_LightingState );
pRenderContext->ClearColor4ub( 128, 128, 128, 0 ); //pRenderContext->ClearBuffersObeyStencilEx( true, true, true );
pRenderContext->ClearBuffers( true, true, true );
// We want the models to use their natural alpha, not depth in alpha
pRenderContext->SetIntRenderingParameter( INT_RENDERPARM_WRITE_DEPTH_TO_DESTALPHA, 0 );
// flashlights can't work in the model panel under queued mode (the state isn't ready yet, so causes a crash)
pRenderContext->SetFlashlightMode( false );
pRenderContext->BindLocalCubemap( m_pCurrentObjectToRender->m_pObject->GetEnvCubeMap() );
m_pCurrentObjectToRender->m_pObject->Draw( m_pCurrentObjectToRender->m_rootToWorld );
pRenderContext->ReadPixels( 0, 0, resolutionX, resolutionY, pDestImage, IMAGE_FORMAT_RGBA8888, m_pRenderTarget );
pRenderContext->PopRenderTargetAndViewport();
pRenderContext->MatrixMode( MATERIAL_MODEL ); pRenderContext->PopMatrix();
pRenderContext->MatrixMode( MATERIAL_VIEW ); pRenderContext->PopMatrix();
pRenderContext->MatrixMode( MATERIAL_PROJECTION ); pRenderContext->PopMatrix(); pRenderContext->Flush(); materials->Unlock( hLock );
g_pStudioRender->UpdateConfig( oldStudioRenderConfig );
m_pCurrentObjectToRender->m_stage = RENDER_TO_RT_STAGE_DONE;
bDidWork = true;
#ifdef WRITE_OUT_ICON_VTFS
static int s_nIconNumber = 0; CUtlBuffer buf; m_pCurrentObjectToRender->m_pResultVTF->Serialize(buf);
char szTextureName[MAX_PATH]; V_snprintf(szTextureName, MAX_PATH, "%s/inventory_icon_%s.vtf", ICON_VTF_BASE_PATH, m_pCurrentObjectToRender->m_pszIconNameSuffix ); FileHandle_t f = g_pFullFileSystem->Open(szTextureName, "wb", NULL);
if ( f != FILESYSTEM_INVALID_HANDLE ) { g_pFullFileSystem->Write( buf.Base(), buf.TellMaxPut(), f ); g_pFullFileSystem->Close(f); } #endif
m_pCurrentObjectToRender = NULL; } }
return bDidWork; }
|