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.

1243 lines
32 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "matsys_controls/potterywheelpanel.h"
  7. #include "matsys_controls/manipulator.h"
  8. #include "vgui/ISystem.h"
  9. #include "vgui/Cursor.h"
  10. #include "vgui/IVGui.h"
  11. #include "vgui/ISurface.h"
  12. #include "vgui/IInput.h"
  13. #include "VGuiMatSurface/IMatSystemSurface.h"
  14. #include "dmxloader/dmxelement.h"
  15. #include "vgui_controls/Frame.h"
  16. #include "convar.h"
  17. #include "tier0/dbg.h"
  18. #include "matsys_controls/matsyscontrols.h"
  19. #include "materialsystem/imaterial.h"
  20. #include "materialsystem/imaterialsystem.h"
  21. #include "istudiorender.h"
  22. #include "materialsystem/imaterialsystemhardwareconfig.h"
  23. #include "tier2/renderutils.h"
  24. #include "tier1/KeyValues.h"
  25. #include "materialsystem/imesh.h"
  26. #include "inputsystem/iinputsystem.h"
  27. #include "renderparm.h"
  28. // memdbgon must be the last include file in a .cpp file!!!
  29. #include "tier0/memdbgon.h"
  30. using namespace vgui;
  31. //-----------------------------------------------------------------------------
  32. // Translation manipulator
  33. //-----------------------------------------------------------------------------
  34. class CTranslationManipulator : public CTransformManipulator
  35. {
  36. public:
  37. CTranslationManipulator( matrix3x4_t *pTransform );
  38. // Methods of IManipulator
  39. virtual void OnMousePressed( vgui::MouseCode code, int x, int y );
  40. virtual void OnCursorMoved( int x, int y );
  41. protected:
  42. int m_lastx, m_lasty;
  43. };
  44. CTranslationManipulator::CTranslationManipulator( matrix3x4_t *pTransform ) : CTransformManipulator( pTransform )
  45. {
  46. m_lastx = m_lasty = 0;
  47. }
  48. void CTranslationManipulator::OnMousePressed( vgui::MouseCode code, int x, int y )
  49. {
  50. m_lasty = y;
  51. m_lastx = x;
  52. }
  53. void CTranslationManipulator::OnCursorMoved( int x, int y )
  54. {
  55. if ( !m_pTransform )
  56. return;
  57. Vector vPosition;
  58. QAngle quakeEuler;
  59. MatrixAngles( *m_pTransform, quakeEuler, vPosition );
  60. Vector forward, right, up;
  61. AngleVectors( quakeEuler, &forward, &right, &up );
  62. int dy = y - m_lasty;
  63. int dx = x - m_lastx;
  64. right *= -0.2f * dx;
  65. up *= 0.2f * dy;
  66. vPosition += up + right;
  67. m_lastx = x;
  68. m_lasty = y;
  69. PositionMatrix( vPosition, *m_pTransform );
  70. }
  71. //-----------------------------------------------------------------------------
  72. // Zoom manipulator
  73. //-----------------------------------------------------------------------------
  74. class CZoomManipulator : public CBaseManipulator
  75. {
  76. public:
  77. CZoomManipulator( float *pDistance );
  78. // Methods of IManipulator
  79. virtual void OnMousePressed( vgui::MouseCode code, int x, int y );
  80. virtual void OnCursorMoved( int x, int y );
  81. protected:
  82. int m_lasty;
  83. float *m_pDistance;
  84. };
  85. CZoomManipulator::CZoomManipulator( float *pDistance )
  86. {
  87. m_lasty = 0;
  88. m_pDistance = pDistance;
  89. }
  90. void CZoomManipulator::OnMousePressed( vgui::MouseCode code, int x, int y )
  91. {
  92. m_lasty = y;
  93. }
  94. void CZoomManipulator::OnCursorMoved( int x, int y )
  95. {
  96. float delta = 0.2f * ( y - m_lasty );
  97. m_lasty = y;
  98. *m_pDistance *= pow( 1.01f, delta );
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Rotation manipulator
  102. //-----------------------------------------------------------------------------
  103. class CRotationManipulator : public CTransformManipulator
  104. {
  105. public:
  106. CRotationManipulator( matrix3x4_t *pTransform );
  107. // Inherited from IManipulator
  108. virtual void OnMousePressed( vgui::MouseCode code, int x, int y );
  109. virtual void OnCursorMoved( int x, int y );
  110. virtual void UpdateTransform();
  111. void UpdateFromMatrix( void );
  112. private:
  113. int m_lastx, m_lasty;
  114. float m_altitude, m_azimuth, m_roll;
  115. bool m_bDoRoll;
  116. };
  117. CRotationManipulator::CRotationManipulator( matrix3x4_t *pTransform ) : CTransformManipulator( pTransform )
  118. {
  119. m_lastx = m_lasty = 0;
  120. m_altitude = M_PI/6;
  121. m_azimuth = -3*M_PI/4;
  122. m_roll = 0.0f;
  123. m_bDoRoll = false;
  124. UpdateTransform();
  125. }
  126. void CRotationManipulator::OnMousePressed( vgui::MouseCode code, int x, int y )
  127. {
  128. if ( input()->IsKeyDown( KEY_LALT ) || input()->IsKeyDown( KEY_RALT ) )
  129. {
  130. m_bDoRoll = true;
  131. }
  132. else
  133. {
  134. m_bDoRoll = false;
  135. }
  136. m_lasty = y;
  137. m_lastx = x;
  138. }
  139. void CRotationManipulator::OnCursorMoved( int x, int y )
  140. {
  141. if ( m_bDoRoll )
  142. {
  143. m_roll += 0.002f * ( m_lastx - x );
  144. }
  145. else
  146. {
  147. m_azimuth += 0.002f * ( m_lastx - x );
  148. m_altitude -= 0.002f * ( m_lasty - y );
  149. m_altitude = max( (float)-M_PI/2, min( (float)M_PI/2, m_altitude ) );
  150. }
  151. m_lastx = x;
  152. m_lasty = y;
  153. UpdateTransform();
  154. }
  155. void CRotationManipulator::UpdateTransform()
  156. {
  157. if ( !m_pTransform )
  158. return;
  159. QAngle angles( RAD2DEG( m_altitude ), RAD2DEG( m_azimuth ), RAD2DEG( m_roll ) );
  160. Vector vecPosition;
  161. MatrixGetColumn( *m_pTransform, 3, vecPosition );
  162. AngleMatrix( angles, vecPosition, *m_pTransform );
  163. }
  164. void CRotationManipulator::UpdateFromMatrix( void )
  165. {
  166. if ( !m_pTransform )
  167. return;
  168. QAngle angDir;
  169. Vector vecPos;
  170. MatrixAngles( *m_pTransform, angDir, vecPos );
  171. m_altitude = DEG2RAD( angDir.x );
  172. m_azimuth = DEG2RAD( angDir.y );
  173. m_roll = DEG2RAD( angDir.z );
  174. }
  175. //-----------------------------------------------------------------------------
  176. // Constructor, destructor
  177. //-----------------------------------------------------------------------------
  178. CPotteryWheelPanel::CPotteryWheelPanel( vgui::Panel *pParent, const char *pName ) :
  179. BaseClass( pParent, pName ),
  180. m_pCameraRotate( NULL ),
  181. m_pCameraTranslate( NULL ),
  182. m_pCameraZoom( NULL ),
  183. m_pLightManip( NULL ),
  184. m_pCurrentManip( NULL ),
  185. m_nCaptureMouseCode( vgui::MouseCode( -1 ) ),
  186. m_xoffset( 0 ), m_yoffset( 0 ),
  187. m_bRenderToTexture( true )
  188. {
  189. m_bHasLightProbe = false;
  190. SetPaintBackgroundEnabled( false );
  191. SetPaintBorderEnabled( false );
  192. m_ClearColor.SetColor( 76, 88, 68, 255 );
  193. SetIdentityMatrix( m_CameraPivot );
  194. CreateDefaultLights();
  195. m_nManipStartX = m_nManipStartY = 0;
  196. m_vecCameraOffset.Init( 100.0f, 0.0f, 0.0f );
  197. m_Camera.m_flZNear = 3.0f;
  198. m_Camera.m_flZFar = 16384.0f * 1.73205080757f;
  199. m_Camera.m_flFOV = 30.0f;
  200. m_pCameraRotate = new CRotationManipulator( &m_CameraPivot );
  201. m_pCameraTranslate = new CTranslationManipulator( &m_CameraPivot );
  202. m_pCameraZoom = new CZoomManipulator( &m_vecCameraOffset.x );
  203. KeyValues *pMaterialKeys = new KeyValues( "Wireframe", "$model", "1" );
  204. pMaterialKeys->SetString( "$vertexcolor", "1" );
  205. m_Wireframe.Init( "potterywheelpanelwireframe", pMaterialKeys );
  206. SetKeyBoardInputEnabled( true );
  207. UpdateCameraTransform();
  208. }
  209. void CPotteryWheelPanel::ApplySettings( KeyValues *inResourceData )
  210. {
  211. BaseClass::ApplySettings( inResourceData );
  212. KeyValues *pLights = inResourceData->FindKey( "lights" );
  213. if ( pLights )
  214. {
  215. ParseLightsFromKV( pLights );
  216. }
  217. }
  218. void CPotteryWheelPanel::Init( int x, int y, int wide, int tall )
  219. {
  220. BaseClass::Init( x, y, wide, tall );
  221. // Used to poll input
  222. vgui::ivgui()->AddTickSignal( GetVPanel() );
  223. }
  224. CPotteryWheelPanel::~CPotteryWheelPanel()
  225. {
  226. m_Wireframe.Shutdown();
  227. m_LightProbeBackground.Shutdown();
  228. m_LightProbeHDRBackground.Shutdown();
  229. m_LightProbeCubemap.Shutdown();
  230. m_LightProbeHDRCubemap.Shutdown();
  231. if ( m_pCameraRotate )
  232. {
  233. delete m_pCameraRotate;
  234. m_pCameraRotate = NULL;
  235. }
  236. if ( m_pCameraZoom )
  237. {
  238. delete m_pCameraZoom;
  239. m_pCameraZoom = NULL;
  240. }
  241. if ( m_pCameraTranslate )
  242. {
  243. delete m_pCameraTranslate;
  244. m_pCameraTranslate = NULL;
  245. }
  246. DestroyLights();
  247. }
  248. void CPotteryWheelPanel::CreateDefaultLights()
  249. {
  250. for ( int i = 0; i < 6; ++i )
  251. {
  252. m_vecAmbientCube[i].Init( 0.4f, 0.4f, 0.4f, 1.0f );
  253. }
  254. memset( &m_Lights[0].m_Desc, 0, sizeof(LightDesc_t) );
  255. SetIdentityMatrix( m_Lights[0].m_LightToWorld );
  256. m_Lights[0].m_Desc.m_Type = MATERIAL_LIGHT_DIRECTIONAL;
  257. m_Lights[0].m_Desc.m_Color.Init( 1.0f, 1.0f, 1.0f );
  258. m_Lights[0].m_Desc.m_Direction.Init( 0.0f, 0.0f, -1.0f );
  259. m_Lights[0].m_Desc.m_Range=0.0;
  260. m_Lights[0].m_Desc.m_Attenuation0 = 1.0;
  261. m_Lights[0].m_Desc.m_Attenuation1 = 0;
  262. m_Lights[0].m_Desc.m_Attenuation2 = 0;
  263. m_Lights[0].m_Desc.RecalculateDerivedValues();
  264. m_nLightCount = 1;
  265. m_pLightManip = new CPotteryWheelManip( &m_Lights[0].m_LightToWorld );
  266. }
  267. void CPotteryWheelPanel::DestroyLights()
  268. {
  269. if ( m_pLightManip )
  270. {
  271. delete m_pLightManip;
  272. m_pLightManip = NULL;
  273. }
  274. m_nLightCount = 0;
  275. }
  276. void StringToFloatArray( float *pVector, int count, const char *pString )
  277. {
  278. char *pstr, *pfront, tempString[128];
  279. int j;
  280. Q_strncpy( tempString, pString, sizeof(tempString) );
  281. pstr = pfront = tempString;
  282. for ( j = 0; j < count; j++ ) // lifted from pr_edict.c
  283. {
  284. pVector[j] = atof( pfront );
  285. // skip any leading whitespace
  286. while ( *pstr && *pstr <= ' ' )
  287. pstr++;
  288. // skip to next whitespace
  289. while ( *pstr && *pstr > ' ' )
  290. pstr++;
  291. if (!*pstr)
  292. break;
  293. pstr++;
  294. pfront = pstr;
  295. }
  296. for ( j++; j < count; j++ )
  297. {
  298. pVector[j] = 0;
  299. }
  300. }
  301. void StringToVector( float *pVector, const char *pString )
  302. {
  303. StringToFloatArray( pVector, 3, pString );
  304. }
  305. //-----------------------------------------------------------------------------
  306. // Sets initialize lights from KeyValues
  307. //-----------------------------------------------------------------------------
  308. void CPotteryWheelPanel::ParseLightsFromKV( KeyValues *pLightsKV )
  309. {
  310. int nLightCount = 0;
  311. FOR_EACH_SUBKEY( pLightsKV, pLocalLight )
  312. {
  313. Assert( nLightCount < MAX_LIGHT_COUNT );
  314. if ( nLightCount >= MAX_LIGHT_COUNT )
  315. break;
  316. LightDesc_t *pDesc = &m_Lights[nLightCount].m_Desc;
  317. const char *pType = pLocalLight->GetString( "name" );
  318. Vector vecColor;
  319. StringToVector( vecColor.Base(), pLocalLight->GetString( "color" ) );
  320. if ( !Q_stricmp( pType, "directional" ) )
  321. {
  322. Vector vecDirection;
  323. StringToVector( vecDirection.Base(), pLocalLight->GetString( "direction" ) );
  324. pDesc->InitDirectional( vecDirection.Normalized(), vecColor );
  325. ++nLightCount;
  326. continue;
  327. }
  328. if ( !Q_stricmp( pType, "point" ) )
  329. {
  330. Vector vecAtten;
  331. StringToVector( vecAtten.Base(), pLocalLight->GetString( "attenuation" ) );
  332. Vector vecOrigin;
  333. StringToVector( vecOrigin.Base(), pLocalLight->GetString( "origin" ) );
  334. pDesc->InitPoint( vecOrigin, vecColor );
  335. pDesc->m_Attenuation0 = vecAtten.x;
  336. pDesc->m_Attenuation1 = vecAtten.y;
  337. pDesc->m_Attenuation2 = vecAtten.z;
  338. pDesc->m_Range = pLocalLight->GetFloat( "maxDistance" );
  339. pDesc->RecalculateDerivedValues();
  340. ++nLightCount;
  341. continue;
  342. }
  343. if ( !Q_stricmp( pType, "spot" ) )
  344. {
  345. Vector vecAtten;
  346. StringToVector( vecAtten.Base(), pLocalLight->GetString( "attenuation" ) );
  347. Vector vecOrigin;
  348. StringToVector( vecOrigin.Base(), pLocalLight->GetString( "origin" ) );
  349. pDesc->InitSpot( vecOrigin, vecColor, vec3_origin,
  350. pLocalLight->GetFloat( "inner_cone_angle" ),
  351. pLocalLight->GetFloat( "outer_cone_angle" ) );
  352. Vector vecDirection;
  353. StringToVector( vecDirection.Base(), pLocalLight->GetString( "direction" ) );
  354. pDesc->m_Direction = vecDirection.Normalized();
  355. pDesc->m_Attenuation0 = vecAtten.x;
  356. pDesc->m_Attenuation1 = vecAtten.y;
  357. pDesc->m_Attenuation2 = vecAtten.z;
  358. pDesc->m_Range = pLocalLight->GetFloat( "maxDistance" );
  359. pDesc->m_Falloff = pLocalLight->GetFloat( "exponent" );
  360. pDesc->RecalculateDerivedValues();
  361. ++nLightCount;
  362. continue;
  363. }
  364. AssertMsg1( 0, "Failed to initialize light with type '%s'", pType );
  365. }
  366. AssertMsg( nLightCount > 0, "Must specify at least one valid light" );
  367. m_nLightCount = nLightCount;
  368. }
  369. //-----------------------------------------------------------------------------
  370. // Sets the background color
  371. //-----------------------------------------------------------------------------
  372. void CPotteryWheelPanel::SetBackgroundColor( int r, int g, int b )
  373. {
  374. m_ClearColor.SetColor( r, g, b, 255 );
  375. }
  376. void CPotteryWheelPanel::SetBackgroundColor( const Color& c )
  377. {
  378. m_ClearColor = c;
  379. }
  380. const Color& CPotteryWheelPanel::GetBackgroundColor() const
  381. {
  382. return m_ClearColor;
  383. }
  384. //-----------------------------------------------------------------------------
  385. // Light probe
  386. //-----------------------------------------------------------------------------
  387. void CPotteryWheelPanel::SetLightProbe( CDmxElement *pLightProbe )
  388. {
  389. m_LightProbeBackground.Shutdown();
  390. m_LightProbeHDRBackground.Shutdown();
  391. m_LightProbeCubemap.Shutdown();
  392. m_LightProbeHDRCubemap.Shutdown();
  393. DestroyLights();
  394. m_bHasLightProbe = ( pLightProbe != NULL );
  395. if ( !m_bHasLightProbe )
  396. {
  397. CreateDefaultLights();
  398. return;
  399. }
  400. const char *pCubemap = pLightProbe->GetValueString( "cubemap" );
  401. m_LightProbeCubemap.Init( pCubemap, TEXTURE_GROUP_OTHER );
  402. const char *pCubemapHDR = pLightProbe->HasAttribute( "cubemapHdr" ) ? pLightProbe->GetValueString( "cubemapHdr" ) : pCubemap;
  403. m_LightProbeHDRCubemap.Init( pCubemapHDR, TEXTURE_GROUP_OTHER );
  404. KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
  405. pVMTKeyValues->SetInt( "$ignorez", 1 );
  406. pVMTKeyValues->SetString( "$envmap", pCubemap );
  407. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  408. pVMTKeyValues->SetInt( "$nocull", 1 );
  409. m_LightProbeBackground.Init( "SPWP_LightProbeBackground", pVMTKeyValues );
  410. m_LightProbeBackground->Refresh();
  411. pVMTKeyValues = new KeyValues( "UnlitGeneric" );
  412. pVMTKeyValues->SetInt( "$ignorez", 1 );
  413. pVMTKeyValues->SetString( "$envmap", pCubemapHDR );
  414. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  415. pVMTKeyValues->SetInt( "$nocull", 1 );
  416. m_LightProbeHDRBackground.Init( "SPWP_LightProbeBackground_HDR", pVMTKeyValues );
  417. m_LightProbeHDRBackground->Refresh();
  418. const CUtlVector< Vector >& ambientCube = pLightProbe->GetArray<Vector>( "ambientCube" );
  419. if ( ambientCube.Count() == 6 )
  420. {
  421. for ( int i = 0; i < 6; ++i )
  422. {
  423. m_vecAmbientCube[i].Init( ambientCube[i].x, ambientCube[i].y, ambientCube[i].z, 0.0f );
  424. }
  425. }
  426. const CUtlVector< CDmxElement* >& localLights = pLightProbe->GetArray< CDmxElement* >( "localLights" );
  427. int nLightCount = localLights.Count();
  428. for ( int i = 0; i < nLightCount; ++i )
  429. {
  430. if ( m_nLightCount == MAX_LIGHT_COUNT )
  431. break;
  432. LightDesc_t *pDesc = &m_Lights[m_nLightCount].m_Desc;
  433. CDmxElement *pLocalLight = localLights[ i ];
  434. const char *pType = pLocalLight->GetValueString( "name" );
  435. const Vector& vecColor = pLocalLight->GetValue<Vector>( "color" );
  436. if ( !Q_stricmp( pType, "directional" ) )
  437. {
  438. pDesc->InitDirectional( pLocalLight->GetValue<Vector>( "direction" ), vecColor );
  439. ++m_nLightCount;
  440. continue;
  441. }
  442. if ( !Q_stricmp( pType, "point" ) )
  443. {
  444. const Vector& vecAtten = pLocalLight->GetValue<Vector>( "attenuation" );
  445. pDesc->InitPoint( pLocalLight->GetValue<Vector>( "origin" ), vecColor );
  446. pDesc->m_Attenuation0 = vecAtten.x;
  447. pDesc->m_Attenuation1 = vecAtten.y;
  448. pDesc->m_Attenuation2 = vecAtten.z;
  449. pDesc->m_Range = pLocalLight->GetValue<float>( "maxDistance" );
  450. pDesc->RecalculateDerivedValues();
  451. ++m_nLightCount;
  452. continue;
  453. }
  454. if ( !Q_stricmp( pType, "spot" ) )
  455. {
  456. const Vector& vecAtten = pLocalLight->GetValue<Vector>( "attenuation" );
  457. pDesc->InitSpot( pLocalLight->GetValue<Vector>( "origin" ), vecColor, vec3_origin,
  458. RAD2DEG ( pLocalLight->GetValue<float>( "theta" ) ),
  459. RAD2DEG ( pLocalLight->GetValue<float>( "phi" ) ) );
  460. pDesc->m_Direction = pLocalLight->GetValue<Vector>( "direction" );
  461. pDesc->m_Attenuation0 = vecAtten.x;
  462. pDesc->m_Attenuation1 = vecAtten.y;
  463. pDesc->m_Attenuation2 = vecAtten.z;
  464. pDesc->m_Range = pLocalLight->GetValue<float>( "maxDistance" );
  465. pDesc->m_Falloff = pLocalLight->GetValue<float>( "exponent" );
  466. pDesc->RecalculateDerivedValues();
  467. ++m_nLightCount;
  468. continue;
  469. }
  470. }
  471. if ( nLightCount > 0 )
  472. {
  473. m_pLightManip = new CPotteryWheelManip( &m_Lights[0].m_LightToWorld );
  474. }
  475. }
  476. bool CPotteryWheelPanel::HasLightProbe() const
  477. {
  478. return m_bHasLightProbe;
  479. }
  480. ITexture *CPotteryWheelPanel::GetLightProbeCubemap( bool bHDR )
  481. {
  482. if ( !m_bHasLightProbe )
  483. return NULL;
  484. return bHDR ? m_LightProbeHDRCubemap : m_LightProbeCubemap;
  485. }
  486. //-----------------------------------------------------------------------------
  487. // Purpose:
  488. //-----------------------------------------------------------------------------
  489. int CPotteryWheelPanel::GetCameraFOV( void )
  490. {
  491. return m_Camera.m_flFOV;
  492. }
  493. //-----------------------------------------------------------------------------
  494. // Purpose:
  495. //-----------------------------------------------------------------------------
  496. void CPotteryWheelPanel::SetCameraFOV( float flFOV )
  497. {
  498. m_Camera.m_flFOV = flFOV;
  499. }
  500. //-----------------------------------------------------------------------------
  501. // Purpose:
  502. //-----------------------------------------------------------------------------
  503. void CPotteryWheelPanel::SetCameraOffset( const Vector &vecOffset )
  504. {
  505. m_vecCameraOffset = vecOffset;
  506. }
  507. //-----------------------------------------------------------------------------
  508. // Purpose:
  509. //-----------------------------------------------------------------------------
  510. void CPotteryWheelPanel::GetCameraOffset( Vector &vecOffset )
  511. {
  512. vecOffset = m_vecCameraOffset;
  513. }
  514. //-----------------------------------------------------------------------------
  515. // Purpose:
  516. //-----------------------------------------------------------------------------
  517. void CPotteryWheelPanel::SetCameraPositionAndAngles( const Vector &vecPos, const QAngle &angDir, bool syncManipulators )
  518. {
  519. SetIdentityMatrix( m_CameraPivot );
  520. AngleMatrix( angDir, vecPos, m_CameraPivot );
  521. UpdateCameraTransform();
  522. if ( syncManipulators )
  523. {
  524. SyncManipulation();
  525. }
  526. }
  527. //-----------------------------------------------------------------------------
  528. // Purpose:
  529. //-----------------------------------------------------------------------------
  530. void CPotteryWheelPanel::GetCameraPositionAndAngles( Vector &vecPos, QAngle &angDir )
  531. {
  532. MatrixAngles( m_CameraPivot, angDir, vecPos );
  533. }
  534. //-----------------------------------------------------------------------------
  535. // Purpose:
  536. //-----------------------------------------------------------------------------
  537. void CPotteryWheelPanel::ResetCameraPivot( void )
  538. {
  539. SetIdentityMatrix( m_CameraPivot );
  540. }
  541. //-----------------------------------------------------------------------------
  542. // Sets the camera to look at the the thing we're spinning around
  543. //-----------------------------------------------------------------------------
  544. void CPotteryWheelPanel::LookAt( float flRadius )
  545. {
  546. // Compute the distance to the camera for the object based on its
  547. // radius and fov.
  548. // since tan( fov/2 ) = f/d
  549. // cos( fov/2 ) = r / r' where r = sphere radius, r' = perp distance from sphere center to max extent of camera
  550. // d/f = r'/d' where d' is distance of camera to sphere
  551. // d' = r' / tan( fov/2 ) * r' = r / ( cos (fov/2) * tan( fov/2 ) ) = r / sin( fov/2 )
  552. float flFOVx = m_Camera.m_flFOV;
  553. // Compute fov/2 in radians
  554. flFOVx *= M_PI / 360.0f;
  555. // Compute an effective fov based on the aspect ratio
  556. // if the height is smaller than the width
  557. int w, h;
  558. GetSize( w, h );
  559. if ( h < w )
  560. {
  561. flFOVx = atan( h * tan( flFOVx ) / w );
  562. }
  563. m_vecCameraOffset.x = -( flRadius / sin( flFOVx ) );
  564. UpdateCameraTransform();
  565. }
  566. void CPotteryWheelPanel::LookAt( const Vector &vecCenter, float flRadius )
  567. {
  568. MatrixSetColumn( vecCenter, 3, m_CameraPivot );
  569. LookAt( flRadius );
  570. }
  571. //-----------------------------------------------------------------------------
  572. // Sets up render state in the material system for rendering
  573. //-----------------------------------------------------------------------------
  574. void CPotteryWheelPanel::SetupRenderState( int nDisplayWidth, int nDisplayHeight )
  575. {
  576. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  577. VMatrix view, projection;
  578. ComputeViewMatrix( &view, m_Camera );
  579. ComputeProjectionMatrix( &projection, m_Camera, nDisplayWidth, nDisplayHeight );
  580. pRenderContext->MatrixMode( MATERIAL_MODEL );
  581. pRenderContext->LoadIdentity( );
  582. pRenderContext->MatrixMode( MATERIAL_VIEW );
  583. pRenderContext->LoadMatrix( view );
  584. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  585. pRenderContext->LoadMatrix( projection );
  586. LightDesc_t *pDesc = (LightDesc_t*)stackalloc( m_nLightCount * sizeof(LightDesc_t) );
  587. for ( int i = 0; i < m_nLightCount; ++i )
  588. {
  589. pDesc[i] = m_Lights[i].m_Desc;
  590. VectorTransform( m_Lights[i].m_Desc.m_Position, m_Lights[i].m_LightToWorld, pDesc->m_Position );
  591. VectorRotate( m_Lights[i].m_Desc.m_Direction, m_Lights[i].m_LightToWorld, pDesc->m_Direction );
  592. VectorNormalize( pDesc->m_Direction );
  593. pRenderContext->SetLight( i, pDesc[i] );
  594. }
  595. LightDesc_t desc;
  596. desc.m_Type = MATERIAL_LIGHT_DISABLE;
  597. int nMaxLightCount = g_pMaterialSystemHardwareConfig->MaxNumLights();
  598. for ( int i = m_nLightCount; i < nMaxLightCount; ++i )
  599. {
  600. pRenderContext->SetLight( i, desc );
  601. }
  602. pRenderContext->SetAmbientLightCube( m_vecAmbientCube );
  603. // FIXME: Remove this! This should automatically happen in DrawModel
  604. // in studiorender.
  605. if ( !g_pStudioRender )
  606. return;
  607. VMatrix worldToCamera;
  608. MatrixInverseTR( view, worldToCamera );
  609. Vector vecOrigin, vecRight, vecUp, vecForward;
  610. MatrixGetColumn( worldToCamera, 0, &vecRight );
  611. MatrixGetColumn( worldToCamera, 1, &vecUp );
  612. MatrixGetColumn( worldToCamera, 2, &vecForward );
  613. MatrixGetColumn( worldToCamera, 3, &vecOrigin );
  614. g_pStudioRender->SetViewState( vecOrigin, vecRight, vecUp, vecForward );
  615. g_pStudioRender->SetLocalLights( m_nLightCount, pDesc );
  616. g_pStudioRender->SetAmbientLightColors( m_vecAmbientCube );
  617. }
  618. //-----------------------------------------------------------------------------
  619. // Compute the camera world position
  620. //-----------------------------------------------------------------------------
  621. void CPotteryWheelPanel::UpdateCameraTransform( )
  622. {
  623. // Set up the render state for the camera + light
  624. matrix3x4_t offset, worldToCamera;
  625. SetIdentityMatrix( offset );
  626. MatrixSetColumn( m_vecCameraOffset, 3, offset );
  627. ConcatTransforms( m_CameraPivot, offset, worldToCamera );
  628. MatrixAngles( worldToCamera, m_Camera.m_angles, m_Camera.m_origin );
  629. }
  630. void CPotteryWheelPanel::ComputeCameraTransform( matrix3x4_t *pWorldToCamera )
  631. {
  632. AngleMatrix( m_Camera.m_angles, m_Camera.m_origin, *pWorldToCamera );
  633. }
  634. //-----------------------------------------------------------------------------
  635. // Computes the position in the panel of a particular 3D point
  636. //-----------------------------------------------------------------------------
  637. void CPotteryWheelPanel::ComputePanelPosition( const Vector &vecPosition, Vector2D *pPanelPos )
  638. {
  639. int w, h;
  640. GetSize( w, h );
  641. matrix3x4_t worldToCamera;
  642. ComputeCameraTransform( &worldToCamera );
  643. MatrixAngles( worldToCamera, m_Camera.m_angles, m_Camera.m_origin );
  644. ComputeScreenSpacePosition( pPanelPos, vecPosition, m_Camera, w, h );
  645. }
  646. //-----------------------------------------------------------------------------
  647. // Utility method to draw a grid at the 'ground'
  648. //-----------------------------------------------------------------------------
  649. void CPotteryWheelPanel::DrawGrid()
  650. {
  651. matrix3x4_t transform;
  652. CMatRenderContextPtr pRenderContext( MaterialSystem() );
  653. pRenderContext->MatrixMode( MATERIAL_MODEL );
  654. pRenderContext->LoadIdentity( );
  655. pRenderContext->Bind( m_Wireframe );
  656. IMesh *pMesh = pRenderContext->GetDynamicMesh();
  657. int nGridDim = 10;
  658. CMeshBuilder meshBuilder;
  659. meshBuilder.Begin( pMesh, MATERIAL_LINES, 2 * nGridDim + 2 );
  660. float bounds = 100.0f;
  661. float delta = 2 * bounds / nGridDim;
  662. for ( int i = 0; i < nGridDim + 1; ++i )
  663. {
  664. float xy = -bounds + delta * i;
  665. meshBuilder.Position3f( xy, -bounds, 0 );
  666. meshBuilder.Color4ub( 255, 255, 255, 255 );
  667. meshBuilder.AdvanceVertex();
  668. meshBuilder.Position3f( xy, bounds, 0 );
  669. meshBuilder.Color4ub( 255, 255, 255, 255 );
  670. meshBuilder.AdvanceVertex();
  671. meshBuilder.Position3f( -bounds, xy, 0 );
  672. meshBuilder.Color4ub( 255, 255, 255, 255 );
  673. meshBuilder.AdvanceVertex();
  674. meshBuilder.Position3f( bounds, xy, 0 );
  675. meshBuilder.Color4ub( 255, 255, 255, 255 );
  676. meshBuilder.AdvanceVertex();
  677. }
  678. meshBuilder.End();
  679. pMesh->Draw();
  680. }
  681. //-----------------------------------------------------------------------------
  682. // paint it!
  683. //-----------------------------------------------------------------------------
  684. void CPotteryWheelPanel::Paint()
  685. {
  686. int iWidth, iHeight;
  687. GetSize( iWidth, iHeight );
  688. int screenw, screenh;
  689. vgui::surface()->GetScreenSize( screenw, screenh );
  690. int windowposx = 0, windowposy = 0;
  691. GetPos( windowposx, windowposy );
  692. int windowposright = windowposx + iWidth;
  693. int windowposbottom = windowposy + iHeight;
  694. if ( windowposright >= screenw )
  695. {
  696. iWidth -= ( windowposright - screenw );
  697. }
  698. if ( windowposbottom >= screenh )
  699. {
  700. iHeight -= ( windowposbottom - screenh );
  701. }
  702. int startx = 0, starty = 0;
  703. if( windowposx < 0 )
  704. {
  705. startx = -windowposx;
  706. iWidth -= startx;
  707. }
  708. if ( windowposy < 0 )
  709. {
  710. starty = -windowposy;
  711. iHeight -= starty;
  712. }
  713. int w, h;
  714. GetSize( w, h );
  715. vgui::MatSystemSurface()->Begin3DPaint( 0, 0, w, h, m_bRenderToTexture );
  716. if ( m_pCurrentManip )
  717. {
  718. m_pCurrentManip->SetViewportSize( iWidth, iHeight );
  719. }
  720. // Set up the render state for the camera + light
  721. SetupRenderState( iWidth, iHeight );
  722. CMatRenderContextPtr pRenderContext( vgui::MaterialSystem() );
  723. if ( m_bUseParentBG && GetParent() )
  724. {
  725. Color bgCol = GetParent()->GetBgColor();
  726. pRenderContext->ClearColor4ub( bgCol.r(), bgCol.g(), bgCol.b(), bgCol.a() );
  727. }
  728. else
  729. {
  730. pRenderContext->ClearColor4ub( m_ClearColor.r(), m_ClearColor.g(), m_ClearColor.b(), m_ClearColor.a() );
  731. }
  732. pRenderContext->ClearBuffers( m_bRenderToTexture, true );
  733. pRenderContext->CullMode( MATERIAL_CULLMODE_CCW );
  734. pRenderContext->SetIntRenderingParameter( INT_RENDERPARM_WRITE_DEPTH_TO_DESTALPHA, false );
  735. if ( HasLightProbe() )
  736. {
  737. IMaterial *pMaterial = ( vgui::MaterialSystemHardwareConfig()->GetHDRType() == HDR_TYPE_NONE ) ?
  738. m_LightProbeBackground : m_LightProbeHDRBackground;
  739. RenderBox( m_Camera.m_origin, vec3_angle, Vector( -100, -100, -100 ), Vector( 100, 100, 100 ),
  740. Color( 255, 255, 255, 255 ), pMaterial, true );
  741. }
  742. OnPaint3D();
  743. pRenderContext->CullMode( MATERIAL_CULLMODE_CW );
  744. vgui::MatSystemSurface()->End3DPaint( );
  745. }
  746. //-----------------------------------------------------------------------------
  747. // called when we're ticked...
  748. //-----------------------------------------------------------------------------
  749. void CPotteryWheelPanel::OnTick()
  750. {
  751. BaseClass::OnTick();
  752. if ( m_pCurrentManip )
  753. {
  754. m_pCurrentManip->OnTick();
  755. UpdateCameraTransform();
  756. }
  757. }
  758. //-----------------------------------------------------------------------------
  759. // input
  760. //-----------------------------------------------------------------------------
  761. void CPotteryWheelPanel::OnKeyCodePressed(KeyCode code)
  762. {
  763. if ( m_pCurrentManip )
  764. {
  765. switch( code )
  766. {
  767. case KEY_RSHIFT:
  768. case KEY_LSHIFT:
  769. // start translate mode
  770. AcceptManipulation( false );
  771. EnterManipulationMode( CAMERA_TRANSLATE, false );
  772. break;
  773. case KEY_RCONTROL:
  774. case KEY_LCONTROL:
  775. // start light mode
  776. AcceptManipulation( false );
  777. EnterManipulationMode( LIGHT_MODE, false );
  778. break;
  779. }
  780. }
  781. BaseClass::OnKeyCodePressed( code );
  782. }
  783. //-----------------------------------------------------------------------------
  784. // Purpose: soaks up any remaining messages
  785. //-----------------------------------------------------------------------------
  786. void CPotteryWheelPanel::OnKeyCodeReleased(KeyCode code)
  787. {
  788. if ( m_pCurrentManip )
  789. {
  790. switch( code )
  791. {
  792. case KEY_RSHIFT:
  793. case KEY_LSHIFT:
  794. case KEY_RCONTROL:
  795. case KEY_LCONTROL:
  796. {
  797. // stop manipulation mode
  798. AcceptManipulation( false );
  799. switch ( m_nCaptureMouseCode )
  800. {
  801. default:
  802. case MOUSE_LEFT:
  803. EnterManipulationMode( CAMERA_ROTATE, false );
  804. break;
  805. case MOUSE_MIDDLE:
  806. EnterManipulationMode( CAMERA_TRANSLATE, false );
  807. break;
  808. case MOUSE_RIGHT:
  809. EnterManipulationMode( CAMERA_ZOOM, false );
  810. break;
  811. }
  812. }
  813. break;
  814. }
  815. }
  816. BaseClass::OnKeyCodeReleased( code );
  817. }
  818. void CPotteryWheelPanel::OnMousePressed( vgui::MouseCode code )
  819. {
  820. if ( m_pCurrentManip )
  821. return;
  822. RequestFocus();
  823. if ( input()->IsKeyDown( KEY_RSHIFT ) || input()->IsKeyDown( KEY_LSHIFT ) )
  824. {
  825. EnterManipulationMode( CAMERA_TRANSLATE, true, code );
  826. }
  827. else if ( input()->IsKeyDown( KEY_RCONTROL ) || input()->IsKeyDown( KEY_LCONTROL ) )
  828. {
  829. EnterManipulationMode( LIGHT_MODE, true, code );
  830. }
  831. else
  832. {
  833. switch ( code )
  834. {
  835. case MOUSE_LEFT:
  836. EnterManipulationMode( CAMERA_ROTATE, true, code );
  837. break;
  838. case MOUSE_MIDDLE:
  839. EnterManipulationMode( CAMERA_TRANSLATE, true, code );
  840. break;
  841. case MOUSE_RIGHT:
  842. EnterManipulationMode( CAMERA_ZOOM, true, code );
  843. break;
  844. }
  845. }
  846. BaseClass::OnMousePressed( code );
  847. }
  848. void CPotteryWheelPanel::OnMouseReleased( vgui::MouseCode code )
  849. {
  850. int x, y;
  851. input()->GetCursorPos( x, y );
  852. ScreenToLocal( x, y );
  853. AcceptManipulation();
  854. BaseClass::OnMouseReleased( code );
  855. }
  856. void CPotteryWheelPanel::OnCursorMoved( int x, int y )
  857. {
  858. if ( m_pCurrentManip )
  859. {
  860. if ( WarpMouse( x, y ) )
  861. {
  862. m_pCurrentManip->OnCursorMoved( x, y );
  863. }
  864. }
  865. BaseClass::OnCursorMoved( x, y );
  866. }
  867. void CPotteryWheelPanel::OnMouseWheeled( int delta )
  868. {
  869. if ( m_pCurrentManip )
  870. {
  871. m_pCurrentManip->OnMouseWheeled( delta );
  872. }
  873. BaseClass::OnMouseWheeled( delta );
  874. }
  875. void CPotteryWheelPanel::EnterManipulationMode( ManipulationMode_t manipMode, bool bMouseCapture, vgui::MouseCode mouseCode /* = -1 */ )
  876. {
  877. switch ( manipMode )
  878. {
  879. case CAMERA_ROTATE:
  880. m_pCurrentManip = m_pCameraRotate;
  881. break;
  882. case CAMERA_TRANSLATE:
  883. m_pCurrentManip = m_pCameraTranslate;
  884. break;
  885. case CAMERA_ZOOM:
  886. m_pCurrentManip = m_pCameraZoom;
  887. break;
  888. case LIGHT_MODE:
  889. m_pCurrentManip = m_pLightManip;
  890. break;
  891. }
  892. if ( !m_pCurrentManip )
  893. return;
  894. m_pCurrentManip->OnBeginManipulation();
  895. m_xoffset = m_yoffset = 0;
  896. // Warp the mouse to the center of the screen
  897. int width, height;
  898. GetSize( width, height );
  899. int x = width / 2;
  900. int y = height / 2;
  901. if ( bMouseCapture )
  902. {
  903. input()->GetCursorPos( m_nManipStartX, m_nManipStartY );
  904. EnableMouseCapture( true, mouseCode );
  905. int xpos = x;
  906. int ypos = y;
  907. LocalToScreen( xpos, ypos );
  908. input()->SetCursorPos( xpos, ypos );
  909. }
  910. m_pCurrentManip->OnMousePressed( mouseCode, x, y );
  911. }
  912. void CPotteryWheelPanel::AcceptManipulation( bool bReleaseMouseCapture )
  913. {
  914. if ( m_pCurrentManip )
  915. {
  916. m_pCurrentManip->OnAcceptManipulation();
  917. if ( bReleaseMouseCapture )
  918. {
  919. EnableMouseCapture( false );
  920. input()->SetCursorPos( m_nManipStartX, m_nManipStartY );
  921. }
  922. m_pCurrentManip = NULL;
  923. }
  924. }
  925. void CPotteryWheelPanel::CancelManipulation()
  926. {
  927. if ( m_pCurrentManip )
  928. {
  929. m_pCurrentManip->OnCancelManipulation();
  930. EnableMouseCapture( false );
  931. input()->SetCursorPos( m_nManipStartX, m_nManipStartY );
  932. m_pCurrentManip = NULL;
  933. }
  934. }
  935. void CPotteryWheelPanel::ApplyManipulation()
  936. {
  937. if ( dynamic_cast< CRotationManipulator * >( m_pCameraRotate ) )
  938. {
  939. dynamic_cast< CRotationManipulator * >( m_pCameraRotate )->UpdateTransform();
  940. }
  941. UpdateCameraTransform();
  942. }
  943. void CPotteryWheelPanel::SyncManipulation()
  944. {
  945. if ( dynamic_cast< CRotationManipulator * >( m_pCameraRotate ) )
  946. {
  947. dynamic_cast< CRotationManipulator * >( m_pCameraRotate )->UpdateFromMatrix();
  948. }
  949. }
  950. void CPotteryWheelPanel::OnMouseCaptureLost()
  951. {
  952. SetCursor( vgui::dc_arrow );
  953. m_nCaptureMouseCode = vgui::MouseCode( -1 );
  954. }
  955. void CPotteryWheelPanel::EnableMouseCapture( bool enable, vgui::MouseCode mouseCode /* = -1 */ )
  956. {
  957. if ( enable )
  958. {
  959. m_nCaptureMouseCode = mouseCode;
  960. SetCursor( vgui::dc_none );
  961. input()->SetMouseCaptureEx( GetVPanel(), m_nCaptureMouseCode );
  962. }
  963. else
  964. {
  965. m_nCaptureMouseCode = vgui::MouseCode( -1 );
  966. input()->SetMouseCapture( (VPANEL)0 );
  967. SetCursor( vgui::dc_arrow );
  968. }
  969. }
  970. bool CPotteryWheelPanel::WarpMouse( int &x, int &y )
  971. {
  972. // Re-force capture if it was lost...
  973. if ( input()->GetMouseCapture() != GetVPanel() )
  974. {
  975. input()->GetCursorPos( m_nManipStartX, m_nManipStartY );
  976. EnableMouseCapture( true, m_nCaptureMouseCode );
  977. }
  978. int width, height;
  979. GetSize( width, height );
  980. int centerx = width / 2;
  981. int centery = height / 2;
  982. // skip this event
  983. if ( x == centerx && y == centery )
  984. return false;
  985. int xpos = centerx;
  986. int ypos = centery;
  987. LocalToScreen( xpos, ypos );
  988. #if defined( DX_TO_GL_ABSTRACTION )
  989. //
  990. // Really reset the cursor to the center for the PotteryWheel Control
  991. //
  992. // In TF2's edit loadout dialog there is a character model that you can rotate
  993. // around using the mouse. This control resets the cursor to the center of the window
  994. // after each mouse move. Except the input()->SetCursorPos results (after a lot of redirection) to
  995. // vgui/matsurface/Cursor.cpp function CursorSetPos but it has a (needed) test to not move the
  996. // cursor if it's currently hidden. Rather than change all the levels between here and there
  997. // to support a flag, we are just jumping to the chase and directly calling the inputsystem
  998. // SetCursorPosition on OpenGL platforms
  999. //
  1000. g_pInputSystem->SetCursorPosition( xpos, ypos );
  1001. #else
  1002. input()->SetCursorPos( xpos, ypos );
  1003. #endif
  1004. int dx = x - centerx;
  1005. int dy = y - centery;
  1006. x += m_xoffset;
  1007. y += m_yoffset;
  1008. m_xoffset += dx;
  1009. m_yoffset += dy;
  1010. return true;
  1011. }