summaryrefslogtreecommitdiff
path: root/vgui2/matsys_controls/potterywheelpanel.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /vgui2/matsys_controls/potterywheelpanel.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'vgui2/matsys_controls/potterywheelpanel.cpp')
-rw-r--r--vgui2/matsys_controls/potterywheelpanel.cpp1243
1 files changed, 1243 insertions, 0 deletions
diff --git a/vgui2/matsys_controls/potterywheelpanel.cpp b/vgui2/matsys_controls/potterywheelpanel.cpp
new file mode 100644
index 0000000..60b3e10
--- /dev/null
+++ b/vgui2/matsys_controls/potterywheelpanel.cpp
@@ -0,0 +1,1243 @@
+//========= 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;
+}