Sync latest code from Team Fortress 2

- Latest code as of 2025/05/14

- Include matsys_controls code to avoid vgui_controls changes being ABI.

Closes: #1249
This commit is contained in:
Autumn Ashton 2025-05-14 01:48:29 +01:00
parent ba5fe6853d
commit 39f6dde8fb
67 changed files with 11899 additions and 38 deletions

View File

@ -441,10 +441,10 @@ void CHudCommentary::Paint()
// Draw the speaker names
// Get our scheme and font information
vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" );
vgui::HFont hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentaryDefault" );
vgui::HFont hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "CommentaryDefault", true );
if ( !hFont )
{
hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "Default" );
hFont = vgui::scheme()->GetIScheme(scheme)->GetFont( "Default", true );
}
vgui::surface()->DrawSetTextFont( hFont );
vgui::surface()->DrawSetTextColor( clr );

View File

@ -837,6 +837,8 @@ void ClientModeShared::StartMessageMode( int iMessageModeType )
}
#if defined( TF_CLIENT_DLL )
if ( iMessageModeType == MM_SAY || iMessageModeType == MM_SAY_TEAM )
{
bool bSuspensionInMatch = GTFGCClientSystem() && GTFGCClientSystem()->BHaveChatSuspensionInCurrentMatch();
if ( !cl_enable_text_chat.GetBool() || bSuspensionInMatch )
{
@ -855,6 +857,7 @@ void ClientModeShared::StartMessageMode( int iMessageModeType )
}
return;
}
}
#endif // TF_CLIENT_DLL
if ( m_pChatElement )

View File

