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.
1243 lines
32 KiB
1243 lines
32 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//============================================================================= |
|
|
|
#include "matsys_controls/potterywheelpanel.h" |
|
#include "matsys_controls/manipulator.h" |
|
#include "vgui/ISystem.h" |
|
#include "vgui/Cursor.h" |
|
#include "vgui/IVGui.h" |
|
#include "vgui/ISurface.h" |
|
#include "vgui/IInput.h" |
|
#include "VGuiMatSurface/IMatSystemSurface.h" |
|
#include "dmxloader/dmxelement.h" |
|
#include "vgui_controls/Frame.h" |
|
#include "convar.h" |
|
#include "tier0/dbg.h" |
|
#include "matsys_controls/matsyscontrols.h" |
|
#include "materialsystem/imaterial.h" |
|
#include "materialsystem/imaterialsystem.h" |
|
#include "istudiorender.h" |
|
#include "materialsystem/imaterialsystemhardwareconfig.h" |
|
#include "tier2/renderutils.h" |
|
#include "tier1/KeyValues.h" |
|
#include "materialsystem/imesh.h" |
|
|
|
#include "inputsystem/iinputsystem.h" |
|
|
|
#include "renderparm.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
|
|
using namespace vgui; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Translation manipulator |
|
//----------------------------------------------------------------------------- |
|
class CTranslationManipulator : public CTransformManipulator |
|
{ |
|
public: |
|
CTranslationManipulator( matrix3x4_t *pTransform ); |
|
|
|
// Methods of IManipulator |
|
virtual void OnMousePressed( vgui::MouseCode code, int x, int y ); |
|
virtual void OnCursorMoved( int x, int y ); |
|
|
|
protected: |
|
int m_lastx, m_lasty; |
|
}; |
|
|
|
|
|
CTranslationManipulator::CTranslationManipulator( matrix3x4_t *pTransform ) : CTransformManipulator( pTransform ) |
|
{ |
|
m_lastx = m_lasty = 0; |
|
} |
|
|
|
void CTranslationManipulator::OnMousePressed( vgui::MouseCode code, int x, int y ) |
|
{ |
|
m_lasty = y; |
|
m_lastx = x; |
|
} |
|
|
|
void CTranslationManipulator::OnCursorMoved( int x, int y ) |
|
{ |
|
if ( !m_pTransform ) |
|
return; |
|
|
|
Vector vPosition; |
|
QAngle quakeEuler; |
|
MatrixAngles( *m_pTransform, quakeEuler, vPosition ); |
|
|
|
Vector forward, right, up; |
|
AngleVectors( quakeEuler, &forward, &right, &up ); |
|
|
|
int dy = y - m_lasty; |
|
int dx = x - m_lastx; |
|
|
|
right *= -0.2f * dx; |
|
up *= 0.2f * dy; |
|
vPosition += up + right; |
|
|
|
m_lastx = x; |
|
m_lasty = y; |
|
|
|
PositionMatrix( vPosition, *m_pTransform ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Zoom manipulator |
|
//----------------------------------------------------------------------------- |
|
class CZoomManipulator : public CBaseManipulator |
|
{ |
|
public: |
|
CZoomManipulator( float *pDistance ); |
|
|
|
// Methods of IManipulator |
|
virtual void OnMousePressed( vgui::MouseCode code, int x, int y ); |
|
virtual void OnCursorMoved( int x, int y ); |
|
|
|
protected: |
|
int m_lasty; |
|
float *m_pDistance; |
|
}; |
|
|
|
CZoomManipulator::CZoomManipulator( float *pDistance ) |
|
{ |
|
m_lasty = 0; |
|
m_pDistance = pDistance; |
|
} |
|
|
|
void CZoomManipulator::OnMousePressed( vgui::MouseCode code, int x, int y ) |
|
{ |
|
m_lasty = y; |
|
} |
|
|
|
void CZoomManipulator::OnCursorMoved( int x, int y ) |
|
{ |
|
float delta = 0.2f * ( y - m_lasty ); |
|
m_lasty = y; |
|
*m_pDistance *= pow( 1.01f, delta ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Rotation manipulator |
|
//----------------------------------------------------------------------------- |
|
class CRotationManipulator : public CTransformManipulator |
|
{ |
|
public: |
|
CRotationManipulator( matrix3x4_t *pTransform ); |
|
|
|
// Inherited from IManipulator |
|
virtual void OnMousePressed( vgui::MouseCode code, int x, int y ); |
|
virtual void OnCursorMoved( int x, int y ); |
|
virtual void UpdateTransform(); |
|
|
|
void UpdateFromMatrix( void ); |
|
|
|
private: |
|
int m_lastx, m_lasty; |
|
float m_altitude, m_azimuth, m_roll; |
|
bool m_bDoRoll; |
|
}; |
|
|
|
|
|
CRotationManipulator::CRotationManipulator( matrix3x4_t *pTransform ) : CTransformManipulator( pTransform ) |
|
{ |
|
m_lastx = m_lasty = 0; |
|
m_altitude = M_PI/6; |
|
m_azimuth = -3*M_PI/4; |
|
m_roll = 0.0f; |
|
m_bDoRoll = false; |
|
UpdateTransform(); |
|
} |
|
|
|
void CRotationManipulator::OnMousePressed( vgui::MouseCode code, int x, int y ) |
|
{ |
|
if ( input()->IsKeyDown( KEY_LALT ) || input()->IsKeyDown( KEY_RALT ) ) |
|
{ |
|
m_bDoRoll = true; |
|
} |
|
else |
|
{ |
|
m_bDoRoll = false; |
|
} |
|
m_lasty = y; |
|
m_lastx = x; |
|
} |
|
|
|
void CRotationManipulator::OnCursorMoved( int x, int y ) |
|
{ |
|
if ( m_bDoRoll ) |
|
{ |
|
m_roll += 0.002f * ( m_lastx - x ); |
|
} |
|
else |
|
{ |
|
m_azimuth += 0.002f * ( m_lastx - x ); |
|
m_altitude -= 0.002f * ( m_lasty - y ); |
|
m_altitude = max( (float)-M_PI/2, min( (float)M_PI/2, m_altitude ) ); |
|
} |
|
|
|
m_lastx = x; |
|
m_lasty = y; |
|
|
|
UpdateTransform(); |
|
} |
|
|
|
void CRotationManipulator::UpdateTransform() |
|
{ |
|
if ( !m_pTransform ) |
|
return; |
|
|
|
QAngle angles( RAD2DEG( m_altitude ), RAD2DEG( m_azimuth ), RAD2DEG( m_roll ) ); |
|
Vector vecPosition; |
|
MatrixGetColumn( *m_pTransform, 3, vecPosition ); |
|
AngleMatrix( angles, vecPosition, *m_pTransform ); |
|
} |
|
|
|
void CRotationManipulator::UpdateFromMatrix( void ) |
|
{ |
|
if ( !m_pTransform ) |
|
return; |
|
|
|
QAngle angDir; |
|
Vector vecPos; |
|
|
|
MatrixAngles( *m_pTransform, angDir, vecPos ); |
|
|
|
m_altitude = DEG2RAD( angDir.x ); |
|
m_azimuth = DEG2RAD( angDir.y ); |
|
m_roll = DEG2RAD( angDir.z ); |
|
} |
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Constructor, destructor |
|
//----------------------------------------------------------------------------- |
|
CPotteryWheelPanel::CPotteryWheelPanel( vgui::Panel *pParent, const char *pName ) : |
|
BaseClass( pParent, pName ), |
|
m_pCameraRotate( NULL ), |
|
m_pCameraTranslate( NULL ), |
|
m_pCameraZoom( NULL ), |
|
m_pLightManip( NULL ), |
|
m_pCurrentManip( NULL ), |
|
m_nCaptureMouseCode( vgui::MouseCode( -1 ) ), |
|
m_xoffset( 0 ), m_yoffset( 0 ), |
|
m_bRenderToTexture( true ) |
|
{ |
|
m_bHasLightProbe = false; |
|
|
|
SetPaintBackgroundEnabled( false ); |
|
SetPaintBorderEnabled( false ); |
|
m_ClearColor.SetColor( 76, 88, 68, 255 ); |
|
|
|
SetIdentityMatrix( m_CameraPivot ); |
|
|
|
CreateDefaultLights(); |
|
|
|
m_nManipStartX = m_nManipStartY = 0; |
|
|
|
m_vecCameraOffset.Init( 100.0f, 0.0f, 0.0f ); |
|
|
|
m_Camera.m_flZNear = 3.0f; |
|
m_Camera.m_flZFar = 16384.0f * 1.73205080757f; |
|
m_Camera.m_flFOV = 30.0f; |
|
|
|
m_pCameraRotate = new CRotationManipulator( &m_CameraPivot ); |
|
m_pCameraTranslate = new CTranslationManipulator( &m_CameraPivot ); |
|
m_pCameraZoom = new CZoomManipulator( &m_vecCameraOffset.x ); |
|
|
|
KeyValues *pMaterialKeys = new KeyValues( "Wireframe", "$model", "1" ); |
|
|
|
pMaterialKeys->SetString( "$vertexcolor", "1" ); |
|
m_Wireframe.Init( "potterywheelpanelwireframe", pMaterialKeys ); |
|
|
|
SetKeyBoardInputEnabled( true ); |
|
UpdateCameraTransform(); |
|
} |
|
|
|
void CPotteryWheelPanel::ApplySettings( KeyValues *inResourceData ) |
|
{ |
|
BaseClass::ApplySettings( inResourceData ); |
|
|
|
KeyValues *pLights = inResourceData->FindKey( "lights" ); |
|
if ( pLights ) |
|
{ |
|
ParseLightsFromKV( pLights ); |
|
} |
|
} |
|
|
|
void CPotteryWheelPanel::Init( int x, int y, int wide, int tall ) |
|
{ |
|
BaseClass::Init( x, y, wide, tall ); |
|
|
|
// Used to poll input |
|
vgui::ivgui()->AddTickSignal( GetVPanel() ); |
|
} |
|
|
|
|
|
CPotteryWheelPanel::~CPotteryWheelPanel() |
|
{ |
|
m_Wireframe.Shutdown(); |
|
m_LightProbeBackground.Shutdown(); |
|
m_LightProbeHDRBackground.Shutdown(); |
|
m_LightProbeCubemap.Shutdown(); |
|
m_LightProbeHDRCubemap.Shutdown(); |
|
|
|
if ( m_pCameraRotate ) |
|
{ |
|
delete m_pCameraRotate; |
|
m_pCameraRotate = NULL; |
|
} |
|
|
|
if ( m_pCameraZoom ) |
|
{ |
|
delete m_pCameraZoom; |
|
m_pCameraZoom = NULL; |
|
} |
|
|
|
if ( m_pCameraTranslate ) |
|
{ |
|
delete m_pCameraTranslate; |
|
m_pCameraTranslate = NULL; |
|
} |
|
|
|
DestroyLights(); |
|
} |
|
|
|
void CPotteryWheelPanel::CreateDefaultLights() |
|
{ |
|
for ( int i = 0; i < 6; ++i ) |
|
{ |
|
m_vecAmbientCube[i].Init( 0.4f, 0.4f, 0.4f, 1.0f ); |
|
} |
|
|
|
memset( &m_Lights[0].m_Desc, 0, sizeof(LightDesc_t) ); |
|
SetIdentityMatrix( m_Lights[0].m_LightToWorld ); |
|
m_Lights[0].m_Desc.m_Type = MATERIAL_LIGHT_DIRECTIONAL; |
|
m_Lights[0].m_Desc.m_Color.Init( 1.0f, 1.0f, 1.0f ); |
|
m_Lights[0].m_Desc.m_Direction.Init( 0.0f, 0.0f, -1.0f ); |
|
m_Lights[0].m_Desc.m_Range=0.0; |
|
m_Lights[0].m_Desc.m_Attenuation0 = 1.0; |
|
m_Lights[0].m_Desc.m_Attenuation1 = 0; |
|
m_Lights[0].m_Desc.m_Attenuation2 = 0; |
|
m_Lights[0].m_Desc.RecalculateDerivedValues(); |
|
m_nLightCount = 1; |
|
|
|
m_pLightManip = new CPotteryWheelManip( &m_Lights[0].m_LightToWorld ); |
|
} |
|
|
|
|
|
void CPotteryWheelPanel::DestroyLights() |
|
{ |
|
if ( m_pLightManip ) |
|
{ |
|
delete m_pLightManip; |
|
m_pLightManip = NULL; |
|
} |
|
|
|
m_nLightCount = 0; |
|
} |
|
|
|
|
|
void StringToFloatArray( float *pVector, int count, const char *pString ) |
|
{ |
|
char *pstr, *pfront, tempString[128]; |
|
int j; |
|
|
|
Q_strncpy( tempString, pString, sizeof(tempString) ); |
|
pstr = pfront = tempString; |
|
|
|
for ( j = 0; j < count; j++ ) // lifted from pr_edict.c |
|
{ |
|
pVector[j] = atof( pfront ); |
|
|
|
// skip any leading whitespace |
|
while ( *pstr && *pstr <= ' ' ) |
|
pstr++; |
|
|
|
// skip to next whitespace |
|
while ( *pstr && *pstr > ' ' ) |
|
pstr++; |
|
|
|
if (!*pstr) |
|
break; |
|
|
|
pstr++; |
|
pfront = pstr; |
|
} |
|
for ( j++; j < count; j++ ) |
|
{ |
|
pVector[j] = 0; |
|
} |
|
} |
|
|
|
void StringToVector( float *pVector, const char *pString ) |
|
{ |
|
StringToFloatArray( pVector, 3, pString ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Sets initialize lights from KeyValues |
|
//----------------------------------------------------------------------------- |
|
void CPotteryWheelPanel::ParseLightsFromKV( KeyValues *pLightsKV ) |
|
{ |
|
int nLightCount = 0; |
|
FOR_EACH_SUBKEY( pLightsKV, pLocalLight ) |
|
{ |
|
Assert( nLightCount < MAX_LIGHT_COUNT ); |
|
if ( nLightCount >= MAX_LIGHT_COUNT ) |
|
break; |
|
|
|
LightDesc_t *pDesc = &m_Lights[nLightCount].m_Desc; |
|
const char *pType = pLocalLight->GetString( "name" ); |
|
Vector vecColor; |
|
StringToVector( vecColor.Base(), pLocalLight->GetString( "color" ) ); |
|
|
|
if ( !Q_stricmp( pType, "directional" ) ) |
|
{ |
|
Vector vecDirection; |
|
StringToVector( vecDirection.Base(), pLocalLight->GetString( "direction" ) ); |
|
pDesc->InitDirectional( vecDirection.Normalized(), vecColor ); |
|
++nLightCount; |
|
continue; |
|
} |
|
|
|
if ( !Q_stricmp( pType, "point" ) ) |
|
{ |
|
Vector vecAtten; |
|
StringToVector( vecAtten.Base(), pLocalLight->GetString( "attenuation" ) ); |
|
Vector vecOrigin; |
|
StringToVector( vecOrigin.Base(), pLocalLight->GetString( "origin" ) ); |
|
pDesc->InitPoint( vecOrigin, vecColor ); |
|
pDesc->m_Attenuation0 = vecAtten.x; |
|
pDesc->m_Attenuation1 = vecAtten.y; |
|
pDesc->m_Attenuation2 = vecAtten.z; |
|
pDesc->m_Range = pLocalLight->GetFloat( "maxDistance" ); |
|
pDesc->RecalculateDerivedValues(); |
|
++nLightCount; |
|
continue; |
|
} |
|
|
|
if ( !Q_stricmp( pType, "spot" ) ) |
|
{ |
|
Vector vecAtten; |
|
StringToVector( vecAtten.Base(), pLocalLight->GetString( "attenuation" ) ); |
|
Vector vecOrigin; |
|
StringToVector( vecOrigin.Base(), pLocalLight->GetString( "origin" ) ); |
|
pDesc->InitSpot( vecOrigin, vecColor, vec3_origin, |
|
pLocalLight->GetFloat( "inner_cone_angle" ), |
|
pLocalLight->GetFloat( "outer_cone_angle" ) ); |
|
|
|
Vector vecDirection; |
|
StringToVector( vecDirection.Base(), pLocalLight->GetString( "direction" ) ); |
|
pDesc->m_Direction = vecDirection.Normalized(); |
|
pDesc->m_Attenuation0 = vecAtten.x; |
|
pDesc->m_Attenuation1 = vecAtten.y; |
|
pDesc->m_Attenuation2 = vecAtten.z; |
|
pDesc->m_Range = pLocalLight->GetFloat( "maxDistance" ); |
|
pDesc->m_Falloff = pLocalLight->GetFloat( "exponent" ); |
|
pDesc->RecalculateDerivedValues(); |
|
++nLightCount; |
|
continue; |
|
} |
|
|
|
AssertMsg1( 0, "Failed to initialize light with type '%s'", pType ); |
|
} |
|
|
|
AssertMsg( nLightCount > 0, "Must specify at least one valid light" ); |
|
|
|
m_nLightCount = nLightCount; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Sets the background color |
|
//----------------------------------------------------------------------------- |
|
void CPotteryWheelPanel::SetBackgroundColor( int r, int g, int b ) |
|
{ |
|
m_ClearColor.SetColor( r, g, b, 255 ); |
|
} |
|
|
|
void CPotteryWheelPanel::SetBackgroundColor( const Color& c ) |
|
{ |
|
m_ClearColor = c; |
|
} |
|
|
|
const Color& CPotteryWheelPanel::GetBackgroundColor() const |
|
{ |
|
return m_ClearColor; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Light probe |
|
//----------------------------------------------------------------------------- |
|
void CPotteryWheelPanel::SetLightProbe( CDmxElement *pLightProbe ) |
|
{ |
|
m_LightProbeBackground.Shutdown(); |
|
m_LightProbeHDRBackground.Shutdown(); |
|
m_LightProbeCubemap.Shutdown(); |
|
m_LightProbeHDRCubemap.Shutdown(); |
|
|
|
DestroyLights(); |
|
|
|
m_bHasLightProbe = ( pLightProbe != NULL ); |
|
if ( !m_bHasLightProbe ) |
|
{ |
|
CreateDefaultLights(); |
|
return; |
|
} |
|
|
|
const char *pCubemap = pLightProbe->GetValueString( "cubemap" ); |
|
m_LightProbeCubemap.Init( pCubemap, TEXTURE_GROUP_OTHER ); |
|
|
|
const char *pCubemapHDR = pLightProbe->HasAttribute( "cubemapHdr" ) ? pLightProbe->GetValueString( "cubemapHdr" ) : pCubemap; |
|
m_LightProbeHDRCubemap.Init( pCubemapHDR, TEXTURE_GROUP_OTHER ); |
|
|
|
KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" ); |
|
pVMTKeyValues->SetInt( "$ignorez", 1 ); |
|
pVMTKeyValues->SetString( "$envmap", pCubemap ); |
|
pVMTKeyValues->SetInt( "$no_fullbright", 1 ); |
|
pVMTKeyValues->SetInt( "$nocull", 1 ); |
|
m_LightProbeBackground.Init( "SPWP_LightProbeBackground", pVMTKeyValues ); |
|
m_LightProbeBackground->Refresh(); |
|
|
|
pVMTKeyValues = new KeyValues( "UnlitGeneric" ); |
|
pVMTKeyValues->SetInt( "$ignorez", 1 ); |
|
pVMTKeyValues->SetString( "$envmap", pCubemapHDR ); |
|
pVMTKeyValues->SetInt( "$no_fullbright", 1 ); |
|
pVMTKeyValues->SetInt( "$nocull", 1 ); |
|
m_LightProbeHDRBackground.Init( "SPWP_LightProbeBackground_HDR", pVMTKeyValues ); |
|
m_LightProbeHDRBackground->Refresh(); |
|
|
|
const CUtlVector< Vector >& ambientCube = pLightProbe->GetArray<Vector>( "ambientCube" ); |
|
if ( ambientCube.Count() == 6 ) |
|
{ |
|
for ( int i = 0; i < 6; ++i ) |
|
{ |
|
m_vecAmbientCube[i].Init( ambientCube[i].x, ambientCube[i].y, ambientCube[i].z, 0.0f ); |
|
} |
|
} |
|
|
|
const CUtlVector< CDmxElement* >& localLights = pLightProbe->GetArray< CDmxElement* >( "localLights" ); |
|
int nLightCount = localLights.Count(); |
|
for ( int i = 0; i < nLightCount; ++i ) |
|
{ |
|
if ( m_nLightCount == MAX_LIGHT_COUNT ) |
|
break; |
|
|
|
LightDesc_t *pDesc = &m_Lights[m_nLightCount].m_Desc; |
|
CDmxElement *pLocalLight = localLights[ i ]; |
|
const char *pType = pLocalLight->GetValueString( "name" ); |
|
const Vector& vecColor = pLocalLight->GetValue<Vector>( "color" ); |
|
|
|
if ( !Q_stricmp( pType, "directional" ) ) |
|
{ |
|
pDesc->InitDirectional( pLocalLight->GetValue<Vector>( "direction" ), vecColor ); |
|
++m_nLightCount; |
|
continue; |
|
} |
|
|
|
if ( !Q_stricmp( pType, "point" ) ) |
|
{ |
|
const Vector& vecAtten = pLocalLight->GetValue<Vector>( "attenuation" ); |
|
pDesc->InitPoint( pLocalLight->GetValue<Vector>( "origin" ), vecColor ); |
|
pDesc->m_Attenuation0 = vecAtten.x; |
|
pDesc->m_Attenuation1 = vecAtten.y; |
|
pDesc->m_Attenuation2 = vecAtten.z; |
|
pDesc->m_Range = pLocalLight->GetValue<float>( "maxDistance" ); |
|
pDesc->RecalculateDerivedValues(); |
|
++m_nLightCount; |
|
continue; |
|
} |
|
|
|
if ( !Q_stricmp( pType, "spot" ) ) |
|
{ |
|
const Vector& vecAtten = pLocalLight->GetValue<Vector>( "attenuation" ); |
|
pDesc->InitSpot( pLocalLight->GetValue<Vector>( "origin" ), vecColor, vec3_origin, |
|
RAD2DEG ( pLocalLight->GetValue<float>( "theta" ) ), |
|
RAD2DEG ( pLocalLight->GetValue<float>( "phi" ) ) ); |
|
|
|
pDesc->m_Direction = pLocalLight->GetValue<Vector>( "direction" ); |
|
pDesc->m_Attenuation0 = vecAtten.x; |
|
pDesc->m_Attenuation1 = vecAtten.y; |
|
pDesc->m_Attenuation2 = vecAtten.z; |
|
pDesc->m_Range = pLocalLight->GetValue<float>( "maxDistance" ); |
|
pDesc->m_Falloff = pLocalLight->GetValue<float>( "exponent" ); |
|
pDesc->RecalculateDerivedValues(); |
|
++m_nLightCount; |
|
continue; |
|
} |
|
} |
|
|
|
if ( nLightCount > 0 ) |
|
{ |
|
m_pLightManip = new CPotteryWheelManip( &m_Lights[0].m_LightToWorld ); |
|
} |
|
} |
|
|
|
bool CPotteryWheelPanel::HasLightProbe() const |
|
{ |
|
return m_bHasLightProbe; |
|
} |
|
|
|
ITexture *CPotteryWheelPanel::GetLightProbeCubemap( bool bHDR ) |
|
{ |
|
if ( !m_bHasLightProbe ) |
|
return NULL; |
|
|
|
return bHDR ? m_LightProbeHDRCubemap : m_LightProbeCubemap; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CPotteryWheelPanel::GetCameraFOV( void ) |
|
{ |
|
return m_Camera.m_flFOV; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CPotteryWheelPanel::SetCameraFOV( float flFOV ) |
|
{ |
|
m_Camera.m_flFOV = flFOV; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CPotteryWheelPanel::SetCameraOffset( const Vector &vecOffset ) |
|
{ |
|
m_vecCameraOffset = vecOffset; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CPotteryWheelPanel::GetCameraOffset( Vector &vecOffset ) |
|
{ |
|
vecOffset = m_vecCameraOffset; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CPotteryWheelPanel::SetCameraPositionAndAngles( const Vector &vecPos, const QAngle &angDir, bool syncManipulators ) |
|
{ |
|
SetIdentityMatrix( m_CameraPivot ); |
|
AngleMatrix( angDir, vecPos, m_CameraPivot ); |
|
|
|
UpdateCameraTransform(); |
|
if ( syncManipulators ) |
|
{ |
|
SyncManipulation(); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CPotteryWheelPanel::GetCameraPositionAndAngles( Vector &vecPos, QAngle &angDir ) |
|
{ |
|
MatrixAngles( m_CameraPivot, angDir, vecPos ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CPotteryWheelPanel::ResetCameraPivot( void ) |
|
{ |
|
SetIdentityMatrix( m_CameraPivot ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Sets the camera to look at the the thing we're spinning around |
|
//----------------------------------------------------------------------------- |
|
void CPotteryWheelPanel::LookAt( float flRadius ) |
|
{ |
|
// Compute the distance to the camera for the object based on its |
|
// radius and fov. |
|
|
|
// 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 = m_Camera.m_flFOV; |
|
|
|
// Compute fov/2 in radians |
|
flFOVx *= M_PI / 360.0f; |
|
|
|
// Compute an effective fov based on the aspect ratio |
|
// if the height is smaller than the width |
|
int w, h; |
|
GetSize( w, h ); |
|
if ( h < w ) |
|
{ |
|
flFOVx = atan( h * tan( flFOVx ) / w ); |
|
} |
|
|
|
m_vecCameraOffset.x = -( flRadius / sin( flFOVx ) ); |
|
UpdateCameraTransform(); |
|
} |
|
|
|
|
|
void CPotteryWheelPanel::LookAt( const Vector &vecCenter, float flRadius ) |
|
{ |
|
MatrixSetColumn( vecCenter, 3, m_CameraPivot ); |
|
LookAt( flRadius ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Sets up render state in the material system for rendering |
|
//----------------------------------------------------------------------------- |
|
void CPotteryWheelPanel::SetupRenderState( int nDisplayWidth, int nDisplayHeight ) |
|
{ |
|
CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); |
|
|
|
VMatrix view, projection; |
|
ComputeViewMatrix( &view, m_Camera ); |
|
ComputeProjectionMatrix( &projection, m_Camera, nDisplayWidth, nDisplayHeight ); |
|
|
|
pRenderContext->MatrixMode( MATERIAL_MODEL ); |
|
pRenderContext->LoadIdentity( ); |
|
|
|
pRenderContext->MatrixMode( MATERIAL_VIEW ); |
|
pRenderContext->LoadMatrix( view ); |
|
|
|
pRenderContext->MatrixMode( MATERIAL_PROJECTION ); |
|
pRenderContext->LoadMatrix( projection ); |
|
|
|
LightDesc_t *pDesc = (LightDesc_t*)stackalloc( m_nLightCount * sizeof(LightDesc_t) ); |
|
for ( int i = 0; i < m_nLightCount; ++i ) |
|
{ |
|
pDesc[i] = m_Lights[i].m_Desc; |
|
VectorTransform( m_Lights[i].m_Desc.m_Position, m_Lights[i].m_LightToWorld, pDesc->m_Position ); |
|
VectorRotate( m_Lights[i].m_Desc.m_Direction, m_Lights[i].m_LightToWorld, pDesc->m_Direction ); |
|
VectorNormalize( pDesc->m_Direction ); |
|
pRenderContext->SetLight( i, pDesc[i] ); |
|
} |
|
|
|
LightDesc_t desc; |
|
desc.m_Type = MATERIAL_LIGHT_DISABLE; |
|
int nMaxLightCount = g_pMaterialSystemHardwareConfig->MaxNumLights(); |
|
for ( int i = m_nLightCount; i < nMaxLightCount; ++i ) |
|
{ |
|
pRenderContext->SetLight( i, desc ); |
|
} |
|
|
|
pRenderContext->SetAmbientLightCube( m_vecAmbientCube ); |
|
|
|
// FIXME: Remove this! This should automatically happen in DrawModel |
|
// in studiorender. |
|
if ( !g_pStudioRender ) |
|
return; |
|
|
|
VMatrix worldToCamera; |
|
MatrixInverseTR( view, worldToCamera ); |
|
Vector vecOrigin, vecRight, vecUp, vecForward; |
|
MatrixGetColumn( worldToCamera, 0, &vecRight ); |
|
MatrixGetColumn( worldToCamera, 1, &vecUp ); |
|
MatrixGetColumn( worldToCamera, 2, &vecForward ); |
|
MatrixGetColumn( worldToCamera, 3, &vecOrigin ); |
|
g_pStudioRender->SetViewState( vecOrigin, vecRight, vecUp, vecForward ); |
|
|
|
g_pStudioRender->SetLocalLights( m_nLightCount, pDesc ); |
|
g_pStudioRender->SetAmbientLightColors( m_vecAmbientCube ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Compute the camera world position |
|
//----------------------------------------------------------------------------- |
|
void CPotteryWheelPanel::UpdateCameraTransform( ) |
|
{ |
|
// Set up the render state for the camera + light |
|
matrix3x4_t offset, worldToCamera; |
|
SetIdentityMatrix( offset ); |
|
MatrixSetColumn( m_vecCameraOffset, 3, offset ); |
|
ConcatTransforms( m_CameraPivot, offset, worldToCamera ); |
|
MatrixAngles( worldToCamera, m_Camera.m_angles, m_Camera.m_origin ); |
|
} |
|
|
|
void CPotteryWheelPanel::ComputeCameraTransform( matrix3x4_t *pWorldToCamera ) |
|
{ |
|
AngleMatrix( m_Camera.m_angles, m_Camera.m_origin, *pWorldToCamera ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Computes the position in the panel of a particular 3D point |
|
//----------------------------------------------------------------------------- |
|
void CPotteryWheelPanel::ComputePanelPosition( const Vector &vecPosition, Vector2D *pPanelPos ) |
|
{ |
|
int w, h; |
|
GetSize( w, h ); |
|
|
|
matrix3x4_t worldToCamera; |
|
ComputeCameraTransform( &worldToCamera ); |
|
MatrixAngles( worldToCamera, m_Camera.m_angles, m_Camera.m_origin ); |
|
ComputeScreenSpacePosition( pPanelPos, vecPosition, m_Camera, w, h ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Utility method to draw a grid at the 'ground' |
|
//----------------------------------------------------------------------------- |
|
void CPotteryWheelPanel::DrawGrid() |
|
{ |
|
matrix3x4_t transform; |
|
CMatRenderContextPtr pRenderContext( MaterialSystem() ); |
|
pRenderContext->MatrixMode( MATERIAL_MODEL ); |
|
pRenderContext->LoadIdentity( ); |
|
|
|
pRenderContext->Bind( m_Wireframe ); |
|
|
|
IMesh *pMesh = pRenderContext->GetDynamicMesh(); |
|
|
|
int nGridDim = 10; |
|
CMeshBuilder meshBuilder; |
|
meshBuilder.Begin( pMesh, MATERIAL_LINES, 2 * nGridDim + 2 ); |
|
|
|
float bounds = 100.0f; |
|
float delta = 2 * bounds / nGridDim; |
|
for ( int i = 0; i < nGridDim + 1; ++i ) |
|
{ |
|
float xy = -bounds + delta * i; |
|
|
|
meshBuilder.Position3f( xy, -bounds, 0 ); |
|
meshBuilder.Color4ub( 255, 255, 255, 255 ); |
|
meshBuilder.AdvanceVertex(); |
|
meshBuilder.Position3f( xy, bounds, 0 ); |
|
meshBuilder.Color4ub( 255, 255, 255, 255 ); |
|
meshBuilder.AdvanceVertex(); |
|
|
|
meshBuilder.Position3f( -bounds, xy, 0 ); |
|
meshBuilder.Color4ub( 255, 255, 255, 255 ); |
|
meshBuilder.AdvanceVertex(); |
|
meshBuilder.Position3f( bounds, xy, 0 ); |
|
meshBuilder.Color4ub( 255, 255, 255, 255 ); |
|
meshBuilder.AdvanceVertex(); |
|
} |
|
|
|
meshBuilder.End(); |
|
pMesh->Draw(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// paint it! |
|
//----------------------------------------------------------------------------- |
|
void CPotteryWheelPanel::Paint() |
|
{ |
|
int iWidth, iHeight; |
|
GetSize( iWidth, iHeight ); |
|
|
|
int screenw, screenh; |
|
vgui::surface()->GetScreenSize( screenw, screenh ); |
|
|
|
int windowposx = 0, windowposy = 0; |
|
GetPos( windowposx, windowposy ); |
|
|
|
int windowposright = windowposx + iWidth; |
|
int windowposbottom = windowposy + iHeight; |
|
|
|
if ( windowposright >= screenw ) |
|
{ |
|
iWidth -= ( windowposright - screenw ); |
|
} |
|
if ( windowposbottom >= screenh ) |
|
{ |
|
iHeight -= ( windowposbottom - screenh ); |
|
} |
|
|
|
int startx = 0, starty = 0; |
|
if( windowposx < 0 ) |
|
{ |
|
startx = -windowposx; |
|
iWidth -= startx; |
|
} |
|
if ( windowposy < 0 ) |
|
{ |
|
starty = -windowposy; |
|
iHeight -= starty; |
|
} |
|
|
|
int w, h; |
|
GetSize( w, h ); |
|
vgui::MatSystemSurface()->Begin3DPaint( 0, 0, w, h, m_bRenderToTexture ); |
|
|
|
if ( m_pCurrentManip ) |
|
{ |
|
m_pCurrentManip->SetViewportSize( iWidth, iHeight ); |
|
} |
|
|
|
// Set up the render state for the camera + light |
|
SetupRenderState( iWidth, iHeight ); |
|
|
|
CMatRenderContextPtr pRenderContext( vgui::MaterialSystem() ); |
|
|
|
if ( m_bUseParentBG && GetParent() ) |
|
{ |
|
Color bgCol = GetParent()->GetBgColor(); |
|
pRenderContext->ClearColor4ub( bgCol.r(), bgCol.g(), bgCol.b(), bgCol.a() ); |
|
} |
|
else |
|
{ |
|
pRenderContext->ClearColor4ub( m_ClearColor.r(), m_ClearColor.g(), m_ClearColor.b(), m_ClearColor.a() ); |
|
} |
|
pRenderContext->ClearBuffers( m_bRenderToTexture, true ); |
|
|
|
pRenderContext->CullMode( MATERIAL_CULLMODE_CCW ); |
|
pRenderContext->SetIntRenderingParameter( INT_RENDERPARM_WRITE_DEPTH_TO_DESTALPHA, false ); |
|
|
|
if ( HasLightProbe() ) |
|
{ |
|
IMaterial *pMaterial = ( vgui::MaterialSystemHardwareConfig()->GetHDRType() == HDR_TYPE_NONE ) ? |
|
m_LightProbeBackground : m_LightProbeHDRBackground; |
|
|
|
RenderBox( m_Camera.m_origin, vec3_angle, Vector( -100, -100, -100 ), Vector( 100, 100, 100 ), |
|
Color( 255, 255, 255, 255 ), pMaterial, true ); |
|
} |
|
|
|
OnPaint3D(); |
|
|
|
pRenderContext->CullMode( MATERIAL_CULLMODE_CW ); |
|
|
|
vgui::MatSystemSurface()->End3DPaint( ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// called when we're ticked... |
|
//----------------------------------------------------------------------------- |
|
void CPotteryWheelPanel::OnTick() |
|
{ |
|
BaseClass::OnTick(); |
|
if ( m_pCurrentManip ) |
|
{ |
|
m_pCurrentManip->OnTick(); |
|
UpdateCameraTransform(); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// input |
|
//----------------------------------------------------------------------------- |
|
void CPotteryWheelPanel::OnKeyCodePressed(KeyCode code) |
|
{ |
|
if ( m_pCurrentManip ) |
|
{ |
|
switch( code ) |
|
{ |
|
case KEY_RSHIFT: |
|
case KEY_LSHIFT: |
|
// start translate mode |
|
AcceptManipulation( false ); |
|
EnterManipulationMode( CAMERA_TRANSLATE, false ); |
|
break; |
|
|
|
case KEY_RCONTROL: |
|
case KEY_LCONTROL: |
|
// start light mode |
|
AcceptManipulation( false ); |
|
EnterManipulationMode( LIGHT_MODE, false ); |
|
break; |
|
} |
|
} |
|
|
|
BaseClass::OnKeyCodePressed( code ); |
|
} |
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: soaks up any remaining messages |
|
//----------------------------------------------------------------------------- |
|
void CPotteryWheelPanel::OnKeyCodeReleased(KeyCode code) |
|
{ |
|
if ( m_pCurrentManip ) |
|
{ |
|
switch( code ) |
|
{ |
|
case KEY_RSHIFT: |
|
case KEY_LSHIFT: |
|
case KEY_RCONTROL: |
|
case KEY_LCONTROL: |
|
{ |
|
// stop manipulation mode |
|
AcceptManipulation( false ); |
|
switch ( m_nCaptureMouseCode ) |
|
{ |
|
default: |
|
case MOUSE_LEFT: |
|
EnterManipulationMode( CAMERA_ROTATE, false ); |
|
break; |
|
|
|
case MOUSE_MIDDLE: |
|
EnterManipulationMode( CAMERA_TRANSLATE, false ); |
|
break; |
|
|
|
case MOUSE_RIGHT: |
|
EnterManipulationMode( CAMERA_ZOOM, false ); |
|
break; |
|
} |
|
} |
|
break; |
|
} |
|
} |
|
BaseClass::OnKeyCodeReleased( code ); |
|
} |
|
|
|
void CPotteryWheelPanel::OnMousePressed( vgui::MouseCode code ) |
|
{ |
|
if ( m_pCurrentManip ) |
|
return; |
|
|
|
RequestFocus(); |
|
|
|
if ( input()->IsKeyDown( KEY_RSHIFT ) || input()->IsKeyDown( KEY_LSHIFT ) ) |
|
{ |
|
EnterManipulationMode( CAMERA_TRANSLATE, true, code ); |
|
} |
|
else if ( input()->IsKeyDown( KEY_RCONTROL ) || input()->IsKeyDown( KEY_LCONTROL ) ) |
|
{ |
|
EnterManipulationMode( LIGHT_MODE, true, code ); |
|
} |
|
else |
|
{ |
|
switch ( code ) |
|
{ |
|
case MOUSE_LEFT: |
|
EnterManipulationMode( CAMERA_ROTATE, true, code ); |
|
break; |
|
|
|
case MOUSE_MIDDLE: |
|
EnterManipulationMode( CAMERA_TRANSLATE, true, code ); |
|
break; |
|
|
|
case MOUSE_RIGHT: |
|
EnterManipulationMode( CAMERA_ZOOM, true, code ); |
|
break; |
|
} |
|
} |
|
|
|
BaseClass::OnMousePressed( code ); |
|
} |
|
|
|
void CPotteryWheelPanel::OnMouseReleased( vgui::MouseCode code ) |
|
{ |
|
int x, y; |
|
input()->GetCursorPos( x, y ); |
|
ScreenToLocal( x, y ); |
|
|
|
AcceptManipulation(); |
|
|
|
BaseClass::OnMouseReleased( code ); |
|
} |
|
|
|
void CPotteryWheelPanel::OnCursorMoved( int x, int y ) |
|
{ |
|
if ( m_pCurrentManip ) |
|
{ |
|
if ( WarpMouse( x, y ) ) |
|
{ |
|
m_pCurrentManip->OnCursorMoved( x, y ); |
|
} |
|
} |
|
|
|
BaseClass::OnCursorMoved( x, y ); |
|
} |
|
|
|
void CPotteryWheelPanel::OnMouseWheeled( int delta ) |
|
{ |
|
if ( m_pCurrentManip ) |
|
{ |
|
m_pCurrentManip->OnMouseWheeled( delta ); |
|
} |
|
|
|
BaseClass::OnMouseWheeled( delta ); |
|
} |
|
|
|
|
|
void CPotteryWheelPanel::EnterManipulationMode( ManipulationMode_t manipMode, bool bMouseCapture, vgui::MouseCode mouseCode /* = -1 */ ) |
|
{ |
|
switch ( manipMode ) |
|
{ |
|
case CAMERA_ROTATE: |
|
m_pCurrentManip = m_pCameraRotate; |
|
break; |
|
|
|
case CAMERA_TRANSLATE: |
|
m_pCurrentManip = m_pCameraTranslate; |
|
break; |
|
|
|
case CAMERA_ZOOM: |
|
m_pCurrentManip = m_pCameraZoom; |
|
break; |
|
|
|
case LIGHT_MODE: |
|
m_pCurrentManip = m_pLightManip; |
|
break; |
|
} |
|
|
|
if ( !m_pCurrentManip ) |
|
return; |
|
|
|
m_pCurrentManip->OnBeginManipulation(); |
|
|
|
m_xoffset = m_yoffset = 0; |
|
|
|
// Warp the mouse to the center of the screen |
|
int width, height; |
|
GetSize( width, height ); |
|
int x = width / 2; |
|
int y = height / 2; |
|
|
|
if ( bMouseCapture ) |
|
{ |
|
input()->GetCursorPos( m_nManipStartX, m_nManipStartY ); |
|
EnableMouseCapture( true, mouseCode ); |
|
|
|
int xpos = x; |
|
int ypos = y; |
|
LocalToScreen( xpos, ypos ); |
|
input()->SetCursorPos( xpos, ypos ); |
|
} |
|
|
|
m_pCurrentManip->OnMousePressed( mouseCode, x, y ); |
|
} |
|
|
|
void CPotteryWheelPanel::AcceptManipulation( bool bReleaseMouseCapture ) |
|
{ |
|
if ( m_pCurrentManip ) |
|
{ |
|
m_pCurrentManip->OnAcceptManipulation(); |
|
|
|
if ( bReleaseMouseCapture ) |
|
{ |
|
EnableMouseCapture( false ); |
|
input()->SetCursorPos( m_nManipStartX, m_nManipStartY ); |
|
} |
|
|
|
m_pCurrentManip = NULL; |
|
} |
|
} |
|
|
|
void CPotteryWheelPanel::CancelManipulation() |
|
{ |
|
if ( m_pCurrentManip ) |
|
{ |
|
m_pCurrentManip->OnCancelManipulation(); |
|
|
|
EnableMouseCapture( false ); |
|
input()->SetCursorPos( m_nManipStartX, m_nManipStartY ); |
|
|
|
m_pCurrentManip = NULL; |
|
} |
|
|
|
} |
|
|
|
void CPotteryWheelPanel::ApplyManipulation() |
|
{ |
|
if ( dynamic_cast< CRotationManipulator * >( m_pCameraRotate ) ) |
|
{ |
|
dynamic_cast< CRotationManipulator * >( m_pCameraRotate )->UpdateTransform(); |
|
} |
|
UpdateCameraTransform(); |
|
} |
|
|
|
void CPotteryWheelPanel::SyncManipulation() |
|
{ |
|
if ( dynamic_cast< CRotationManipulator * >( m_pCameraRotate ) ) |
|
{ |
|
dynamic_cast< CRotationManipulator * >( m_pCameraRotate )->UpdateFromMatrix(); |
|
} |
|
} |
|
|
|
void CPotteryWheelPanel::OnMouseCaptureLost() |
|
{ |
|
SetCursor( vgui::dc_arrow ); |
|
m_nCaptureMouseCode = vgui::MouseCode( -1 ); |
|
} |
|
|
|
void CPotteryWheelPanel::EnableMouseCapture( bool enable, vgui::MouseCode mouseCode /* = -1 */ ) |
|
{ |
|
if ( enable ) |
|
{ |
|
m_nCaptureMouseCode = mouseCode; |
|
SetCursor( vgui::dc_none ); |
|
input()->SetMouseCaptureEx( GetVPanel(), m_nCaptureMouseCode ); |
|
} |
|
else |
|
{ |
|
m_nCaptureMouseCode = vgui::MouseCode( -1 ); |
|
input()->SetMouseCapture( (VPANEL)0 ); |
|
SetCursor( vgui::dc_arrow ); |
|
} |
|
} |
|
|
|
bool CPotteryWheelPanel::WarpMouse( int &x, int &y ) |
|
{ |
|
// Re-force capture if it was lost... |
|
if ( input()->GetMouseCapture() != GetVPanel() ) |
|
{ |
|
input()->GetCursorPos( m_nManipStartX, m_nManipStartY ); |
|
EnableMouseCapture( true, m_nCaptureMouseCode ); |
|
} |
|
|
|
int width, height; |
|
GetSize( width, height ); |
|
|
|
int centerx = width / 2; |
|
int centery = height / 2; |
|
|
|
// skip this event |
|
if ( x == centerx && y == centery ) |
|
return false; |
|
|
|
int xpos = centerx; |
|
int ypos = centery; |
|
LocalToScreen( xpos, ypos ); |
|
|
|
#if defined( DX_TO_GL_ABSTRACTION ) |
|
// |
|
// Really reset the cursor to the center for the PotteryWheel Control |
|
// |
|
// In TF2's edit loadout dialog there is a character model that you can rotate |
|
// around using the mouse. This control resets the cursor to the center of the window |
|
// after each mouse move. Except the input()->SetCursorPos results (after a lot of redirection) to |
|
// vgui/matsurface/Cursor.cpp function CursorSetPos but it has a (needed) test to not move the |
|
// cursor if it's currently hidden. Rather than change all the levels between here and there |
|
// to support a flag, we are just jumping to the chase and directly calling the inputsystem |
|
// SetCursorPosition on OpenGL platforms |
|
// |
|
g_pInputSystem->SetCursorPosition( xpos, ypos ); |
|
#else |
|
input()->SetCursorPos( xpos, ypos ); |
|
#endif |
|
|
|
int dx = x - centerx; |
|
int dy = y - centery; |
|
|
|
x += m_xoffset; |
|
y += m_yoffset; |
|
|
|
m_xoffset += dx; |
|
m_yoffset += dy; |
|
|
|
return true; |
|
}
|
|
|