@ -1596,7 +1596,7 @@ void CHudCloseCaption::CreateFonts( void )
{
vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );
m_hFonts[CCFONT_NORMAL] = pScheme->GetFont( "CloseCaption_Normal", true );
m_hFonts[CCFONT_NORMAL] = pScheme->GetFont( "CloseCaption", true );
if ( IsPC() )
{

View File

@ -850,9 +850,16 @@ void CWaveStatusPanel::UpdateEnemyCounts( void )
AddClassIconBeingUsed( classIconsBeingUsed, support[i].pchClassIconName );
if ( pPanel->m_pEnemyCountImageBG )
{
if ( support[i].iFlags & MVM_CLASS_FLAG_MINIBOSS )
{
pPanel->m_pEnemyCountImageBG->SetBgColor( m_clrMiniBoss );
}
else
{
pPanel->m_pEnemyCountImageBG->SetBgColor( m_clrNormal );
}
}
if ( pPanel->m_pEnemyCountCritBG )
{

View File

@ -17,6 +17,10 @@
static int g_ActiveVoiceMenu = 0;
#if defined( TF_CLIENT_DLL )
extern ConVar tf_voice_command_suspension_mode;
#endif
void OpenVoiceMenu( int index )
{
// do not show the menu if the player is dead or is an observer
@ -28,7 +32,7 @@ void OpenVoiceMenu( int index )
return;
#if defined ( TF_CLIENT_DLL )
if ( GTFGCClientSystem() && GTFGCClientSystem()->BHaveChatSuspensionInCurrentMatch() )
if ( GTFGCClientSystem() && GTFGCClientSystem()->BHaveChatSuspensionInCurrentMatch() && tf_voice_command_suspension_mode.GetInt() == 1 )
{
CBaseHudChat *pHUDChat = ( CBaseHudChat * ) GET_HUDELEMENT( CHudChat );
if ( pHUDChat )

View File

@ -704,9 +704,9 @@ DEFINE_SCRIPTFUNC( IsOnAnyMission, "Return true if this bot has a current missio
DEFINE_SCRIPTFUNC_WRAPPED( SetMissionTarget, "Set this bot's mission target to the given entity" )
DEFINE_SCRIPTFUNC_WRAPPED( GetMissionTarget, "Get this bot's current mission target" )
DEFINE_SCRIPTFUNC( SetBehaviorFlag, "Set the given behavior flag(s) for this bot" )
DEFINE_SCRIPTFUNC( ClearBehaviorFlag, "Clear the given behavior flag(s) for this bot" )
DEFINE_SCRIPTFUNC( IsBehaviorFlagSet, "Return true if the given behavior flag(s) are set for this bot" )
DEFINE_SCRIPTFUNC_WRAPPED( SetBehaviorFlag, "Set the given behavior flag(s) for this bot" )
DEFINE_SCRIPTFUNC_WRAPPED( ClearBehaviorFlag, "Clear the given behavior flag(s) for this bot" )
DEFINE_SCRIPTFUNC_WRAPPED( IsBehaviorFlagSet, "Return true if the given behavior flag(s) are set for this bot" )
DEFINE_SCRIPTFUNC_WRAPPED( SetActionPoint, "Set the given action point for this bot" )
DEFINE_SCRIPTFUNC_WRAPPED( GetActionPoint, "Get the given action point for this bot" )

View File

@ -331,6 +331,9 @@ public:
void SetBehaviorFlag( unsigned int flags );
void ClearBehaviorFlag( unsigned int flags );
bool IsBehaviorFlagSet( unsigned int flags ) const;
void ScriptSetBehaviorFlag( int flags ) { this->SetBehaviorFlag( (unsigned int)flags ); }
void ScriptClearBehaviorFlag( int flags ) { this->ClearBehaviorFlag( (unsigned int)flags ); }
bool ScriptIsBehaviorFlagSet( int flags ) const { return this->IsBehaviorFlagSet( (unsigned int)flags ); }
bool FindSplashTarget( CBaseEntity *target, float maxSplashRadius, Vector *splashTarget ) const;
@ -358,11 +361,11 @@ public:
CBaseEntity *GetMissionTarget( void ) const;
void SetMissionString( CUtlString string );
CUtlString *GetMissionString( void );
void ScriptSetMission( unsigned int mission, bool resetBehaviorSystem = true ) { this->SetMission( (MissionType)mission, resetBehaviorSystem ); }
void ScriptSetPrevMission( unsigned int mission ) { this->SetPrevMission( (MissionType)mission ); }
unsigned int ScriptGetMission( void ) const { return (unsigned int)this->GetMission(); }
unsigned int ScriptGetPrevMission( void ) const { return (unsigned int)this->GetPrevMission(); }
bool ScriptHasMission( unsigned int mission ) const { return this->HasMission( (MissionType)mission ); }
void ScriptSetMission( int mission, bool resetBehaviorSystem = true ) { this->SetMission( (MissionType)mission, resetBehaviorSystem ); }
void ScriptSetPrevMission( int mission ) { this->SetPrevMission( (MissionType)mission ); }
int ScriptGetMission( void ) const { return (int)this->GetMission(); }
int ScriptGetPrevMission( void ) const { return (int)this->GetPrevMission(); }
bool ScriptHasMission( int mission ) const { return this->HasMission( (MissionType)mission ); }
void ScriptSetMissionTarget( HSCRIPT hTarget ) { this->SetMissionTarget( ToEnt( hTarget ) ); }
HSCRIPT ScriptGetMissionTarget( void ) const { return ToHScript( this->GetMissionTarget() ); }

View File

@ -210,6 +210,7 @@ void CCurrencyPack::ComeToRest( void )
}
}
}
// Or a func_respawnroom (robots can drop money in their own spawn)
for ( int i = 0; i < IFuncRespawnRoomAutoList::AutoList().Count(); i++ )
{
@ -219,6 +220,7 @@ void CCurrencyPack::ComeToRest( void )
if ( IsPointInBox( GetCollideable()->GetCollisionOrigin(), vecMins, vecMaxs ) )
{
TFGameRules()->DistributeCurrencyAmount( m_nAmount );
m_bTouched = true;
UTIL_Remove( this );
}

View File

@ -277,6 +277,7 @@ extern ConVar sv_vote_allow_spectators;
ConVar sv_vote_late_join_time( "sv_vote_late_join_time", "90", FCVAR_NONE, "Grace period after the match starts before players who join the match receive a vote-creation cooldown" );
ConVar sv_vote_late_join_cooldown( "sv_vote_late_join_cooldown", "300", FCVAR_NONE, "Length of the vote-creation cooldown when joining the server after the grace period has expired" );
extern ConVar tf_voice_command_suspension_mode;
extern ConVar tf_feign_death_duration;
extern ConVar spec_freeze_time;
extern ConVar spec_freeze_traveltime;
@ -19993,7 +19994,20 @@ bool CTFPlayer::ShouldShowVoiceSubtitleToEnemy( void )
//-----------------------------------------------------------------------------
bool CTFPlayer::CanSpeakVoiceCommand( void )
{
return ( gpGlobals->curtime > m_flNextVoiceCommandTime );
if ( tf_voice_command_suspension_mode.GetInt() == 1 )
return false;
if ( gpGlobals->curtime <= m_flNextVoiceCommandTime )
return false;
// misyl: New F2P voice command rate-limiting path.
if ( BHaveChatSuspensionInCurrentMatch() && tf_voice_command_suspension_mode.GetInt() == 2 )
{
if ( !m_RateLimitedVoiceCommandTokenBucket.BTakeToken( gpGlobals->curtime ) )
return false;
}
return true;
}
//-----------------------------------------------------------------------------

View File

@ -66,6 +66,46 @@ enum EAmmoSource
kAmmoSource_ResourceMeter, // it regenerated after a cooldown
};
extern ConVar tf_voice_command_suspension_rate_limit_bucket_count;
extern ConVar tf_voice_command_suspension_rate_limit_bucket_refill_rate;
class CVoiceCommandBucketSizer
{
public:
int GetBucketSize() const { return tf_voice_command_suspension_rate_limit_bucket_count.GetInt(); }
float GetBucketRefillRate() const { return tf_voice_command_suspension_rate_limit_bucket_refill_rate.GetFloat(); }
};
template <typename TBucketSizer>
class CRateLimitingTokenBucket : public TBucketSizer
{
public:
CRateLimitingTokenBucket()
: m_nBucket( this->GetBucketSize() )
{
}
bool BTakeToken( float flNow )
{
// misyl: This token bucket doesn't go negative, so you don't ever dig yourself into a hole by spamming.
// You might want that if you use this class, feel free to add something to the BucketSizer.
int nNewBucket = MIN( m_nBucket + ( flNow - m_flLastTokenTaken ) / this->GetBucketRefillRate(), this->GetBucketSize() ) - 1;
if ( nNewBucket <= 0 )
{
return false;
}
m_nBucket = nNewBucket;
m_flLastTokenTaken = flNow;
return true;
}
private:
float m_flLastTokenTaken = 0.0f;
int m_nBucket = 0;
};
//=============================================================================
//
// TF Player
@ -483,6 +523,8 @@ public:
float m_flNextVoiceCommandTime;
int m_iVoiceSpamCounter;
CRateLimitingTokenBucket<CVoiceCommandBucketSizer> m_RateLimitedVoiceCommandTokenBucket;
float m_flNextSpeakWeaponFire;
virtual int CalculateTeamBalanceScore( void );

View File

@ -333,6 +333,7 @@ void CSave::Log( const char *pName, fieldtype_t fieldType, void *value, int coun
byte *pColor = &pValue[iCount*4];
Q_snprintf( szTempBuf, sizeof( szTempBuf ), "(%d %d %d %d)", ( int )pColor[0], ( int )pColor[1], ( int )pColor[2], ( int )pColor[3] );
Q_strncat( szBuf, szTempBuf, sizeof( szTempBuf ), COPY_ALL_CHARACTERS );
break;
}
case FIELD_EMBEDDED:
case FIELD_CUSTOM:

View File

@ -1107,7 +1107,13 @@ ConVar tf_competitive_required_late_join_confirm_timeout( "tf_competitive_requir
ConVar tf_gamemode_community ( "tf_gamemode_community", "0", FCVAR_REPLICATED | FCVAR_NOTIFY | FCVAR_DEVELOPMENTONLY );
ConVar tf_voice_command_suspension_mode( "tf_voice_command_suspension_mode", "2", FCVAR_REPLICATED, "0 = None | 1 = No Voice Commands | 2 = Rate Limited" );
#ifdef GAME_DLL
ConVar tf_voice_command_suspension_rate_limit_bucket_count( "tf_voice_command_suspension_rate_limit_bucket_count", "5" ); // Bucket size of 5.
ConVar tf_voice_command_suspension_rate_limit_bucket_refill_rate( "tf_voice_command_suspension_rate_limit_bucket_refill_rate", "6" ); // 6s
void cc_powerup_mode( IConVar *pConVar, const char *pOldString, float flOldValue )
{
ConVarRef var( pConVar );
@ -10127,7 +10133,12 @@ VoiceCommandMenuItem_t *CTFGameRules::VoiceCommand( CBaseMultiplayerPlayer *pPla
if ( pTFPlayer )
{
if ( pTFPlayer->BHaveChatSuspensionInCurrentMatch() )
{
if ( tf_voice_command_suspension_mode.GetInt() == 1 )
{
return NULL;
}
}
if ( pTFPlayer->m_Shared.InCond( TF_COND_HALLOWEEN_GHOST_MODE ) )
{

View File

@ -9698,7 +9698,9 @@ void CTFPlayerShared::StunPlayer( float flTime, float flReductionAmount, int iSt
float flRemapAmount = RemapValClamped( flReductionAmount, 0.0, 1.0, 0, 255 );
#ifdef GAME_DLL
int iOldStunFlags = GetStunFlags();
#endif
// Already stunned
bool bStomp = false;

View File

@ -2110,7 +2110,7 @@ bool CTFFlameThrower::EffectMeterShouldFlash( void )
//-----------------------------------------------------------------------------
Vector CTFFlameThrower::GetMuzzlePosHelper( bool bVisualPos )
{
Vector vecMuzzlePos;
Vector vecMuzzlePos = vec3_origin;
CTFPlayer *pOwner = GetTFPlayerOwner();
if ( pOwner )
{

View File

@ -424,6 +424,9 @@ void CTFWeaponBase::Activate( void )
GiveDefaultAmmo();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFWeaponBase::GiveDefaultAmmo( void )
{
BaseClass::GiveDefaultAmmo();

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -121,7 +121,7 @@
#define FL_INWATER (1<<9) // In water
// NOTE if you move things up, make sure to change this value
#define PLAYER_FLAG_BITS 10
#define PLAYER_FLAG_BITS 32
#define FL_FLY (1<<10) // Changes the SV_Movestep() behavior to not need to be on ground
#define FL_SWIM (1<<11) // Changes the SV_Movestep() behavior to not need to be on ground (but stay in water)

View File

@ -101,6 +101,7 @@ public:
virtual ~CProtoBufMsgBase();
bool BIsInitialized() const;
bool InitFromPacket( IMsgNetPacket * pNetPacket );
bool BAsyncSend( IProtoBufSendHandler & pSender ) const;
bool BAsyncSendWithPreSerializedBody( IProtoBufSendHandler & pSender, const byte *pubBody, uint32 cubBody ) const;

View File

@ -0,0 +1,727 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#if defined(WIN32) && !defined( _X360 )
#include <windows.h>
#endif
#include "filesystem.h"
#include "filesystem_init.h"
#include "appframework/IAppSystemGroup.h"
#include "appframework/IAppSystem.h"
#include "appframework/AppFramework.h"
#include "filesystem_helpers.h"
#include "matsys_controls/QCGenerator.h"
#include "tier1/KeyValues.h"
#include "tier2/vconfig.h"
#include "vgui_controls/ListPanel.h"
#include "vgui_controls/TextEntry.h"
#include "vgui_controls/Button.h"
#include "vgui_controls/FileOpenDialog.h"
#include "vgui_controls/DirectorySelectDialog.h"
#include "vgui_controls/ComboBox.h"
#include "vgui_controls/CheckButton.h"
#include "vgui_controls/MessageBox.h"
#include "vgui/ISurface.h"
#include "vgui/IInput.h"
#include "vgui/Cursor.h"
#include "vgui_controls/KeyBoardEditorDialog.h"
#if defined( _X360 )
#include "xbox/xbox_win32stubs.h"
#endif
using namespace vgui;
#define MAX_KEYVALUE 1024
//-----------------------------------------------------------------------------
// Purpose: returns a pointer to the 'count' occurence of a character from the end of a string
// returns 0 of there aren't 'count' number of the character in the string
//-----------------------------------------------------------------------------
char *strrchrcount(char *string, int character, int count )
{
int j = count;
int numChars = V_strlen( string );
for( int i = numChars; i > 0; i-- )
{
if( string[i-1] == character )
{
j--;
}
if( j == 0 )
{
return string + i-1;
}
}
return 0;
}
class CModalPreserveMessageBox : public vgui::MessageBox
{
public:
CModalPreserveMessageBox(const char *title, const char *text, vgui::Panel *parent)
: vgui::MessageBox( title, text, parent )
{
m_PrevAppFocusPanel = vgui::input()->GetAppModalSurface();
}
~CModalPreserveMessageBox()
{
vgui::input()->SetAppModalSurface( m_PrevAppFocusPanel );
}
public:
vgui::VPANEL m_PrevAppFocusPanel;
};
void VGUIMessageBox( vgui::Panel *pParent, const char *pTitle, const char *pMsg, ... )
{
char msg[4096];
va_list marker;
va_start( marker, pMsg );
Q_vsnprintf( msg, sizeof( msg ), pMsg, marker );
va_end( marker );
vgui::MessageBox *dlg = new CModalPreserveMessageBox( pTitle, msg, pParent );
dlg->DoModal();
dlg->Activate();
dlg->RequestFocus();
}
//-----------------------------------------------------------------------------
// Purpose: Places all the info from the vgui controls into the QCInfo struct
//-----------------------------------------------------------------------------
void QCInfo::SyncFromControls()
{
char tempText[MAX_PATH];
vgui::Panel *pTargetField = pQCGenerator->FindChildByName( "staticPropCheck" );
bStaticProp = ((CheckButton *)pTargetField)->IsSelected();
pTargetField = pQCGenerator->FindChildByName( "mostlyOpaqueCheck" );
bMostlyOpaque = ((CheckButton *)pTargetField)->IsSelected();
pTargetField = pQCGenerator->FindChildByName( "disableCollisionsCheck" );
bDisableCollision = ((CheckButton *)pTargetField)->IsSelected();
pTargetField = pQCGenerator->FindChildByName( "referencePhysicsCheck" );
bReferenceAsPhys = ((CheckButton *)pTargetField)->IsSelected();
pTargetField = pQCGenerator->FindChildByName( "concaveCheck" );
bConcave = ((CheckButton *)pTargetField)->IsSelected();
pTargetField = pQCGenerator->FindChildByName( "automassCheck" );
bAutomass = ((CheckButton *)pTargetField)->IsSelected();
pTargetField = pQCGenerator->FindChildByName( "massField" );
((TextEntry *)pTargetField)->GetText(tempText, MAX_PATH);
fMass = atof(tempText);
pTargetField = pQCGenerator->FindChildByName( "scaleField" );
((TextEntry *)pTargetField)->GetText(tempText, MAX_PATH);
fScale = atof(tempText);
pTargetField = pQCGenerator->FindChildByName( "collisionSMDField" );
((TextEntry *)pTargetField)->GetText( tempText, MAX_PATH );
V_strcpy_safe( pszCollisionPath, tempText );
pTargetField = pQCGenerator->FindChildByName( "surfacePropertyDropDown" );
((ComboBox *)pTargetField)->GetText( tempText, MAX_PATH );
V_strcpy_safe( pszSurfaceProperty, tempText );
pTargetField = pQCGenerator->FindChildByName( "materialsField" );
((TextEntry *)pTargetField)->GetText( tempText, MAX_PATH );
V_strcpy_safe( pszMaterialPath, tempText );
LODs.RemoveAll();
pTargetField = pQCGenerator->FindChildByName( "LODList" );
int numLOD = ((ListPanel *)pTargetField)->GetItemCount();
for ( int i = 0; i < numLOD; i++ )
{
KeyValues *key = ((ListPanel *)pTargetField)->GetItem( i );
LODInfo newLOD;
V_strcpy_safe( newLOD.pszFilename, key->GetString( "SMD" ) );
newLOD.iLOD = key->GetInt( "LOD" );
LODs.AddToTail( newLOD );
}
}
//-----------------------------------------------------------------------------
// Purpose: Called during intialization to setup the initial state of the VGUI controls
//-----------------------------------------------------------------------------
void QCInfo::SyncToControls()
{
char tempText[MAX_PATH];
vgui::Panel *pTargetField = pQCGenerator->FindChildByName( "staticPropCheck" );
((CheckButton *)pTargetField)->SetSelected( bStaticProp );
pTargetField = pQCGenerator->FindChildByName( "mostlyOpaqueCheck" );
((CheckButton *)pTargetField)->SetSelected( bMostlyOpaque );
pTargetField = pQCGenerator->FindChildByName( "disableCollisionsCheck" );
((CheckButton *)pTargetField)->SetSelected( bDisableCollision );
pTargetField = pQCGenerator->FindChildByName( "referencePhysicsCheck" );
((CheckButton *)pTargetField)->SetSelected( bReferenceAsPhys );
pTargetField = pQCGenerator->FindChildByName( "concaveCheck" );
((CheckButton *)pTargetField)->SetSelected( bConcave );
pTargetField = pQCGenerator->FindChildByName( "automassCheck" );
((CheckButton *)pTargetField)->SetSelected( bAutomass );
Q_snprintf( tempText, 10, "%d", (int)fMass );
pTargetField = pQCGenerator->FindChildByName( "massField" );
((TextEntry *)pTargetField)->SetText( tempText );
Q_snprintf( tempText, 10, "%d", (int)fScale );
pTargetField = pQCGenerator->FindChildByName( "scaleField" );
((TextEntry *)pTargetField)->SetText( tempText );
pTargetField = pQCGenerator->FindChildByName( "collisionSMDField" );
((TextEntry *)pTargetField)->SetText( pszCollisionPath );
pTargetField = pQCGenerator->FindChildByName( "materialsField" );
((TextEntry *)pTargetField)->SetText( pszMaterialPath );
pTargetField = pQCGenerator->FindChildByName( "surfacePropertyDropDown" );
int numItems = ((ComboBox *)pTargetField)->GetItemCount();
for( int i = 0; i < numItems; i++ )
{
((ComboBox *)pTargetField)->GetItemText( i, tempText, MAX_PATH );
if ( !Q_strcmp( tempText, pszSurfaceProperty ) )
{
((ComboBox *)pTargetField)->SetItemEnabled( i, true );
((ComboBox *)pTargetField)->SetText( tempText );
break;
}
}
}
CBrowseButton::CBrowseButton( vgui::Panel *pParent ) : BaseClass( pParent, "Browse Button", "...", pParent, "browse" )
{
SetParent( pParent );
pszStartingDirectory = NULL;
pszFileFilter = NULL;
pszTargetField = NULL;
}
CBrowseButton::~CBrowseButton()
{
}
void CBrowseButton::SetCharVar( char **pVar, const char *pszNewText )
{
if ( *pVar && pszNewText && !Q_strcmp( *pVar, pszNewText ) )
{
return;
}
if ( *pVar )
{
delete [] *pVar;
*pVar = NULL;
}
if ( pszNewText )
{
int len = Q_strlen( pszNewText ) + 1;
*pVar = new char[ len ];
Q_strncpy( *pVar, pszNewText, len );
}
}
void CBrowseButton::InitBrowseInfo( int x, int y, const char *pszName, const char *pszDir, const char *pszFilter, const char *pszField )
{
SetSize( 24, 24 );
SetPos( x, y );
SetName( pszName );
SetCharVar( GetStartingDirectory(), pszDir );
SetCharVar( GetFileFilter(), pszFilter );
SetCharVar( GetTargetField(), pszField );
SetActionMessage();
}
void CBrowseButton::SetActionMessage()
{
KeyValues *newActionMessage = new KeyValues( "browse", "directory", pszStartingDirectory, "filter", pszFileFilter);
newActionMessage->SetString( "targetField", pszTargetField );
SetCommand( newActionMessage );
}
const char *ParseKeyvalue( const char *pBuffer, char *key, char *value )
{
char com_token[1024];
pBuffer = (const char *)ParseFile( pBuffer, com_token, NULL );
if ( Q_strlen( com_token ) < MAX_KEYVALUE )
{
Q_strncpy( key, com_token, MAX_KEYVALUE );
Q_strlower( key );
}
// no value on a close brace
if ( !Q_strcmp( key, "}" ) )
{
value[0] = 0;
return pBuffer;
}
pBuffer = (const char *)ParseFile( pBuffer, com_token, NULL );
if ( Q_strlen( com_token ) < MAX_KEYVALUE )
{
Q_strncpy( value, com_token, MAX_KEYVALUE );
Q_strlower( value );
}
return pBuffer;
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CQCGenerator::CQCGenerator( vgui::Panel *pParent, const char *pszPath, const char *pszScene ) : BaseClass( pParent, "QCGenerator" )
{
m_szTargetField[0] = 0;
m_nSelectedSequence = 0;
m_nSelectedColumn = 0;
m_QCInfo_t.Init( this );
SetMinimumSize(846, 770);
m_pLODPanel = new ListPanel(this, "LODList");
m_pLODPanel->SetSelectIndividualCells( true );
m_pLODPanel->AddColumnHeader(0, "SMD", "LOD SMD", 450, 0);
m_pLODPanel->AddColumnHeader(1, "LOD", "LOD Distance", 50, 0);
m_pLODPanel->AddActionSignalTarget( this );
m_pLODPanel->SetMouseInputEnabled( true );
LoadControlSettings( "QCGenerator.res" );
m_pCollisionBrowseButton = new CBrowseButton( this );
m_pCollisionBrowseButton->InitBrowseInfo( 808, 158, "collisionBrowseButton", pszPath, "*.smd", "collisionSMDField" );
char szTerminatedPath[1024] = "\0";
sprintf( szTerminatedPath, "%s\\", pszPath );
InitializeSMDPaths( szTerminatedPath, pszScene );
char *pszMaterialsStart = strrchrcount( szTerminatedPath, '\\', 3 ) + 1;
char *pszMaterialsEnd = strrchr( szTerminatedPath, '\\');
Q_strncpy( m_QCInfo_t.pszMaterialPath, pszMaterialsStart, pszMaterialsEnd - pszMaterialsStart + 1 );
SetParent( pParent );
char szGamePath[1024] = "\0";
char szSearchPath[1024] = "\0";
// Get the currently set game configuration
GetVConfigRegistrySetting( GAMEDIR_TOKEN, szGamePath, sizeof( szGamePath ) );
static const char *pSurfacePropFilename = "\\scripts\\surfaceproperties.txt";
sprintf( szSearchPath, "%s%s", szGamePath, pSurfacePropFilename );
FileHandle_t fp = g_pFullFileSystem->Open( szSearchPath, "rb" );
if ( !fp )
{
//the set game configuration didn't have a surfaceproperties file; we are grabbing it from hl2
//TODO: This only works if they are in a subdirectory that is a peer to an hl2 directory
// that contains the file. It potentially needs to search the entire drive or prompt for the location
char *pszEndGamePath = Q_strrchr( szGamePath, '\\' );
pszEndGamePath[0] = 0;
V_strcat_safe( szGamePath, "\\hl2" );
sprintf( szSearchPath, "%s%s", szGamePath, pSurfacePropFilename );
fp = g_pFullFileSystem->Open( szSearchPath, "rb" );
}
int len = g_pFullFileSystem->Size( fp );
const char *szSurfacePropContents = new char[len+1];
g_pFullFileSystem->Read( (void *)szSurfacePropContents, len, fp );
char key[MAX_KEYVALUE], value[MAX_KEYVALUE];
vgui::Panel *pSurfacePropDropDown = FindChildByName( "surfacePropertyDropDown" );
//filling up the surface property dropdown
while ( szSurfacePropContents )
{
szSurfacePropContents = ParseKeyvalue( szSurfacePropContents, key, value );
((ComboBox *)pSurfacePropDropDown)->AddItem( key, NULL );
while ( szSurfacePropContents )
{
szSurfacePropContents = ParseKeyvalue( szSurfacePropContents, key, value );
if (!stricmp( key, "}" ) )
{
break;
}
}
}
m_QCInfo_t.SyncToControls();
m_pLODEdit = 0;
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CQCGenerator::~CQCGenerator()
{
}
void CQCGenerator::OnCommand( const char *command )
{
if ( Q_stricmp( command, "createQC" ) == 0 )
{
m_QCInfo_t.SyncFromControls();
GenerateQCFile();
}
if ( Q_stricmp( command, "deleteSeq" ) == 0 )
{
//delete it
DeleteLOD();
}
if ( Q_stricmp( command, "editSeq" ) == 0 )
{
//edit
EditLOD();
}
BaseClass::OnCommand( command );
}
void CQCGenerator::OnKeyCodeTyped( KeyCode code )
{
switch ( code )
{
case KEY_ENTER:
EditLOD();
}
}
void CQCGenerator::OnBrowse( KeyValues *data )
{
V_strcpy_safe( m_szTargetField, data->GetString( "targetField" ) );
const char *filter = data->GetString( "filter" );
if ( Q_strlen( filter ) == 0 )
{
// BrowseDirectory( data );
}
else
{
BrowseFile( data );
}
}
/*
//This function is no longer used in the current version of the program.
void CQCGenerator::BrowseDirectory( KeyValues *data )
{
DirectorySelectDialog *pDialog = new DirectorySelectDialog( this, "Select Directory" );
pDialog->AddActionSignalTarget( this );
pDialog->DoModal();
pDialog->SetStartDirectory( data->GetString( "directory" ) );
}
*/
void CQCGenerator::BrowseFile( KeyValues *data )
{
const char *filter = data->GetString( "filter" );
FileOpenDialog *pDialog = new FileOpenDialog( this, "Select File", true );
pDialog->AddFilter( filter, filter, true );
pDialog->AddActionSignalTarget(this);
pDialog->SetStartDirectory( data->GetString( "directory" ) );
pDialog->DoModal( true );
}
void CQCGenerator::OnFileSelected( KeyValues *data )
{
if ( *m_szTargetField )
{
vgui::Panel *pTargetField = FindChildByName( m_szTargetField );
((TextEntry *)pTargetField)->SetText( data->GetString( "fullpath" ) );
Repaint();
}
}
void CQCGenerator::OnDirectorySelected( KeyValues *data )
{
if ( *m_szTargetField )
{
vgui::Panel *pTargetField = FindChildByName( m_szTargetField );
((TextEntry *)pTargetField)->SetText( data->GetString( "dir" ) );
Repaint();
}
}
bool CQCGenerator::GenerateQCFile()
{
//TODO: clean this up. Consider creating a datatype that includes the string to write out when the QC file is created
char *nameBegin = strrchr( m_QCInfo_t.pszSMDPath, '\\' );
char szPath[MAX_PATH];
char szName[MAX_PATH];
Q_strncpy( szPath, m_QCInfo_t.pszSMDPath, nameBegin - m_QCInfo_t.pszSMDPath + 2 );
V_strcpy_safe( szName, szPath);
V_strcat_safe( szName, m_QCInfo_t.pszSceneName);
V_strcat_safe( szName, ".qc" );
FileHandle_t pSaveFile = g_pFullFileSystem->Open( szName, "wt" );
if (!pSaveFile)
{
char szSaveError[1024] = "";
Q_snprintf( szSaveError, 1024, "Save failed: invalid file name '%s'\n\nDirectory '%s' must exist.", szName, szPath );
VGUIMessageBox( this, "QC Generator error", szSaveError );
return 0;
}
//write qc header
g_pFullFileSystem->FPrintf( pSaveFile, "//\n// .qc file version 1.0\n\n");
//write out modelname info
char szModelName[MAX_PATH];
char *modelStart = strrchrcount( szName, '\\', 2) + 1;
char *modelEnd = strrchr( szName, '.' );
Q_strncpy( szModelName, modelStart, modelEnd - modelStart + 1 );
V_strcat_safe( szModelName, ".mdl" );
g_pFullFileSystem->FPrintf( pSaveFile, "$modelname %s\n\n", szModelName );
//write out scale info
g_pFullFileSystem->FPrintf( pSaveFile, "$scale %f\n", m_QCInfo_t.fScale );
//write out body info
g_pFullFileSystem->FPrintf( pSaveFile, "$body \"Body\" \"%s\"\n", strrchr( m_QCInfo_t.pszSMDPath, '\\' ) + 1 );
if ( m_QCInfo_t.bStaticProp == true )
{
g_pFullFileSystem->FPrintf( pSaveFile, "$staticprop\n" );
}
if ( m_QCInfo_t.bMostlyOpaque == true )
{
g_pFullFileSystem->FPrintf( pSaveFile, "$mostlyopaque\n" );
}
//write out surfaceprop info
g_pFullFileSystem->FPrintf( pSaveFile, "$surfaceprop \"%s\"\n\n", m_QCInfo_t.pszSurfaceProperty );
//write materials
g_pFullFileSystem->FPrintf( pSaveFile, "$cdmaterials %s\n\n", m_QCInfo_t.pszMaterialPath);
if ( m_QCInfo_t.bStaticProp || m_QCInfo_t.bNoAnimation )
{
g_pFullFileSystem->FPrintf( pSaveFile, "// --------- Animation sequences -------\n");
g_pFullFileSystem->FPrintf( pSaveFile, "$sequence \"idle\" \"%s\" fps 30\n\n", strrchr(m_QCInfo_t.pszSMDPath, '\\')+1);
}
//write out lod info
for( int i = 0; i < m_QCInfo_t.LODs.Count(); i++ )
{
LODInfo thisLOD = m_QCInfo_t.LODs.Element( i );
g_pFullFileSystem->FPrintf( pSaveFile, "$lod %d\n{\n\treplacemodel \"%s\" \"%s\"\n}\n\n", thisLOD.iLOD, strrchr(m_QCInfo_t.pszSMDPath, '\\')+1, thisLOD.pszFilename );
}
if ( m_QCInfo_t.bDisableCollision != true )
{
//write out collision header
g_pFullFileSystem->FPrintf( pSaveFile, "\n" );
//write out collision info
if ( m_QCInfo_t.bReferenceAsPhys == true )
{
g_pFullFileSystem->FPrintf( pSaveFile, "$collisionmodel \"%s\"", strrchr( m_QCInfo_t.pszSMDPath, '\\' ) + 1 );
}
else
{
if( Q_strcmp( m_QCInfo_t.pszCollisionPath, "" ) )
{
g_pFullFileSystem->FPrintf( pSaveFile, "$collisionmodel \"%s\"", strrchr( m_QCInfo_t.pszCollisionPath, '\\' ) + 1 );
}
}
g_pFullFileSystem->FPrintf( pSaveFile, " {\n\t// Mass in kilograms\n ");
if ( m_QCInfo_t.bAutomass == true )
{
g_pFullFileSystem->FPrintf( pSaveFile, "\t$automass\n" );
}
else
{
g_pFullFileSystem->FPrintf( pSaveFile, "\t$mass %f\n", m_QCInfo_t.fMass );
}
if ( m_QCInfo_t.bConcave == true )
{
g_pFullFileSystem->FPrintf( pSaveFile, "\t$concave\n" );
}
g_pFullFileSystem->FPrintf( pSaveFile, "}\n\n");
}
g_pFullFileSystem->Close( pSaveFile );
char szCommand[MAX_PATH];
char szGamePath[MAX_PATH];
char studiomdlPath[512];
g_pFullFileSystem->RelativePathToFullPath( "studiomdl.bat", NULL, studiomdlPath, sizeof( studiomdlPath ));
GetVConfigRegistrySetting( GAMEDIR_TOKEN, szGamePath, sizeof( szGamePath ) );
#ifdef WIN32
STARTUPINFO startup;
PROCESS_INFORMATION process;
memset(&startup, 0, sizeof(startup));
startup.cb = sizeof(startup);
sprintf( szCommand, "%s -game %s %s", studiomdlPath, szGamePath, szName);
bool bReturn = CreateProcess( NULL, szCommand, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &startup, &process);
#else
Assert( !"Implement me, why aren't we using a thread tool abstraction?" );
bool bReturn = false;
#endif
return bReturn;
}
void CQCGenerator::InitializeSMDPaths( const char *pszPath, const char *pszScene )
{
V_strcpy_safe( m_QCInfo_t.pszSceneName, pszScene );
FileFindHandle_t *pFileHandle = new FileFindHandle_t();
g_pFullFileSystem->AddSearchPath( pszPath, "SMD_DIR" );
const char *filename = g_pFullFileSystem->FindFirst( "*.smd", pFileHandle );
bool bFoundReference = false;
bool bFoundCollision = false;
bool bFoundLOD = false;
//iterate through .smd files
const char *startName = pszScene;
int nSearchLength = Q_strlen( pszScene );
int currentLOD = 1;
while( filename )
{
if ( !strncmp( startName, filename, nSearchLength ) )
{
const char *filenameEnd = filename + nSearchLength;
if ( !strncmp( filenameEnd, "_ref", 4 ) || !strncmp( filenameEnd, ".smd", 4 ) )
{
bFoundReference = true;
//we have found the reference smd.
V_strcpy_safe( m_QCInfo_t.pszSMDPath, pszPath );
V_strcat_safe( m_QCInfo_t.pszSMDPath, filename );
}
if ( !strncmp( filenameEnd, "_phy", 4) || !strncmp( filenameEnd, "_col", 4 ) )
{
bFoundCollision = true;
//we have found the collision smd.
V_strcpy_safe( m_QCInfo_t.pszCollisionPath, pszPath );
V_strcat_safe( m_QCInfo_t.pszCollisionPath, filename );
}
if ( !strncmp( filenameEnd, "_lod", 4) )
{
bFoundLOD = true;
//we found an LOD smd.
char lodName[255];
Q_snprintf( lodName, Q_strlen( lodName ), "lod%d", currentLOD );
//we found an LOD
KeyValues *newKv = new KeyValues( lodName, "SMD", filename, "LOD", "10" );
m_pLODPanel->AddItem( newKv, currentLOD, false, false );
currentLOD++;
}
}
filename = g_pFullFileSystem->FindNext( *pFileHandle );
}
char pszMessage[2048] = "";
char pszRefMessage[1024] = "";
char pszColMessage[1024] = "";
if (!bFoundReference )
{
V_strcat_safe( m_QCInfo_t.pszSMDPath, pszPath );
V_strcat_safe( m_QCInfo_t.pszSMDPath, pszScene );
V_strcat_safe( m_QCInfo_t.pszSMDPath, ".smd" );
Q_snprintf( pszRefMessage, 1024, "Reference SMD not found.\n\nValid default reference SMDs are %s%s_ref*.smd and %s%s.smd\nUsing default of %s. Model will not compile.\n\n", pszPath, pszScene, pszPath, pszScene, m_QCInfo_t.pszSMDPath );
}
if ( !bFoundCollision )
{
Q_snprintf( pszColMessage, 1024, "Collision SMD not found.\n\nThe valid default collision SMD is %s%s_phy*.smd.\nUsing reference SMD as default.\n", pszPath, pszScene );
V_strcpy_safe( m_QCInfo_t.pszCollisionPath, m_QCInfo_t.pszSMDPath );
m_QCInfo_t.bReferenceAsPhys = true;
}
if ( !bFoundReference || !bFoundCollision)
{
V_strcpy_safe( pszMessage, pszRefMessage );
V_strcat_safe( pszMessage, pszColMessage );
VGUIMessageBox( this, "Error Initializing Paths", pszMessage );
}
}
void CQCGenerator::DeleteLOD()
{
int numSelected = m_pLODPanel->GetSelectedItemsCount();
int selected;
for ( int i = numSelected-1; i >= 0; i-- )
{
selected = m_pLODPanel->GetSelectedItem( i );
m_pLODPanel->RemoveItem( selected );
}
}
void CQCGenerator::EditLOD()
{
int numSelected = m_pLODPanel->GetSelectedItemsCount();
if ( numSelected == 1 && !m_pLODPanel->IsInEditMode() )
{
if ( m_pLODEdit )
{
m_pLODEdit->MarkForDeletion();
m_pLODEdit = NULL;
}
m_pLODEdit = new vgui::TextEntry( this, "Edit" );
m_pLODEdit->SendNewLine( true );
m_nSelectedSequence = m_pLODPanel->GetSelectedItem( 0 );
m_nSelectedColumn = m_pLODPanel->GetSelectedColumn();
m_pLODPanel->EnterEditMode( m_nSelectedSequence, m_nSelectedColumn, m_pLODEdit );
}
}
void CQCGenerator::OnNewLODText()
{
KeyValues *pEditItem = m_pLODPanel->GetItem( m_nSelectedSequence );
KeyValues *pListItem = pEditItem;
wchar_t szEditText[MAX_PATH];
pEditItem = pEditItem->GetFirstValue();
const char *name = pEditItem->GetName();
for( int i = 0; i < m_nSelectedColumn; i++ )
{
pEditItem = pEditItem->GetNextValue();
name = pEditItem->GetName();
}
m_pLODEdit->GetText( szEditText, MAX_PATH );
pListItem->SetWString( name, szEditText );
m_pLODPanel->LeaveEditMode();
m_pLODPanel->InvalidateLayout();
return;
}

View File

@ -0,0 +1,47 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "matsys_controls/assetpicker.h"
using namespace vgui;
//-----------------------------------------------------------------------------
//
// Asset Picker with no preview
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CAssetPicker::CAssetPicker( vgui::Panel *pParent, const char *pAssetType,
const char *pExt, const char *pSubDir, const char *pTextType ) :
BaseClass( pParent, pAssetType, pExt, pSubDir, pTextType )
{
CreateStandardControls( this );
LoadControlSettingsAndUserConfig( "resource/assetpicker.res" );
}
//-----------------------------------------------------------------------------
//
// Purpose: Modal picker frame
//
//-----------------------------------------------------------------------------
CAssetPickerFrame::CAssetPickerFrame( vgui::Panel *pParent, const char *pTitle,
const char *pAssetType, const char *pExt, const char *pSubDir, const char *pTextType ) :
BaseClass( pParent )
{
SetAssetPicker( new CAssetPicker( this, pAssetType, pExt, pSubDir, pTextType ) );
LoadControlSettingsAndUserConfig( "resource/assetpickerframe.res" );
SetTitle( pTitle, false );
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,200 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//===========================================================================//
#include "matsys_controls/curveeditorpanel.h"
#include "matsys_controls/matsyscontrols.h"
#include "tier1/KeyValues.h"
#include "vgui/ISurface.h"
#include "vgui/IInput.h"
#include "vgui/MouseCode.h"
using namespace vgui;
//-----------------------------------------------------------------------------
// constructor, destructor
//-----------------------------------------------------------------------------
CCurveEditorPanel::CCurveEditorPanel( vgui::Panel *pParent, const char *pName ) : BaseClass( pParent, pName )
{
m_nSelectedPoint = -1;
SetMouseInputEnabled( true );
SetKeyBoardInputEnabled( true );
m_nHighlightedPoint = -1;
}
CCurveEditorPanel::~CCurveEditorPanel()
{
}
//-----------------------------------------------------------------------------
// Converts screen location to normalized values
//-----------------------------------------------------------------------------
void CCurveEditorPanel::ScreenToValue( int x, int y, float *pIn, float *pOut )
{
int w, h;
GetSize( w, h );
*pIn = (float)x / (w-1);
*pOut = 1.0f - ((float)y / (h-1));
}
void CCurveEditorPanel::ValueToScreen( float flIn, float flOut, int *x, int *y )
{
int w, h;
GetSize( w, h );
*x = (int)(flIn * (w-1) + 0.5f);
*y = (h-1) - (int)(flOut * (h-1) + 0.5f);
}
//-----------------------------------------------------------------------------
// Handle input
//-----------------------------------------------------------------------------
void CCurveEditorPanel::OnMousePressed( vgui::MouseCode code )
{
BaseClass::OnMousePressed( code );
int x, y;
input()->GetCursorPos( x, y );
ScreenToLocal( x, y );
if ( code == MOUSE_LEFT )
{
int w, h;
GetSize( w, h );
float flIn, flOut;
ScreenToValue( x, y, &flIn, &flOut );
float flTolerance = 5.0f / (w-1); // +/- 3 pixels to select the point
m_nSelectedPoint = FindOrAddControlPoint( flIn, flTolerance, flOut );
}
}
void CCurveEditorPanel::OnMouseReleased( vgui::MouseCode code )
{
BaseClass::OnMouseReleased( code );
if ( code == MOUSE_LEFT )
{
m_nSelectedPoint = -1;
}
}
void CCurveEditorPanel::OnCursorMoved( int x, int y )
{
BaseClass::OnCursorMoved( x, y );
float flIn, flOut;
ScreenToValue( x, y, &flIn, &flOut );
int w, h;
GetSize( w, h );
float flTolerance = 5.0f / (w-1); // +/- 3 pixels to select the point
m_nHighlightedPoint = FindControlPoint( flIn, flTolerance );
if ( m_nSelectedPoint < 0 )
return;
m_nSelectedPoint = ModifyControlPoint( m_nSelectedPoint, flIn, flOut );
}
//-----------------------------------------------------------------------------
// Handles keypresses
//-----------------------------------------------------------------------------
void CCurveEditorPanel::OnKeyCodePressed( vgui::KeyCode code )
{
BaseClass::OnKeyCodePressed( code );
if ( m_nSelectedPoint >= 0 )
{
RemoveControlPoint( m_nSelectedPoint );
m_nSelectedPoint = -1;
}
}
//-----------------------------------------------------------------------------
// This paints the grid behind the curves
//-----------------------------------------------------------------------------
void CCurveEditorPanel::PaintBackground( void )
{
int w, h;
GetSize( w, h );
vgui::surface()->DrawSetColor( 255, 255, 255, 255 );
vgui::surface()->DrawFilledRect( 0, 0, w, h );
vgui::surface()->DrawSetColor( 128, 128, 128, 255 );
vgui::surface()->DrawLine( 0, h/4, w, h/4 );
vgui::surface()->DrawLine( 0, h/2, w, h/2 );
vgui::surface()->DrawLine( 0, 3*h/4, w, 3*h/4 );
vgui::surface()->DrawLine( w/4, 0, w/4, h );
vgui::surface()->DrawLine( w/2, 0, w/2, h );
vgui::surface()->DrawLine( 3*w/4, 0, 3*w/4, h );
vgui::surface()->DrawSetColor( 0, 0, 0, 255 );
vgui::surface()->DrawLine( 0, 0, w, 0 );
vgui::surface()->DrawLine( w, 0, w, h );
vgui::surface()->DrawLine( w, h, 0, h );
vgui::surface()->DrawLine( 0, h, 0, 0 );
}
//-----------------------------------------------------------------------------
// Sets the color curves operation to edit
//-----------------------------------------------------------------------------
void CCurveEditorPanel::Paint( void )
{
int w, h;
GetSize( w, h );
int x0 = 0, y0 = 0;
// FIXME: Add method to draw multiple lines DrawPolyLine connects the 1st and last points... bleah
vgui::surface()->DrawSetColor( 0, 0, 0, 255 );
for ( int i = 0; i < w; ++i )
{
float flIn = (float)i / (w-1);
float flOut = GetValue( flIn );
int x = i;
int y = (h-1) - (int)(flOut * (h-1) + 0.5f);
y = clamp( y, 0, h-1 );
if ( i != 0 )
{
vgui::surface()->DrawLine( x0, y0, x, y );
}
x0 = x; y0 = y;
}
// This will paint the control points
// The currently selected one will be painted red and filled.
for ( int i = ControlPointCount(); --i >= 0; )
{
float flIn, flOut;
GetControlPoint( i, &flIn, &flOut );
int cx, cy;
ValueToScreen( flIn, flOut, &cx, &cy );
if ( (i == m_nSelectedPoint) || ((m_nSelectedPoint == -1) && (i == m_nHighlightedPoint)) )
{
vgui::surface()->DrawSetColor( 255, 0, 0, 255 );
vgui::surface()->DrawFilledRect( cx-3, cy-3, cx+3, cy+3 );
}
else
{
vgui::surface()->DrawSetColor( 0, 0, 0, 255 );
vgui::surface()->DrawOutlinedRect( cx-3, cy-3, cx+3, cy+3 );
}
}
}

View File

@ -0,0 +1,301 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#if defined(WIN32) && !defined( _X360 )
#include <windows.h>
#endif
#undef PropertySheet
#include "matsys_controls/gamefiletreeview.h"
#include "filesystem.h"
#include "tier1/KeyValues.h"
#include "vgui/ISurface.h"
#include "vgui/Cursor.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
//-----------------------------------------------------------------------------
// list of all tree view icons
//-----------------------------------------------------------------------------
enum
{
IMAGE_FOLDER = 1,
IMAGE_OPENFOLDER,
IMAGE_FILE,
};
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
CGameFileTreeView::CGameFileTreeView( Panel *parent, const char *name, const char *pRootFolderName, const char *pRootDir, const char *pExtension ) : BaseClass(parent, name), m_Images( false )
{
m_RootDir = pRootDir;
m_Ext = pExtension;
m_bUseExt = ( pExtension != NULL );
m_RootFolderName = pRootFolderName;
// build our list of images
m_Images.AddImage( scheme()->GetImage( "resource/icon_folder", false ) );
m_Images.AddImage( scheme()->GetImage( "resource/icon_folder_selected", false ) );
m_Images.AddImage( scheme()->GetImage( "resource/icon_file", false ) );
SetImageList( &m_Images, false );
}
//-----------------------------------------------------------------------------
// Purpose: Refreshes the active file list
//-----------------------------------------------------------------------------
void CGameFileTreeView::RefreshFileList()
{
RemoveAll();
SetFgColor(Color(216, 222, 211, 255));
// add the base node
KeyValues *pkv = new KeyValues( "root" );
pkv->SetString( "text", m_RootFolderName );
pkv->SetInt( "root", 1 );
pkv->SetInt( "expand", 1 );
int iRoot = AddItem( pkv, GetRootItemIndex() );
pkv->deleteThis();
ExpandItem( iRoot, true );
}
//-----------------------------------------------------------------------------
// Selects the root folder
//-----------------------------------------------------------------------------
void CGameFileTreeView::SelectRoot()
{
AddSelectedItem( GetRootItemIndex(), true );
}
//-----------------------------------------------------------------------------
// Gets the number of root directories
//-----------------------------------------------------------------------------
int CGameFileTreeView::GetRootDirectoryCount()
{
return GetNumChildren( GetRootItemIndex() );
}
//-----------------------------------------------------------------------------
// Gets the ith root directory
//-----------------------------------------------------------------------------
const char *CGameFileTreeView::GetRootDirectory( int nIndex )
{
int nItemIndex = GetChild( GetRootItemIndex(), nIndex );
KeyValues *kv = GetItemData( nItemIndex );
if ( !kv )
return NULL;
return kv->GetString( "path", NULL );
}
//-----------------------------------------------------------------------------
// Populate the root node (necessary since tree view can't have multiple roots)
//-----------------------------------------------------------------------------
void CGameFileTreeView::PopulateRootNode( int itemIndex )
{
AddDirectoriesOfNode( itemIndex, m_RootDir );
if ( m_bUseExt )
{
AddFilesOfNode( itemIndex, m_RootDir, m_Ext );
}
}
//-----------------------------------------------------------------------------
// Populate the root node with directories
//-----------------------------------------------------------------------------
bool CGameFileTreeView::DoesDirectoryHaveSubdirectories( const char *pFilePath )
{
char pSearchString[MAX_PATH];
Q_snprintf( pSearchString, MAX_PATH, "%s\\*", pFilePath );
// get the list of files
FileFindHandle_t findHandle;
// generate children
// add all the items
const char *pszFileName = g_pFullFileSystem->FindFirstEx( pSearchString, "GAME", &findHandle );
while ( pszFileName )
{
bool bIsDirectory = g_pFullFileSystem->FindIsDirectory( findHandle );
if ( bIsDirectory && Q_strnicmp( pszFileName, ".", 2 ) && Q_strnicmp( pszFileName, "..", 3 ) )
return true;
pszFileName = g_pFullFileSystem->FindNext( findHandle );
}
g_pFullFileSystem->FindClose( findHandle );
return false;
}
//-----------------------------------------------------------------------------
// Populate the root node with directories
//-----------------------------------------------------------------------------
void CGameFileTreeView::AddDirectoriesOfNode( int itemIndex, const char *pFilePath )
{
char pSearchString[MAX_PATH];
Q_snprintf( pSearchString, MAX_PATH, "%s\\*", pFilePath );
// get the list of files
FileFindHandle_t findHandle;
// generate children
// add all the items
const char *pszFileName = g_pFullFileSystem->FindFirstEx( pSearchString, "GAME", &findHandle );
while ( pszFileName )
{
bool bIsDirectory = g_pFullFileSystem->FindIsDirectory( findHandle );
if ( bIsDirectory && Q_strnicmp( pszFileName, ".", 2 ) && Q_strnicmp( pszFileName, "..", 3 ) )
{
KeyValues *kv = new KeyValues( "node", "text", pszFileName );
char pFullPath[MAX_PATH];
Q_snprintf( pFullPath, sizeof(pFullPath), "%s/%s", pFilePath, pszFileName );
Q_FixSlashes( pFullPath );
Q_strlower( pFullPath );
bool bHasSubdirectories = DoesDirectoryHaveSubdirectories( pFullPath );
kv->SetString( "path", pFullPath );
kv->SetInt( "expand", bHasSubdirectories );
kv->SetInt( "dir", 1 );
kv->SetInt( "image", IMAGE_FOLDER );
int itemID = AddItem(kv, itemIndex);
kv->deleteThis();
// mark directories in orange
SetItemColorForDirectories( itemID );
}
pszFileName = g_pFullFileSystem->FindNext( findHandle );
}
g_pFullFileSystem->FindClose( findHandle );
}
//-----------------------------------------------------------------------------
// Populate the root node with files
//-----------------------------------------------------------------------------
void CGameFileTreeView::AddFilesOfNode( int itemIndex, const char *pFilePath, const char *pExt )
{
char pSearchString[MAX_PATH];
Q_snprintf( pSearchString, MAX_PATH, "%s\\*.%s", pFilePath, pExt );
// get the list of files
FileFindHandle_t findHandle;
// generate children
// add all the items
const char *pszFileName = g_pFullFileSystem->FindFirst( pSearchString, &findHandle );
while ( pszFileName )
{
if ( !g_pFullFileSystem->FindIsDirectory( findHandle ) )
{
KeyValues *kv = new KeyValues( "node", "text", pszFileName );
char pFullPath[MAX_PATH];
Q_snprintf( pFullPath, MAX_PATH, "%s\\%s", pFilePath, pszFileName );
kv->SetString( "path", pFullPath );
kv->SetInt( "image", IMAGE_FILE );
AddItem(kv, itemIndex);
kv->deleteThis();
}
pszFileName = g_pFullFileSystem->FindNext( findHandle );
}
g_pFullFileSystem->FindClose( findHandle );
}
//-----------------------------------------------------------------------------
// override to incremental request and show p4 directories
//-----------------------------------------------------------------------------
void CGameFileTreeView::GenerateChildrenOfNode(int itemIndex)
{
KeyValues *pkv = GetItemData(itemIndex);
if ( pkv->GetInt("root") )
{
PopulateRootNode( itemIndex );
return;
}
if (!pkv->GetInt("dir"))
return;
const char *pFilePath = pkv->GetString("path", "");
if (!pFilePath[0])
return;
surface()->SetCursor(dc_waitarrow);
AddDirectoriesOfNode( itemIndex, pFilePath );
if ( m_bUseExt )
{
AddFilesOfNode( itemIndex, pFilePath, m_Ext );
}
}
//-----------------------------------------------------------------------------
// setup a context menu whenever a directory is clicked on
//-----------------------------------------------------------------------------
void CGameFileTreeView::GenerateContextMenu( int itemIndex, int x, int y )
{
return;
/*
KeyValues *pkv = GetItemData(itemIndex);
const char *pFilePath = pkv->GetString("path", "");
if (!pFilePath[0])
return;
Menu *pContext = new Menu(this, "FileContext");
pContext->AddMenuItem("Cloak folder", new KeyValues("CloakFolder", "item", itemIndex), GetParent(), NULL);
// show the context menu
pContext->SetPos(x, y);
pContext->SetVisible(true);
*/
}
//-----------------------------------------------------------------------------
// Sets an item to be colored as if its a menu
//-----------------------------------------------------------------------------
void CGameFileTreeView::SetItemColorForDirectories( int itemID )
{
// mark directories in orange
SetItemFgColor( itemID, Color(224, 192, 0, 255) );
}
//-----------------------------------------------------------------------------
// setup a smaller font
//-----------------------------------------------------------------------------
void CGameFileTreeView::ApplySchemeSettings(IScheme *pScheme)
{
BaseClass::ApplySchemeSettings(pScheme);
SetFont( pScheme->GetFont("DefaultSmall") );
}

View File

@ -0,0 +1,201 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================
#include "matsys_controls/manipulator.h"
#include "materialsystem/imaterialsystem.h"
#include "vgui/IVGui.h"
#include "vgui/IInput.h"
#include "vgui/ISystem.h"
#include "vgui/MouseCode.h"
#include "mathlib/vector.h"
#include "mathlib/vmatrix.h"
#include "mathlib/mathlib.h"
#include <float.h>
using namespace vgui;
//-----------------------------------------------------------------------------
// local helper functions
//-----------------------------------------------------------------------------
static float UpdateTime( float &flLastTime )
{
float flTime = vgui::system()->GetFrameTime();
float dt = flTime - flLastTime;
flLastTime = flTime;
return dt;
}
//-----------------------------------------------------------------------------
// Base class for manipulators which operate on transforms
//-----------------------------------------------------------------------------
CTransformManipulator::CTransformManipulator( matrix3x4_t *pTransform ) :
m_pTransform( pTransform )
{
}
void CTransformManipulator::SetTransform( matrix3x4_t *pTransform )
{
m_pTransform = pTransform;
}
matrix3x4_t *CTransformManipulator::GetTransform( void )
{
return m_pTransform;
}
//-----------------------------------------------------------------------------
// CPotteryWheelManip - nendo-style camera manipulator
//-----------------------------------------------------------------------------
CPotteryWheelManip::CPotteryWheelManip( matrix3x4_t *pTransform ) :
CTransformManipulator( pTransform ),
m_lastx( -1 ), m_lasty( -1 ),
m_zoom( 100.0f ), m_altitude( 0.0f ), m_azimuth( 0.0f ),
m_prevZoom( 100.0f ), m_prevAltitude( 0.0f ), m_prevAzimuth( 0.0f ),
m_flLastMouseTime( 0.0f ), m_flLastTickTime( 0.0f ),
m_flSpin( 0.0f ), m_bSpin( false )
{
}
void CPotteryWheelManip::OnBeginManipulation( void )
{
m_prevZoom = m_zoom;
m_prevAltitude = m_altitude;
m_prevAzimuth = m_azimuth;
m_flLastMouseTime = m_flLastTickTime = vgui::system()->GetFrameTime();
m_flSpin = 0.0f;
m_bSpin = false;
}
// Sets the zoom level
void CPotteryWheelManip::SetZoom( float flZoom )
{
m_prevZoom = m_zoom = flZoom;
}
void CPotteryWheelManip::OnAcceptManipulation( void )
{
m_flSpin = 0.0f;
m_bSpin = false;
}
void CPotteryWheelManip::OnCancelManipulation( void )
{
m_zoom = m_prevZoom;
m_altitude = m_prevAltitude;
m_azimuth = m_prevAzimuth;
m_flSpin = 0.0f;
m_bSpin = false;
UpdateTransform();
}
void CPotteryWheelManip::OnTick( void )
{
float dt = UpdateTime( m_flLastTickTime );
if ( m_bSpin )
{
m_azimuth += dt * m_flSpin;
UpdateTransform();
}
}
void CPotteryWheelManip::OnCursorMoved( int x, int y )
{
float dt = UpdateTime( m_flLastMouseTime );
if ( m_bSpin )
{
m_lastx = x;
m_lasty = y;
return;
}
if ( input()->IsMouseDown( MOUSE_MIDDLE ) )
{
int dy = y - m_lasty;
int dx = x - m_lastx;
if ( abs( dx ) < 2 * abs( dy ) )
{
UpdateZoom( 0.2f * dy );
}
else
{
m_flSpin = (dt != 0.0f) ? 0.002f * dx / dt : 0.0f;
m_azimuth += 0.002f * dx;
}
}
else
{
m_azimuth += 0.002f * ( x - m_lastx );
m_altitude -= 0.002f * ( y - m_lasty );
m_altitude = max( (float)-M_PI/2, min( (float)M_PI/2, m_altitude ) );
}
m_lastx = x;
m_lasty = y;
UpdateTransform();
}
void CPotteryWheelManip::OnMousePressed( vgui::MouseCode code, int x, int y )
{
UpdateTime( m_flLastMouseTime );
m_lastx = x;
m_lasty = y;
m_bSpin = false;
m_flSpin = 0.0f;
}
void CPotteryWheelManip::OnMouseReleased( vgui::MouseCode code, int x, int y )
{
UpdateTime( m_flLastMouseTime );
if ( code == MOUSE_MIDDLE )
{
m_bSpin = ( fabs( m_flSpin ) > 1.0f );
}
m_lastx = x;
m_lasty = y;
}
void CPotteryWheelManip::OnMouseWheeled( int delta )
{
UpdateTime( m_flLastMouseTime );
UpdateZoom( -10.0f * delta );
UpdateTransform();
}
void CPotteryWheelManip::UpdateTransform()
{
if ( !m_pTransform )
return;
float y = m_zoom * sin( m_altitude );
float xz = m_zoom * cos( m_altitude );
float x = xz * sin( m_azimuth );
float z = xz * cos( m_azimuth );
Vector position(x, y, z);
AngleMatrix( RadianEuler( -m_altitude, m_azimuth, 0 ), position, *m_pTransform );
}
void CPotteryWheelManip::UpdateZoom( float delta )
{
m_zoom *= pow( 1.01f, delta );
}

View File

@ -0,0 +1,66 @@
//-----------------------------------------------------------------------------
// MATSYS_CONTROLS.VPC
//
// Project Script
//-----------------------------------------------------------------------------
$macro SRCDIR "..\.."
$include "$SRCDIR\vpc_scripts\source_lib_base.vpc"
$Project "matsys_controls"
{
$Folder "Source Files"
{
$File "assetpicker.cpp"
$File "baseassetpicker.cpp"
$File "colorpickerpanel.cpp"
$File "curveeditorpanel.cpp"
$File "gamefiletreeview.cpp"
$File "manipulator.cpp"
$File "matsyscontrols.cpp"
$File "mdlpanel.cpp"
$File "mdlpicker.cpp"
$File "mdlsequencepicker.cpp"
$File "picker.cpp"
$File "potterywheelpanel.cpp"
$File "proceduraltexturepanel.cpp"
$File "QCGenerator.cpp"
$File "sequencepicker.cpp"
$File "tgapreviewpanel.cpp"
$File "vmtpicker.cpp"
$File "vmtpreviewpanel.cpp"
$File "vtfpicker.cpp"
$File "vtfpreviewpanel.cpp"
$File "vmtpanel.cpp"
}
$Folder "Header Files"
{
$File "$SRCDIR\public\matsys_controls\assetpicker.h"
$File "$SRCDIR\public\matsys_controls\baseassetpicker.h"
$File "$SRCDIR\public\matsys_controls\colorpickerpanel.h"
$File "$SRCDIR\public\matsys_controls\gamefiletreeview.h"
$File "$SRCDIR\public\matsys_controls\manipulator.h"
$File "$SRCDIR\public\matsys_controls\matsyscontrols.h"
$File "$SRCDIR\public\matsys_controls\mdlpanel.h"
$File "$SRCDIR\public\matsys_controls\mdlpicker.h"
$File "$SRCDIR\public\matsys_controls\mdlsequencepicker.h"
$File "$SRCDIR\public\matsys_controls\picker.h"
$File "$SRCDIR\public\matsys_controls\potterywheelpanel.h"
$File "$SRCDIR\public\matsys_controls\proceduraltexturepanel.h"
$File "$SRCDIR\public\matsys_controls\QCGenerator.h"
$File "$SRCDIR\public\matsys_controls\sequencepicker.h"
$File "$SRCDIR\public\matsys_controls\tgapreviewpanel.h"
$File "$SRCDIR\public\matsys_controls\vmtpicker.h"
$File "$SRCDIR\public\matsys_controls\vmtpreviewpanel.h"
$File "$SRCDIR\public\matsys_controls\vtfpicker.h"
$File "$SRCDIR\public\matsys_controls\vtfpreviewpanel.h"
$File "$SRCDIR\public\matsys_controls\vmtpanel.h"
}
$Folder "Link Libraries"
{
$Lib bitmap [$WIN32]
}
}

View File

@ -0,0 +1,100 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#include "matsys_controls/matsyscontrols.h"
#include <materialsystem/imaterialsystem.h>
#include <materialsystem/imaterialsystemhardwareconfig.h>
#include <datacache/imdlcache.h>
#include <VGuiMatSurface/IMatSystemSurface.h>
#include <istudiorender.h>
#include "vgui_controls/Controls.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
namespace vgui
{
IMaterialSystem *g_pMaterialSystem = NULL;
IMaterialSystem *MaterialSystem()
{
return g_pMaterialSystem;
}
IMaterialSystemHardwareConfig *g_pMaterialSystemHardwareConfig = NULL;
IMaterialSystemHardwareConfig *MaterialSystemHardwareConfig()
{
return g_pMaterialSystemHardwareConfig;
}
IMDLCache *g_pMDLCache = NULL;
IMDLCache *MDLCache()
{
return g_pMDLCache;
}
IMatSystemSurface *g_pMatSystemSurface = NULL;
IMatSystemSurface *MatSystemSurface()
{
return g_pMatSystemSurface;
}
IStudioRender *g_pStudioRender = NULL;
IStudioRender *StudioRender()
{
return g_pStudioRender;
}
//-----------------------------------------------------------------------------
// Purpose: finds a particular interface in the factory set
//-----------------------------------------------------------------------------
static void *InitializeInterface( char const *interfaceName, CreateInterfaceFn *factoryList, int numFactories )
{
void *retval;
for ( int i = 0; i < numFactories; i++ )
{
CreateInterfaceFn factory = factoryList[ i ];
if ( !factory )
continue;
retval = factory( interfaceName, NULL );
if ( retval )
return retval;
}
// No provider for requested interface!!!
// Assert( !"No provider for requested interface!!!" );
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Initializes the controls
//-----------------------------------------------------------------------------
bool VGui_InitMatSysInterfacesList( const char *moduleName, CreateInterfaceFn *factoryList, int numFactories )
{
if ( !vgui::VGui_InitInterfacesList( moduleName, factoryList, numFactories ) )
return false;
g_pMaterialSystem = (IMaterialSystem *)InitializeInterface( MATERIAL_SYSTEM_INTERFACE_VERSION, factoryList, numFactories );
g_pMatSystemSurface = (IMatSystemSurface *)InitializeInterface( MAT_SYSTEM_SURFACE_INTERFACE_VERSION, factoryList, numFactories );
g_pMDLCache = (IMDLCache *)InitializeInterface( MDLCACHE_INTERFACE_VERSION, factoryList, numFactories );
g_pStudioRender = (IStudioRender *)InitializeInterface( STUDIO_RENDER_INTERFACE_VERSION, factoryList, numFactories );
g_pMaterialSystemHardwareConfig = (IMaterialSystemHardwareConfig *)InitializeInterface( MATERIALSYSTEM_HARDWARECONFIG_INTERFACE_VERSION, factoryList, numFactories );
// MDL cache + studiorender are optional
return ( g_pMaterialSystem && g_pMatSystemSurface && g_pMaterialSystemHardwareConfig );
}
} // namespace vgui

View File

@ -0,0 +1,981 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "matsys_controls/mdlpanel.h"
#include "materialsystem/imaterialsystem.h"
#include "materialsystem/imaterialsystemhardwareconfig.h"
#include "materialsystem/imesh.h"
#include "vgui/IVGui.h"
#include "tier1/KeyValues.h"
#include "vgui_controls/Frame.h"
#include "tier1/convar.h"
#include "tier0/dbg.h"
#include "tier1/fmtstr.h"
#include "istudiorender.h"
#include "matsys_controls/matsyscontrols.h"
#include "vcollide.h"
#include "vcollide_parse.h"
#include "bone_setup.h"
#include "vphysics_interface.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
DECLARE_BUILD_FACTORY( CMDLPanel );
static const int THUMBNAIL_SAFE_ZONE_SIZE = 512;
static const int THUMBNAIL_SAFE_ZONE_HEIGHT = 92;
static const float THUMBNAIL_SAFE_ZONE_HEIGHT_SCALE = (float)THUMBNAIL_SAFE_ZONE_HEIGHT / THUMBNAIL_SAFE_ZONE_SIZE;
//-----------------------------------------------------------------------------
// Purpose: Keeps a global clock to autoplay sequences to run from
// Also deals with speedScale changes
//-----------------------------------------------------------------------------
float GetAutoPlayTime( void )
{
static int g_prevTicks;
static float g_time;
int ticks = Plat_MSTime();
// limit delta so that float time doesn't overflow
if (g_prevTicks == 0)
{
g_prevTicks = ticks;
}
g_time += ( ticks - g_prevTicks ) / 1000.0f;
g_prevTicks = ticks;
return g_time;
}
//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
CMDLPanel::CMDLPanel( vgui::Panel *pParent, const char *pName ) : BaseClass( pParent, pName )
{
SetVisible( true );
// Used to poll input
vgui::ivgui()->AddTickSignal( GetVPanel() );
// Deal with the default cubemap
ITexture *pCubemapTexture = vgui::MaterialSystem()->FindTexture( "editor/cubemap", NULL, true );
m_DefaultEnvCubemap.Init( pCubemapTexture );
pCubemapTexture = vgui::MaterialSystem()->FindTexture( "editor/cubemap.hdr", NULL, true );
m_DefaultHDREnvCubemap.Init( pCubemapTexture );
SetIdentityMatrix( m_RootMDL.m_MDLToWorld );
m_RootMDL.m_pStudioHdr = NULL;
m_RootMDL.m_unMdlCacheSerial = 0;
m_bDrawCollisionModel = false;
m_bWireFrame = false;
m_bGroundGrid = false;
m_bLockView = false;
m_bLookAtCamera = true;
m_bThumbnailSafeZone = false;
m_nNumSequenceLayers = 0;
ResetAnimationEventState( &m_EventState );
}
CMDLPanel::~CMDLPanel()
{
m_aMergeMDLs.Purge();
m_DefaultEnvCubemap.Shutdown( );
m_DefaultHDREnvCubemap.Shutdown();
if ( m_RootMDL.m_pStudioHdr )
{
delete m_RootMDL.m_pStudioHdr;
m_RootMDL.m_pStudioHdr = NULL;
}
}
//-----------------------------------------------------------------------------
// Scheme settings
//-----------------------------------------------------------------------------
void CMDLPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
SetBackgroundColor( GetBgColor() );
SetBorder( pScheme->GetBorder( "MenuBorder") );
}
//-----------------------------------------------------------------------------
// Rendering options
//-----------------------------------------------------------------------------
void CMDLPanel::SetCollsionModel( bool bVisible )
{
m_bDrawCollisionModel = bVisible;
}
void CMDLPanel::SetGroundGrid( bool bVisible )
{
m_bGroundGrid = bVisible;
}
void CMDLPanel::SetWireFrame( bool bVisible )
{
m_bWireFrame = bVisible;
}
void CMDLPanel::SetLockView( bool bLocked )
{
m_bLockView = bLocked;
}
void CMDLPanel::SetLookAtCamera( bool bLookAtCamera )
{
m_bLookAtCamera = bLookAtCamera;
}
void CMDLPanel::SetIgnoreDoubleClick( bool bState )
{
m_bIgnoreDoubleClick = bState;
}
void CMDLPanel::SetThumbnailSafeZone( bool bVisible )
{
m_bThumbnailSafeZone = bVisible;
}
//-----------------------------------------------------------------------------
// Stores the clip
//-----------------------------------------------------------------------------
void CMDLPanel::SetMDL( MDLHandle_t handle, void *pProxyData )
{
m_RootMDL.m_MDL.SetMDL( handle );
if ( m_RootMDL.m_pStudioHdr )
{
delete m_RootMDL.m_pStudioHdr;
}
m_RootMDL.m_pStudioHdr = new CStudioHdr( m_RootMDL.m_MDL.GetStudioHdr(), g_pMDLCache );
m_RootMDL.m_MDL.m_pProxyData = pProxyData;
Vector vecMins, vecMaxs;
GetMDLBoundingBox( &vecMins, &vecMaxs, handle, m_RootMDL.m_MDL.m_nSequence );
m_RootMDL.m_MDL.m_bWorldSpaceViewTarget = false;
m_RootMDL.m_MDL.m_vecViewTarget.Init( 100.0f, 0.0f, vecMaxs.z );
m_RootMDL.m_flCycleStartTime = 0.f;
// Set the pose parameters to the default for the mdl
SetPoseParameters( NULL, 0 );
// Clear any sequence layers
SetSequenceLayers( NULL, 0 );
ResetAnimationEventState( &m_EventState );
}
//-----------------------------------------------------------------------------
// An MDL was selected
//-----------------------------------------------------------------------------
void CMDLPanel::SetMDL( const char *pMDLName, void *pProxyData )
{
MDLHandle_t hMDLFindResult = vgui::MDLCache()->FindMDL( pMDLName );
MDLHandle_t hMDL = pMDLName ? hMDLFindResult : MDLHANDLE_INVALID;
if ( vgui::MDLCache()->IsErrorModel( hMDL ) )
{
hMDL = MDLHANDLE_INVALID;
}
SetMDL( hMDL, pProxyData );
// FindMDL takes a reference and the the CMDL will also hold a reference for as long as it sticks around. Release the FindMDL reference.
int nRef = vgui::MDLCache()->Release( hMDLFindResult );
(void)nRef; // Avoid unreferenced variable warning
AssertMsg( hMDL == MDLHANDLE_INVALID || nRef > 0, "CMDLPanel::SetMDL referenced a model that has a zero ref count." );
}
//-----------------------------------------------------------------------------
// Purpose: Returns a model bounding box.
//-----------------------------------------------------------------------------
bool CMDLPanel::GetBoundingBox( Vector &vecBoundsMin, Vector &vecBoundsMax )
{
// Check to see if we have a valid model to look at.
if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID )
return false;
GetMDLBoundingBox( &vecBoundsMin, &vecBoundsMax, m_RootMDL.m_MDL.GetMDL(), m_RootMDL.m_MDL.m_nSequence );
return true;
}
//-----------------------------------------------------------------------------
// Purpose: Returns a more accurate bounding sphere
//-----------------------------------------------------------------------------
bool CMDLPanel::GetBoundingSphere( Vector &vecCenter, float &flRadius )
{
// Check to see if we have a valid model to look at.
if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID )
return false;
Vector vecEngineCenter;
GetMDLBoundingSphere( &vecEngineCenter, &flRadius, m_RootMDL.m_MDL.GetMDL(), m_RootMDL.m_MDL.m_nSequence );
VectorTransform( vecEngineCenter, m_RootMDL.m_MDLToWorld, vecCenter );
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMDLPanel::SetModelAnglesAndPosition( const QAngle &angRot, const Vector &vecPos )
{
SetIdentityMatrix( m_RootMDL.m_MDLToWorld );
AngleMatrix( angRot, vecPos, m_RootMDL.m_MDLToWorld );
}
//-----------------------------------------------------------------------------
// Sets the camera to look at the model
//-----------------------------------------------------------------------------
void CMDLPanel::LookAtMDL()
{
// Check to see if we have a valid model to look at.
if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID )
return;
if ( m_bLockView )
return;
float flRadius;
Vector vecCenter;
GetBoundingSphere( vecCenter, flRadius );
LookAt( vecCenter, flRadius );
}
//-----------------------------------------------------------------------------
// FIXME: This should be moved into studiorender
//-----------------------------------------------------------------------------
static ConVar r_showenvcubemap( "r_showenvcubemap", "0", FCVAR_CHEAT );
static ConVar r_eyegloss ( "r_eyegloss", "1", FCVAR_ARCHIVE ); // wet eyes
static ConVar r_eyemove ( "r_eyemove", "1", FCVAR_ARCHIVE ); // look around
static ConVar r_eyeshift_x ( "r_eyeshift_x", "0", FCVAR_ARCHIVE ); // eye X position
static ConVar r_eyeshift_y ( "r_eyeshift_y", "0", FCVAR_ARCHIVE ); // eye Y position
static ConVar r_eyeshift_z ( "r_eyeshift_z", "0", FCVAR_ARCHIVE ); // eye Z position
static ConVar r_eyesize ( "r_eyesize", "0", FCVAR_ARCHIVE ); // adjustment to iris textures
static ConVar mat_softwareskin( "mat_softwareskin", "0", FCVAR_CHEAT );
static ConVar r_nohw ( "r_nohw", "0", FCVAR_CHEAT );
static ConVar r_nosw ( "r_nosw", "0", FCVAR_CHEAT );
static ConVar r_teeth ( "r_teeth", "1" );
static ConVar r_drawentities ( "r_drawentities", "1", FCVAR_CHEAT );
static ConVar r_flex ( "r_flex", "1" );
static ConVar r_eyes ( "r_eyes", "1" );
static ConVar r_skin ( "r_skin","0", FCVAR_CHEAT );
static ConVar r_maxmodeldecal ( "r_maxmodeldecal", "50" );
static ConVar r_modelwireframedecal ( "r_modelwireframedecal", "0", FCVAR_CHEAT );
static ConVar mat_normals ( "mat_normals", "0", FCVAR_CHEAT );
static ConVar r_eyeglintlodpixels ( "r_eyeglintlodpixels", "0", FCVAR_CHEAT );
static ConVar r_rootlod ( "r_rootlod", "0" );
static StudioRenderConfig_t s_StudioRenderConfig;
void CMDLPanel::UpdateStudioRenderConfig( void )
{
memset( &s_StudioRenderConfig, 0, sizeof(s_StudioRenderConfig) );
s_StudioRenderConfig.bEyeMove = !!r_eyemove.GetInt();
s_StudioRenderConfig.fEyeShiftX = r_eyeshift_x.GetFloat();
s_StudioRenderConfig.fEyeShiftY = r_eyeshift_y.GetFloat();
s_StudioRenderConfig.fEyeShiftZ = r_eyeshift_z.GetFloat();
s_StudioRenderConfig.fEyeSize = r_eyesize.GetFloat();
if( mat_softwareskin.GetInt() || m_bWireFrame )
{
s_StudioRenderConfig.bSoftwareSkin = true;
}
else
{
s_StudioRenderConfig.bSoftwareSkin = false;
}
s_StudioRenderConfig.bNoHardware = !!r_nohw.GetInt();
s_StudioRenderConfig.bNoSoftware = !!r_nosw.GetInt();
s_StudioRenderConfig.bTeeth = !!r_teeth.GetInt();
s_StudioRenderConfig.drawEntities = r_drawentities.GetInt();
s_StudioRenderConfig.bFlex = !!r_flex.GetInt();
s_StudioRenderConfig.bEyes = !!r_eyes.GetInt();
s_StudioRenderConfig.bWireframe = m_bWireFrame;
s_StudioRenderConfig.bDrawNormals = mat_normals.GetBool();
s_StudioRenderConfig.skin = r_skin.GetInt();
s_StudioRenderConfig.maxDecalsPerModel = r_maxmodeldecal.GetInt();
s_StudioRenderConfig.bWireframeDecals = r_modelwireframedecal.GetInt() != 0;
s_StudioRenderConfig.fullbright = false;
s_StudioRenderConfig.bSoftwareLighting = false;
s_StudioRenderConfig.bShowEnvCubemapOnly = r_showenvcubemap.GetInt() ? true : false;
s_StudioRenderConfig.fEyeGlintPixelWidthLODThreshold = r_eyeglintlodpixels.GetFloat();
StudioRender()->UpdateConfig( s_StudioRenderConfig );
}
void CMDLPanel::DrawCollisionModel()
{
if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID )
{
return;
}
vcollide_t *pCollide = MDLCache()->GetVCollide( m_RootMDL.m_MDL.GetMDL() );
if ( !pCollide || pCollide->solidCount <= 0 )
return;
static color32 color = {255,0,0,0};
IVPhysicsKeyParser *pParser = g_pPhysicsCollision->VPhysicsKeyParserCreate( pCollide->pKeyValues );
CStudioHdr &studioHdr = *m_RootMDL.m_pStudioHdr;
matrix3x4_t pBoneToWorld[MAXSTUDIOBONES];
m_RootMDL.m_MDL.SetUpBones( m_RootMDL.m_MDLToWorld, MAXSTUDIOBONES, pBoneToWorld );
// PERFORMANCE: Just parse the script each frame. It's fast enough for tools. If you need
// this to go faster then cache off the bone index mapping in an array like HLMV does
while ( !pParser->Finished() )
{
const char *pBlock = pParser->GetCurrentBlockName();
if ( !stricmp( pBlock, "solid" ) )
{
solid_t solid;
pParser->ParseSolid( &solid, NULL );
int boneIndex = Studio_BoneIndexByName( &studioHdr, solid.name );
Vector *outVerts;
int vertCount = g_pPhysicsCollision->CreateDebugMesh( pCollide->solids[solid.index], &outVerts );
if ( vertCount )
{
CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
pRenderContext->CullMode( MATERIAL_CULLMODE_CCW );
// NOTE: assumes these have been set up already by the model render code
// So this is a little bit of a back door to a cache of the bones
// this code wouldn't work unless you draw the model this frame before calling
// this routine. CMDLPanel always does this, but it's worth noting.
// A better solution would be to move the ragdoll visulization into the CDmeMdl
// and either draw it there or make it queryable and query/draw here.
matrix3x4_t xform;
SetIdentityMatrix( xform );
if ( boneIndex >= 0 )
{
MatrixCopy( pBoneToWorld[ boneIndex ], xform );
}
IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_Wireframe );
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, vertCount/3 );
for ( int j = 0; j < vertCount; j++ )
{
Vector out;
VectorTransform( outVerts[j].Base(), xform, out.Base() );
meshBuilder.Position3fv( out.Base() );
meshBuilder.Color4ub( color.r, color.g, color.b, color.a );
meshBuilder.TexCoord2f( 0, 0, 0 );
meshBuilder.AdvanceVertex();
}
meshBuilder.End();
pMesh->Draw();
}
g_pPhysicsCollision->DestroyDebugMesh( vertCount, outVerts );
}
else
{
pParser->SkipBlock();
}
}
g_pPhysicsCollision->VPhysicsKeyParserDestroy( pParser );
}
void CMDLPanel::SetupRenderState( int nDisplayWidth, int nDisplayHeight )
{
int iWidth = nDisplayWidth;
int iHeight = nDisplayHeight;
if ( m_bThumbnailSafeZone )
{
iWidth = THUMBNAIL_SAFE_ZONE_SIZE;
iHeight = THUMBNAIL_SAFE_ZONE_SIZE;
}
BaseClass::SetupRenderState( iWidth, iHeight );
}
//-----------------------------------------------------------------------------
// paint it!
//-----------------------------------------------------------------------------
void CMDLPanel::OnPaint3D()
{
if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID )
return;
// FIXME: Move this call into DrawModel in StudioRender
StudioRenderConfig_t oldStudioRenderConfig;
StudioRender()->GetCurrentConfig( oldStudioRenderConfig );
UpdateStudioRenderConfig();
CMatRenderContextPtr pRenderContext( vgui::MaterialSystem() );
if ( vgui::MaterialSystemHardwareConfig()->GetHDRType() == HDR_TYPE_NONE )
{
ITexture *pMyCube = HasLightProbe() ? GetLightProbeCubemap( false ) : m_DefaultEnvCubemap;
pRenderContext->BindLocalCubemap( pMyCube );
}
else
{
ITexture *pMyCube = HasLightProbe() ? GetLightProbeCubemap( true ) : m_DefaultHDREnvCubemap;
pRenderContext->BindLocalCubemap( pMyCube );
}
PrePaint3D( pRenderContext );
if ( m_bGroundGrid )
{
DrawGrid();
}
if ( m_bLookAtCamera )
{
matrix3x4_t worldToCamera;
ComputeCameraTransform( &worldToCamera );
Vector vecPosition;
MatrixGetColumn( worldToCamera, 3, vecPosition );
m_RootMDL.m_MDL.m_bWorldSpaceViewTarget = true;
m_RootMDL.m_MDL.m_vecViewTarget = vecPosition;
}
// Draw the MDL
CStudioHdr &studioHdr = *m_RootMDL.m_pStudioHdr;
SetupFlexWeights();
matrix3x4_t *pBoneToWorld = g_pStudioRender->LockBoneMatrices( studioHdr.numbones() );
m_RootMDL.m_MDL.SetUpBones( m_RootMDL.m_MDLToWorld, studioHdr.numbones(), pBoneToWorld, m_PoseParameters, m_SequenceLayers, m_nNumSequenceLayers );
g_pStudioRender->UnlockBoneMatrices();
IMaterial* pOverrideMaterial = GetOverrideMaterial( m_RootMDL.m_MDL.GetMDL() );
if ( pOverrideMaterial != NULL )
g_pStudioRender->ForcedMaterialOverride( pOverrideMaterial );
m_RootMDL.m_MDL.Draw( m_RootMDL.m_MDLToWorld, pBoneToWorld );
if ( pOverrideMaterial != NULL )
g_pStudioRender->ForcedMaterialOverride( NULL );
pOverrideMaterial = NULL;
// Draw the merge MDLs.
matrix3x4_t matMergeBoneToWorld[MAXSTUDIOBONES];
int nMergeCount = m_aMergeMDLs.Count();
for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge )
{
if ( m_aMergeMDLs[iMerge].m_bDisabled )
continue;
// Get the merge studio header.
CStudioHdr *pMergeHdr = m_aMergeMDLs[iMerge].m_pStudioHdr;
matrix3x4_t *pMergeBoneToWorld = &matMergeBoneToWorld[0];
// If we have a valid mesh, bonemerge it. If we have an invalid mesh we can't bonemerge because
// it'll crash trying to pull data from the missing header.
if ( pMergeHdr != NULL )
{
CStudioHdr &mergeHdr = *pMergeHdr;
m_aMergeMDLs[iMerge].m_MDL.SetupBonesWithBoneMerge( &mergeHdr, pMergeBoneToWorld, &studioHdr, pBoneToWorld, m_RootMDL.m_MDLToWorld );
pOverrideMaterial = GetOverrideMaterial( m_aMergeMDLs[iMerge].m_MDL.GetMDL() );
if ( pOverrideMaterial != NULL )
g_pStudioRender->ForcedMaterialOverride( pOverrideMaterial );
m_aMergeMDLs[iMerge].m_MDL.Draw( m_aMergeMDLs[iMerge].m_MDLToWorld, pMergeBoneToWorld );
if ( pOverrideMaterial != NULL )
g_pStudioRender->ForcedMaterialOverride( NULL );
// Notify of model render
RenderingMergedModel( pRenderContext, &mergeHdr, m_aMergeMDLs[iMerge].m_MDL.GetMDL(), pMergeBoneToWorld );
}
}
RenderingRootModel( pRenderContext, &studioHdr, m_RootMDL.m_MDL.GetMDL(), pBoneToWorld );
PostPaint3D( pRenderContext );
if ( m_bDrawCollisionModel )
{
DrawCollisionModel();
}
pRenderContext->Flush();
StudioRender()->UpdateConfig( oldStudioRenderConfig );
}
//-----------------------------------------------------------------------------
// Sets the current LOD
//-----------------------------------------------------------------------------
void CMDLPanel::SetLOD( int nLOD )
{
m_RootMDL.m_MDL.m_nLOD = nLOD;
int nMergeCount = m_aMergeMDLs.Count();
for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge )
{
m_aMergeMDLs[iMerge].m_MDL.m_nLOD = nLOD;
}
}
//-----------------------------------------------------------------------------
// Sets the current sequence
//-----------------------------------------------------------------------------
void CMDLPanel::SetSequence( int nSequence, bool bResetSequence )
{
m_RootMDL.m_MDL.m_nSequence = nSequence;
if ( bResetSequence )
{
m_RootMDL.m_flCycleStartTime = GetAutoPlayTime();
}
}
//-----------------------------------------------------------------------------
// Set the current pose parameters. If NULL the pose parameters will be reset
// to the default values.
//-----------------------------------------------------------------------------
void CMDLPanel::SetPoseParameters( const float *pPoseParameters, int nCount )
{
if ( pPoseParameters )
{
int nParameters = MIN( MAXSTUDIOPOSEPARAM, nCount );
for ( int iParam = 0; iParam < nParameters; ++iParam )
{
m_PoseParameters[ iParam ] = pPoseParameters[ iParam ];
}
}
else if ( m_RootMDL.m_MDL.GetMDL() != MDLHANDLE_INVALID )
{
CStudioHdr &studioHdr = *m_RootMDL.m_pStudioHdr;
Studio_CalcDefaultPoseParameters( &studioHdr, m_PoseParameters, MAXSTUDIOPOSEPARAM );
}
}
//-----------------------------------------------------------------------------
// Set a pose parameter by name
//-----------------------------------------------------------------------------
bool CMDLPanel::SetPoseParameterByName( const char *pszName, float fValue )
{
if ( !m_RootMDL.m_pStudioHdr )
return false;
CStudioHdr &studioHdr = *m_RootMDL.m_pStudioHdr;
int nPoseCount = studioHdr.GetNumPoseParameters();
for ( int i = 0; i < nPoseCount; ++i )
{
const mstudioposeparamdesc_t &Pose = studioHdr.pPoseParameter( i );
if ( V_strcasecmp( pszName, Pose.pszName() ) == 0 )
{
m_PoseParameters[ i ] = fValue;
return true;
}
}
return false;
}
//-----------------------------------------------------------------------------
// Set the overlay sequence layers
//-----------------------------------------------------------------------------
void CMDLPanel::SetSequenceLayers( const MDLSquenceLayer_t *pSequenceLayers, int nCount )
{
if ( pSequenceLayers )
{
m_nNumSequenceLayers = MIN( MAX_SEQUENCE_LAYERS, nCount );
for ( int iLayer = 0; iLayer < m_nNumSequenceLayers; ++iLayer )
{
m_SequenceLayers[ iLayer ] = pSequenceLayers[ iLayer ];
ResetAnimationEventState( &m_SequenceLayerEventState[ iLayer ] );
}
}
else
{
m_nNumSequenceLayers = 0;
V_memset( m_SequenceLayers, 0, sizeof( m_SequenceLayers ) );
}
}
//-----------------------------------------------------------------------------
// Set the current skin
//-----------------------------------------------------------------------------
void CMDLPanel::SetSkin( int nSkin )
{
m_RootMDL.m_MDL.m_nSkin = nSkin;
}
//-----------------------------------------------------------------------------
// called when we're ticked...
//-----------------------------------------------------------------------------
void CMDLPanel::OnTick()
{
BaseClass::OnTick();
if ( m_RootMDL.m_MDL.GetMDL() != MDLHANDLE_INVALID )
{
ValidateMDLs();
m_RootMDL.m_MDL.m_flTime = ( GetAutoPlayTime() - m_RootMDL.m_flCycleStartTime );
DoAnimationEvents();
}
}
void CMDLPanel::Paint()
{
BaseClass::Paint();
if ( m_bThumbnailSafeZone )
{
int iWidth, iHeight;
GetSize( iWidth, iHeight );
CMatRenderContextPtr pRenderContext( vgui::MaterialSystem() );
IMaterial *safezone = materials->FindMaterial( "vgui/thumbnails_safezone", TEXTURE_GROUP_VGUI, true );
if ( safezone )
{
safezone->IncrementReferenceCount();
}
int screenposx = 0;
int screenposy = 0;
LocalToScreen( screenposx, screenposy );
int iScaledHeight = THUMBNAIL_SAFE_ZONE_HEIGHT_SCALE * iHeight;
int iRemappedHeight = RemapVal( iScaledHeight, 0, THUMBNAIL_SAFE_ZONE_HEIGHT, 0, iScaledHeight );
pRenderContext->DrawScreenSpaceRectangle( safezone, screenposx, screenposy, iWidth, iRemappedHeight,
0, 0,
THUMBNAIL_SAFE_ZONE_SIZE, THUMBNAIL_SAFE_ZONE_HEIGHT,
THUMBNAIL_SAFE_ZONE_SIZE, THUMBNAIL_SAFE_ZONE_SIZE );
screenposx = 0;
screenposy = iHeight - iRemappedHeight;
LocalToScreen( screenposx, screenposy );
pRenderContext->DrawScreenSpaceRectangle( safezone, screenposx, screenposy, iWidth, iRemappedHeight,
0, 0,
THUMBNAIL_SAFE_ZONE_SIZE, THUMBNAIL_SAFE_ZONE_HEIGHT,
THUMBNAIL_SAFE_ZONE_SIZE, THUMBNAIL_SAFE_ZONE_SIZE );
if ( safezone )
{
safezone->DecrementReferenceCount();
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMDLPanel::DoAnimationEvents()
{
if ( !m_RootMDL.m_pStudioHdr )
return;
CStudioHdr &studioHdr = *m_RootMDL.m_pStudioHdr;
// If we don't have any sequences, don't do anything
if ( studioHdr.GetNumSeq() < 1 )
{
Assert( studioHdr.GetNumSeq() >= 1 );
return;
}
// we're holding onto model data that can be forced reloaded when importing workshop items
// detect the vmodel change here and force an update if so, until we fix the real issue of the studioHdr not being updated itself
if ( studioHdr.GetVirtualModel() != nullptr && studioHdr.GetVirtualModel() != studioHdr.GetRenderHdr()->GetVirtualModel() )
{
studioHdr.ResetVModel( studioHdr.GetRenderHdr()->GetVirtualModel() );
}
DoAnimationEvents( &studioHdr, m_RootMDL.m_MDL.m_nSequence, m_RootMDL.m_MDL.m_flTime, false, &m_EventState );
for ( int i = 0; i < m_nNumSequenceLayers; ++i )
{
float flTime = m_RootMDL.m_MDL.m_flTime - m_SequenceLayers[ i ].m_flCycleBeganAt;
//Plat_DebugString( CFmtStr("Animation: time = %f, started = %f, delta = %f\n",m_RootMDL.m_MDL.m_flTime,m_SequenceLayers[ i ].m_flCycleBeganAt,flTime ) );
DoAnimationEvents( &studioHdr, m_SequenceLayers[ i ].m_nSequenceIndex, flTime, m_SequenceLayers[ i ].m_bNoLoop, &m_SequenceLayerEventState[ i ] );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMDLPanel::DoAnimationEvents( CStudioHdr *pStudioHdr, int nSeqNum, float flTime, bool bNoLoop, MDLAnimEventState_t *pEventState )
{
if ( nSeqNum < 0 || nSeqNum >= pStudioHdr->GetNumSeq() )
{
return;
}
mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( nSeqNum );
if ( seqdesc.numevents == 0 )
{
return;
}
mstudioevent_t *pevent = seqdesc.pEvent( 0 );
int nFrameCount = Studio_MaxFrame( pStudioHdr, nSeqNum, m_PoseParameters );
if ( nFrameCount == 0 )
{
nFrameCount = 1;
}
float flEventCycle = ( flTime * m_RootMDL.m_MDL.m_flPlaybackRate ) / nFrameCount;
//Plat_DebugString( CFmtStr("Event cycle: %f, playback rate: %f, frame count: %d\n", flEventCycle, m_RootMDL.m_MDL.m_flPlaybackRate, nFrameCount ) );
if ( bNoLoop )
{
flEventCycle = MIN(flEventCycle, 1.0f);
}
else
{
flEventCycle -= (int)(flEventCycle);
}
if ( pEventState->m_nEventSequence != nSeqNum )
{
pEventState->m_nEventSequence = nSeqNum;
flEventCycle = 0.0f;
pEventState->m_flPrevEventCycle = -0.01f; // back up to get 0'th frame animations
}
if ( flEventCycle == pEventState->m_flPrevEventCycle )
{
return;
}
// check for looping
BOOL bLooped = (flEventCycle < pEventState->m_flPrevEventCycle);
// This makes sure events that occur at the end of a sequence occur are
// sent before events that occur at the beginning of a sequence.
if (bLooped)
{
for (int i = 0; i < (int)seqdesc.numevents; i++)
{
if ( pevent[i].cycle <= pEventState->m_flPrevEventCycle )
continue;
FireEvent( pevent[ i ].pszEventName(), pevent[ i ].pszOptions() );
}
// Necessary to get the next loop working
pEventState->m_flPrevEventCycle = -0.01f;
}
for (int i = 0; i < (int)seqdesc.numevents; i++)
{
if ( (pevent[i].cycle > pEventState->m_flPrevEventCycle && pevent[i].cycle <= flEventCycle) )
{
FireEvent( pevent[ i ].pszEventName(), pevent[ i ].pszOptions() );
}
}
pEventState->m_flPrevEventCycle = flEventCycle;
}
void CMDLPanel::FireEvent( const char *pszEventName, const char *pszEventOptions )
{
KeyValues* pKVEvent = new KeyValues( "AnimEvent" );
pKVEvent->SetString( "name", pszEventName );
pKVEvent->SetString( "options", pszEventOptions );
PostActionSignal( pKVEvent );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMDLPanel::ResetAnimationEventState( MDLAnimEventState_t *pEventState )
{
pEventState->m_nEventSequence = -1;
pEventState->m_flPrevEventCycle = -0.01f;
}
//-----------------------------------------------------------------------------
// input
//-----------------------------------------------------------------------------
void CMDLPanel::OnMouseDoublePressed( vgui::MouseCode code )
{
if ( m_bIgnoreDoubleClick )
return;
float flRadius;
Vector vecCenter;
GetBoundingSphere( vecCenter, flRadius );
LookAt( vecCenter, flRadius );
BaseClass::OnMouseDoublePressed( code );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMDLPanel::SetMergeMDL( MDLHandle_t handle, void *pProxyData, int nSkin /*= -1 */ )
{
// Verify that we have a root model to merge to.
if ( m_RootMDL.m_MDL.GetMDL() == MDLHANDLE_INVALID )
return;
int iIndex = m_aMergeMDLs.AddToTail();
if ( !m_aMergeMDLs.IsValidIndex( iIndex ) )
return;
m_aMergeMDLs[iIndex].m_MDL.SetMDL( handle );
if ( nSkin != -1 )
{
m_aMergeMDLs[iIndex].m_MDL.m_nSkin = nSkin;
}
m_aMergeMDLs[iIndex].m_MDL.m_nLOD = m_RootMDL.m_MDL.m_nLOD;
m_aMergeMDLs[iIndex].m_MDL.m_pProxyData = pProxyData;
SetIdentityMatrix( m_aMergeMDLs[iIndex].m_MDLToWorld );
m_aMergeMDLs[iIndex].m_bDisabled = false;
m_aMergeMDLs[iIndex].m_pStudioHdr = new CStudioHdr( m_aMergeMDLs[iIndex].m_MDL.GetStudioHdr(), g_pMDLCache );
// Need to invalidate the layout so the panel will adjust is LookAt for the new model.
InvalidateLayout();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
MDLHandle_t CMDLPanel::SetMergeMDL( const char *pMDLName, void *pProxyData, int nSkin /*= -1 */ )
{
MDLHandle_t hMDLFindResult = vgui::MDLCache()->FindMDL( pMDLName );
MDLHandle_t hMDL = pMDLName ? hMDLFindResult : MDLHANDLE_INVALID;
if ( vgui::MDLCache()->IsErrorModel( hMDL ) )
{
hMDL = MDLHANDLE_INVALID;
}
SetMergeMDL( hMDL, pProxyData, nSkin );
// FindMDL takes a reference and the the CMDL will also hold a reference for as long as it sticks around. Release the FindMDL reference.
int nRef = vgui::MDLCache()->Release( hMDLFindResult );
(void)nRef; // Avoid unreferenced variable warning
AssertMsg( hMDL == MDLHANDLE_INVALID || nRef > 0, "CMDLPanel::SetMergeMDL referenced a model that has a zero ref count." );
return hMDL;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CMDLPanel::GetMergeMDLIndex( void *pProxyData )
{
int nMergeCount = m_aMergeMDLs.Count();
for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge )
{
if ( m_aMergeMDLs[iMerge].m_MDL.m_pProxyData == pProxyData )
return iMerge;
}
return -1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CMDLPanel::GetMergeMDLIndex( MDLHandle_t handle )
{
int nMergeCount = m_aMergeMDLs.Count();
for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge )
{
if ( m_aMergeMDLs[iMerge].m_MDL.GetMDL() == handle )
return iMerge;
}
return -1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CMDL *CMDLPanel::GetMergeMDL( MDLHandle_t handle )
{
int nMergeCount = m_aMergeMDLs.Count();
for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge )
{
if ( m_aMergeMDLs[iMerge].m_MDL.GetMDL() == handle )
return (&m_aMergeMDLs[iMerge].m_MDL);
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CStudioHdr *CMDLPanel::GetMergeMDLStudioHdr( MDLHandle_t handle )
{
int nMergeCount = m_aMergeMDLs.Count();
for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge )
{
if ( m_aMergeMDLs[ iMerge ].m_MDL.GetMDL() == handle )
return ( m_aMergeMDLs[ iMerge ].m_pStudioHdr );
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CMDLPanel::ClearMergeMDLs( void )
{
const int nMergeCount = m_aMergeMDLs.Count();
for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge )
{
if ( !m_aMergeMDLs[iMerge].m_pStudioHdr )
{
continue;
}
delete m_aMergeMDLs[iMerge].m_pStudioHdr;
m_aMergeMDLs[iMerge].m_pStudioHdr = NULL;
}
m_aMergeMDLs.Purge();
}
void CMDLPanel::ValidateMDLs()
{
uint32 uMdlCacheSerial = vgui::ivgui()->GetMdlCacheSerial();
if ( m_RootMDL.m_pStudioHdr && m_RootMDL.m_unMdlCacheSerial != uMdlCacheSerial )
{
m_RootMDL.m_pStudioHdr = new CStudioHdr( m_RootMDL.m_MDL.GetStudioHdr(), g_pMDLCache );
m_RootMDL.m_unMdlCacheSerial = uMdlCacheSerial;
}
const int nMergeCount = m_aMergeMDLs.Count();
for ( int iMerge = 0; iMerge < nMergeCount; ++iMerge )
{
if ( m_aMergeMDLs[iMerge].m_pStudioHdr && m_aMergeMDLs[iMerge].m_unMdlCacheSerial != uMdlCacheSerial )
{
m_aMergeMDLs[iMerge].m_pStudioHdr = new CStudioHdr( m_aMergeMDLs[iMerge].m_MDL.GetStudioHdr(), g_pMDLCache );
m_aMergeMDLs[iMerge].m_unMdlCacheSerial = uMdlCacheSerial;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,539 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "matsys_controls/mdlsequencepicker.h"
#include "tier1/KeyValues.h"
#include "tier1/utldict.h"
#include "datacache/imdlcache.h"
#include "filesystem.h"
#include "studio.h"
#include "vgui/IVGui.h"
#include "vgui/Cursor.h"
#include "vgui/ISurface.h"
#include "vgui_controls/Splitter.h"
#include "vgui_controls/ComboBox.h"
#include "vgui_controls/PropertySheet.h"
#include "vgui_controls/PropertyPage.h"
#include "vgui_controls/ToolWindow.h"
#include "vgui_controls/Button.h"
#include "matsys_controls/gamefiletreeview.h"
#include "matsys_controls/matsyscontrols.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
//-----------------------------------------------------------------------------
//
// MDL Sequence Picker
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CMDLSequencePicker::CMDLSequencePicker( vgui::Panel *pParent ) : BaseClass(pParent, "MDLSequencePicker"), m_Images(false)
{
vgui::ivgui()->AddTickSignal( GetVPanel() );
m_hSelectedMDL = MDLHANDLE_INVALID;
// Horizontal splitter for mdls
m_pMDLSplitter = new Splitter( this, "MDLSplitter", SPLITTER_MODE_VERTICAL, 1 );
vgui::Panel *pSplitterLeftSide = m_pMDLSplitter->GetChild( 0 );
vgui::Panel *pSplitterRightSide = m_pMDLSplitter->GetChild( 1 );
// filter selection
m_pFilterList = new ComboBox( pSplitterLeftSide, "FilterList", 16, true );
m_pFilterList->AddActionSignalTarget( this );
// file browser tree controls
m_pFileTree = new CGameFileTreeView( pSplitterLeftSide, "FileTree", "All .MDLs", "models", "mdl" );
// build our list of images
m_Images.AddImage( scheme()->GetImage( "resource/icon_folder", false ) );
m_Images.AddImage( scheme()->GetImage( "resource/icon_folder_selected", false ) );
m_Images.AddImage( scheme()->GetImage( "resource/icon_file", false ) );
m_pFileTree->SetImageList( &m_Images, false );
m_pFileTree->AddActionSignalTarget( this );
// property sheet - revisions, changes, etc.
m_pSequenceSplitter = new Splitter( pSplitterRightSide, "SequenceSplitter", SPLITTER_MODE_HORIZONTAL, 1 );
vgui::Panel *pSplitterTopSide = m_pSequenceSplitter->GetChild( 0 );
vgui::Panel *pSplitterBottomSide = m_pSequenceSplitter->GetChild( 1 );
// MDL preview
m_pMDLPreview = new CMDLPanel( pSplitterTopSide, "MDLPreview" );
SetSkipChildDuringPainting( m_pMDLPreview );
m_pViewsSheet = new vgui::PropertySheet( pSplitterBottomSide, "ViewsSheet" );
m_pViewsSheet->AddActionSignalTarget( this );
// sequences
m_pSequencesPage = new PropertyPage( m_pViewsSheet, "SequencesPage" );
m_pViewsSheet->AddPage( m_pSequencesPage, "Sequences" );
m_pSequencesList = new ListPanel( m_pSequencesPage, "SequencesList" );
m_pSequencesList->AddColumnHeader( 0, "sequence", "sequence", 52, 0 );
m_pSequencesList->AddActionSignalTarget( this );
m_pSequencesList->SetSelectIndividualCells( true );
m_pSequencesList->SetEmptyListText("No .MDL file currently selected.");
m_pSequencesList->SetDragEnabled( true );
m_pSequencesList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 );
// Activities
m_pActivitiesPage = new PropertyPage( m_pViewsSheet, "ActivitiesPage" );
m_pViewsSheet->AddPage( m_pActivitiesPage, "Activities" );
m_pActivitiesList = new ListPanel( m_pActivitiesPage, "ActivitiesList" );
m_pActivitiesList->AddColumnHeader( 0, "activity", "activity", 52, 0 );
m_pActivitiesList->AddActionSignalTarget( this );
m_pActivitiesList->SetSelectIndividualCells( true );
m_pActivitiesList->SetEmptyListText( "No .MDL file currently selected." );
m_pActivitiesList->SetDragEnabled( true );
m_pActivitiesList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 );
// Load layout settings; has to happen before pinning occurs in code
LoadControlSettingsAndUserConfig( "resource/mdlsequencepicker.res" );
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CMDLSequencePicker::~CMDLSequencePicker()
{
}
//-----------------------------------------------------------------------------
// Purpose: This is a bit of a hack to make sure that the ToolWindow containing this picker punches
// a hold for the rendering viewport, too
// Input : -
//-----------------------------------------------------------------------------
void CMDLSequencePicker::OnTick()
{
BaseClass::OnTick();
if ( GetParent() )
{
ToolWindow *tw = dynamic_cast< ToolWindow * >( GetParent()->GetParent() );
if ( tw )
{
tw->SetSkipChildDuringPainting( IsVisible() ? m_pMDLPreview : NULL );
}
}
}
//-----------------------------------------------------------------------------
// Purpose: stops app on close
//-----------------------------------------------------------------------------
void CMDLSequencePicker::OnClose()
{
BaseClass::OnClose();
}
//-----------------------------------------------------------------------------
// Purpose: called to open
//-----------------------------------------------------------------------------
void CMDLSequencePicker::Activate()
{
RefreshFileList();
RefreshActivitiesAndSequencesList();
}
//-----------------------------------------------------------------------------
// Performs layout
//-----------------------------------------------------------------------------
void CMDLSequencePicker::PerformLayout()
{
// NOTE: This call should cause auto-resize to occur
// which should fix up the width of the panels
BaseClass::PerformLayout();
int w, h;
GetSize( w, h );
// Layout the mdl splitter
m_pMDLSplitter->SetBounds( 0, 0, w, h );
}
//-----------------------------------------------------------------------------
// Purpose: Refreshes the active file list
//-----------------------------------------------------------------------------
void CMDLSequencePicker::RefreshFileList()
{
m_pFileTree->RefreshFileList();
}
//-----------------------------------------------------------------------------
// Purpose: rebuilds the list of activities
//-----------------------------------------------------------------------------
void CMDLSequencePicker::RefreshActivitiesAndSequencesList()
{
m_pActivitiesList->RemoveAll();
m_pSequencesList->RemoveAll();
m_pMDLPreview->SetSequence( 0 );
if ( m_hSelectedMDL == MDLHANDLE_INVALID )
{
m_pActivitiesList->SetEmptyListText("No .MDL file currently selected");
m_pSequencesList->SetEmptyListText("No .MDL file currently selected");
return;
}
m_pActivitiesList->SetEmptyListText(".MDL file contains no activities");
m_pSequencesList->SetEmptyListText(".MDL file contains no sequences");
studiohdr_t *hdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL );
CUtlDict<int, unsigned short> activityNames( true, 0, hdr->GetNumSeq() );
for (int j = 0; j < hdr->GetNumSeq(); j++)
{
if ( /*g_viewerSettings.showHidden ||*/ !(hdr->pSeqdesc(j).flags & STUDIO_HIDDEN))
{
const char *pActivityName = hdr->pSeqdesc(j).pszActivityName();
if ( pActivityName && pActivityName[0] )
{
// Multiple sequences can have the same activity name; only add unique activity names
if ( activityNames.Find( pActivityName ) == activityNames.InvalidIndex() )
{
KeyValues *pkv = new KeyValues("node", "activity", pActivityName );
int nItemID = m_pActivitiesList->AddItem( pkv, 0, false, false );
KeyValues *pDrag = new KeyValues( "drag", "text", pActivityName );
pDrag->SetString( "texttype", "activityName" );
pDrag->SetString( "mdl", vgui::MDLCache()->GetModelName( m_hSelectedMDL ) );
m_pActivitiesList->SetItemDragData( nItemID, pDrag );
activityNames.Insert( pActivityName, j );
}
}
const char *pSequenceName = hdr->pSeqdesc(j).pszLabel();
if ( pSequenceName && pSequenceName[0] )
{
KeyValues *pkv = new KeyValues("node", "sequence", pSequenceName);
pkv->SetInt( "seqindex", j );
int nItemID = m_pSequencesList->AddItem( pkv, 0, false, false );
KeyValues *pDrag = new KeyValues( "drag", "text", pSequenceName );
pDrag->SetString( "texttype", "sequenceName" );
pDrag->SetString( "mdl", vgui::MDLCache()->GetModelName( m_hSelectedMDL ) );
m_pSequencesList->SetItemDragData( nItemID, pDrag );
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: refreshes dialog on text changing
//-----------------------------------------------------------------------------
void CMDLSequencePicker::OnTextChanged( vgui::Panel *pPanel, const char *pText )
{
// m_pFileTree->SetFilter( pText );
RefreshFileList();
}
/*
//-----------------------------------------------------------------------------
// Purpose: Selects an sequence based on an activity
//-----------------------------------------------------------------------------
int SelectWeightedSequence( studiohdr_t *pstudiohdr, int activity, int curSequence )
{
if (! pstudiohdr)
return 0;
VerifySequenceIndex( pstudiohdr );
int weighttotal = 0;
int seq = ACTIVITY_NOT_AVAILABLE;
int weight = 0;
for (int i = 0; i < pstudiohdr->GetNumSeq(); i++)
{
int curActivity = GetSequenceActivity( pstudiohdr, i, &weight );
if (curActivity == activity)
{
if ( curSequence == i && weight < 0 )
{
seq = i;
break;
}
weighttotal += iabs(weight);
int randomValue;
if ( IsInPrediction() )
randomValue = SharedRandomInt( "SelectWeightedSequence", 0, weighttotal - 1, i );
else
randomValue = RandomInt( 0, weighttotal - 1 );
if (!weighttotal || randomValue < iabs(weight))
seq = i;
}
}
return seq;
}
*/
//-----------------------------------------------------------------------------
// Plays the selected activity
//-----------------------------------------------------------------------------
void CMDLSequencePicker::PlaySelectedActivity( )
{
int nIndex = m_pActivitiesList->GetSelectedItem( 0 );
if ( nIndex < 0 )
return;
KeyValues *pkv = m_pActivitiesList->GetItem( nIndex );
const char *pActivityName = pkv->GetString( "activity", NULL );
if ( !pActivityName )
return;
studiohdr_t *pstudiohdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL );
for ( int i = 0; i < pstudiohdr->GetNumSeq(); i++ )
{
mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
if ( stricmp( seqdesc.pszActivityName(), pActivityName ) == 0 )
{
// FIXME: Add weighted sequence selection logic?
m_pMDLPreview->SetSequence( i );
break;
}
}
}
//-----------------------------------------------------------------------------
// Plays the selected sequence
//-----------------------------------------------------------------------------
void CMDLSequencePicker::PlaySelectedSequence( )
{
int nIndex = m_pSequencesList->GetSelectedItem( 0 );
if ( nIndex < 0 )
return;
KeyValues *pkv = m_pSequencesList->GetItem( nIndex );
const char *pSequenceName = pkv->GetString( "sequence", NULL );
if ( !pSequenceName )
return;
studiohdr_t *pstudiohdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL );
for (int i = 0; i < pstudiohdr->GetNumSeq(); i++)
{
mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
if ( !Q_stricmp( seqdesc.pszLabel(), pSequenceName ) )
{
m_pMDLPreview->SetSequence( i );
break;
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Called when a page is shown
//-----------------------------------------------------------------------------
void CMDLSequencePicker::OnPageChanged( )
{
if ( m_pViewsSheet->GetActivePage() == m_pSequencesPage )
{
PlaySelectedSequence();
return;
}
if ( m_pViewsSheet->GetActivePage() == m_pActivitiesPage )
{
PlaySelectedActivity();
return;
}
}
//-----------------------------------------------------------------------------
// Purpose: refreshes dialog on text changing
//-----------------------------------------------------------------------------
void CMDLSequencePicker::OnItemSelected( KeyValues *kv )
{
Panel *pPanel = (Panel *)kv->GetPtr("panel", NULL);
if ( pPanel == m_pSequencesList )
{
PlaySelectedSequence();
return;
}
if ( pPanel == m_pActivitiesList )
{
PlaySelectedActivity();
return;
}
}
//-----------------------------------------------------------------------------
// An MDL was selected
//-----------------------------------------------------------------------------
void CMDLSequencePicker::SelectMDL( const char *pMDLName )
{
m_hSelectedMDL = pMDLName ? vgui::MDLCache()->FindMDL( pMDLName ) : MDLHANDLE_INVALID;
if ( vgui::MDLCache()->IsErrorModel( m_hSelectedMDL ) )
{
m_hSelectedMDL = MDLHANDLE_INVALID;
}
m_pMDLPreview->SetMDL( m_hSelectedMDL );
m_pMDLPreview->LookAtMDL();
RefreshActivitiesAndSequencesList();
}
//-----------------------------------------------------------------------------
// Purpose: updates revision view on a file being selected
//-----------------------------------------------------------------------------
void CMDLSequencePicker::OnFileSelected()
{
// update list
int iItem = m_pFileTree->GetFirstSelectedItem();
if ( iItem < 0 )
return;
// Don't bother to change if a directory was selected
KeyValues *pkv = m_pFileTree->GetItemData(iItem);
if ( pkv->GetInt("dir") || pkv->GetInt("root") )
return;
surface()->SetCursor(dc_waitarrow);
const char *pFullPathName = pkv->GetString( "path" );
char pRelativePathName[MAX_PATH];
g_pFullFileSystem->FullPathToRelativePath( pFullPathName, pRelativePathName, sizeof(pRelativePathName) );
// FIXME: Check that we're not actually opening the wrong file!!
SelectMDL( pRelativePathName );
}
char const *CMDLSequencePicker::GetModelName()
{
if ( MDLHANDLE_INVALID == m_hSelectedMDL )
{
return "";
}
return vgui::MDLCache()->GetModelName( m_hSelectedMDL );
}
char const *CMDLSequencePicker::GetSequenceName()
{
int nIndex = m_pSequencesList->GetSelectedItem( 0 );
if ( nIndex < 0 )
return "";
KeyValues *pkv = m_pSequencesList->GetItem( nIndex );
const char *pSequenceName = pkv->GetString( "sequence", NULL );
if ( !pSequenceName )
return "";
return pSequenceName;
}
int CMDLSequencePicker::GetSequenceNumber()
{
int nIndex = m_pSequencesList->GetSelectedItem( 0 );
if ( nIndex < 0 )
return -1;
KeyValues *pkv = m_pSequencesList->GetItem( nIndex );
return pkv->GetInt( "seqindex", -1 );
}
//-----------------------------------------------------------------------------
// Sequence picker frame
//-----------------------------------------------------------------------------
CMDLSequencePickerFrame::CMDLSequencePickerFrame( vgui::Panel *parent, char const *title ) :
BaseClass( parent, "MDLSequencePickerFrame" )
{
m_pMDLSequencePicker = new CMDLSequencePicker( this );
SetTitle( title, true );
SetSizeable( false );
SetCloseButtonVisible( false );
SetMoveable( true );
SetMinimumSize( 640, 480 );
Activate();
m_pMDLSequencePicker->Activate();
m_pOK = new Button( this, "OK", "#vgui_ok", this );
m_pOK->SetCommand( new KeyValues( "OnOK" ) );
m_pCancel= new Button( this, "Cancel", "#vgui_cancel", this );
m_pOK->SetCommand( new KeyValues( "OnCancel" ) );
m_pOK->SetEnabled( false );
vgui::ivgui()->AddTickSignal( GetVPanel(), 0 );
}
CMDLSequencePickerFrame::~CMDLSequencePickerFrame()
{
}
void CMDLSequencePickerFrame::OnTick()
{
BaseClass::OnTick();
bool bHasModel = m_pMDLSequencePicker->GetModelName()[ 0 ] != 0 ? true : false;
bool bHasSequence = m_pMDLSequencePicker->GetSequenceNumber() != -1 ? true : false;
m_pOK->SetEnabled( bHasModel && bHasSequence );
}
void CMDLSequencePickerFrame::PerformLayout()
{
BaseClass::PerformLayout();
int x, y, w, h;
GetClientArea( x, y, w, h );
h -= 24;
m_pMDLSequencePicker->SetBounds( x, y, w, h );
h += 5;
int bw = 120;
int bwwithGap = 2 * bw + 10;
x = ( w - bwwithGap ) / 2;
m_pOK->SetBounds( x, y + h, bw, 16 );
x += bw + 10;
m_pCancel->SetBounds( x, y + h, bw, 16 );
}
void CMDLSequencePickerFrame::OnCancel()
{
KeyValues *pActionKeys = new KeyValues( "AssetSelected" );
pActionKeys->SetString( "ModelName", m_pMDLSequencePicker->GetModelName() );
pActionKeys->SetString( "SequenceName", m_pMDLSequencePicker->GetSequenceName() );
pActionKeys->SetInt( "SequenceNumber", m_pMDLSequencePicker->GetSequenceNumber() );
PostActionSignal( pActionKeys );
CloseModal();
}
void CMDLSequencePickerFrame::OnOK()
{
CloseModal();
}

View File

@ -0,0 +1,318 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "filesystem.h"
#include "matsys_controls/picker.h"
#include "tier1/KeyValues.h"
#include "vgui_controls/ListPanel.h"
#include "vgui_controls/TextEntry.h"
#include "vgui_controls/Button.h"
#include "vgui/ISurface.h"
#include "vgui/IInput.h"
using namespace vgui;
//-----------------------------------------------------------------------------
//
// Base asset Picker
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Sort by asset name
//-----------------------------------------------------------------------------
static int __cdecl PickerBrowserSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
{
const char *string1 = item1.kv->GetString("choice");
const char *string2 = item2.kv->GetString("choice");
return stricmp( string1, string2 );
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CPicker::CPicker( vgui::Panel *pParent, const char *pColumnHeader, const char *pTextType ) :
BaseClass( pParent, "Picker" )
{
m_pPickerType = pColumnHeader;
m_pPickerTextType = pTextType;
// FIXME: Make this an image browser
m_pPickerBrowser = new vgui::ListPanel( this, "Browser" );
m_pPickerBrowser->AddColumnHeader( 0, "choice", m_pPickerType, 52, 0 );
m_pPickerBrowser->SetSelectIndividualCells( true );
m_pPickerBrowser->SetEmptyListText( "Nothing to pick" );
m_pPickerBrowser->SetDragEnabled( true );
m_pPickerBrowser->AddActionSignalTarget( this );
m_pPickerBrowser->SetSortFunc( 0, PickerBrowserSortFunc );
m_pPickerBrowser->SetSortColumn( 0 );
// filter selection
m_pFilterList = new TextEntry( this, "FilterList" );
m_pFilterList->AddActionSignalTarget( this );
m_pFilterList->RequestFocus();
LoadControlSettingsAndUserConfig( "resource/picker.res" );
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CPicker::~CPicker()
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CPicker::OnKeyCodePressed( KeyCode code )
{
if (( code == KEY_UP ) || ( code == KEY_DOWN ) || ( code == KEY_PAGEUP ) || ( code == KEY_PAGEDOWN ))
{
KeyValues *pMsg = new KeyValues("KeyCodePressed", "code", code);
vgui::ipanel()->SendMessage( m_pPickerBrowser->GetVPanel(), pMsg, GetVPanel());
pMsg->deleteThis();
}
else
{
BaseClass::OnKeyCodePressed( code );
}
}
//-----------------------------------------------------------------------------
// Purpose: refreshes the asset list
//-----------------------------------------------------------------------------
void CPicker::SetStringList( const PickerList_t &list )
{
m_Type = list.m_Type;
m_pPickerBrowser->RemoveAll();
int nCount = list.Count();
for ( int i = 0; i < nCount; ++i )
{
const char *pPickerName = list[i].m_pChoiceString;
KeyValues *kv = new KeyValues( "node", "choice", pPickerName );
if ( m_Type == PICKER_CHOICE_STRING )
{
kv->SetString( "value", list[i].m_pChoiceValue );
}
else
{
kv->SetPtr( "value", list[i].m_pChoiceValuePtr );
}
int nItemID = m_pPickerBrowser->AddItem( kv, 0, false, false );
if ( m_Type == PICKER_CHOICE_STRING )
{
KeyValues *pDrag = new KeyValues( "drag", "text", list[i].m_pChoiceValue );
if ( m_pPickerTextType )
{
pDrag->SetString( "texttype", m_pPickerTextType );
}
m_pPickerBrowser->SetItemDragData( nItemID, pDrag );
}
}
RefreshChoiceList();
}
//-----------------------------------------------------------------------------
// Purpose: refreshes the choice list
//-----------------------------------------------------------------------------
void CPicker::RefreshChoiceList( )
{
// Check the filter matches
int nMatchingCount = 0;
int nTotalCount = 0;
for ( int nItemID = m_pPickerBrowser->FirstItem(); nItemID != m_pPickerBrowser->InvalidItemID(); nItemID = m_pPickerBrowser->NextItem( nItemID ) )
{
KeyValues *kv = m_pPickerBrowser->GetItem( nItemID );
const char *pPickerName = kv->GetString( "choice" );
bool bVisible = !m_Filter.Length() || Q_stristr( pPickerName, m_Filter.Get() );
m_pPickerBrowser->SetItemVisible( nItemID, bVisible );
if ( bVisible )
{
++nMatchingCount;
}
++nTotalCount;
}
char pColumnTitle[512];
Q_snprintf( pColumnTitle, sizeof(pColumnTitle), "%s (%d/%d)",
m_pPickerType, nMatchingCount, nTotalCount );
m_pPickerBrowser->SetColumnHeaderText( 0, pColumnTitle );
m_pPickerBrowser->SortList();
if ( ( m_pPickerBrowser->GetSelectedItemsCount() == 0 ) && ( m_pPickerBrowser->GetItemCount() > 0 ) )
{
int nItemID = m_pPickerBrowser->GetItemIDFromRow( 0 );
m_pPickerBrowser->SetSelectedCell( nItemID, 0 );
}
}
//-----------------------------------------------------------------------------
// Purpose: refreshes dialog on text changing
//-----------------------------------------------------------------------------
void CPicker::OnTextChanged( )
{
int nLength = m_pFilterList->GetTextLength();
m_Filter.SetLength( nLength );
if ( nLength > 0 )
{
m_pFilterList->GetText( m_Filter.GetForModify(), nLength+1 );
}
RefreshChoiceList();
}
//-----------------------------------------------------------------------------
// Returns the selected string
//-----------------------------------------------------------------------------
PickerChoiceType_t CPicker::GetSelectionType() const
{
return m_Type;
}
const char *CPicker::GetSelectedString( ) const
{
if ( m_pPickerBrowser->GetSelectedItemsCount() == 0 )
return NULL;
if ( m_Type != PICKER_CHOICE_STRING )
return NULL;
int nIndex = m_pPickerBrowser->GetSelectedItem( 0 );
KeyValues *pItemKeyValues = m_pPickerBrowser->GetItem( nIndex );
return pItemKeyValues->GetString( "value" );
}
void *CPicker::GetSelectedPtr( ) const
{
if ( m_pPickerBrowser->GetSelectedItemsCount() == 0 )
return NULL;
if ( m_Type != PICKER_CHOICE_PTR )
return NULL;
int nIndex = m_pPickerBrowser->GetSelectedItem( 0 );
KeyValues *pItemKeyValues = m_pPickerBrowser->GetItem( nIndex );
return pItemKeyValues->GetPtr( "value" );
}
//-----------------------------------------------------------------------------
// Returns the index of the selected string
//-----------------------------------------------------------------------------
int CPicker::GetSelectedIndex()
{
if ( m_pPickerBrowser->GetSelectedItemsCount() == 0 )
return -1;
return m_pPickerBrowser->GetSelectedItem( 0 );
}
//-----------------------------------------------------------------------------
//
// Purpose: Modal picker frame
//
//-----------------------------------------------------------------------------
CPickerFrame::CPickerFrame( vgui::Panel *pParent, const char *pTitle, const char *pPickerType, const char *pTextType ) :
BaseClass( pParent, "PickerFrame" )
{
m_pContextKeyValues = NULL;
SetDeleteSelfOnClose( true );
m_pPicker = new CPicker( this, pPickerType, pTextType );
m_pPicker->AddActionSignalTarget( this );
m_pOpenButton = new Button( this, "OpenButton", "#FileOpenDialog_Open", this, "Open" );
m_pCancelButton = new Button( this, "CancelButton", "#FileOpenDialog_Cancel", this, "Cancel" );
SetBlockDragChaining( true );
LoadControlSettingsAndUserConfig( "resource/pickerframe.res" );
SetTitle( pTitle, false );
}
CPickerFrame::~CPickerFrame()
{
CleanUpMessage();
}
//-----------------------------------------------------------------------------
// Deletes the message
//-----------------------------------------------------------------------------
void CPickerFrame::CleanUpMessage()
{
if ( m_pContextKeyValues )
{
m_pContextKeyValues->deleteThis();
m_pContextKeyValues = NULL;
}
}
//-----------------------------------------------------------------------------
// Purpose: Activate the dialog
//-----------------------------------------------------------------------------
void CPickerFrame::DoModal( const PickerList_t &list, KeyValues *pContextKeyValues )
{
CleanUpMessage();
m_pContextKeyValues = pContextKeyValues;
m_pPicker->SetStringList( list );
BaseClass::DoModal();
}
//-----------------------------------------------------------------------------
// On command
//-----------------------------------------------------------------------------
void CPickerFrame::OnCommand( const char *pCommand )
{
if ( !Q_stricmp( pCommand, "Open" ) )
{
KeyValues *pActionKeys = new KeyValues( "Picked" );
pActionKeys->SetInt( "choiceIndex", m_pPicker->GetSelectedIndex( ) );
if ( m_pPicker->GetSelectionType() == PICKER_CHOICE_STRING )
{
const char *pPickerName = m_pPicker->GetSelectedString( );
pActionKeys->SetString( "choice", pPickerName );
}
else
{
void *pPickerPtr = m_pPicker->GetSelectedPtr( );
pActionKeys->SetPtr( "choice", pPickerPtr );
}
if ( m_pContextKeyValues )
{
pActionKeys->AddSubKey( m_pContextKeyValues );
m_pContextKeyValues = NULL;
}
PostActionSignal( pActionKeys );
CloseModal();
return;
}
if ( !Q_stricmp( pCommand, "Cancel" ) )
{
CloseModal();
return;
}
BaseClass::OnCommand( pCommand );
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,239 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//===========================================================================//
#include "matsys_controls/proceduraltexturepanel.h"
#include "matsys_controls/matsyscontrols.h"
#include "materialsystem/imaterialsystem.h"
#include "materialsystem/itexture.h"
#include "VGuiMatSurface/IMatSystemSurface.h"
#include "tier1/KeyValues.h"
#include "pixelwriter.h"
using namespace vgui;
//-----------------------------------------------------------------------------
// constructor
//-----------------------------------------------------------------------------
CProceduralTexturePanel::CProceduralTexturePanel( vgui::Panel *pParent, const char *pName ) : BaseClass( pParent, pName )
{
m_pImageBuffer = NULL;
m_bMaintainProportions = false;
m_bUsePaintRect = false;
m_PaintRect.x = m_PaintRect.y = 0;
m_PaintRect.width = m_PaintRect.height = 0;
}
CProceduralTexturePanel::~CProceduralTexturePanel()
{
CleanUp();
}
//-----------------------------------------------------------------------------
// initialization, shutdown
//-----------------------------------------------------------------------------
bool CProceduralTexturePanel::Init( int nWidth, int nHeight, bool bAllocateImageBuffer )
{
m_nWidth = nWidth;
m_nHeight = nHeight;
if ( bAllocateImageBuffer )
{
m_pImageBuffer = new BGRA8888_t[nWidth * nHeight];
}
m_TextureSubRect.x = m_TextureSubRect.y = 0;
m_TextureSubRect.width = nWidth;
m_TextureSubRect.height = nHeight;
char pTemp[512];
Q_snprintf( pTemp, 512, "__%s", GetName() );
ITexture *pTex = MaterialSystem()->CreateProceduralTexture( pTemp, TEXTURE_GROUP_VGUI,
m_nWidth, m_nHeight, IMAGE_FORMAT_BGRX8888,
TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_NOMIP |
TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_PROCEDURAL | TEXTUREFLAGS_SINGLECOPY );
pTex->SetTextureRegenerator( this );
m_ProceduralTexture.Init( pTex );
KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
pVMTKeyValues->SetString( "$basetexture", pTemp );
pVMTKeyValues->SetInt( "$nocull", 1 );
pVMTKeyValues->SetInt( "$nodebug", 1 );
m_ProceduralMaterial.Init( MaterialSystem()->CreateMaterial( pTemp, pVMTKeyValues ));
m_nTextureID = MatSystemSurface()->CreateNewTextureID( false );
MatSystemSurface()->DrawSetTextureMaterial( m_nTextureID, m_ProceduralMaterial );
return true;
}
void CProceduralTexturePanel::Shutdown()
{
CleanUp();
}
//-----------------------------------------------------------------------------
// Maintain proportions when drawing
//-----------------------------------------------------------------------------
void CProceduralTexturePanel::MaintainProportions( bool bEnable )
{
m_bMaintainProportions = bEnable;
}
//-----------------------------------------------------------------------------
// Returns the image buffer + dimensions
//-----------------------------------------------------------------------------
void CProceduralTexturePanel::CleanUp()
{
if ( (ITexture*)m_ProceduralTexture )
{
m_ProceduralTexture->SetTextureRegenerator( NULL );
}
m_ProceduralTexture.Shutdown();
m_ProceduralMaterial.Shutdown();
if ( m_pImageBuffer )
{
delete[] m_pImageBuffer;
m_pImageBuffer = NULL;
}
}
//-----------------------------------------------------------------------------
// Default implementation of regenerate texture bits
//-----------------------------------------------------------------------------
void CProceduralTexturePanel::RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect )
{
Assert( m_pImageBuffer );
Assert( pVTFTexture->FrameCount() == 1 );
Assert( pVTFTexture->FaceCount() == 1 );
Assert( !pTexture->IsMipmapped() );
int nWidth, nHeight, nDepth;
pVTFTexture->ComputeMipLevelDimensions( 0, &nWidth, &nHeight, &nDepth );
Assert( nDepth == 1 );
Assert( nWidth == m_nWidth && nHeight == m_nHeight );
CPixelWriter pixelWriter;
pixelWriter.SetPixelMemory( pVTFTexture->Format(),
pVTFTexture->ImageData( 0, 0, 0 ), pVTFTexture->RowSizeInBytes( 0 ) );
for ( int y = 0; y < nHeight; ++y )
{
pixelWriter.Seek( 0, y );
BGRA8888_t *pTexel = &m_pImageBuffer[y * m_nWidth];
for ( int x = 0; x < nWidth; ++x, ++pTexel )
{
pixelWriter.WritePixel( pTexel->r, pTexel->g, pTexel->b, pTexel->a );
}
}
}
//-----------------------------------------------------------------------------
// Returns the image buffer + dimensions
//-----------------------------------------------------------------------------
BGRA8888_t *CProceduralTexturePanel::GetImageBuffer()
{
Assert( m_pImageBuffer );
return m_pImageBuffer;
}
int CProceduralTexturePanel::GetImageWidth() const
{
return m_nWidth;
}
int CProceduralTexturePanel::GetImageHeight() const
{
return m_nHeight;
}
//-----------------------------------------------------------------------------
// Sets the paint rect
//-----------------------------------------------------------------------------
void CProceduralTexturePanel::SetPaintRect( const Rect_t *pPaintRect )
{
m_bUsePaintRect = ( pPaintRect != NULL );
if ( m_bUsePaintRect )
{
m_PaintRect = *pPaintRect;
}
}
//-----------------------------------------------------------------------------
// Sets the draw rect
//-----------------------------------------------------------------------------
void CProceduralTexturePanel::SetTextureSubRect( const Rect_t &subRect )
{
m_TextureSubRect = subRect;
}
//-----------------------------------------------------------------------------
// Redownloads the procedural texture
//-----------------------------------------------------------------------------
void CProceduralTexturePanel::DownloadTexture()
{
m_ProceduralTexture->Download();
}
//-----------------------------------------------------------------------------
// Paints the texture
//-----------------------------------------------------------------------------
void CProceduralTexturePanel::Paint( void )
{
vgui::surface()->DrawSetTexture( m_nTextureID );
vgui::surface()->DrawSetColor( 255, 255, 255, 255 );
int x = 0;
int y = 0;
int w, h;
GetSize( w, h );
if ( m_bUsePaintRect )
{
x = m_PaintRect.x;
y = m_PaintRect.y;
w = m_PaintRect.width;
h = m_PaintRect.height;
}
if ( m_bMaintainProportions )
{
if ( m_TextureSubRect.width > m_TextureSubRect.height )
{
h = w * m_TextureSubRect.height / m_TextureSubRect.width;
}
else
{
w = h * m_TextureSubRect.width / m_TextureSubRect.height;
}
}
// Rotated version of the bitmap!
// Rotate about the center of the bitmap
vgui::Vertex_t verts[4];
verts[0].m_Position.Init( x, y );
verts[0].m_TexCoord.Init( (float)m_TextureSubRect.x / m_nWidth, (float)m_TextureSubRect.y / m_nHeight );
verts[1].m_Position.Init( w+x, y );
verts[1].m_TexCoord.Init( (float)(m_TextureSubRect.x + m_TextureSubRect.width) / m_nWidth, (float)m_TextureSubRect.y / m_nHeight );
verts[2].m_Position.Init( w+x, h+y );
verts[2].m_TexCoord.Init( (float)(m_TextureSubRect.x + m_TextureSubRect.width) / m_nWidth, (float)(m_TextureSubRect.y + m_TextureSubRect.height) / m_nHeight );
verts[3].m_Position.Init( x, h+y );
verts[3].m_TexCoord.Init( (float)m_TextureSubRect.x / m_nWidth, (float)(m_TextureSubRect.y + m_TextureSubRect.height) / m_nHeight );
vgui::surface()->DrawTexturedPolygon( 4, verts );
}

View File

@ -0,0 +1,485 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "matsys_controls/sequencepicker.h"
#include "tier1/utldict.h"
#include "tier1/KeyValues.h"
#include "studio.h"
#include "vgui/IInput.h"
#include "vgui/ISurface.h"
#include "vgui_controls/Splitter.h"
#include "vgui_controls/PropertyPage.h"
#include "vgui_controls/PropertySheet.h"
#include "vgui_controls/ListPanel.h"
#include "vgui_controls/Button.h"
#include "matsys_controls/matsyscontrols.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
using namespace vgui;
//-----------------------------------------------------------------------------
//
// Sequence Picker
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Sort by sequence name
//-----------------------------------------------------------------------------
static int __cdecl SequenceSortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
{
const char *string1 = item1.kv->GetString("sequence");
const char *string2 = item2.kv->GetString("sequence");
return stricmp( string1, string2 );
}
static int __cdecl ActivitySortFunc( vgui::ListPanel *pPanel, const ListPanelItem &item1, const ListPanelItem &item2 )
{
const char *string1 = item1.kv->GetString("activity");
const char *string2 = item2.kv->GetString("activity");
return stricmp( string1, string2 );
}
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CSequencePicker::CSequencePicker( vgui::Panel *pParent, int nFlags ) : BaseClass( pParent, "SequencePicker" )
{
m_hSelectedMDL = MDLHANDLE_INVALID;
// property sheet - revisions, changes, etc.
m_pPreviewSplitter = new Splitter( this, "PreviewSplitter", SPLITTER_MODE_HORIZONTAL, 1 );
vgui::Panel *pSplitterTopSide = m_pPreviewSplitter->GetChild( 0 );
vgui::Panel *pSplitterBottomSide = m_pPreviewSplitter->GetChild( 1 );
// MDL preview
m_pMDLPreview = new CMDLPanel( pSplitterTopSide, "MDLPreview" );
SetSkipChildDuringPainting( m_pMDLPreview );
m_pViewsSheet = new vgui::PropertySheet( pSplitterBottomSide, "ViewsSheet" );
m_pViewsSheet->AddActionSignalTarget( this );
// sequences
m_pSequencesPage = NULL;
m_pSequencesList = NULL;
if ( nFlags & PICK_SEQUENCES )
{
m_pSequencesPage = new PropertyPage( m_pViewsSheet, "SequencesPage" );
m_pViewsSheet->AddPage( m_pSequencesPage, "Sequences" );
m_pSequencesList = new ListPanel( m_pSequencesPage, "SequencesList" );
m_pSequencesList->AddColumnHeader( 0, "sequence", "sequence", 52, 0 );
m_pSequencesList->AddActionSignalTarget( this );
m_pSequencesList->SetSelectIndividualCells( true );
m_pSequencesList->SetEmptyListText(".MDL file contains no activities");
m_pSequencesList->SetDragEnabled( true );
m_pSequencesList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 );
m_pSequencesList->SetSortFunc( 0, SequenceSortFunc );
m_pSequencesList->SetSortColumn( 0 );
}
// Activities
m_pActivitiesPage = NULL;
m_pActivitiesList = NULL;
if ( nFlags & PICK_ACTIVITIES )
{
m_pActivitiesPage = new PropertyPage( m_pViewsSheet, "ActivitiesPage" );
m_pViewsSheet->AddPage( m_pActivitiesPage, "Activities" );
m_pActivitiesList = new ListPanel( m_pActivitiesPage, "ActivitiesList" );
m_pActivitiesList->AddColumnHeader( 0, "activity", "activity", 52, 0 );
m_pActivitiesList->AddActionSignalTarget( this );
m_pActivitiesList->SetSelectIndividualCells( true );
m_pActivitiesList->SetEmptyListText( ".MDL file contains no activities" );
m_pActivitiesList->SetDragEnabled( true );
m_pActivitiesList->SetAutoResize( Panel::PIN_TOPLEFT, Panel::AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 );
m_pActivitiesList->SetSortFunc( 0, ActivitySortFunc );
m_pActivitiesList->SetSortColumn( 0 );
}
// Load layout settings; has to happen before pinning occurs in code
LoadControlSettingsAndUserConfig( "resource/sequencepicker.res" );
SETUP_PANEL( this );
}
//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CSequencePicker::~CSequencePicker()
{
}
//-----------------------------------------------------------------------------
// Performs layout
//-----------------------------------------------------------------------------
void CSequencePicker::PerformLayout()
{
// NOTE: This call should cause auto-resize to occur
// which should fix up the width of the panels
BaseClass::PerformLayout();
int w, h;
GetSize( w, h );
// Layout the mdl splitter
m_pPreviewSplitter->SetBounds( 0, 0, w, h );
}
//-----------------------------------------------------------------------------
// Purpose: rebuilds the list of activities + sequences
//-----------------------------------------------------------------------------
void CSequencePicker::RefreshActivitiesAndSequencesList()
{
if ( m_pActivitiesList )
{
m_pActivitiesList->RemoveAll();
}
if ( m_pSequencesList )
{
m_pSequencesList->RemoveAll();
}
m_pMDLPreview->SetSequence( 0 );
if ( m_hSelectedMDL == MDLHANDLE_INVALID )
return;
studiohdr_t *hdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL );
CUtlDict<int, unsigned short> activityNames( true, 0, hdr->GetNumSeq() );
for (int j = 0; j < hdr->GetNumSeq(); j++)
{
if ( /*g_viewerSettings.showHidden ||*/ !(hdr->pSeqdesc(j).flags & STUDIO_HIDDEN))
{
const char *pActivityName = hdr->pSeqdesc(j).pszActivityName();
if ( m_pActivitiesList && pActivityName && pActivityName[0] )
{
// Multiple sequences can have the same activity name; only add unique activity names
if ( activityNames.Find( pActivityName ) == activityNames.InvalidIndex() )
{
KeyValues *pkv = new KeyValues("node", "activity", pActivityName );
int nItemID = m_pActivitiesList->AddItem( pkv, 0, false, false );
KeyValues *pDrag = new KeyValues( "drag", "text", pActivityName );
pDrag->SetString( "texttype", "activityName" );
pDrag->SetString( "mdl", vgui::MDLCache()->GetModelName( m_hSelectedMDL ) );
m_pActivitiesList->SetItemDragData( nItemID, pDrag );
activityNames.Insert( pActivityName, j );
}
}
const char *pSequenceName = hdr->pSeqdesc(j).pszLabel();
if ( m_pSequencesList && pSequenceName && pSequenceName[0] )
{
KeyValues *pkv = new KeyValues("node", "sequence", pSequenceName);
int nItemID = m_pSequencesList->AddItem( pkv, 0, false, false );
KeyValues *pDrag = new KeyValues( "drag", "text", pSequenceName );
pDrag->SetString( "texttype", "sequenceName" );
pDrag->SetString( "mdl", vgui::MDLCache()->GetModelName( m_hSelectedMDL ) );
m_pSequencesList->SetItemDragData( nItemID, pDrag );
}
}
}
if ( m_pSequencesList )
{
m_pSequencesList->SortList();
}
if ( m_pActivitiesList )
{
m_pActivitiesList->SortList();
}
}
/*
//-----------------------------------------------------------------------------
// Purpose: Selects an sequence based on an activity
//-----------------------------------------------------------------------------
int SelectWeightedSequence( studiohdr_t *pstudiohdr, int activity, int curSequence )
{
if (! pstudiohdr)
return 0;
VerifySequenceIndex( pstudiohdr );
int weighttotal = 0;
int seq = ACTIVITY_NOT_AVAILABLE;
int weight = 0;
for (int i = 0; i < pstudiohdr->GetNumSeq(); i++)
{
int curActivity = GetSequenceActivity( pstudiohdr, i, &weight );
if (curActivity == activity)
{
if ( curSequence == i && weight < 0 )
{
seq = i;
break;
}
weighttotal += iabs(weight);
int randomValue;
if ( IsInPrediction() )
randomValue = SharedRandomInt( "SelectWeightedSequence", 0, weighttotal - 1, i );
else
randomValue = RandomInt( 0, weighttotal - 1 );
if (!weighttotal || randomValue < iabs(weight))
seq = i;
}
}
return seq;
}
*/
//-----------------------------------------------------------------------------
// Gets the selected activity/sequence
//-----------------------------------------------------------------------------
CSequencePicker::PickType_t CSequencePicker::GetSelectedSequenceType( )
{
if ( m_pSequencesPage && ( m_pViewsSheet->GetActivePage() == m_pSequencesPage ) )
return PICK_SEQUENCES;
if ( m_pActivitiesPage && ( m_pViewsSheet->GetActivePage() == m_pActivitiesPage ) )
return PICK_ACTIVITIES;
return PICK_NONE;
}
const char *CSequencePicker::GetSelectedSequenceName( )
{
if ( m_pSequencesPage && ( m_pViewsSheet->GetActivePage() == m_pSequencesPage ) )
{
int nIndex = m_pSequencesList->GetSelectedItem( 0 );
if ( nIndex >= 0 )
{
KeyValues *pkv = m_pSequencesList->GetItem( nIndex );
return pkv->GetString( "sequence", NULL );
}
return NULL;
}
if ( m_pActivitiesPage && ( m_pViewsSheet->GetActivePage() == m_pActivitiesPage ) )
{
int nIndex = m_pActivitiesList->GetSelectedItem( 0 );
if ( nIndex >= 0 )
{
KeyValues *pkv = m_pActivitiesList->GetItem( nIndex );
return pkv->GetString( "activity", NULL );
}
return NULL;
}
return NULL;
}
//-----------------------------------------------------------------------------
// Plays the selected activity
//-----------------------------------------------------------------------------
void CSequencePicker::PlayActivity( const char *pActivityName )
{
studiohdr_t *pstudiohdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL );
for ( int i = 0; i < pstudiohdr->GetNumSeq(); i++ )
{
mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
if ( stricmp( seqdesc.pszActivityName(), pActivityName ) == 0 )
{
// FIXME: Add weighted sequence selection logic?
m_pMDLPreview->SetSequence( i );
break;
}
}
}
//-----------------------------------------------------------------------------
// Plays the selected sequence
//-----------------------------------------------------------------------------
void CSequencePicker::PlaySequence( const char *pSequenceName )
{
studiohdr_t *pstudiohdr = vgui::MDLCache()->GetStudioHdr( m_hSelectedMDL );
for (int i = 0; i < pstudiohdr->GetNumSeq(); i++)
{
mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
if ( !Q_stricmp( seqdesc.pszLabel(), pSequenceName ) )
{
m_pMDLPreview->SetSequence( i );
break;
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Called when a page is shown
//-----------------------------------------------------------------------------
void CSequencePicker::OnPageChanged( )
{
if ( m_pSequencesPage && ( m_pViewsSheet->GetActivePage() == m_pSequencesPage ) )
{
const char *pSequenceName = GetSelectedSequenceName();
if ( pSequenceName )
{
PlaySequence( pSequenceName );
PostActionSignal( new KeyValues( "SequencePreviewChanged", "sequence", pSequenceName ) );
}
return;
}
if ( m_pActivitiesPage && ( m_pViewsSheet->GetActivePage() == m_pActivitiesPage ) )
{
const char *pActivityName = GetSelectedSequenceName();
if ( pActivityName )
{
PlayActivity( pActivityName );
PostActionSignal( new KeyValues( "SequencePreviewChanged", "activity", pActivityName ) );
}
return;
}
}
//-----------------------------------------------------------------------------
// Purpose: refreshes dialog on text changing
//-----------------------------------------------------------------------------
void CSequencePicker::OnItemSelected( KeyValues *kv )
{
Panel *pPanel = (Panel *)kv->GetPtr("panel", NULL);
if ( m_pSequencesList && (pPanel == m_pSequencesList ) )
{
const char *pSequenceName = GetSelectedSequenceName();
if ( pSequenceName )
{
PlaySequence( pSequenceName );
PostActionSignal( new KeyValues( "SequencePreviewChanged", "sequence", pSequenceName ) );
}
return;
}
if ( m_pActivitiesList && ( pPanel == m_pActivitiesList ) )
{
const char *pActivityName = GetSelectedSequenceName();
if ( pActivityName )
{
PlayActivity( pActivityName );
PostActionSignal( new KeyValues( "SequencePreviewChanged", "activity", pActivityName ) );
}
return;
}
}
//-----------------------------------------------------------------------------
// Sets the MDL to select sequences in
//-----------------------------------------------------------------------------
void CSequencePicker::SetMDL( const char *pMDLName )
{
m_hSelectedMDL = pMDLName ? vgui::MDLCache()->FindMDL( pMDLName ) : MDLHANDLE_INVALID;
if ( vgui::MDLCache()->IsErrorModel( m_hSelectedMDL ) )
{
m_hSelectedMDL = MDLHANDLE_INVALID;
}
m_pMDLPreview->SetMDL( m_hSelectedMDL );
m_pMDLPreview->LookAtMDL();
RefreshActivitiesAndSequencesList();
}
//-----------------------------------------------------------------------------
//
// Purpose: Modal picker frame
//
//-----------------------------------------------------------------------------
CSequencePickerFrame::CSequencePickerFrame( vgui::Panel *pParent, int nFlags ) : BaseClass( pParent, "SequencePickerFrame" )
{
SetDeleteSelfOnClose( true );
m_pPicker = new CSequencePicker( this, nFlags );
m_pPicker->AddActionSignalTarget( this );
m_pOpenButton = new Button( this, "OpenButton", "#FileOpenDialog_Open", this, "Open" );
m_pCancelButton = new Button( this, "CancelButton", "#FileOpenDialog_Cancel", this, "Cancel" );
SetBlockDragChaining( true );
LoadControlSettingsAndUserConfig( "resource/sequencepickerframe.res" );
m_pOpenButton->SetEnabled( false );
}
//-----------------------------------------------------------------------------
// Purpose: Activate the dialog
//-----------------------------------------------------------------------------
void CSequencePickerFrame::DoModal( const char *pMDLName )
{
m_pPicker->SetMDL( pMDLName );
BaseClass::DoModal();
}
//-----------------------------------------------------------------------------
// On mdl preview changed
//-----------------------------------------------------------------------------
void CSequencePickerFrame::OnSequencePreviewChanged( KeyValues *pKeyValues )
{
const char *pSequence = pKeyValues->GetString( "sequence", NULL );
const char *pActivity = pKeyValues->GetString( "activity", NULL );
m_pOpenButton->SetEnabled( pSequence || pActivity );
}
//-----------------------------------------------------------------------------
// On command
//-----------------------------------------------------------------------------
void CSequencePickerFrame::OnCommand( const char *pCommand )
{
if ( !Q_stricmp( pCommand, "Open" ) )
{
CSequencePicker::PickType_t type = m_pPicker->GetSelectedSequenceType( );
if (( type == CSequencePicker::PICK_SEQUENCES ) || ( type == CSequencePicker::PICK_ACTIVITIES ))
{
const char *pSequenceName = m_pPicker->GetSelectedSequenceName();
if ( pSequenceName )
{
if ( type == CSequencePicker::PICK_SEQUENCES )
{
PostActionSignal( new KeyValues("SequenceSelected", "sequence", pSequenceName ) );
}
else
{
PostActionSignal( new KeyValues("SequenceSelected", "activity", pSequenceName ) );
}
CloseModal();
return;
}
}
return;
}
if ( !Q_stricmp( pCommand, "Cancel" ) )
{
CloseModal();
return;
}
BaseClass::OnCommand( pCommand );
}

View File

@ -0,0 +1,72 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//===========================================================================//
#include "matsys_controls/tgapreviewpanel.h"
#include "bitmap/tgaloader.h"
#include "tier1/utlbuffer.h"
#include "filesystem.h"
using namespace vgui;
//-----------------------------------------------------------------------------
//
// TGA Preview panel
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// constructor
//-----------------------------------------------------------------------------
CTGAPreviewPanel::CTGAPreviewPanel( vgui::Panel *pParent, const char *pName ) :
BaseClass( pParent, pName )
{
}
//-----------------------------------------------------------------------------
// Sets the current TGA
//-----------------------------------------------------------------------------
void CTGAPreviewPanel::SetTGA( const char *pFullPath )
{
int nWidth, nHeight;
ImageFormat format;
float flGamma;
CUtlBuffer buf;
if ( !g_pFullFileSystem->ReadFile( pFullPath, NULL, buf ) )
{
Warning( "Can't open TGA file: %s\n", pFullPath );
return;
}
TGALoader::GetInfo( buf, &nWidth, &nHeight, &format, &flGamma );
Shutdown();
Init( nWidth, nHeight, true );
m_TGAName = pFullPath;
buf.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
if ( !TGALoader::Load( (unsigned char*)GetImageBuffer(), buf,
nWidth, nHeight, IMAGE_FORMAT_BGRA8888, flGamma, false ) )
{
Shutdown();
}
else
{
DownloadTexture();
}
}
//-----------------------------------------------------------------------------
// Gets the current TGA
//-----------------------------------------------------------------------------
const char *CTGAPreviewPanel::GetTGA() const
{
return m_TGAName;
}

View File

@ -0,0 +1,458 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//===========================================================================//
#include "matsys_controls/vmtpanel.h"
#include "materialsystem/imesh.h"
#include "materialsystem/imaterial.h"
#include "materialsystem/itexture.h"
#include "VGuiMatSurface/IMatSystemSurface.h"
#include "vgui_controls/ScrollBar.h"
#include "matsys_controls/matsyscontrols.h"
#include "vgui/IVGui.h"
#include "vgui_controls/ToolWindow.h"
#include "tier2/renderutils.h"
using namespace vgui;
//-----------------------------------------------------------------------------
// Enums
//-----------------------------------------------------------------------------
enum
{
SCROLLBAR_SIZE=18, // the width of a scrollbar
WINDOW_BORDER_WIDTH=2 // the width of the window's border
};
#define SPHERE_RADIUS 10.0f
//-----------------------------------------------------------------------------
// Constructor, destructor
//-----------------------------------------------------------------------------
CVMTPanel::CVMTPanel( vgui::Panel *pParent, const char *pName ) : BaseClass( pParent, pName )
{
m_bUseActualSize = true;
m_pMaterial = NULL;
m_pHorizontalBar = new ScrollBar( this, "HorizScrollBar", false );
m_pHorizontalBar->AddActionSignalTarget(this);
m_pHorizontalBar->SetVisible(false);
m_pVerticalBar = new ScrollBar( this, "VertScrollBar", true );
m_pVerticalBar->AddActionSignalTarget(this);
m_pVerticalBar->SetVisible(false);
LookAt( SPHERE_RADIUS );
m_pLightmapTexture.Init( "//platform/materials/debug/defaultlightmap", "editor" );
m_DefaultEnvCubemap.Init( "editor/cubemap", "editor", true );
}
CVMTPanel::~CVMTPanel()
{
m_pLightmapTexture.Shutdown();
m_DefaultEnvCubemap.Shutdown();
if (m_pMaterial)
{
m_pMaterial->DecrementReferenceCount();
}
}
//-----------------------------------------------------------------------------
// Scheme
//-----------------------------------------------------------------------------
void CVMTPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
SetBorder( pScheme->GetBorder( "MenuBorder") );
}
//-----------------------------------------------------------------------------
// Set the material to draw
//-----------------------------------------------------------------------------
void CVMTPanel::SetMaterial( IMaterial *pMaterial )
{
if (pMaterial)
{
pMaterial->IncrementReferenceCount();
}
if (m_pMaterial)
{
m_pMaterial->DecrementReferenceCount();
}
m_pMaterial = pMaterial;
InvalidateLayout();
}
//-----------------------------------------------------------------------------
// Set rendering mode (stretch to full screen, or use actual size)
//-----------------------------------------------------------------------------
void CVMTPanel::RenderUsingActualSize( bool bEnable )
{
m_bUseActualSize = bEnable;
InvalidateLayout();
}
//-----------------------------------------------------------------------------
// Purpose: relayouts out the panel after any internal changes
//-----------------------------------------------------------------------------
void CVMTPanel::PerformLayout()
{
BaseClass::PerformLayout();
return;
// Get the current size, see if it's big enough to view the entire thing
int iWidth, iHeight;
GetSize( iWidth, iHeight );
// In the case of stretching, just stretch to the size and blow off
// the scrollbars. Same holds true if there's no material
if (!m_bUseActualSize || !m_pMaterial)
{
m_iViewableWidth = iWidth;
m_iViewableHeight = iHeight;
m_pHorizontalBar->SetVisible(false);
m_pVerticalBar->SetVisible(false);
return;
}
// Check the size of the material...
int iMaterialWidth = m_pMaterial->GetMappingWidth();
int iMaterialHeight = m_pMaterial->GetMappingHeight();
// Check if the scroll bars are visible
bool bHorizScrollVisible = (iMaterialWidth > iWidth);
bool bVertScrollVisible = (iMaterialHeight > iHeight);
m_pHorizontalBar->SetVisible(bHorizScrollVisible);
m_pVerticalBar->SetVisible(bVertScrollVisible);
// Shrink the bars if both are visible
m_iViewableWidth = bVertScrollVisible ? iWidth - SCROLLBAR_SIZE - WINDOW_BORDER_WIDTH : iWidth;
m_iViewableHeight = bHorizScrollVisible ? iHeight - SCROLLBAR_SIZE - WINDOW_BORDER_WIDTH : iHeight;
// Set the position of the horizontal bar...
if (bHorizScrollVisible)
{
m_pHorizontalBar->SetPos(0, iHeight - SCROLLBAR_SIZE);
m_pHorizontalBar->SetSize( m_iViewableWidth, SCROLLBAR_SIZE );
m_pHorizontalBar->SetRangeWindow( m_iViewableWidth );
m_pHorizontalBar->SetRange( 0, iMaterialWidth );
// FIXME: Change scroll amount based on how much is not visible?
m_pHorizontalBar->SetButtonPressedScrollValue( 5 );
}
// Set the position of the vertical bar...
if (bVertScrollVisible)
{
m_pVerticalBar->SetPos(iWidth - SCROLLBAR_SIZE, 0);
m_pVerticalBar->SetSize(SCROLLBAR_SIZE, m_iViewableHeight);
m_pVerticalBar->SetRangeWindow( m_iViewableHeight );
m_pVerticalBar->SetRange( 0, iMaterialHeight);
m_pVerticalBar->SetButtonPressedScrollValue( 5 );
}
}
//-----------------------------------------------------------------------------
// paint it stretched to the window size
//-----------------------------------------------------------------------------
void CVMTPanel::DrawStretchedToPanel( CMeshBuilder &meshBuilder )
{
// Draw a polygon the size of the panel
meshBuilder.Color4ub( 255, 255, 255, 255 );
meshBuilder.Position3f( 0, 0, 0 );
meshBuilder.TexCoord2f( 0, 0, 0 );
meshBuilder.AdvanceVertex();
meshBuilder.Color4ub( 255, 255, 255, 255 );
meshBuilder.Position3f( 0, m_iViewableHeight, 0 );
meshBuilder.TexCoord2f( 0, 0, 1 );
meshBuilder.AdvanceVertex();
meshBuilder.Color4ub( 255, 255, 255, 255 );
meshBuilder.Position3f( m_iViewableWidth, m_iViewableHeight, 0 );
meshBuilder.TexCoord2f( 0, 1, 1 );
meshBuilder.AdvanceVertex();
meshBuilder.Color4ub( 255, 255, 255, 255 );
meshBuilder.Position3f( m_iViewableWidth, 0, 0 );
meshBuilder.TexCoord2f( 0, 0, 1 );
meshBuilder.AdvanceVertex();
}
//-----------------------------------------------------------------------------
// paint it actual size
//-----------------------------------------------------------------------------
void CVMTPanel::DrawActualSize( CMeshBuilder &meshBuilder )
{
// Check the size of the material...
int iMaterialWidth = m_pMaterial->GetMappingWidth();
int iMaterialHeight = m_pMaterial->GetMappingHeight();
Vector2D ul;
Vector2D lr;
Vector2D tul;
Vector2D tlr;
if (m_iViewableWidth >= iMaterialWidth)
{
// Center the material if we've got enough horizontal space
ul.x = (m_iViewableWidth - iMaterialWidth) * 0.5f;
lr.x = ul.x + iMaterialWidth;
tul.x = 0.0f; tlr.x = 1.0f;
}
else
{
// Use the scrollbars here...
int val = m_pHorizontalBar->GetValue();
tul.x = (float)val / (float)iMaterialWidth;
tlr.x = tul.x + (float)m_iViewableWidth / (float)iMaterialWidth;
ul.x = 0;
lr.x = m_iViewableWidth;
}
if (m_iViewableHeight >= iMaterialHeight)
{
// Center the material if we've got enough vertical space
ul.y = (m_iViewableHeight - iMaterialHeight) * 0.5f;
lr.y = ul.y + iMaterialHeight;
tul.y = 0.0f; tlr.y = 1.0f;
}
else
{
// Use the scrollbars here...
int val = m_pVerticalBar->GetValue();
tul.y = (float)val / (float)iMaterialHeight;
tlr.y = tul.y + (float)m_iViewableHeight / (float)iMaterialHeight;
ul.y = 0;
lr.y = m_iViewableHeight;
}
meshBuilder.Color4ub( 255, 255, 255, 255 );
meshBuilder.Position3f( ul.x, ul.y, 0 );
meshBuilder.TexCoord2f( 0, tul.x, tul.y );
meshBuilder.AdvanceVertex();
meshBuilder.Color4ub( 255, 255, 255, 255 );
meshBuilder.Position3f( lr.x, ul.y, 0 );
meshBuilder.TexCoord2f( 0, tlr.x, tul.y );
meshBuilder.AdvanceVertex();
meshBuilder.Color4ub( 255, 255, 255, 255 );
meshBuilder.Position3f( lr.x, lr.y, 0 );
meshBuilder.TexCoord2f( 0, tlr.x, tlr.y );
meshBuilder.AdvanceVertex();
meshBuilder.Color4ub( 255, 255, 255, 255 );
meshBuilder.Position3f( ul.x, lr.y, 0 );
meshBuilder.TexCoord2f( 0, tul.x, tlr.y );
meshBuilder.AdvanceVertex();
}
//-----------------------------------------------------------------------------
// Draw it on a sphere
//-----------------------------------------------------------------------------
void CVMTPanel::RenderSphere( const Vector &vCenter, float flRadius, int nTheta, int nPhi )
{
int nVertices = nTheta * nPhi;
int nIndices = 2 * ( nTheta + 1 ) * ( nPhi - 1 );
CMatRenderContextPtr pRenderContext( MaterialSystem() );
pRenderContext->FogMode( MATERIAL_FOG_NONE );
pRenderContext->SetNumBoneWeights( 0 );
pRenderContext->Bind( m_pMaterial );
pRenderContext->BindLightmapTexture( m_pLightmapTexture );
pRenderContext->BindLocalCubemap( m_DefaultEnvCubemap );
IMesh* pMesh = pRenderContext->GetDynamicMesh();
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, nVertices, nIndices );
bool bIsUsingLightmap = m_pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_LIGHTMAP );
bool bIsUsingBumpedLightmap = m_pMaterial->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS );
int nLightmapWidth = m_pLightmapTexture->GetActualWidth();
float flHalfLuxel = 0.5f / nLightmapWidth;
//
// Build the index buffer.
//
int i, j;
for ( i = 0; i < nPhi; ++i )
{
for ( j = 0; j < nTheta; ++j )
{
float u = j / ( float )(nTheta - 1);
float v = i / ( float )(nPhi - 1);
float theta = ( j != nTheta-1 ) ? 2.0f * M_PI * u : 0.0f;
float phi = M_PI * v;
Vector vecPos;
vecPos.x = flRadius * sin(phi) * cos(theta);
vecPos.y = flRadius * sin(phi) * sin(theta);
vecPos.z = flRadius * cos(phi);
Vector vecNormal = vecPos;
VectorNormalize( vecNormal );
Vector4D vecTangentS;
Vector vecTangentT;
vecTangentS.Init( -vecPos.y, vecPos.x, 0.0f, 1.0f );
if ( VectorNormalize( vecTangentS.AsVector3D() ) == 0.0f )
{
vecTangentS.Init( 1.0f, 0.0f, 0.0f, 1.0f );
}
CrossProduct( vecNormal, vecTangentS.AsVector3D(), vecTangentT );
unsigned char red = (int)( u * 255.0f );
unsigned char green = (int)( v * 255.0f );
unsigned char blue = (int)( v * 255.0f );
unsigned char alpha = (int)( v * 255.0f );
vecPos += vCenter;
float u1, u2, v1, v2;
u1 = u2 = u;
v1 = v2 = v;
if ( bIsUsingLightmap )
{
u1 = RemapVal( u1, 0.0f, 1.0f, flHalfLuxel, 0.25 - flHalfLuxel );
if ( bIsUsingBumpedLightmap )
{
u2 = 0.25f;
v2 = 0.0f;
}
}
meshBuilder.Position3fv( vecPos.Base() );
meshBuilder.Normal3fv( vecNormal.Base() );
meshBuilder.Color4ub( red, green, blue, alpha );
meshBuilder.TexCoord2f( 0, u, v );
meshBuilder.TexCoord2f( 1, u1, v1 );
meshBuilder.TexCoord2f( 2, u2, v2 );
meshBuilder.TangentS3fv( vecTangentS.Base() );
meshBuilder.TangentT3fv( vecTangentT.Base() );
meshBuilder.UserData( vecTangentS.Base() );
meshBuilder.AdvanceVertex();
}
}
//
// Emit the triangle strips.
//
int idx = 0;
for ( i = 0; i < nPhi - 1; ++i )
{
for ( j = 0; j < nTheta; ++j )
{
idx = nTheta * i + j;
meshBuilder.FastIndex( idx );
meshBuilder.FastIndex( idx + nTheta );
}
//
// Emit a degenerate triangle to skip to the next row without
// a connecting triangle.
//
if ( i < nPhi - 2 )
{
meshBuilder.FastIndex( idx + 1 );
meshBuilder.FastIndex( idx + 1 + nTheta );
}
}
meshBuilder.End();
pMesh->Draw();
}
//-----------------------------------------------------------------------------
// Power of two FB texture
//-----------------------------------------------------------------------------
static CTextureReference s_pPowerOfTwoFrameBufferTexture;
static ITexture *GetPowerOfTwoFrameBufferTexture( void )
{
if( !s_pPowerOfTwoFrameBufferTexture )
{
s_pPowerOfTwoFrameBufferTexture.Init( materials->FindTexture( "_rt_PowerOfTwoFB", TEXTURE_GROUP_RENDER_TARGET ) );
}
return s_pPowerOfTwoFrameBufferTexture;
}
//-----------------------------------------------------------------------------
// paint it!
//-----------------------------------------------------------------------------
void CVMTPanel::OnPaint3D()
{
if (!m_pMaterial)
return;
// Deal with refraction
CMatRenderContextPtr pRenderContext( MaterialSystem() );
if ( m_pMaterial->NeedsPowerOfTwoFrameBufferTexture() )
{
ITexture *pTexture = GetPowerOfTwoFrameBufferTexture();
if ( pTexture && !pTexture->IsError() )
{
pRenderContext->CopyRenderTargetToTexture( pTexture );
pRenderContext->SetFrameBufferCopyTexture( pTexture );
}
}
// Draw a background (translucent objects will appear that way)
// FIXME: Draw the outline of this panel?
pRenderContext->CullMode( MATERIAL_CULLMODE_CW );
RenderSphere( vec3_origin, SPHERE_RADIUS, 20, 20 );
/*
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
pRenderContext->LoadIdentity();
pRenderContext->Ortho( 0, 0, m_iViewableWidth, m_iViewableHeight, 0, 1 );
pRenderContext->Bind( m_pMaterial );
IMesh *pMesh = pRenderContext->GetDynamicMesh();
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
if (!m_bUseActualSize)
{
DrawStretchedToPanel( meshBuilder );
}
else
{
DrawActualSize( meshBuilder );
}
meshBuilder.End();
pMesh->Draw();
*/
}

View File

@ -0,0 +1,78 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "filesystem.h"
#include "matsys_controls/vmtpicker.h"
#include "matsys_controls/vmtpreviewpanel.h"
#include "vgui_controls/Splitter.h"
using namespace vgui;
//-----------------------------------------------------------------------------
//
// Asset Picker with no preview
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CVMTPicker::CVMTPicker( vgui::Panel *pParent, bool bAllowMultiselect ) :
BaseClass( pParent, "VMT Files", "vmt", "materials", "vmtName" )
{
// Horizontal splitter for preview
m_pPreviewSplitter = new Splitter( this, "PreviewSplitter", SPLITTER_MODE_VERTICAL, 1 );
vgui::Panel *pSplitterLeftSide = m_pPreviewSplitter->GetChild( 0 );
vgui::Panel *pSplitterRightSide = m_pPreviewSplitter->GetChild( 1 );
m_p2D3DSplitter = new Splitter( pSplitterRightSide, "2D3DSplitter", SPLITTER_MODE_HORIZONTAL, 1 );
vgui::Panel *pSplitterTopSide = m_p2D3DSplitter->GetChild( 0 );
vgui::Panel *pSplitterBottomSide = m_p2D3DSplitter->GetChild( 1 );
// VMT preview
m_pVMTPreview2D = new CVMTPreviewPanel( pSplitterTopSide, "VMTPreview2D" );
m_pVMTPreview3D = new CVMTPreviewPanel( pSplitterBottomSide, "VMTPreview3D" );
m_pVMTPreview3D->DrawIn3DMode( true );
// Standard browser controls
CreateStandardControls( pSplitterLeftSide, bAllowMultiselect );
LoadControlSettingsAndUserConfig( "resource/vmtpicker.res" );
}
CVMTPicker::~CVMTPicker()
{
}
//-----------------------------------------------------------------------------
// Derived classes have this called when the previewed asset changes
//-----------------------------------------------------------------------------
void CVMTPicker::OnSelectedAssetPicked( const char *pAssetName )
{
m_pVMTPreview2D->SetVMT( pAssetName );
m_pVMTPreview3D->SetVMT( pAssetName );
}
//-----------------------------------------------------------------------------
//
// Purpose: Modal picker frame
//
//-----------------------------------------------------------------------------
CVMTPickerFrame::CVMTPickerFrame( vgui::Panel *pParent, const char *pTitle, bool bAllowMultiselect ) :
BaseClass( pParent )
{
SetAssetPicker( new CVMTPicker( this, bAllowMultiselect ) );
LoadControlSettingsAndUserConfig( "resource/vmtpickerframe.res" );
SetTitle( pTitle, false );
}

View File

@ -0,0 +1,625 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//===========================================================================//
#include "matsys_controls/vmtpreviewpanel.h"
#include "matsys_controls/matsyscontrols.h"
#include "VGuiMatSurface/IMatSystemSurface.h"
#include "materialsystem/MaterialSystemUtil.h"
#include "materialsystem/imaterialsystem.h"
#include "materialsystem/imaterial.h"
#include "materialsystem/itexture.h"
#include "materialsystem/imesh.h"
#include "tier1/KeyValues.h"
using namespace vgui;
#define FOV 90.0f
#define ZNEAR 0.1f
#define ZFAR 2000.0f
#define ROTATION_SPEED 40.0f // degrees/sec
#define VIEW_DISTANCE 12.0f
//-----------------------------------------------------------------------------
//
// VMT Preview panel
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// constructor
//-----------------------------------------------------------------------------
CVMTPreviewPanel::CVMTPreviewPanel( vgui::Panel *pParent, const char *pName ) :
BaseClass( pParent, pName )
{
SetVMT( "//platform/materials/vgui/vtfnotloaded" );
m_pLightmapTexture.Init( "//platform/materials/debug/defaultlightmap", "editor" );
m_DefaultEnvCubemap.Init( "editor/cubemap", "editor", true );
m_LightDirection.Init( 0.0f, 1.0f, -1.0f );
m_LightColor.SetColor( 255, 255, 255, 255 );
m_flLightIntensity = 2.0f;
m_bDrawIn3DMode = false;
// Reset the camera direction
m_vecCameraDirection.Init( 1.0f, 0.0f, 0.0f );
m_flLastRotationTime = Plat_FloatTime();
}
//-----------------------------------------------------------------------------
// Sets the current VMT
//-----------------------------------------------------------------------------
void CVMTPreviewPanel::SetVMT( const char *pMaterialName )
{
m_Material.Init( pMaterialName, "editor material" );
m_VMTName = pMaterialName;
}
//-----------------------------------------------------------------------------
// Gets the current VMT
//-----------------------------------------------------------------------------
const char *CVMTPreviewPanel::GetVMT() const
{
return m_VMTName;
}
//-----------------------------------------------------------------------------
// View it in 3D or 2D mode
//-----------------------------------------------------------------------------
void CVMTPreviewPanel::DrawIn3DMode( bool b3DMode )
{
m_bDrawIn3DMode = b3DMode;
}
//-----------------------------------------------------------------------------
// Sets up lighting state
//-----------------------------------------------------------------------------
void CVMTPreviewPanel::SetupLightingState()
{
LightDesc_t desc;
memset( &desc, 0, sizeof(desc) );
desc.m_Type = MATERIAL_LIGHT_DIRECTIONAL;
desc.m_Color[0] = m_LightColor.r();
desc.m_Color[1] = m_LightColor.g();
desc.m_Color[2] = m_LightColor.b();
desc.m_Color *= m_flLightIntensity / 255.0f;
desc.m_Attenuation0 = 1.0f;
desc.m_Attenuation1 = 0.0f;
desc.m_Attenuation2 = 0.0f;
desc.m_Flags = LIGHTTYPE_OPTIMIZATIONFLAGS_HAS_ATTENUATION0;
desc.m_Direction = m_LightDirection;
VectorNormalize( desc.m_Direction );
desc.m_Theta = 0.0f;
desc.m_Phi = 0.0f;
desc.m_Falloff = 1.0f;
CMatRenderContextPtr pRenderContext( MaterialSystem() );
pRenderContext->SetLight( 0, desc );
}
//-----------------------------------------------------------------------------
// Draw a sphere
//-----------------------------------------------------------------------------
void CVMTPreviewPanel::RenderSphere( const Vector &vCenter, float flRadius, int nTheta, int nPhi )
{
int nVertices = nTheta * nPhi;
int nIndices = 2 * ( nTheta + 1 ) * ( nPhi - 1 );
CMatRenderContextPtr pRenderContext( MaterialSystem() );
IMesh* pMesh = pRenderContext->GetDynamicMesh();
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, nVertices, nIndices );
bool bIsUsingLightmap = m_Material->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_LIGHTMAP );
bool bIsUsingBumpedLightmap = m_Material->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS );
int nLightmapWidth = m_pLightmapTexture->GetActualWidth();
float flHalfLuxel = 0.5f / nLightmapWidth;
//
// Build the index buffer.
//
int i, j;
for ( i = 0; i < nPhi; ++i )
{
for ( j = 0; j < nTheta; ++j )
{
float u = j / ( float )(nTheta - 1);
float v = i / ( float )(nPhi - 1);
float theta = ( j != nTheta-1 ) ? 2.0f * M_PI * u : 0.0f;
float phi = M_PI * v;
Vector vecPos;
vecPos.x = flRadius * sin(phi) * cos(theta);
vecPos.y = flRadius * sin(phi) * sin(theta);
vecPos.z = flRadius * cos(phi);
Vector vecNormal = vecPos;
VectorNormalize( vecNormal );
Vector4D vecTangentS;
Vector vecTangentT;
vecTangentS.Init( vecPos.z, -vecPos.x, 0.0f, 1.0f );
if ( VectorNormalize( vecTangentS.AsVector3D() ) == 0.0f )
{
vecTangentS.Init( 1.0f, 0.0f, 0.0f, 1.0f );
}
CrossProduct( vecNormal, vecTangentS.AsVector3D(), vecTangentT );
unsigned char red = (int)( u * 255.0f );
unsigned char green = (int)( v * 255.0f );
unsigned char blue = (int)( v * 255.0f );
unsigned char alpha = (int)( v * 255.0f );
vecPos += vCenter;
float u1, u2, v1, v2;
u1 = u2 = u;
v1 = v2 = v;
if ( bIsUsingLightmap )
{
u1 = RemapVal( u1, 0.0f, 1.0f, flHalfLuxel, 0.25 - flHalfLuxel );
if ( bIsUsingBumpedLightmap )
{
u2 = 0.25f;
v2 = 0.0f;
}
}
meshBuilder.Position3fv( vecPos.Base() );
meshBuilder.Normal3fv( vecNormal.Base() );
meshBuilder.Color4ub( red, green, blue, alpha );
meshBuilder.TexCoord2f( 0, 2.0f * u, v );
meshBuilder.TexCoord2f( 1, u1, v1 );
meshBuilder.TexCoord2f( 2, u2, v2 );
meshBuilder.TangentS3fv( vecTangentS.Base() );
meshBuilder.TangentT3fv( vecTangentT.Base() );
meshBuilder.BoneWeight( 0, 1.0f );
meshBuilder.BoneMatrix( 0, 0 );
meshBuilder.UserData( vecTangentS.Base() );
meshBuilder.AdvanceVertex();
}
}
//
// Emit the triangle strips.
//
int idx = 0;
for ( i = 0; i < nPhi - 1; ++i )
{
for ( j = 0; j < nTheta; ++j )
{
idx = nTheta * i + j;
meshBuilder.FastIndex( idx );
meshBuilder.FastIndex( idx + nTheta );
}
//
// Emit a degenerate triangle to skip to the next row without
// a connecting triangle.
//
if ( i < nPhi - 2 )
{
meshBuilder.FastIndex( idx + 1 );
meshBuilder.FastIndex( idx + 1 + nTheta );
}
}
meshBuilder.End();
pMesh->Draw();
}
//-----------------------------------------------------------------------------
// Draw sprite-card based materials
//-----------------------------------------------------------------------------
void CVMTPreviewPanel::RenderSpriteCard( const Vector &vCenter, float flRadius )
{
CMatRenderContextPtr pRenderContext( MaterialSystem() );
IMesh *pMesh = pRenderContext->GetDynamicMesh();
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
// Draw a polygon the size of the panel
meshBuilder.Position3fv( vCenter.Base() );
meshBuilder.Color4ub( 255, 255, 255, 255 );
meshBuilder.TexCoord4f( 0, 0.0f, 0.0f, 1.0f, 1.0f );
meshBuilder.TexCoord4f( 1, 0.0f, 0.0f, 1.0f, 1.0f );
meshBuilder.TexCoord4f( 2, 0.0f, 0.0f, flRadius, 0.0f );
meshBuilder.TexCoord2f( 3, 0, 0 );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( vCenter.Base() );
meshBuilder.Color4ub( 255, 255, 255, 255 );
meshBuilder.TexCoord4f( 0, 0.0f, 0.0f, 1.0f, 1.0f );
meshBuilder.TexCoord4f( 1, 0.0f, 0.0f, 1.0f, 1.0f );
meshBuilder.TexCoord4f( 2, 0.0f, 0.0f, flRadius, 0.0f );
meshBuilder.TexCoord2f( 3, 0, 1 );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( vCenter.Base() );
meshBuilder.Color4ub( 255, 255, 255, 255 );
meshBuilder.TexCoord4f( 0, 0.0f, 0.0f, 1.0f, 1.0f );
meshBuilder.TexCoord4f( 1, 0.0f, 0.0f, 1.0f, 1.0f );
meshBuilder.TexCoord4f( 2, 0.0f, 0.0f, flRadius, 0.0f );
meshBuilder.TexCoord2f( 3, 1, 1 );
meshBuilder.AdvanceVertex();
meshBuilder.Position3fv( vCenter.Base() );
meshBuilder.Color4ub( 255, 255, 255, 255 );
meshBuilder.TexCoord4f( 0, 0.0f, 0.0f, 1.0f, 1.0f );
meshBuilder.TexCoord4f( 1, 0.0f, 0.0f, 1.0f, 1.0f );
meshBuilder.TexCoord4f( 2, 0.0f, 0.0f, flRadius, 0.0f );
meshBuilder.TexCoord2f( 3, 1, 0 );
meshBuilder.AdvanceVertex();
meshBuilder.End();
pMesh->Draw();
}
//-----------------------------------------------------------------------------
// Paints a regular texture
//-----------------------------------------------------------------------------
void CVMTPreviewPanel::DrawRectangle( void )
{
// Get the aspect ratio of the material
int tw = m_Material->GetMappingWidth();
int th = m_Material->GetMappingHeight();
if ( tw <= 0 || th <= 0 )
return;
int w, h;
GetSize( w, h );
if ( w == 0 || h == 0 )
return;
SetupOrthoMatrix( w, h );
SetupLightingState();
CMatRenderContextPtr pRenderContext( MaterialSystem() );
pRenderContext->MatrixMode( MATERIAL_VIEW );
pRenderContext->LoadIdentity();
pRenderContext->MatrixMode( MATERIAL_MODEL );
pRenderContext->LoadIdentity();
IMesh* pMesh = pRenderContext->GetDynamicMesh();
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, 4, 4 );
bool bIsUsingLightmap = m_Material->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_LIGHTMAP );
bool bIsUsingBumpedLightmap = m_Material->GetPropertyFlag( MATERIAL_PROPERTY_NEEDS_BUMPED_LIGHTMAPS );
int nLightmapWidth = m_pLightmapTexture->GetActualWidth();
float flHalfLuxel = 0.5f / nLightmapWidth;
Vector2D halfTexel( 0.5f / tw, 0.5f / th );
Vector vecNormal( 0.0f, 0.0f, 1.0f );
Vector4D vecTangentS( 1.0f, 0.0f, 0.0f, 1.0f );
Vector vecTangentT;
CrossProduct( vecNormal, vecTangentS.AsVector3D(), vecTangentT );
float screenaspect = (float)tw / (float)th;
float aspect = (float)w / (float)h;
float ratio = screenaspect / aspect;
// Screen is wider, need bars at top and bottom
int x2, y2;
int x, y;
x = y = 0;
int nXBorder = w > 15 ? 5 : w / 3;
int nYBorder = h > 15 ? 5 : h / 3;
w -= 2 * nXBorder;
h -= 2 * nYBorder;
if ( ratio > 1.0f )
{
int usetall = (float)w / screenaspect;
y = ( h - usetall ) / 2;
h = usetall;
}
// Screen is narrower, need bars at left/right
else
{
int usewide = (float)h * screenaspect;
x = ( w - usewide ) / 2;
w = usewide;
}
x += nXBorder;
y += nYBorder;
x2 = x+w; y2 = y+h;
float u = halfTexel.x;
float v = halfTexel.y;
float u1_l, u1_r, v1_t, v1_b;
float u2_l, u2_r, v2_t, v2_b;
u1_l = u2_l = u;
u1_r = u2_r = 1.0f - u;
v1_t = v2_t = v;
v1_b = v2_b = 1.0f - v;
if ( bIsUsingLightmap )
{
u1_l = v1_t = flHalfLuxel;
u1_r = v1_b = 0.25 - flHalfLuxel;
if ( bIsUsingBumpedLightmap )
{
u2_l = u2_r = 0.25f;
v2_t = v2_b = 0.0f;
}
}
meshBuilder.Position3f( x, y2, 0.0f );
meshBuilder.Normal3fv( vecNormal.Base() );
meshBuilder.Color4ub( 255, 0, 0, 255 );
meshBuilder.TexCoord2f( 0, u, v );
meshBuilder.TexCoord2f( 1, u1_l, v1_t );
meshBuilder.TexCoord2f( 2, u2_l, v2_t );
meshBuilder.TangentS3fv( vecTangentS.Base() );
meshBuilder.TangentT3fv( vecTangentT.Base() );
meshBuilder.BoneWeight( 0, 1.0f );
meshBuilder.BoneMatrix( 0, 0 );
meshBuilder.UserData( vecTangentS.Base() );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( x, y, 0.0f );
meshBuilder.Normal3fv( vecNormal.Base() );
meshBuilder.Color4ub( 255, 255, 255, 64 );
meshBuilder.TexCoord2f( 0, u, 1.0f - v );
meshBuilder.TexCoord2f( 1, u1_l, v1_b );
meshBuilder.TexCoord2f( 2, u2_l, v2_b );
meshBuilder.TangentS3fv( vecTangentS.Base() );
meshBuilder.TangentT3fv( vecTangentT.Base() );
meshBuilder.BoneWeight( 0, 1.0f );
meshBuilder.BoneMatrix( 0, 0 );
meshBuilder.UserData( vecTangentS.Base() );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( x2, y2, 0.0f );
meshBuilder.Normal3fv( vecNormal.Base() );
meshBuilder.Color4ub( 0, 0, 255, 255 );
meshBuilder.TexCoord2f( 0, 1.0f - u, v );
meshBuilder.TexCoord2f( 1, u1_r, v1_t );
meshBuilder.TexCoord2f( 2, u2_r, v2_t );
meshBuilder.TangentS3fv( vecTangentS.Base() );
meshBuilder.TangentT3fv( vecTangentT.Base() );
meshBuilder.BoneWeight( 0, 1.0f );
meshBuilder.BoneMatrix( 0, 0 );
meshBuilder.UserData( vecTangentS.Base() );
meshBuilder.AdvanceVertex();
meshBuilder.Position3f( x2, y, 0.0f );
meshBuilder.Normal3fv( vecNormal.Base() );
meshBuilder.Color4ub( 0, 255, 0, 64 );
meshBuilder.TexCoord2f( 0, 1.0f - u, 1.0f - v );
meshBuilder.TexCoord2f( 1, u1_r, v1_b );
meshBuilder.TexCoord2f( 2, u2_r, v2_b );
meshBuilder.TangentS3fv( vecTangentS.Base() );
meshBuilder.TangentT3fv( vecTangentT.Base() );
meshBuilder.BoneWeight( 0, 1.0f );
meshBuilder.BoneMatrix( 0, 0 );
meshBuilder.UserData( vecTangentS.Base() );
meshBuilder.AdvanceVertex();
meshBuilder.FastIndex( 0 );
meshBuilder.FastIndex( 1 );
meshBuilder.FastIndex( 2 );
meshBuilder.FastIndex( 3 );
meshBuilder.End();
pMesh->Draw();
}
//-----------------------------------------------------------------------------
// Paints a cubemap texture
//-----------------------------------------------------------------------------
void CVMTPreviewPanel::DrawSphere( void )
{
float flNewTime = Plat_FloatTime();
// Circle the camera around the origin
VMatrix rot;
MatrixBuildRotateZ( rot, ROTATION_SPEED * (flNewTime - m_flLastRotationTime ) );
Vector vecTemp;
Vector3DMultiply( rot, m_vecCameraDirection, vecTemp );
m_vecCameraDirection = vecTemp;
m_flLastRotationTime = flNewTime;
int w, h;
GetSize( w, h );
SetupProjectionMatrix( w, h );
SetupLightingState();
LookAt( vec3_origin, VIEW_DISTANCE );
// Draw a sphere at the origin
if ( !m_Material->IsSpriteCard() )
{
RenderSphere( vec3_origin, 10.0f, 20, 20 );
}
else
{
RenderSpriteCard( vec3_origin, 10.0f );
}
}
//-----------------------------------------------------------------------------
// Sets the camera to look at the the thing we're spinning around
//-----------------------------------------------------------------------------
void CVMTPreviewPanel::LookAt( const Vector &vecLookAt, 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 = FOV;
// 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 );
}
float flDistance = flRadius / sin( flFOVx );
Vector vecMDLOrigin = vecLookAt;
Vector vecCameraOrigin;
VectorMA( vecMDLOrigin, -flDistance, m_vecCameraDirection, vecCameraOrigin );
CMatRenderContextPtr pRenderContext( MaterialSystem() );
QAngle angles;
VectorAngles( m_vecCameraDirection, angles );
pRenderContext->MatrixMode( MATERIAL_VIEW );
pRenderContext->LoadIdentity();
// convert from a right handed system to a left handed system
// since dx for wants it that way.
// pRenderContext->Scale( 1.0f, 1.0f, -1.0f );
pRenderContext->Rotate( -90, 1, 0, 0 ); // put Z going up
pRenderContext->Rotate( 90, 0, 0, 1 ); // put Z going up
pRenderContext->Rotate( -angles[2], 1, 0, 0 );
pRenderContext->Rotate( -angles[0], 0, 1, 0 );
pRenderContext->Rotate( -angles[1], 0, 0, 1 );
pRenderContext->Translate( -vecCameraOrigin[0], -vecCameraOrigin[1], -vecCameraOrigin[2] );
}
//-----------------------------------------------------------------------------
// Set up a projection matrix for a 90 degree fov
//-----------------------------------------------------------------------------
void CVMTPreviewPanel::SetupProjectionMatrix( int nWidth, int nHeight )
{
VMatrix proj;
float flFOV = FOV;
float flZNear = ZNEAR;
float flZFar = ZFAR;
float flApsectRatio = (nHeight != 0.0f) ? (float)nWidth / (float)nHeight : 100.0f;
float halfWidth = tan( flFOV * M_PI / 360.0 );
float halfHeight = halfWidth / flApsectRatio;
memset( proj.Base(), 0, sizeof( proj ) );
proj[0][0] = 1.0f / halfWidth;
proj[1][1] = 1.0f / halfHeight;
proj[2][2] = flZFar / ( flZNear - flZFar );
proj[3][2] = -1.0f;
proj[2][3] = flZNear * flZFar / ( flZNear - flZFar );
CMatRenderContextPtr pRenderContext( MaterialSystem() );
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
pRenderContext->LoadMatrix( proj );
}
//-----------------------------------------------------------------------------
// Set up a orthographic projection matrix
//-----------------------------------------------------------------------------
void CVMTPreviewPanel::SetupOrthoMatrix( int nWidth, int nHeight )
{
CMatRenderContextPtr pRenderContext( MaterialSystem() );
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
pRenderContext->LoadIdentity();
pRenderContext->Ortho( 0, 0, nWidth, nHeight, -1.0f, 1.0f );
}
//-----------------------------------------------------------------------------
// Power of two FB texture
//-----------------------------------------------------------------------------
static CTextureReference s_pPowerOfTwoFrameBufferTexture;
static ITexture *GetPowerOfTwoFrameBufferTexture( void )
{
if( !s_pPowerOfTwoFrameBufferTexture )
{
s_pPowerOfTwoFrameBufferTexture.Init( vgui::MaterialSystem()->FindTexture( "_rt_PowerOfTwoFB", TEXTURE_GROUP_RENDER_TARGET ) );
}
return s_pPowerOfTwoFrameBufferTexture;
}
//-----------------------------------------------------------------------------
// Paints the texture
//-----------------------------------------------------------------------------
void CVMTPreviewPanel::Paint( void )
{
CMatRenderContextPtr pRenderContext( MaterialSystem() );
int w, h;
GetSize( w, h );
vgui::MatSystemSurface()->Begin3DPaint( 0, 0, w, h );
// Deal with refraction
if ( m_Material->NeedsPowerOfTwoFrameBufferTexture() )
{
ITexture *pTexture = GetPowerOfTwoFrameBufferTexture();
if ( pTexture && !pTexture->IsError() )
{
pRenderContext->CopyRenderTargetToTexture( pTexture );
pRenderContext->SetFrameBufferCopyTexture( pTexture );
}
}
pRenderContext->ClearColor4ub( 76, 88, 68, 255 );
pRenderContext->ClearBuffers( true, true );
pRenderContext->FogMode( MATERIAL_FOG_NONE );
pRenderContext->SetNumBoneWeights( 0 );
pRenderContext->Bind( m_Material );
pRenderContext->BindLightmapTexture( m_pLightmapTexture );
pRenderContext->BindLocalCubemap( m_DefaultEnvCubemap );
if ( m_bDrawIn3DMode || m_Material->IsSpriteCard() )
{
DrawSphere();
}
else
{
DrawRectangle();
}
vgui::MatSystemSurface()->End3DPaint( );
}

View File

@ -0,0 +1,71 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================
#include "filesystem.h"
#include "matsys_controls/vtfpicker.h"
#include "matsys_controls/vtfpreviewpanel.h"
#include "vgui_controls/Splitter.h"
using namespace vgui;
//-----------------------------------------------------------------------------
//
// Asset Picker with no preview
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CVTFPicker::CVTFPicker( vgui::Panel *pParent ) :
BaseClass( pParent, "VTF Files", "vtf", "materials", "vtfName" )
{
// Horizontal splitter for preview
m_pPreviewSplitter = new Splitter( this, "PreviewSplitter", SPLITTER_MODE_VERTICAL, 1 );
vgui::Panel *pSplitterLeftSide = m_pPreviewSplitter->GetChild( 0 );
vgui::Panel *pSplitterRightSide = m_pPreviewSplitter->GetChild( 1 );
// VTF preview
m_pVTFPreview = new CVTFPreviewPanel( pSplitterRightSide, "VTFPreview" );
// Standard browser controls
CreateStandardControls( pSplitterLeftSide );
LoadControlSettingsAndUserConfig( "resource/vtfpicker.res" );
}
CVTFPicker::~CVTFPicker()
{
}
//-----------------------------------------------------------------------------
// Derived classes have this called when the previewed asset changes
//-----------------------------------------------------------------------------
void CVTFPicker::OnSelectedAssetPicked( const char *pAssetName )
{
m_pVTFPreview->SetVTF( pAssetName );
}
//-----------------------------------------------------------------------------
//
// Purpose: Modal picker frame
//
//-----------------------------------------------------------------------------
CVTFPickerFrame::CVTFPickerFrame( vgui::Panel *pParent, const char *pTitle ) :
BaseClass( pParent )
{
SetAssetPicker( new CVTFPicker( this ) );
LoadControlSettingsAndUserConfig( "resource/vtfpickerframe.res" );
SetTitle( pTitle, false );
}

View File

@ -0,0 +1,398 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//===========================================================================//
#include "matsys_controls/vtfpreviewpanel.h"
#include "matsys_controls/matsyscontrols.h"
#include "VGuiMatSurface/IMatSystemSurface.h"
#include "materialsystem/MaterialSystemUtil.h"
#include "materialsystem/imaterialsystem.h"
#include "materialsystem/itexture.h"
#include "materialsystem/imesh.h"
#include "tier1/KeyValues.h"
using namespace vgui;
#define FOV 90.0f
#define ZNEAR 0.1f
#define ZFAR 2000.0f
#define ROTATION_SPEED 120.0f // degrees/sec
//-----------------------------------------------------------------------------
//
// VTF Preview panel
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// constructor
//-----------------------------------------------------------------------------
CVTFPreviewPanel::CVTFPreviewPanel( vgui::Panel *pParent, const char *pName ) :
BaseClass( pParent, pName )
{
SetVTF( "//platform/materials/vgui/vtfnotloaded", true );
m_nTextureID = MatSystemSurface()->CreateNewTextureID( false );
}
CVTFPreviewPanel::~CVTFPreviewPanel()
{
if ( vgui::surface() && m_nTextureID != -1 )
{
vgui::surface()->DestroyTextureID( m_nTextureID );
m_nTextureID = -1;
}
}
//-----------------------------------------------------------------------------
// Sets the current VTF
//-----------------------------------------------------------------------------
void CVTFPreviewPanel::SetVTF( const char *pFullPath, bool bLoadImmediately )
{
m_PreviewTexture.Init( pFullPath, "editor texture" );
m_VTFName = pFullPath;
KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
if ( m_PreviewTexture->IsCubeMap() )
{
pVMTKeyValues->SetString( "$envmap", pFullPath );
}
else if ( m_PreviewTexture->IsNormalMap() )
{
pVMTKeyValues->SetString( "$bumpmap", pFullPath );
}
else
{
pVMTKeyValues->SetString( "$basetexture", pFullPath );
}
pVMTKeyValues->SetInt( "$nocull", 1 );
pVMTKeyValues->SetInt( "$nodebug", 1 );
m_PreviewMaterial.Init( MaterialSystem()->CreateMaterial( pFullPath, pVMTKeyValues ));
MatSystemSurface()->DrawSetTextureMaterial( m_nTextureID, m_PreviewMaterial );
// Reset the camera direction
m_vecCameraDirection.Init( 1.0f, 0.0f, 0.0f );
m_flLastRotationTime = Plat_FloatTime();
}
//-----------------------------------------------------------------------------
// Gets the current VTF
//-----------------------------------------------------------------------------
const char *CVTFPreviewPanel::GetVTF() const
{
return m_VTFName;
}
//-----------------------------------------------------------------------------
// Draw a sphere
//-----------------------------------------------------------------------------
void CVTFPreviewPanel::RenderSphere( const Vector &vCenter, float flRadius, int nTheta, int nPhi )
{
CMatRenderContextPtr pRenderContext( MaterialSystem() );
int nVertices = nTheta * nPhi;
int nIndices = 2 * ( nTheta + 1 ) * ( nPhi - 1 );
pRenderContext->FogMode( MATERIAL_FOG_NONE );
pRenderContext->SetNumBoneWeights( 0 );
pRenderContext->Bind( m_PreviewMaterial );
IMesh* pMesh = pRenderContext->GetDynamicMesh();
CMeshBuilder meshBuilder;
meshBuilder.Begin( pMesh, MATERIAL_TRIANGLE_STRIP, nVertices, nIndices );
//
// Build the index buffer.
//
int i, j;
for ( i = 0; i < nPhi; ++i )
{
for ( j = 0; j < nTheta; ++j )
{
float u = j / ( float )(nTheta - 1);
float v = i / ( float )(nPhi - 1);
float theta = ( j != nTheta-1 ) ? 2.0f * M_PI * u : 0.0f;
float phi = M_PI * v;
Vector vecPos;
vecPos.x = flRadius * sin(phi) * cos(theta);
vecPos.y = flRadius * cos(phi);
vecPos.z = -flRadius * sin(phi) * sin(theta);
Vector vecNormal = vecPos;
VectorNormalize( vecNormal );
Vector4D vecTangentS;
Vector vecTangentT;
vecTangentS.Init( vecPos.z, -vecPos.x, 0.0f, 1.0f );
if ( VectorNormalize( vecTangentS.AsVector3D() ) == 0.0f )
{
vecTangentS.Init( 1.0f, 0.0f, 0.0f, 1.0f );
}
CrossProduct( vecNormal, vecTangentS.AsVector3D(), vecTangentT );
unsigned char red = (int)( u * 255.0f );
unsigned char green = (int)( v * 255.0f );
unsigned char blue = (int)( v * 255.0f );
unsigned char alpha = (int)( v * 255.0f );
vecPos += vCenter;
float u1, u2, v1, v2;
u1 = u2 = u;
v1 = v2 = v;
meshBuilder.Position3fv( vecPos.Base() );
meshBuilder.Normal3fv( vecNormal.Base() );
meshBuilder.Color4ub( red, green, blue, alpha );
meshBuilder.TexCoord2f( 0, u, v );
meshBuilder.TexCoord2f( 1, u1, v1 );
meshBuilder.TexCoord2f( 2, u2, v2 );
meshBuilder.TangentS3fv( vecTangentS.Base() );
meshBuilder.TangentT3fv( vecTangentT.Base() );
meshBuilder.BoneWeight( 0, 1.0f );
meshBuilder.BoneMatrix( 0, 0 );
meshBuilder.UserData( vecTangentS.Base() );
meshBuilder.AdvanceVertex();
}
}
//
// Emit the triangle strips.
//
int idx = 0;
for ( i = 0; i < nPhi - 1; ++i )
{
for ( j = 0; j < nTheta; ++j )
{
idx = nTheta * i + j;
meshBuilder.FastIndex( idx );
meshBuilder.FastIndex( idx + nTheta );
}
//
// Emit a degenerate triangle to skip to the next row without
// a connecting triangle.
//
if ( i < nPhi - 2 )
{
meshBuilder.FastIndex( idx + 1 );
meshBuilder.FastIndex( idx + 1 + nTheta );
}
}
meshBuilder.End();
pMesh->Draw();
}
//-----------------------------------------------------------------------------
// Paints a regular texture
//-----------------------------------------------------------------------------
void CVTFPreviewPanel::PaintStandardTexture( void )
{
int x, y, w, h;
x = y = 0;
GetSize( w, h );
vgui::surface()->DrawSetTexture( m_nTextureID );
vgui::surface()->DrawSetColor( 255, 255, 255, 255 );
// Get the aspect ratio of the texture
int tw = m_PreviewTexture->GetActualWidth();
int th = m_PreviewTexture->GetActualHeight();
if ( th > 0 && h > 0 )
{
float screenaspect = (float)tw / (float)th;
float aspect = (float)w / (float)h;
float ratio = screenaspect / aspect;
// Screen is wider, need bars at top and bottom
if ( ratio > 1.0f )
{
int usetall = (float)w / screenaspect;
y = ( h - usetall ) / 2;
h = usetall;
}
// Screen is narrower, need bars at left/right
else
{
int usewide = (float)h * screenaspect;
x = ( w - usewide ) / 2;
w = usewide;
}
}
vgui::surface()->DrawTexturedRect( x, y, x+w, y+h );
}
//-----------------------------------------------------------------------------
// Paints a normalmap texture
//-----------------------------------------------------------------------------
void CVTFPreviewPanel::PaintNormalMapTexture( void )
{
}
//-----------------------------------------------------------------------------
// Paints a volume texture
//-----------------------------------------------------------------------------
void CVTFPreviewPanel::PaintVolumeTexture( void )
{
}
//-----------------------------------------------------------------------------
// Paints a cubemap texture
//-----------------------------------------------------------------------------
void CVTFPreviewPanel::PaintCubeTexture( void )
{
float flNewTime = Plat_FloatTime();
// Circle the camera around the origin
VMatrix rot;
MatrixBuildRotateZ( rot, ROTATION_SPEED * (flNewTime - m_flLastRotationTime ) );
Vector vecTemp;
Vector3DMultiply( rot, m_vecCameraDirection, vecTemp );
m_vecCameraDirection = vecTemp;
m_flLastRotationTime = flNewTime;
LookAt( vec3_origin, 12.0f );
// Draw a sphere at the origin
RenderSphere( vec3_origin, 10.0f, 20, 20 );
}
//-----------------------------------------------------------------------------
// Sets the camera to look at the the thing we're spinning around
//-----------------------------------------------------------------------------
void CVTFPreviewPanel::LookAt( const Vector &vecLookAt, 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 = FOV;
// 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 );
}
float flDistance = flRadius / sin( flFOVx );
Vector vecMDLOrigin = vecLookAt;
Vector vecCameraOrigin;
VectorMA( vecMDLOrigin, -flDistance, m_vecCameraDirection, vecCameraOrigin );
CMatRenderContextPtr pRenderContext( MaterialSystem() );
QAngle angles;
VectorAngles( m_vecCameraDirection, angles );
pRenderContext->MatrixMode( MATERIAL_VIEW );
pRenderContext->LoadIdentity();
// convert from a right handed system to a left handed system
// since dx for wants it that way.
// pRenderContext->Scale( 1.0f, 1.0f, -1.0f );
pRenderContext->Rotate( -90, 1, 0, 0 ); // put Z going up
pRenderContext->Rotate( 90, 0, 0, 1 ); // put Z going up
pRenderContext->Rotate( -angles[2], 1, 0, 0 );
pRenderContext->Rotate( -angles[0], 0, 1, 0 );
pRenderContext->Rotate( -angles[1], 0, 0, 1 );
pRenderContext->Translate( -vecCameraOrigin[0], -vecCameraOrigin[1], -vecCameraOrigin[2] );
}
//-----------------------------------------------------------------------------
// Set up a projection matrix for a 90 degree fov
//-----------------------------------------------------------------------------
void CVTFPreviewPanel::SetupProjectionMatrix( int nWidth, int nHeight )
{
CMatRenderContextPtr pRenderContext( MaterialSystem() );
VMatrix proj;
float flFOV = FOV;
float flZNear = ZNEAR;
float flZFar = ZFAR;
float flApsectRatio = (nHeight != 0.0f) ? (float)nWidth / (float)nHeight : 100.0f;
#if 1
float halfWidth = tan( flFOV * M_PI / 360.0 );
float halfHeight = halfWidth / flApsectRatio;
#else
float halfHeight = tan( flFOV * M_PI / 360.0 );
float halfWidth = flApsectRatio * halfHeight;
#endif
memset( proj.Base(), 0, sizeof( proj ) );
proj[0][0] = 1.0f / halfWidth;
proj[1][1] = 1.0f / halfHeight;
proj[2][2] = flZFar / ( flZNear - flZFar );
proj[3][2] = -1.0f;
proj[2][3] = flZNear * flZFar / ( flZNear - flZFar );
pRenderContext->MatrixMode( MATERIAL_PROJECTION );
pRenderContext->LoadMatrix( proj );
}
//-----------------------------------------------------------------------------
// Paints the texture
//-----------------------------------------------------------------------------
void CVTFPreviewPanel::Paint( void )
{
if ( !m_PreviewTexture->IsCubeMap() && /*!m_PreviewTexture->IsNormalMap() &&*/ !m_PreviewTexture->IsVolumeTexture() )
{
PaintStandardTexture();
return;
}
CMatRenderContextPtr pRenderContext( MaterialSystem() );
int w, h;
GetSize( w, h );
vgui::MatSystemSurface()->Begin3DPaint( 0, 0, w, h );
pRenderContext->ClearColor4ub( 76, 88, 68, 255 );
pRenderContext->ClearBuffers( true, true );
SetupProjectionMatrix( w, h );
if ( m_PreviewTexture->IsCubeMap() )
{
PaintCubeTexture();
}
else if ( m_PreviewTexture->IsNormalMap() )
{
PaintNormalMapTexture();
}
else if ( m_PreviewTexture->IsVolumeTexture() )
{
PaintVolumeTexture();
}
vgui::MatSystemSurface()->End3DPaint( );
}

View File

@ -19,6 +19,7 @@ $Group "game"
"client"
"launcher_main"
"mathlib"
"matsys_controls"
"raytrace"
"server"
"tier1"
@ -40,6 +41,7 @@ $Group "everything"
"height2normal"
"launcher_main"
"mathlib"
"matsys_controls"
"motionmapper"
"phonemeextractor"
"qc_eyes"

View File

@ -65,6 +65,11 @@ $Project "mathlib"
"mathlib\mathlib.vpc"
}
$Project "matsys_controls"
{
"vgui2\matsys_controls\matsys_controls.vpc"
}
$Project "motionmapper"
{
"utils\motionmapper\motionmapper.vpc" [$WINDOWS]

View File

@ -58,6 +58,8 @@ $Configuration
$DisableSpecificWarnings "$BASE;4577" [$AT_LEAST_VS2015] // 'noexcept' used with no exception handling mode specified; termination on exception is not guaranteed. Specify /EHsc
$DisableSpecificWarnings "$BASE;4091" [$AT_LEAST_VS2015] // 'keyword' : ignored on left of 'type' when no variable is declared
$DisableSpecificWarnings "$BASE;4355" [$AT_LEAST_VS2015]
// Started appearning now since compiler updates... We have warnings as errors on Win32, so disable this there.
$DisableSpecificWarnings "$BASE;4101" [$WIN32 && $AT_LEAST_VS2022] // 'Start': unreferenced local variable