You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
7631 lines
228 KiB
7631 lines
228 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//============================================================================= |
|
// |
|
// TODO: |
|
// * Bring in Jeff Hameluck's translucency support: |
|
// QC with any $translucent 1 VMT should have $mostlyopaque |
|
// * Add help icons with tooltips on valid asset constraints |
|
// |
|
// Maybe TODO: |
|
// * Add wireframe view to preview |
|
// * Fix issues with gesture support (no animation blending/easing, no weapon state logic) |
|
// |
|
//============================================================================= |
|
|
|
#include "cbase.h" |
|
|
|
#include "tier2/tier2.h" |
|
#include "tier2/p4helpers.h" |
|
#include "tier2/fileutils.h" |
|
#include "ienginevgui.h" |
|
#include "imageutils.h" |
|
#include "filesystem.h" |
|
#include "vgui_controls/FileOpenDialog.h" |
|
#include "vgui_controls/ImagePanel.h" |
|
#include "vgui_controls/Label.h" |
|
#include "vgui_bitmapimage.h" |
|
#include "bitmap/bitmap.h" |
|
#include "itemtest/itemtest.h" |
|
|
|
#include "econ_controls.h" |
|
#include "econ_item_system.h" |
|
#include "tf_item_inventory.h" |
|
#include "c_tf_player.h" |
|
#include "confirm_dialog.h" |
|
#include "steampublishedfiles/publish_file_dialog.h" |
|
#include "vgui/store/v2/tf_store_preview_item2.h" |
|
#include "vgui/tf_playermodelpanel.h" |
|
#include "bone_setup.h" |
|
|
|
#include "scenefilecache/ISceneFileCache.h" |
|
|
|
#include "workshop/item_import.h" |
|
|
|
#include "choreoscene.h" |
|
#include "choreoactor.h" |
|
#include "choreochannel.h" |
|
|
|
#include "../public/zip_utils.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include <tier0/memdbgon.h> |
|
|
|
|
|
static const char *kClassFolders[TF_LAST_NORMAL_CLASS] = { |
|
"", // TF_CLASS_UNDEFINED |
|
"scout", // TF_CLASS_SCOUT |
|
"sniper", // TF_CLASS_SNIPER, |
|
"soldier", // TF_CLASS_SOLDIER, |
|
"demo", // TF_CLASS_DEMOMAN, |
|
"medic", // TF_CLASS_MEDIC, |
|
"heavy", //TF_CLASS_HEAVYWEAPONS, |
|
"pyro", // TF_CLASS_PYRO, |
|
"spy", // TF_CLASS_SPY, |
|
"engineer", // TF_CLASS_ENGINEER, |
|
}; |
|
static const char *kClassFolderMulticlass = "all_class"; |
|
|
|
static const int NUM_IMPORT_LODS = 3; |
|
static const int NUM_IMPORT_MATERIALS_PER_TEAM = 2; |
|
static const int MAX_MATERIAL_COUNT = NUM_IMPORT_MATERIALS_PER_TEAM * 2; |
|
static const int MAX_TEXT_EDIT_SIZE = 8192; |
|
static const int MAX_TAUNT_DURATION = 30.f; |
|
|
|
static const int kStartWorkshopItemIndex = 30000; |
|
|
|
static const char *kBodygroupArray[] = |
|
{ |
|
"backpack", |
|
"dogtags", |
|
"grenades", |
|
"hands", |
|
"hat", |
|
"head", |
|
"headphones", |
|
"shoes", |
|
"shoes_socks", |
|
}; |
|
|
|
extern IFileSystem *g_pFullFileSystem; |
|
|
|
// This should be a constant since it's in the game directory hierarchy now |
|
//static ConVar tf_steam_workshop_dir( "tf_steam_workshop_dir", "workshop", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Directory used to hold import sessions for the Steam Workshop." ); |
|
static const char *kSteamWorkshopDir = "%s/import_source"; |
|
static const char *kWorkshopSchemaFile = "scripts/items/unencrypted/_items_workshop.txt"; |
|
static const char *kWorkshopSoundScriptFile = "scripts/game_sounds_taunt_workshop.txt"; |
|
|
|
static ConVar tf_steam_workshop_import_icon_path( "tf_steam_workshop_import_icon_path", "", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Default location to load backpack icons from" ); |
|
static ConVar tf_steam_workshop_import_model_path( "tf_steam_workshop_import_model_path", "", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Default location to load models from" ); |
|
static ConVar tf_steam_workshop_import_material_path( "tf_steam_workshop_import_material_path", "", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Default location to load materials from" ); |
|
|
|
#ifdef STAGING_ONLY |
|
static ConVar tf_steam_workshop_max_taunt_duration( "tf_steam_workshop_max_taunt_duration", "-1" ); |
|
#endif // STAGING_ONLY |
|
|
|
// Item data tokens |
|
static const char *kItemName = "name"; |
|
static const char *kWorkshopName = "import_name"; |
|
static const char *kTFEnglishName = "tf_english_name"; |
|
static const char *kItemPrefab = "prefab"; |
|
static const char *kItemIcon = "icon"; |
|
static const char *kItemPaintable = "paintable%d"; |
|
static const char *kAnimationLoopable = "loopable"; |
|
static const char *kClassQC = "Classes/%s/QC"; |
|
static const char *kClassQCI = "Classes/%s/QCI"; |
|
static const char *kClassLODN = "Classes/%s/LOD%d"; |
|
static const char *kClassLODNFile = "Classes/%s/LOD%d/file"; |
|
static const char *kClassAnimation = "Classes/%s/Animation"; |
|
static const char *kClassAnimationSourceFile = "Classes/%s/Animation/source_file"; |
|
static const char *kClassAnimationVCDFile = "Classes/%s/Animation/vcd_file"; |
|
static const char *kClassAnimationDuration = "Classes/%s/Animation/taunt_duration"; |
|
static const char *kMaterialN = "Materials/Material%d"; |
|
static const char *kMaterialSkinN = "Materials/Skins/%s/Material%d"; |
|
static const char *kMaterialSkinNFile = "Materials/Skins/%s/Material%d/%s_texture_file"; |
|
static const char *kMaterialSkinNVMT = "Materials/Skins/%s/Material%d/vmt"; |
|
static const char *kItemSchema = "ItemSchema"; |
|
static const char *kBuildOutput = "output"; |
|
static const char *kSkinType = "skin_type"; |
|
static const char *kEquipRegion = "equip_region"; |
|
static const char *kBodygroup = "bodygroup"; |
|
static const char *kPaintDefIndex = "paint_def_index"; |
|
static const char *kWorkshopID = "workshop_id"; |
|
|
|
// The default triangle budget for items |
|
static const int kDefaultTriangleBudget[] = { 1400, 1000, 700 }; |
|
COMPILE_TIME_ASSERT( ARRAYSIZE( kDefaultTriangleBudget ) == NUM_IMPORT_LODS ); |
|
|
|
static const int kDefaultBoneBudget = 5; |
|
|
|
static const char *kBuildResultMessages[] = { |
|
"", |
|
"#TF_ImportFile_BuildFailedNoSDK", |
|
"#TF_ImportFile_BuildFailedNoName", |
|
"#TF_ImportFile_BuildFailedNoType", |
|
"#TF_ImportFile_BuildFailedNoModels", |
|
"#TF_ImportFile_BuildFailedNumLODMismatch", |
|
"#TF_ImportFile_BuildFailedNoMaterials", |
|
"#TF_ImportFile_BuildFailedNumMaterialMismatch", |
|
"#TF_ImportFile_BuildFailedNoBackpackIcon", |
|
"#TF_ImportFile_BuildFailedBadName", |
|
"TF English Name already exists in item schema.", |
|
"#TF_ImportFile_BuildFailedBadType", |
|
"#TF_ImportFile_BuildFailedBadModel", |
|
"#TF_ImportFile_BuildFailedBadMaterialType", |
|
"#TF_ImportFile_BuildFailedBadMaterial", |
|
"#TF_ImportFile_BuildFailedMaterialMissingShader", |
|
"#TF_ImportFile_BuildFailedMaterialMissingCloak", |
|
"#TF_ImportFile_BuildFailedMaterialMissingBurning", |
|
"#TF_ImportFile_BuildFailedMaterialMissingJarate", |
|
"#TF_ImportFile_BuildFailedMaterialMissingPaintable", |
|
"#TF_ImportFile_BuildFailedMissingModel", |
|
"#TF_ImportFile_BuildFailedNeedMoreLOD", |
|
"#TF_ImportFile_BuildFailedComplexModel", |
|
"#TF_ImportFile_BuildFailedBadImage", |
|
"#TF_ImportFile_BuildFailedCompile", |
|
"#TF_ImportFile_BuildFailedNoWorkshopID", |
|
"#TF_ImportFile_ImageUnsupportedFileType", |
|
"#TF_ImportFile_ImageResolutionNotPowerOf2", |
|
"#TF_ImportFile_ImageResolutionOverLimit", |
|
"#TF_ImportFile_BuildFailedNoTaunts", |
|
"#TF_ImportFile_BuildFailedBadVCD", |
|
"#TF_ImportFile_BuildFailedVCDMissingEventSequence", |
|
"#TF_ImportFile_BuildFailedVCDEventSequenceTooLong", |
|
}; |
|
COMPILE_TIME_ASSERT( ARRAYSIZE( kBuildResultMessages ) == CTFFileImportDialog::NUM_BUILD_RESULTS ); |
|
|
|
static const char *kLoadResultMessages[ CTFFileImportDialog::NUM_LOAD_RESULTS ] = { |
|
"", |
|
"#TF_ImportFile_LoadFailedBadFile", |
|
"#TF_ImportFile_LoadFailedBadFile", |
|
"#TF_ImportFile_BuildFailedComplexModel", |
|
"#TF_ImportFile_LoadFailedTooManyBones", |
|
"#TF_ImportFile_LoadFailedBadFile", |
|
"#TF_ImportFile_LoadFailedTooManyMaterials", |
|
"#TF_ImportFile_LoadFailedMaterialCountMismatch", |
|
"#TF_ImportFile_LoadFailedAnimationTooLong", |
|
}; |
|
COMPILE_TIME_ASSERT( ARRAYSIZE( kLoadResultMessages ) == CTFFileImportDialog::NUM_LOAD_RESULTS ); |
|
|
|
static const char *kSaveResultMessages[ CTFFileImportDialog::NUM_SAVE_RESULTS ] = { |
|
"", |
|
"#TF_ImportFile_SaveFailedBadFile", |
|
}; |
|
COMPILE_TIME_ASSERT( ARRAYSIZE( kSaveResultMessages ) == CTFFileImportDialog::NUM_SAVE_RESULTS ); |
|
|
|
static const char *kWarningMessages[ CTFFileImportDialog::NUM_WARNINGS ] = |
|
{ |
|
"TF_ImportFile_Warning_BaseAlphaMask", |
|
}; |
|
COMPILE_TIME_ASSERT( ARRAYSIZE( kWarningMessages ) == CTFFileImportDialog::NUM_WARNINGS ); |
|
|
|
static const char *kLODLevels[] = |
|
{ |
|
"HIGH LOD", |
|
"MEDIUM LOD", |
|
"LOW LOD" |
|
}; |
|
COMPILE_TIME_ASSERT( ARRAYSIZE( kLODLevels ) == NUM_IMPORT_LODS ); |
|
|
|
static const char *kPrefabs[] = |
|
{ |
|
"hat", |
|
"misc", |
|
"taunt" |
|
}; |
|
COMPILE_TIME_ASSERT( ARRAYSIZE( kPrefabs ) == CTFFileImportDialog::PREFAB_COUNT ); |
|
|
|
static const char* kDefaultPrefab = "hat"; |
|
static const char* kDefaultEquipRegion = "hat"; |
|
|
|
// Poses that your character can do in the item preview |
|
static const char *kModelPoses[] = { |
|
"REF", |
|
"STAND", |
|
"CROUCH", |
|
"RUN", |
|
}; |
|
static const int kDefaultModelPoseIndex = 1; |
|
|
|
static const char *kModelActions[] = { |
|
"taunt_laugh.vcd", |
|
// The attack and reload animations don't work properly with the Heavy and Pyro |
|
//"gesture_attack", |
|
//"gesture_reload", |
|
}; |
|
static const int kDefaultModelActionIndex = 0; |
|
|
|
static const char* s_pszMaterialFilePrefixes[] = |
|
{ |
|
"base", |
|
"normal", |
|
"phongexponent", |
|
"selfillum" |
|
}; |
|
COMPILE_TIME_ASSERT( ARRAYSIZE( s_pszMaterialFilePrefixes ) == NUM_MATERIAL_TEXTURE_FILE_TYPE ); |
|
|
|
// Each preview needs a unique model name so it actually gets reloaded if it changes |
|
static int s_nLastPreviewModel; |
|
|
|
static const char* kDefaultBumpmap = "models/player/shared/shared_normal"; |
|
|
|
struct LightwarpInfo_t |
|
{ |
|
const char *pszName; |
|
const char *pszPath; |
|
}; |
|
|
|
static LightwarpInfo_t kLightwarps[] = |
|
{ |
|
{ "pyro", "models/player/pyro/pyro_lightwarp" }, |
|
{ "weapon", "models/lightwarps/weapon_lightwarp" }, |
|
{ "robot", "models/lightwarps/robot_lightwarp" }, |
|
{ "sentry1", "models/buildables/sentry1/sentry1_lightwarp" }, |
|
{ "sentry2", "models/buildables/sentry2/sentry2_lightwarp" }, |
|
{ "sentry3", "models/buildables/sentry3/sentry3_lightwarp" }, |
|
{ "ambassador", "models/weapons/c_items/c_ambassador_lightwarp" }, |
|
{ "jarate", "models/lightwarps/jarate_lightwarp" }, |
|
}; |
|
static const char *kLightwarpPath = "lightwarp_path"; |
|
|
|
struct EnvmapInfo_t |
|
{ |
|
const char *pszName; |
|
const char *pszPath; |
|
}; |
|
|
|
static EnvmapInfo_t kEnvmaps[] = |
|
{ |
|
{ "none", "" }, |
|
{ "world cube map", "env_cubemap" }, |
|
{ "saxxy gold", "effects/saxxy/saxxy_gold" }, |
|
{ "pyro land goggles", "effects/pyrocube" } |
|
}; |
|
static const char *kEnvmapPath = "envmap_path"; |
|
|
|
struct EnvmapMaskInfo_t |
|
{ |
|
const char *pszDisplayName; |
|
const char *pszVarName; |
|
}; |
|
|
|
static EnvmapMaskInfo_t kEnvmapMasks[] = |
|
{ |
|
{ "none", "" }, |
|
{ "base alpha", "$basealphaenvmapmask" }, |
|
{ "normal map alpha", "$normalmapalphaenvmapmask" } |
|
}; |
|
static const char *kEnvmapMaskVarName = "envmapmask_varname"; |
|
|
|
|
|
static float GetMaxTauntDuration() |
|
{ |
|
#ifdef STAGING_ONLY |
|
if ( tf_steam_workshop_max_taunt_duration.GetFloat() > 0 ) |
|
{ |
|
return tf_steam_workshop_max_taunt_duration.GetFloat(); |
|
} |
|
#endif // STAGING_ONLY |
|
return MAX_TAUNT_DURATION; |
|
} |
|
|
|
|
|
static const char *GetWorkshopSoundScriptFile() |
|
{ |
|
static char szCorrectCaseFilePath[MAX_PATH]; |
|
char szItemWorkshopSoundScriptAbsPath[MAX_PATH]; |
|
if ( GenerateFullPath( kWorkshopSoundScriptFile, "MOD", szItemWorkshopSoundScriptAbsPath, ARRAYSIZE( szItemWorkshopSoundScriptAbsPath ) ) ) |
|
{ |
|
g_pFullFileSystem->GetCaseCorrectFullPath( szItemWorkshopSoundScriptAbsPath, szCorrectCaseFilePath ); |
|
} |
|
else |
|
{ |
|
Warning( "Failed to GenerateFullPath %s\n", kWorkshopSoundScriptFile ); |
|
return NULL; |
|
} |
|
|
|
return szCorrectCaseFilePath; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
static void SetMessageFileVariable( KeyValues *pData, const char *pszFilePath ) |
|
{ |
|
if ( !pData ) |
|
return; |
|
|
|
wchar_t unicodeFile[MAX_PATH]; |
|
g_pVGuiLocalize->ConvertANSIToUnicode( pszFilePath, unicodeFile, sizeof(unicodeFile) ); |
|
pData->SetWString( "file", unicodeFile ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
static void ShowMessageBoxWithFile( const char *pTitle, const char *pText, const char *pszFilePath) |
|
{ |
|
KeyValuesAD pData( "data" ); |
|
SetMessageFileVariable( pData, pszFilePath ); |
|
ShowMessageBox( pTitle, pText, pData ); |
|
} |
|
|
|
static void SaveBrowsePath( ConVar &conVar, const char *pszFilePath ) |
|
{ |
|
char pszDirPath[MAX_PATH]; |
|
V_ExtractFilePath( pszFilePath, pszDirPath, sizeof(pszDirPath) ); |
|
conVar.SetValue( pszDirPath ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Save build output for presenting to the user |
|
//----------------------------------------------------------------------------- |
|
class CBuildLog : public CItemLog |
|
{ |
|
public: |
|
CBuildLog() : CItemLog(), m_log( 0, 0, CUtlBuffer::TEXT_BUFFER ) { } |
|
|
|
virtual void Log( ItemtestLogLevel_t nLogLevel, const char *pszMessage ) const |
|
{ |
|
static const char *pszIgnoredMessages[] = { |
|
"CDynamicFunction: " |
|
}; |
|
|
|
// See if this is a message we want to ignore in user output |
|
for ( int i = 0; i < ARRAYSIZE(pszIgnoredMessages); ++i ) |
|
{ |
|
if ( V_strncmp( pszMessage, pszIgnoredMessages[ i ], V_strlen( pszIgnoredMessages[ i ] ) ) == 0 ) |
|
return; |
|
} |
|
|
|
switch ( nLogLevel ) |
|
{ |
|
case kItemtest_Log_Info: |
|
::Msg( "%s", pszMessage ); |
|
break; |
|
case kItemtest_Log_Warning: |
|
::Warning( "%s", pszMessage ); |
|
break; |
|
case kItemtest_Log_Error: |
|
::Error( "%s", pszMessage ); |
|
break; |
|
} |
|
m_log.PutString( pszMessage ); |
|
} |
|
|
|
const char *Get() { return (char*)m_log.Base(); } |
|
|
|
protected: |
|
mutable CUtlBuffer m_log; |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Import text edit dialog |
|
//----------------------------------------------------------------------------- |
|
class CTFFileImportTextEditDialog : public vgui::Frame |
|
{ |
|
DECLARE_CLASS_SIMPLE( CTFFileImportTextEditDialog, Frame ); |
|
|
|
public: |
|
CTFFileImportTextEditDialog( vgui::Panel *parent, const char *pszTitle, const char *pszCommand = NULL ); |
|
|
|
virtual ~CTFFileImportTextEditDialog() { } |
|
|
|
virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); |
|
|
|
virtual void OnCommand( const char *command ); |
|
|
|
void HideCancelButton() { m_bShowCancelButton = false; } |
|
|
|
void SetText( const char *pszText ); |
|
bool GetText( char *pszText, int nMaxSize ); |
|
|
|
protected: |
|
bool m_bShowCancelButton; |
|
CUtlString m_sTitle; |
|
CUtlString m_sText; |
|
CUtlString m_sCommand; |
|
vgui::TextEntry *m_pTextEntry; |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFFileImportTextEditDialog::CTFFileImportTextEditDialog( vgui::Panel *parent, const char *pszTitle, const char *pszCommand ) : Frame( parent, "ImportFileTextEditDialog" ) |
|
, m_bShowCancelButton( true ) |
|
, m_sTitle( pszTitle ) |
|
, m_sText() |
|
, m_sCommand( pszCommand ) |
|
, m_pTextEntry( NULL ) |
|
{ |
|
vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme" ); |
|
SetScheme(scheme); |
|
SetProportional( true ); |
|
SetDeleteSelfOnClose( true ); |
|
SetTitle( "", false ); |
|
SetSizeable( false ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportTextEditDialog::ApplySchemeSettings( vgui::IScheme *pScheme ) |
|
{ |
|
BaseClass::ApplySchemeSettings( pScheme ); |
|
|
|
LoadControlSettings( "Resource/UI/ImportFileTextEditDialog.res" ); |
|
|
|
vgui::Label *pLabel = FindControl<vgui::Label>( "TitleLabel" ); |
|
if ( pLabel ) |
|
{ |
|
pLabel->SetText( m_sTitle ); |
|
} |
|
|
|
m_pTextEntry = FindControl<vgui::TextEntry>( "TextEntry" ); |
|
if ( m_pTextEntry ) |
|
{ |
|
m_pTextEntry->RequestFocus(); |
|
m_pTextEntry->SetMultiline( true ); |
|
m_pTextEntry->SetCatchEnterKey( true ); |
|
m_pTextEntry->SetVerticalScrollbar( true ); |
|
m_pTextEntry->SetText( m_sText ); |
|
} |
|
|
|
if ( !m_bShowCancelButton ) |
|
{ |
|
vgui::Panel *pButton = FindControl<vgui::Panel>( "ButtonClose" ); |
|
if ( pButton ) |
|
{ |
|
pButton->SetVisible( false ); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportTextEditDialog::OnCommand( const char *command ) |
|
{ |
|
if ( V_stricmp( command, "Done" ) == 0 ) |
|
{ |
|
if ( m_sCommand.IsEmpty() ) |
|
{ |
|
OnCommand( "Close" ); |
|
} |
|
else |
|
{ |
|
GetParent()->OnCommand( m_sCommand ); |
|
} |
|
} |
|
else |
|
{ |
|
BaseClass::OnCommand( command ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportTextEditDialog::SetText( const char *pszText ) |
|
{ |
|
m_sText = pszText; |
|
|
|
if ( m_pTextEntry ) |
|
{ |
|
m_pTextEntry->SetText( pszText ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportTextEditDialog::GetText( char *pszText, int nMaxSize ) |
|
{ |
|
if ( m_pTextEntry ) |
|
{ |
|
m_pTextEntry->GetText( pszText, nMaxSize ); |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Import material edit dialog |
|
//----------------------------------------------------------------------------- |
|
class CTFImportMaterialEditDialog : public vgui::Frame |
|
{ |
|
DECLARE_CLASS_SIMPLE( CTFImportMaterialEditDialog, Frame ); |
|
|
|
public: |
|
CTFImportMaterialEditDialog( vgui::Panel *parent, int nSkinIndex, int nMaterialIndex, KeyValues *pItemValues ); |
|
|
|
virtual ~CTFImportMaterialEditDialog() { } |
|
|
|
virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); |
|
|
|
virtual void OnCommand( const char *command ); |
|
|
|
MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", data ); |
|
MESSAGE_FUNC_CHARPTR( OnFileSelected, "FileSelected", fullpath ); |
|
|
|
void SetVMTKeyValues( const char *pszRedVMTText, const char *pszBlueVMTText ); |
|
KeyValues* GetVMTKeyValues( int nSkinIndex ); |
|
|
|
const char* GetBaseTextureFile( int nSkinIndex ) const { return m_strBaseTextureFile[nSkinIndex].String(); } |
|
const char* GetNormalTextureFile() const { return m_strNormalTextureFile.String(); } |
|
const char* GetPhongExponentTextureFile() const { return m_strPhongExponentTextureFile.String(); } |
|
const char* GetSelfIllumTextureFile() const { return m_bSelfIllumEnabled ? m_strSelfIllumTextureFile.String() : ""; } |
|
|
|
private: |
|
void OnCommandEditSkin( int nSkinIndex ); |
|
void OnCommandBrowseMaterial( MATERIAL_FILE_TYPE fileType ); |
|
|
|
void SetColorTintBase( int nSkinIndex, const char* pszColorTintBase ); |
|
void SetSelfIllumTint( int nSkinIndex, const char* pszSelfIllumTint ); |
|
|
|
void UpdateBackgroundTexture( int nSkinIndex ); |
|
|
|
void UpdateBaseTexture( const char *pszBaseTextureFile ); |
|
void UpdateNormalTexture( const char *pszNormalTextureFile ); |
|
void UpdatePhongExponentTexture( const char* pszPhongExponentTextureFile ); |
|
void UpdateSelfIllumTexture( const char *pszSelfIllumTextureFile ); |
|
|
|
void UpdateBaseMapAlphaPhongMask(); |
|
void UpdateRimMask(); |
|
void UpdateRimMaskDisplay( bool bEnable ); |
|
void UpdateHalfLambert(); |
|
void UpdateBlendTintByBaseAlpha(); |
|
void UpdateBlendTintColorOverBaseDisplay( bool bEnable ); |
|
void UpdateColorTintBase( int nSkinIndex, const char* pszColor ); |
|
void UpdateAdditive(); |
|
void UpdateTranslucent(); |
|
void UpdateAlphaTest(); |
|
void UpdateAlphaTestDiaplay( bool bEnable ); |
|
void UpdateSelfIllum(); |
|
void UpdateSelfIllumDisplay( bool bEnable ); |
|
void UpdateSelfIllumTint( int nSkinIndex, const char* pszColor ); |
|
void UpdateEnvmapDisplay( bool bEnable ); |
|
|
|
void UpdateUniqueLabels(); |
|
|
|
CUtlString m_sCommand; |
|
KeyValuesAD m_VMTKeyValues; |
|
int m_nSkinIndex; |
|
int m_nMaterialIndex; |
|
KeyValues *m_pItemValues; |
|
|
|
// unique values per skin |
|
CUtlString m_strBaseTextureFile[NUM_IMPORT_MATERIALS_PER_TEAM]; |
|
CUtlString m_strColorTintBase[NUM_IMPORT_MATERIALS_PER_TEAM]; |
|
CUtlString m_strSelfIllumTint[NUM_IMPORT_MATERIALS_PER_TEAM]; |
|
|
|
CUtlString m_strNormalTextureFile; |
|
CUtlString m_strPhongExponentTextureFile; |
|
bool m_bSelfIllumEnabled; |
|
CUtlString m_strSelfIllumTextureFile; |
|
MATERIAL_FILE_TYPE m_browseMaterialFileType; |
|
|
|
vgui::Button *m_pRedTeamButton; |
|
vgui::Button *m_pBlueTeamButton; |
|
|
|
vgui::Label *m_pBaseTextureFileLabel; |
|
vgui::Label *m_pNormalTextureFileLabel; |
|
vgui::Label *m_pPhongExponentTextureFileLabel; |
|
vgui::Label *m_pSelfIllumTextureFileLabel; |
|
|
|
// Lighting |
|
vgui::ComboBox *m_pLightwarpComboBox; |
|
vgui::CheckButton *m_pBaseMapAlphaPhongMaskCheckButton; |
|
vgui::TextEntry *m_pPhongExponentTextEntry; |
|
vgui::TextEntry *m_pPhongBoostTextEntry; |
|
vgui::TextEntry *m_pRimLightExponentTextEntry; |
|
vgui::TextEntry *m_pRimLightBoostTextEntry; |
|
vgui::CheckButton *m_pRimMaskCheckButton; |
|
vgui::CheckButton *m_pHalfLambertCheckButton; |
|
|
|
// Paint |
|
vgui::CheckButton *m_pBlendTintByBaseAlphaCheckButton; |
|
vgui::TextEntry *m_pBlendTintColorOverBaseTextEntry; |
|
vgui::TextEntry *m_pColorTintBaseRedTextEntry; |
|
vgui::TextEntry *m_pColorTintBaseGreenTextEntry; |
|
vgui::TextEntry *m_pColorTintBaseBlueTextEntry; |
|
|
|
// Translucent |
|
vgui::CheckButton *m_pAdditiveCheckButton; |
|
vgui::CheckButton *m_pTranslucentCheckButton; |
|
vgui::CheckButton *m_pAlphaTestCheckButton; |
|
|
|
// Cube map |
|
vgui::ComboBox *m_pEnvmapComboBox; |
|
vgui::ComboBox *m_pEnvmapAlphaMaskComboBox; |
|
vgui::TextEntry *m_pCubemapTintRedTextEntry; |
|
vgui::TextEntry *m_pCubemapTintGreenTextEntry; |
|
vgui::TextEntry *m_pCubemapTintBlueTextEntry; |
|
|
|
// Self Illum |
|
vgui::CheckButton *m_pSelfIllumCheckButton; |
|
vgui::TextEntry *m_pSelfIllumTintRedTextEntry; |
|
vgui::TextEntry *m_pSelfIllumTintGreenTextEntry; |
|
vgui::TextEntry *m_pSelfIllumTintBlueTextEntry; |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFImportMaterialEditDialog::CTFImportMaterialEditDialog( vgui::Panel *parent, int nSkinIndex, int nMaterialIndex, KeyValues* pItemValues ) : Frame( parent, "ImportMaterialEditDialog" ) |
|
, m_sCommand( CFmtStr( "EditMaterialDone%d,%d", nSkinIndex, nMaterialIndex ) ) |
|
, m_VMTKeyValues( "VMT" ) |
|
, m_nSkinIndex( nSkinIndex ) |
|
, m_nMaterialIndex( nMaterialIndex ) |
|
, m_pItemValues( pItemValues ) |
|
{ |
|
vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme" ); |
|
SetScheme(scheme); |
|
SetProportional( true ); |
|
SetDeleteSelfOnClose( true ); |
|
SetTitle( "", false ); |
|
SetSizeable( false ); |
|
|
|
bool bSetSharedTextures = false; |
|
for ( int nSkin=0; nSkin<CItemUpload::Manifest()->GetNumMaterialSkins(); ++nSkin ) |
|
{ |
|
KeyValues* pMaterialKey = m_pItemValues->FindKey( CFmtStr( kMaterialSkinN, CItemUpload::Manifest()->GetMaterialSkin( nSkin ), m_nMaterialIndex ) ); |
|
if ( pMaterialKey ) |
|
{ |
|
m_strBaseTextureFile[nSkin] = pMaterialKey->GetString( CFmtStr( "%s_texture_file", s_pszMaterialFilePrefixes[MATERIAL_FILE_BASETEXTURE] ) ); |
|
if ( !bSetSharedTextures ) |
|
{ |
|
m_strNormalTextureFile = pMaterialKey->GetString( CFmtStr( "%s_texture_file", s_pszMaterialFilePrefixes[MATERIAL_FILE_NORMAL] ) ); |
|
m_strPhongExponentTextureFile = pMaterialKey->GetString( CFmtStr( "%s_texture_file", s_pszMaterialFilePrefixes[MATERIAL_FILE_PHONGEXPONENT] ) ); |
|
m_strSelfIllumTextureFile = pMaterialKey->GetString( CFmtStr( "%s_texture_file", s_pszMaterialFilePrefixes[MATERIAL_FILE_SELFILLUM] ) ); |
|
bSetSharedTextures = true; |
|
} |
|
} |
|
} |
|
|
|
m_pRedTeamButton = NULL; |
|
m_pBlueTeamButton = NULL; |
|
m_pBaseTextureFileLabel = NULL; |
|
m_pNormalTextureFileLabel = NULL; |
|
m_pPhongExponentTextureFileLabel = NULL; |
|
m_bSelfIllumEnabled = false; |
|
m_pSelfIllumTextureFileLabel = NULL; |
|
m_pLightwarpComboBox = NULL; |
|
m_pBaseMapAlphaPhongMaskCheckButton = NULL; |
|
m_pPhongExponentTextEntry = NULL; |
|
m_pPhongBoostTextEntry = NULL; |
|
m_pRimLightExponentTextEntry = NULL; |
|
m_pRimLightBoostTextEntry = NULL; |
|
m_pRimMaskCheckButton = NULL; |
|
m_pHalfLambertCheckButton = NULL; |
|
m_pBlendTintByBaseAlphaCheckButton = NULL; |
|
m_pBlendTintColorOverBaseTextEntry = NULL; |
|
m_pColorTintBaseRedTextEntry = NULL; |
|
m_pColorTintBaseGreenTextEntry = NULL; |
|
m_pColorTintBaseBlueTextEntry = NULL; |
|
m_pAdditiveCheckButton = NULL; |
|
m_pTranslucentCheckButton = NULL; |
|
m_pAlphaTestCheckButton = NULL; |
|
m_pEnvmapComboBox = NULL; |
|
m_pEnvmapAlphaMaskComboBox = NULL; |
|
m_pCubemapTintRedTextEntry = NULL; |
|
m_pCubemapTintGreenTextEntry = NULL; |
|
m_pCubemapTintBlueTextEntry = NULL; |
|
m_pSelfIllumCheckButton = NULL; |
|
m_pSelfIllumTintRedTextEntry = NULL; |
|
m_pSelfIllumTintGreenTextEntry = NULL; |
|
m_pSelfIllumTintBlueTextEntry = NULL; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::ApplySchemeSettings( vgui::IScheme *pScheme ) |
|
{ |
|
BaseClass::ApplySchemeSettings( pScheme ); |
|
|
|
LoadControlSettings( "Resource/UI/ImportMaterialEditDialog.res" ); |
|
|
|
bool bAllTeam = m_pItemValues->GetInt( kSkinType ) == 0; |
|
|
|
if ( !bAllTeam ) |
|
{ |
|
m_pRedTeamButton = FindControl<vgui::Button>( "RedTeamButton" ); |
|
if ( m_pRedTeamButton ) |
|
{ |
|
m_pRedTeamButton->SetVisible( true ); |
|
m_pRedTeamButton->SetEnabled( true ); |
|
} |
|
|
|
m_pBlueTeamButton = FindControl<vgui::Button>( "BlueTeamButton" ); |
|
if ( m_pBlueTeamButton ) |
|
{ |
|
m_pBlueTeamButton->SetVisible( true ); |
|
m_pBlueTeamButton->SetEnabled( true ); |
|
} |
|
|
|
UpdateUniqueLabels(); |
|
} |
|
|
|
UpdateBackgroundTexture( m_nSkinIndex ); |
|
|
|
vgui::Label *pTitleLabel = FindControl<vgui::Label>( "TitleLabel" ); |
|
if ( pTitleLabel ) |
|
{ |
|
pTitleLabel->SetText( CFmtStr( "#TF_ImportFile_EditVMT%d", m_nMaterialIndex ) ); |
|
} |
|
|
|
m_pBaseTextureFileLabel = FindControl<vgui::Label>( "BaseTextureFileLabel" ); |
|
m_pNormalTextureFileLabel = FindControl< vgui::Label >( "NormalTextureFileLabel" ); |
|
m_pPhongExponentTextureFileLabel = FindControl< vgui::Label >( "PhongExponentTextureFileLabel" ); |
|
m_pSelfIllumTextureFileLabel = FindControl< vgui::Label >( "SelfIllumTextureFileLabel" ); |
|
|
|
m_pLightwarpComboBox = FindControl<vgui::ComboBox>( "LightwarpComboBox" ); |
|
if ( m_pLightwarpComboBox ) |
|
{ |
|
m_pLightwarpComboBox->RemoveAll(); |
|
|
|
KeyValuesAD pKeyValues( "data" ); |
|
for ( int i=0; i<ARRAYSIZE( kLightwarps ); ++i ) |
|
{ |
|
pKeyValues->SetString( kLightwarpPath, kLightwarps[i].pszPath ); |
|
m_pLightwarpComboBox->AddItem( kLightwarps[i].pszName, pKeyValues ); |
|
} |
|
|
|
m_pLightwarpComboBox->AddActionSignalTarget( this ); |
|
} |
|
|
|
// Lighting |
|
m_pBaseMapAlphaPhongMaskCheckButton = FindControl<vgui::CheckButton>( "BaseMapAlphaPhongMaskCheckButton" ); |
|
if ( m_pBaseMapAlphaPhongMaskCheckButton ) |
|
{ |
|
m_pBaseMapAlphaPhongMaskCheckButton->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pPhongExponentTextEntry = FindControl<vgui::TextEntry>( "PhongExponentTextEntry" ); |
|
if ( m_pPhongExponentTextEntry ) |
|
{ |
|
m_pPhongExponentTextEntry->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pPhongBoostTextEntry = FindControl<vgui::TextEntry>( "PhongBoostTextEntry" ); |
|
if ( m_pPhongBoostTextEntry ) |
|
{ |
|
m_pPhongBoostTextEntry->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pRimLightExponentTextEntry = FindControl<vgui::TextEntry>( "RimLightExponentTextEntry" ); |
|
if ( m_pRimLightExponentTextEntry ) |
|
{ |
|
m_pRimLightExponentTextEntry->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pRimLightBoostTextEntry = FindControl<vgui::TextEntry>( "RimLightBoostTextEntry" ); |
|
if ( m_pRimLightBoostTextEntry ) |
|
{ |
|
m_pRimLightBoostTextEntry->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pRimMaskCheckButton = FindControl<vgui::CheckButton>( "RimMaskCheckButton" ); |
|
if ( m_pRimMaskCheckButton ) |
|
{ |
|
m_pRimMaskCheckButton->AddActionSignalTarget( this ); |
|
m_pRimMaskCheckButton->SetCheckButtonCheckable( false ); |
|
} |
|
|
|
m_pHalfLambertCheckButton = FindControl<vgui::CheckButton>( "HalfLambertCheckButton" ); |
|
if ( m_pHalfLambertCheckButton ) |
|
{ |
|
m_pHalfLambertCheckButton->AddActionSignalTarget( this ); |
|
} |
|
|
|
// Paint |
|
m_pBlendTintByBaseAlphaCheckButton = FindControl<vgui::CheckButton>( "BlendTintByBaseAlphaCheckButton" ); |
|
if ( m_pBlendTintByBaseAlphaCheckButton ) |
|
{ |
|
m_pBlendTintByBaseAlphaCheckButton->AddActionSignalTarget( this ); |
|
m_pBlendTintByBaseAlphaCheckButton->SetCheckButtonCheckable( false ); |
|
} |
|
|
|
m_pBlendTintColorOverBaseTextEntry = FindControl<vgui::TextEntry>( "BlendTintColorOverBaseTextEntry" ); |
|
if ( m_pBlendTintColorOverBaseTextEntry ) |
|
{ |
|
m_pBlendTintColorOverBaseTextEntry->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pColorTintBaseRedTextEntry = FindControl<vgui::TextEntry>( "ColorTintBaseRedTextEntry" ); |
|
if ( m_pColorTintBaseRedTextEntry ) |
|
{ |
|
m_pColorTintBaseRedTextEntry->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pColorTintBaseGreenTextEntry = FindControl<vgui::TextEntry>( "ColorTintBaseGreenTextEntry" ); |
|
if ( m_pColorTintBaseGreenTextEntry ) |
|
{ |
|
m_pColorTintBaseGreenTextEntry->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pColorTintBaseBlueTextEntry = FindControl<vgui::TextEntry>( "ColorTintBaseBlueTextEntry" ); |
|
if ( m_pColorTintBaseBlueTextEntry ) |
|
{ |
|
m_pColorTintBaseBlueTextEntry->AddActionSignalTarget( this ); |
|
} |
|
|
|
// enable paintable UI |
|
const char* pszPaintable = CFmtStr( kItemPaintable, m_nMaterialIndex ); |
|
if ( m_pItemValues->GetBool( pszPaintable ) ) |
|
{ |
|
m_pBlendTintByBaseAlphaCheckButton->SetEnabled( true ); |
|
m_pBlendTintByBaseAlphaCheckButton->SetCheckButtonCheckable( true ); |
|
m_pBlendTintColorOverBaseTextEntry->SetEnabled( true ); |
|
m_pColorTintBaseRedTextEntry->SetEnabled( true ); |
|
m_pColorTintBaseGreenTextEntry->SetEnabled( true ); |
|
m_pColorTintBaseBlueTextEntry->SetEnabled( true ); |
|
|
|
static const char* paintableUILabels[] = |
|
{ |
|
"BlendTintByBaseAlphaLabel", |
|
"BlendTintColorOverBaseLabel", |
|
"ColorTintBaseLabel" |
|
}; |
|
|
|
for ( int i=0; i<ARRAYSIZE( paintableUILabels ); ++i ) |
|
{ |
|
vgui::Label *pLabel = FindControl<vgui::Label>( paintableUILabels[i] ); |
|
if ( pLabel ) |
|
{ |
|
pLabel->SetEnabled( true ); |
|
} |
|
} |
|
} |
|
|
|
// Translucent |
|
m_pAdditiveCheckButton = FindControl<vgui::CheckButton>( "AdditiveCheckButton" ); |
|
if ( m_pAdditiveCheckButton ) |
|
{ |
|
m_pAdditiveCheckButton->AddActionSignalTarget( this ); |
|
} |
|
m_pTranslucentCheckButton = FindControl<vgui::CheckButton>( "TranslucentCheckButton" ); |
|
if ( m_pTranslucentCheckButton ) |
|
{ |
|
m_pTranslucentCheckButton->AddActionSignalTarget( this ); |
|
} |
|
m_pAlphaTestCheckButton = FindControl<vgui::CheckButton>( "AlphaTestCheckButton" ); |
|
if ( m_pAlphaTestCheckButton ) |
|
{ |
|
m_pAlphaTestCheckButton->AddActionSignalTarget( this ); |
|
m_pAlphaTestCheckButton->SetCheckButtonCheckable( false ); |
|
} |
|
|
|
// Cube map |
|
m_pEnvmapComboBox = FindControl<vgui::ComboBox>( "EnvmapComboBox" ); |
|
if ( m_pEnvmapComboBox ) |
|
{ |
|
KeyValuesAD pKeyValues( "data" ); |
|
for ( int i=0; i<ARRAYSIZE(kEnvmaps); ++i ) |
|
{ |
|
pKeyValues->SetString( kEnvmapPath, kEnvmaps[i].pszPath ); |
|
m_pEnvmapComboBox->AddItem( kEnvmaps[i].pszName, pKeyValues ); |
|
} |
|
|
|
m_pEnvmapComboBox->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pEnvmapAlphaMaskComboBox = FindControl<vgui::ComboBox>( "EnvmapAlphaMaskComboBox" ); |
|
if ( m_pEnvmapAlphaMaskComboBox ) |
|
{ |
|
KeyValuesAD pKeyValues( "data" ); |
|
for ( int i=0; i<ARRAYSIZE(kEnvmapMasks); ++i ) |
|
{ |
|
pKeyValues->SetString( kEnvmapMaskVarName, kEnvmapMasks[i].pszVarName ); |
|
m_pEnvmapAlphaMaskComboBox->AddItem( kEnvmapMasks[i].pszDisplayName, pKeyValues ); |
|
} |
|
|
|
m_pEnvmapAlphaMaskComboBox->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pCubemapTintRedTextEntry = FindControl<vgui::TextEntry>( "CubemapTintRedTextEntry" ); |
|
if ( m_pCubemapTintRedTextEntry ) |
|
{ |
|
m_pCubemapTintRedTextEntry->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pCubemapTintGreenTextEntry = FindControl<vgui::TextEntry>( "CubemapTintGreenTextEntry" ); |
|
if ( m_pCubemapTintGreenTextEntry ) |
|
{ |
|
m_pCubemapTintGreenTextEntry->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pCubemapTintBlueTextEntry = FindControl<vgui::TextEntry>( "CubemapTintBlueTextEntry" ); |
|
if ( m_pCubemapTintBlueTextEntry ) |
|
{ |
|
m_pCubemapTintBlueTextEntry->AddActionSignalTarget( this ); |
|
} |
|
|
|
// Self Illum |
|
m_pSelfIllumCheckButton = FindControl<vgui::CheckButton>( "SelfIllumCheckButton" ); |
|
if ( m_pSelfIllumCheckButton ) |
|
{ |
|
m_pSelfIllumCheckButton->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pSelfIllumTintRedTextEntry = FindControl<vgui::TextEntry>( "SelfIllumTintRedTextEntry" ); |
|
if ( m_pSelfIllumTintRedTextEntry ) |
|
{ |
|
m_pSelfIllumTintRedTextEntry->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pSelfIllumTintGreenTextEntry = FindControl<vgui::TextEntry>( "SelfIllumTintGreenTextEntry" ); |
|
if ( m_pSelfIllumTintGreenTextEntry ) |
|
{ |
|
m_pSelfIllumTintGreenTextEntry->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pSelfIllumTintBlueTextEntry = FindControl<vgui::TextEntry>( "SelfIllumTintBlueTextEntry" ); |
|
if ( m_pSelfIllumTintBlueTextEntry ) |
|
{ |
|
m_pSelfIllumTintBlueTextEntry->AddActionSignalTarget( this ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::OnCommand( const char *command ) |
|
{ |
|
if ( FStrEq( command, "Done" ) ) |
|
{ |
|
if ( m_sCommand.IsEmpty() ) |
|
{ |
|
OnCommand( "Close" ); |
|
} |
|
else if ( GetParent() ) |
|
{ |
|
GetParent()->OnCommand( m_sCommand ); |
|
} |
|
} |
|
else if ( V_strncasecmp( command, "EditSkin", V_strlen( "EditSkin" ) ) == 0 ) |
|
{ |
|
int index = V_atoi( &command[ V_strlen( "EditSkin" ) ] ); |
|
OnCommandEditSkin( index ); |
|
} |
|
else if ( FStrEq( command, "BrowseMaterial" ) ) |
|
{ |
|
OnCommandBrowseMaterial( MATERIAL_FILE_BASETEXTURE ); |
|
} |
|
else if ( FStrEq( command, "BrowseNormalTexture" ) ) |
|
{ |
|
OnCommandBrowseMaterial( MATERIAL_FILE_NORMAL ); |
|
} |
|
else if ( FStrEq( command, "BrowsePhongExponentTexture" ) ) |
|
{ |
|
OnCommandBrowseMaterial( MATERIAL_FILE_PHONGEXPONENT ); |
|
} |
|
else if ( FStrEq( command, "BrowseSelfIllumTexture" ) ) |
|
{ |
|
OnCommandBrowseMaterial( MATERIAL_FILE_SELFILLUM ); |
|
} |
|
else if ( FStrEq( command, "ClearNormalTexture" ) ) |
|
{ |
|
UpdateNormalTexture( "" ); |
|
} |
|
else if ( FStrEq( command, "ClearPhongExponentTexture" ) ) |
|
{ |
|
UpdatePhongExponentTexture( "" ); |
|
} |
|
else if ( FStrEq( command, "ClearSelfIllumTexture" ) ) |
|
{ |
|
UpdateSelfIllumTexture( "" ); |
|
} |
|
else if ( FStrEq( command, "UpdateBaseMapAlphaPhongMask" ) ) |
|
{ |
|
UpdateBaseMapAlphaPhongMask(); |
|
} |
|
else if ( FStrEq( command, "UpdateRimMask" ) ) |
|
{ |
|
UpdateRimMask(); |
|
} |
|
else if ( FStrEq( command, "UpdateHalfLambert" ) ) |
|
{ |
|
UpdateHalfLambert(); |
|
} |
|
else if ( FStrEq( command, "UpdateBlendTintByBaseAlpha" ) ) |
|
{ |
|
UpdateBlendTintByBaseAlpha(); |
|
} |
|
else if ( FStrEq( command, "UpdateAdditive" ) ) |
|
{ |
|
UpdateAdditive(); |
|
} |
|
else if ( FStrEq( command, "UpdateTranslucent" ) ) |
|
{ |
|
UpdateTranslucent(); |
|
} |
|
else if ( FStrEq( command, "UpdateAlphaTest" ) ) |
|
{ |
|
UpdateAlphaTest(); |
|
} |
|
else if ( FStrEq( command, "UpdateSelfIllum" ) ) |
|
{ |
|
UpdateSelfIllum(); |
|
} |
|
else |
|
{ |
|
BaseClass::OnCommand( command ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::OnCommandEditSkin( int nSkinIndex ) |
|
{ |
|
if ( m_nSkinIndex == nSkinIndex ) |
|
{ |
|
return; |
|
} |
|
|
|
m_nSkinIndex = nSkinIndex; |
|
|
|
UpdateBackgroundTexture( m_nSkinIndex ); |
|
UpdateBaseTexture( m_strBaseTextureFile[m_nSkinIndex] ); |
|
UpdateColorTintBase( m_nSkinIndex, m_strColorTintBase[m_nSkinIndex] ); |
|
UpdateSelfIllumTint( m_nSkinIndex, m_strSelfIllumTint[m_nSkinIndex] ); |
|
UpdateUniqueLabels(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::OnCommandBrowseMaterial( MATERIAL_FILE_TYPE fileType ) |
|
{ |
|
vgui::FileOpenDialog *pDialog = new vgui::FileOpenDialog( NULL, "#TF_ImportFile_SelectMaterial", vgui::FOD_OPEN ); |
|
pDialog->AddFilter( "*.tga,*.psd", "#TF_ImportFile_MaterialFileType", true); |
|
pDialog->AddActionSignalTarget( this ); |
|
const char *pszStartPath = tf_steam_workshop_import_material_path.GetString(); |
|
if ( pszStartPath && *pszStartPath ) |
|
{ |
|
pDialog->SetStartDirectory( pszStartPath ); |
|
} |
|
pDialog->DoModal(); |
|
pDialog->Activate(); |
|
|
|
m_browseMaterialFileType = fileType; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFFileImportDialog::BUILD_RESULT CheckImageSize( const char *fullpath, MATERIAL_FILE_TYPE materialFileType, KeyValues *pMessageVariables ) |
|
{ |
|
CAssetTF asset; |
|
CTargetTGA image( &asset, NULL ); |
|
if ( !image.SetInputFile( fullpath ) ) |
|
{ |
|
SetMessageFileVariable( pMessageVariables, image.GetInputFile() ); |
|
return CTFFileImportDialog::BUILD_FAILED_IMAGEUNSUPPORTEDFILETYPE; |
|
} |
|
|
|
int nLimitWidth = 0; |
|
int nLimitHeight = 0; |
|
|
|
switch ( materialFileType ) |
|
{ |
|
case MATERIAL_FILE_BASETEXTURE: |
|
{ |
|
// 512x512 |
|
nLimitWidth = nLimitHeight = 512; |
|
} |
|
break; |
|
case MATERIAL_FILE_NORMAL: |
|
{ |
|
// 512x512 |
|
nLimitWidth = nLimitHeight = 512; |
|
} |
|
break; |
|
case MATERIAL_FILE_PHONGEXPONENT: |
|
{ |
|
// 256x256 |
|
nLimitWidth = nLimitHeight = 256; |
|
} |
|
break; |
|
case MATERIAL_FILE_SELFILLUM: |
|
{ |
|
// 256x256 |
|
nLimitWidth = nLimitHeight = 256; |
|
} |
|
break; |
|
} |
|
|
|
if ( image.GetWidth() > nLimitWidth || image.GetHeight() > nLimitHeight ) |
|
{ |
|
SetMessageFileVariable( pMessageVariables, image.GetInputFile() ); |
|
pMessageVariables->SetInt( "width", nLimitWidth ); |
|
pMessageVariables->SetInt( "height", nLimitHeight ); |
|
return CTFFileImportDialog::BUILD_FAILED_IMAGERESOLUTIONOVERLIMIT; |
|
} |
|
|
|
if ( !IsPowerOfTwo( image.GetWidth() ) || !IsPowerOfTwo( image.GetHeight() ) ) |
|
{ |
|
SetMessageFileVariable( pMessageVariables, image.GetInputFile() ); |
|
return CTFFileImportDialog::BUILD_FAILED_IMAGERESOLUTIONNOTPOWEROF2; |
|
} |
|
|
|
return CTFFileImportDialog::BUILD_OKAY; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::OnFileSelected( char const *fullpath ) |
|
{ |
|
SaveBrowsePath( tf_steam_workshop_import_material_path, fullpath ); |
|
|
|
KeyValuesAD pKV("data"); |
|
CTFFileImportDialog::BUILD_RESULT result = CheckImageSize( fullpath, m_browseMaterialFileType, pKV ); |
|
if ( result != CTFFileImportDialog::BUILD_OKAY ) |
|
{ |
|
ShowMessageBox( "#TF_ImportFile_LoadFailed", kBuildResultMessages[result], pKV ); |
|
return; |
|
} |
|
|
|
switch ( m_browseMaterialFileType ) |
|
{ |
|
case MATERIAL_FILE_BASETEXTURE: |
|
{ |
|
UpdateBaseTexture( fullpath ); |
|
} |
|
break; |
|
case MATERIAL_FILE_NORMAL: |
|
{ |
|
UpdateNormalTexture( fullpath ); |
|
} |
|
break; |
|
case MATERIAL_FILE_PHONGEXPONENT: |
|
{ |
|
UpdatePhongExponentTexture( fullpath ); |
|
} |
|
break; |
|
case MATERIAL_FILE_SELFILLUM: |
|
{ |
|
UpdateSelfIllumTexture( fullpath ); |
|
} |
|
break; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::OnTextChanged( KeyValues *data ) |
|
{ |
|
Panel *pPanel = reinterpret_cast<vgui::Panel *>( data->GetPtr( "panel" ) ); |
|
|
|
vgui::ComboBox *pComboBox = dynamic_cast< vgui::ComboBox * >( pPanel ); |
|
if ( pComboBox ) |
|
{ |
|
if( pComboBox == m_pLightwarpComboBox ) |
|
{ |
|
KeyValues *pData = m_pLightwarpComboBox->GetActiveItemUserData(); |
|
m_VMTKeyValues->SetString( "$lightwarptexture", pData->GetString( kLightwarpPath ) ); |
|
} |
|
else if ( pComboBox == m_pEnvmapComboBox ) |
|
{ |
|
KeyValues *pData = m_pEnvmapComboBox->GetActiveItemUserData(); |
|
const char* pszEnvmapPath = pData->GetString( kEnvmapPath ); |
|
m_VMTKeyValues->SetString( "$envmap", pszEnvmapPath ); |
|
UpdateEnvmapDisplay( !FStrEq( pszEnvmapPath, "" ) ); |
|
} |
|
else if ( pComboBox == m_pEnvmapAlphaMaskComboBox ) |
|
{ |
|
KeyValues *pData = m_pEnvmapAlphaMaskComboBox->GetActiveItemUserData(); |
|
const char* pszEnvmapMaskVarName = pData->GetString( kEnvmapMaskVarName ); |
|
for ( int i=0; i<ARRAYSIZE(kEnvmapMasks); ++i ) |
|
{ |
|
const char* pszCurrentVarName = kEnvmapMasks[i].pszVarName; |
|
if ( FStrEq( pszCurrentVarName, "" ) ) |
|
{ |
|
continue; |
|
} |
|
|
|
bool bSet = FStrEq( pszCurrentVarName, pszEnvmapMaskVarName ); |
|
m_VMTKeyValues->SetBool( pszCurrentVarName, bSet ); |
|
} |
|
|
|
// pop a warning |
|
static bool bWarned = false; |
|
if ( FStrEq( pszEnvmapMaskVarName, "$basealphaenvmapmask" ) ) |
|
{ |
|
bool bHasNormal = !m_strNormalTextureFile.IsEmpty(); |
|
if ( !bWarned && bHasNormal ) |
|
{ |
|
bWarned = true; |
|
ShowMessageBox( "#TF_ImportFile_Warning", kWarningMessages[ CTFFileImportDialog::WARNING_BASEALPHAMASK ] ); |
|
} |
|
} |
|
else |
|
{ |
|
bWarned = false; |
|
} |
|
} |
|
|
|
return; |
|
} |
|
|
|
vgui::TextEntry *pTextEntry = dynamic_cast< vgui::TextEntry * >( pPanel ); |
|
if ( pTextEntry ) |
|
{ |
|
if ( pTextEntry == m_pPhongExponentTextEntry ) |
|
{ |
|
m_VMTKeyValues->SetFloat( "$phongexponent", m_pPhongExponentTextEntry->GetValueAsFloat() ); |
|
} |
|
else if ( pTextEntry == m_pPhongBoostTextEntry ) |
|
{ |
|
m_VMTKeyValues->SetFloat( "$phongboost", m_pPhongBoostTextEntry->GetValueAsFloat() ); |
|
} |
|
else if ( pTextEntry == m_pRimLightExponentTextEntry ) |
|
{ |
|
m_VMTKeyValues->SetFloat( "$rimlightexponent", m_pRimLightExponentTextEntry->GetValueAsFloat() ); |
|
} |
|
else if ( pTextEntry == m_pRimLightBoostTextEntry ) |
|
{ |
|
m_VMTKeyValues->SetFloat( "$rimlightboost", m_pRimLightBoostTextEntry->GetValueAsFloat() ); |
|
} |
|
else if ( pTextEntry == m_pBlendTintColorOverBaseTextEntry ) |
|
{ |
|
float flClampedValue = clamp( m_pBlendTintColorOverBaseTextEntry->GetValueAsFloat(), 0.f, 1.f ); |
|
m_VMTKeyValues->SetFloat( "$blendtintcoloroverbase", flClampedValue ); |
|
} |
|
else if ( pTextEntry == m_pColorTintBaseRedTextEntry || |
|
pTextEntry == m_pColorTintBaseGreenTextEntry || |
|
pTextEntry == m_pColorTintBaseBlueTextEntry ) |
|
{ |
|
const char* pszColor = CFmtStr( "{ %d %d %d }", |
|
clamp( m_pColorTintBaseRedTextEntry->GetValueAsInt(), 0, 255 ), |
|
clamp( m_pColorTintBaseGreenTextEntry->GetValueAsInt(), 0, 255 ), |
|
clamp( m_pColorTintBaseBlueTextEntry->GetValueAsInt(), 0, 255 ) ); |
|
SetColorTintBase( m_nSkinIndex, pszColor ); |
|
} |
|
else if ( pTextEntry == m_pCubemapTintRedTextEntry || |
|
pTextEntry == m_pCubemapTintGreenTextEntry || |
|
pTextEntry == m_pCubemapTintBlueTextEntry ) |
|
{ |
|
float flR = (float)clamp( m_pCubemapTintRedTextEntry->GetValueAsInt(), 0, 255 ) / 255.f; |
|
float flG = (float)clamp( m_pCubemapTintGreenTextEntry->GetValueAsInt(), 0, 255 ) / 255.f; |
|
float flB = (float)clamp( m_pCubemapTintBlueTextEntry->GetValueAsInt(), 0, 255 ) / 255.f; |
|
const char* pszColor = CFmtStr( "[%f %f %f]", flR, flG, flB ); |
|
m_VMTKeyValues->SetString( "$envmaptint", pszColor ); |
|
} |
|
else if ( pTextEntry == m_pSelfIllumTintRedTextEntry || |
|
pTextEntry == m_pSelfIllumTintGreenTextEntry || |
|
pTextEntry == m_pSelfIllumTintBlueTextEntry ) |
|
{ |
|
float flR = m_pSelfIllumTintRedTextEntry->GetValueAsFloat() / 255.f; |
|
float flG = m_pSelfIllumTintGreenTextEntry->GetValueAsFloat() / 255.f; |
|
float flB = m_pSelfIllumTintBlueTextEntry->GetValueAsFloat() / 255.f; |
|
const char* pszColor = CFmtStr( "[%f %f %f]", flR, flG, flB ); |
|
SetSelfIllumTint( m_nSkinIndex, pszColor ); |
|
} |
|
|
|
return; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::SetColorTintBase( int nSkinIndex, const char* pszColorTintBase ) |
|
{ |
|
m_VMTKeyValues->SetString( "$colortint_base", pszColorTintBase ); |
|
m_VMTKeyValues->SetString( "$color2", pszColorTintBase ); |
|
|
|
m_strColorTintBase[nSkinIndex] = pszColorTintBase; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::SetSelfIllumTint( int nSkinIndex, const char* pszSelfIllumTint ) |
|
{ |
|
m_VMTKeyValues->SetString( "$selfillumtint", pszSelfIllumTint ); |
|
|
|
m_strSelfIllumTint[nSkinIndex] = pszSelfIllumTint; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::SetVMTKeyValues( const char *pszRedVMTText, const char *pszBlueVMTText ) |
|
{ |
|
m_VMTKeyValues->Clear(); |
|
|
|
// read the unique data |
|
const char* pszVMTs[NUM_IMPORT_MATERIALS_PER_TEAM] = { pszRedVMTText, pszBlueVMTText }; |
|
for ( int i=0; i<ARRAYSIZE( pszVMTs ); ++i ) |
|
{ |
|
KeyValuesAD pKV( "VMT" ); |
|
if ( pKV->LoadFromBuffer( "VMT", pszVMTs[i] ) ) |
|
{ |
|
m_strColorTintBase[i] = pKV->GetString( "$colortint_base" ); |
|
m_strSelfIllumTint[i] = pKV->GetString( "$selfillumtint" ); |
|
} |
|
} |
|
|
|
const char* pszVMTText = m_nSkinIndex == 0 ? pszRedVMTText : pszBlueVMTText; |
|
if ( m_VMTKeyValues->LoadFromBuffer( "VMT", pszVMTText ) ) |
|
{ |
|
// update the UI here |
|
UpdateBaseTexture( m_strBaseTextureFile[m_nSkinIndex].String() ); |
|
UpdateNormalTexture( m_strNormalTextureFile.String() ); |
|
UpdatePhongExponentTexture( m_strPhongExponentTextureFile.String() ); |
|
UpdateSelfIllumTexture( m_strSelfIllumTextureFile.String() ); |
|
|
|
if ( m_pLightwarpComboBox ) |
|
{ |
|
const char* pszCurrentLightwarpPath = m_VMTKeyValues->GetString( "$lightwarptexture" ); |
|
for ( int i=0; i<ARRAYSIZE(kLightwarps); ++i ) |
|
{ |
|
if ( FStrEq( pszCurrentLightwarpPath, kLightwarps[i].pszPath ) ) |
|
{ |
|
m_pLightwarpComboBox->ActivateItemByRow( i ); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
const char* pszFloatFormat = "%.3f"; |
|
|
|
// Lighting |
|
if ( m_pBaseMapAlphaPhongMaskCheckButton ) |
|
{ |
|
m_pBaseMapAlphaPhongMaskCheckButton->SetSelected( m_VMTKeyValues->GetBool( "$basemapalphaphongmask" ) ); |
|
} |
|
if ( m_pPhongExponentTextEntry ) |
|
{ |
|
m_pPhongExponentTextEntry->SetText( CFmtStr( pszFloatFormat, m_VMTKeyValues->GetFloat( "$phongexponent" ) ) ); |
|
} |
|
if ( m_pPhongBoostTextEntry ) |
|
{ |
|
m_pPhongBoostTextEntry->SetText( CFmtStr( pszFloatFormat, m_VMTKeyValues->GetFloat( "$phongboost" ) ) ); |
|
} |
|
if ( m_pRimLightExponentTextEntry ) |
|
{ |
|
m_pRimLightExponentTextEntry->SetText( CFmtStr( pszFloatFormat, m_VMTKeyValues->GetFloat( "$rimlightexponent" ) ) ); |
|
} |
|
if ( m_pRimLightBoostTextEntry ) |
|
{ |
|
m_pRimLightBoostTextEntry->SetText( CFmtStr( pszFloatFormat, m_VMTKeyValues->GetFloat( "$rimlightboost" ) ) ); |
|
} |
|
if ( m_pRimMaskCheckButton ) |
|
{ |
|
UpdateRimMaskDisplay( !m_strPhongExponentTextureFile.IsEmpty() ); |
|
m_pRimMaskCheckButton->SetSelected( m_VMTKeyValues->GetBool( "$rimmask" ) ); |
|
} |
|
if ( m_pHalfLambertCheckButton ) |
|
{ |
|
m_pHalfLambertCheckButton->SetSelected( m_VMTKeyValues->GetBool( "$halflambert" ) ); |
|
} |
|
|
|
// Paint |
|
if ( m_pBlendTintByBaseAlphaCheckButton ) |
|
{ |
|
m_pBlendTintByBaseAlphaCheckButton->SetSelected( m_VMTKeyValues->GetBool( "$blendtintbybasealpha" ) ); |
|
} |
|
if ( m_pBlendTintColorOverBaseTextEntry ) |
|
{ |
|
m_pBlendTintColorOverBaseTextEntry->SetText( CFmtStr( pszFloatFormat, m_VMTKeyValues->GetFloat( "$blendtintcoloroverbase" ) ) ); |
|
} |
|
|
|
UpdateColorTintBase( m_nSkinIndex, m_VMTKeyValues->GetString( "$colortint_base" ) ); |
|
|
|
// Translucent |
|
if ( m_pAdditiveCheckButton ) |
|
{ |
|
m_pAdditiveCheckButton->SetSelected( m_VMTKeyValues->GetBool( "$additive" ) ); |
|
} |
|
if ( m_pTranslucentCheckButton ) |
|
{ |
|
m_pTranslucentCheckButton->SetSelected( m_VMTKeyValues->GetBool( "$translucent" ) ); |
|
} |
|
if ( m_pAlphaTestCheckButton ) |
|
{ |
|
bool bTranslucent = m_pTranslucentCheckButton->IsSelected(); |
|
UpdateAlphaTestDiaplay( bTranslucent ); |
|
m_pAlphaTestCheckButton->SetSelected( m_VMTKeyValues->GetBool( "$alphatest" ) ); |
|
} |
|
|
|
// Cube map |
|
if ( m_pEnvmapComboBox ) |
|
{ |
|
const char *pszEnvmap = m_VMTKeyValues->GetString( "$envmap" ); |
|
for ( int i=0; i<m_pEnvmapComboBox->GetItemCount(); ++i ) |
|
{ |
|
KeyValues *pKey = m_pEnvmapComboBox->GetItemUserData( i ); |
|
const char *pszPath = pKey->GetString( kEnvmapPath ); |
|
if ( FStrEq( pszEnvmap, pszPath ) ) |
|
{ |
|
m_pEnvmapComboBox->ActivateItemByRow( i ); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if ( m_pEnvmapAlphaMaskComboBox ) |
|
{ |
|
int nRow = 0; |
|
for ( int i=0; i<m_pEnvmapAlphaMaskComboBox->GetItemCount(); ++i ) |
|
{ |
|
KeyValues *pKey = m_pEnvmapAlphaMaskComboBox->GetItemUserData( i ); |
|
const char *pszMask = pKey->GetString( kEnvmapMaskVarName ); |
|
if ( pKey && m_VMTKeyValues->GetBool( pszMask ) ) |
|
{ |
|
nRow = i; |
|
break; |
|
} |
|
} |
|
m_pEnvmapAlphaMaskComboBox->ActivateItemByRow( nRow ); |
|
} |
|
|
|
const char *pszStrippedEnvmapTintColor = m_VMTKeyValues->GetString( "$envmaptint" ) + 1; |
|
float entmapTint[3]; |
|
UTIL_StringToFloatArray( entmapTint, ARRAYSIZE( entmapTint ), pszStrippedEnvmapTintColor ); |
|
if ( m_pCubemapTintRedTextEntry ) |
|
{ |
|
m_pCubemapTintRedTextEntry->SetText( CFmtStr( "%d", int( entmapTint[0] * 255.f ) ) ); |
|
} |
|
if ( m_pCubemapTintGreenTextEntry ) |
|
{ |
|
m_pCubemapTintGreenTextEntry->SetText( CFmtStr( "%d", int( entmapTint[1] * 255.f ) ) ); |
|
} |
|
if ( m_pCubemapTintBlueTextEntry ) |
|
{ |
|
m_pCubemapTintBlueTextEntry->SetText( CFmtStr( "%d", int( entmapTint[2] * 255.f ) ) ); |
|
} |
|
|
|
// Self Illum |
|
bool bSelfIllum = m_VMTKeyValues->GetBool( ">=DX90/$selfillum" ); |
|
if ( m_pSelfIllumCheckButton ) |
|
{ |
|
m_pSelfIllumCheckButton->SetSelected( bSelfIllum ); |
|
UpdateSelfIllumDisplay( bSelfIllum ); |
|
} |
|
|
|
UpdateSelfIllumTint( m_nSkinIndex, m_VMTKeyValues->GetString( "$selfillumtint" ) ); |
|
} |
|
else |
|
{ |
|
Warning( "CTFImportMaterialEditDialog::SetKeyValues failed to LoadFromBuffer\n" ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
KeyValues* CTFImportMaterialEditDialog::GetVMTKeyValues( int nSkinIndex ) |
|
{ |
|
//set unique values for the skin index here |
|
m_VMTKeyValues->SetString( "$colortint_base", m_strColorTintBase[nSkinIndex] ); |
|
m_VMTKeyValues->SetString( "$color2", m_strColorTintBase[nSkinIndex] ); |
|
m_VMTKeyValues->SetString( "$selfillumtint", m_strSelfIllumTint[nSkinIndex] ); |
|
|
|
return m_VMTKeyValues; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdateBackgroundTexture( int nSkinIndex ) |
|
{ |
|
static const char* pszBGs[] = { "RedBG", "BlueBG" }; |
|
for ( int i=0; i<ARRAYSIZE(pszBGs); ++i ) |
|
{ |
|
vgui::ImagePanel *pBG = FindControl<vgui::ImagePanel>( pszBGs[i] ); |
|
if ( pBG ) |
|
{ |
|
bool bVisible = nSkinIndex == i; |
|
pBG->SetVisible( bVisible ); |
|
pBG->SetEnabled( bVisible ); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdateBaseTexture( const char *pszBaseTextureFile ) |
|
{ |
|
if ( m_pBaseTextureFileLabel && pszBaseTextureFile ) |
|
{ |
|
m_pBaseTextureFileLabel->InvalidateLayout( true, true ); |
|
|
|
if ( *pszBaseTextureFile ) |
|
{ |
|
char file[MAX_PATH]; |
|
V_FileBase( pszBaseTextureFile, file, sizeof(file) ); |
|
m_pBaseTextureFileLabel->SetText( file ); |
|
m_pBaseTextureFileLabel->SetFgColor( Color( 255, 255, 255, 255 ) ); |
|
} |
|
else |
|
{ |
|
m_pBaseTextureFileLabel->SetText( "#TF_PublishFile_NoFileSelected" ); |
|
m_pBaseTextureFileLabel->SetFgColor( Color( 255, 0, 0, 255 ) ); |
|
} |
|
|
|
m_strBaseTextureFile[m_nSkinIndex] = pszBaseTextureFile; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdateNormalTexture( const char *pszNormalTextureFile ) |
|
{ |
|
if ( m_pNormalTextureFileLabel && pszNormalTextureFile ) |
|
{ |
|
if ( *pszNormalTextureFile ) |
|
{ |
|
char file[MAX_PATH]; |
|
V_FileBase( pszNormalTextureFile, file, sizeof(file) ); |
|
m_pNormalTextureFileLabel->SetText( file ); |
|
} |
|
else |
|
{ |
|
m_pNormalTextureFileLabel->SetText( "#TF_PublishFile_Optional" ); |
|
} |
|
|
|
m_strNormalTextureFile = pszNormalTextureFile; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdatePhongExponentTexture( const char* pszPhongExponentTextureFile ) |
|
{ |
|
if ( m_pPhongExponentTextureFileLabel && pszPhongExponentTextureFile ) |
|
{ |
|
if ( *pszPhongExponentTextureFile ) |
|
{ |
|
char file[MAX_PATH]; |
|
V_FileBase( pszPhongExponentTextureFile, file, sizeof(file) ); |
|
m_pPhongExponentTextureFileLabel->SetText( file ); |
|
} |
|
else |
|
{ |
|
m_pPhongExponentTextureFileLabel->SetText( "#TF_PublishFile_Optional" ); |
|
} |
|
|
|
m_strPhongExponentTextureFile = pszPhongExponentTextureFile; |
|
|
|
UpdateRimMaskDisplay( !m_strPhongExponentTextureFile.IsEmpty() ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdateSelfIllumTexture( const char *pszSelfIllumTextureFile ) |
|
{ |
|
if ( m_pSelfIllumTextureFileLabel && pszSelfIllumTextureFile ) |
|
{ |
|
if ( *pszSelfIllumTextureFile ) |
|
{ |
|
char file[MAX_PATH]; |
|
V_FileBase( pszSelfIllumTextureFile, file, sizeof(file) ); |
|
m_pSelfIllumTextureFileLabel->SetText( file ); |
|
} |
|
else |
|
{ |
|
m_pSelfIllumTextureFileLabel->SetText( "#TF_PublishFile_Optional" ); |
|
} |
|
|
|
m_strSelfIllumTextureFile = pszSelfIllumTextureFile; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdateBaseMapAlphaPhongMask() |
|
{ |
|
if ( m_pBaseMapAlphaPhongMaskCheckButton ) |
|
{ |
|
m_VMTKeyValues->SetBool( "$basemapalphaphongmask", m_pBaseMapAlphaPhongMaskCheckButton->IsSelected() ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdateRimMask() |
|
{ |
|
if ( m_pRimMaskCheckButton ) |
|
{ |
|
m_VMTKeyValues->SetBool( "$rimmask", m_pRimMaskCheckButton->IsSelected() ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdateRimMaskDisplay( bool bEnable ) |
|
{ |
|
if ( m_pRimMaskCheckButton ) |
|
{ |
|
m_pRimMaskCheckButton->SetEnabled( bEnable ); |
|
m_pRimMaskCheckButton->SetCheckButtonCheckable( bEnable ); |
|
} |
|
|
|
vgui::Label* pLabel = FindControl< vgui::Label >( "RimMaskLabel" ); |
|
if ( pLabel ) |
|
{ |
|
pLabel->SetEnabled( bEnable ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdateHalfLambert() |
|
{ |
|
if ( m_pHalfLambertCheckButton ) |
|
{ |
|
m_VMTKeyValues->SetBool( "$halflambert", m_pHalfLambertCheckButton->IsSelected() ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdateBlendTintByBaseAlpha() |
|
{ |
|
if ( m_pBlendTintByBaseAlphaCheckButton ) |
|
{ |
|
bool bSelected = m_pBlendTintByBaseAlphaCheckButton->IsSelected(); |
|
m_VMTKeyValues->SetBool( "$blendtintbybasealpha", bSelected ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdateBlendTintColorOverBaseDisplay( bool bEnable ) |
|
{ |
|
if ( m_pBlendTintColorOverBaseTextEntry ) |
|
{ |
|
if ( !bEnable ) |
|
{ |
|
m_VMTKeyValues->SetFloat( "$blendtintcoloroverbase", 0.f ); |
|
} |
|
m_pBlendTintColorOverBaseTextEntry->SetText( CFmtStr( "%.3f", m_VMTKeyValues->GetFloat( "$blendtintcoloroverbase" ) ) ); |
|
m_pBlendTintColorOverBaseTextEntry->SetEnabled( bEnable ); |
|
|
|
vgui::Label *pLabel = FindControl<vgui::Label>( "BlendTintColorOverBaseLabel" ); |
|
if ( pLabel ) |
|
{ |
|
pLabel->SetEnabled( bEnable ); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdateColorTintBase( int nSkinIndex, const char* pszColor ) |
|
{ |
|
m_strColorTintBase[nSkinIndex] = pszColor; |
|
|
|
int colorTintBase[3]; |
|
// color string +2 to skip "{ " or "[ " |
|
const char *pszStrippedColorTintBase = pszColor + 2; |
|
UTIL_StringToIntArray( colorTintBase, 3, pszStrippedColorTintBase ); |
|
if ( m_pColorTintBaseRedTextEntry ) |
|
{ |
|
m_pColorTintBaseRedTextEntry->SetText( CFmtStr( "%d", colorTintBase[0] ) ); |
|
} |
|
if ( m_pColorTintBaseGreenTextEntry ) |
|
{ |
|
m_pColorTintBaseGreenTextEntry->SetText( CFmtStr( "%d", colorTintBase[1] ) ); |
|
} |
|
if ( m_pColorTintBaseBlueTextEntry ) |
|
{ |
|
m_pColorTintBaseBlueTextEntry->SetText( CFmtStr( "%d", colorTintBase[2] ) ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdateAdditive() |
|
{ |
|
if ( m_pAdditiveCheckButton ) |
|
{ |
|
m_VMTKeyValues->SetBool( "$additive", m_pAdditiveCheckButton->IsSelected() ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdateTranslucent() |
|
{ |
|
if ( m_pTranslucentCheckButton ) |
|
{ |
|
bool bSelected = m_pTranslucentCheckButton->IsSelected(); |
|
UpdateAlphaTestDiaplay( bSelected ); |
|
m_VMTKeyValues->SetBool( "$translucent", bSelected ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdateAlphaTest() |
|
{ |
|
if ( m_pAlphaTestCheckButton ) |
|
{ |
|
m_VMTKeyValues->SetBool( "$alphatest", m_pAlphaTestCheckButton->IsSelected() ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdateAlphaTestDiaplay( bool bEnable ) |
|
{ |
|
if ( m_pAlphaTestCheckButton ) |
|
{ |
|
m_pAlphaTestCheckButton->SetEnabled( bEnable ); |
|
m_pAlphaTestCheckButton->SetCheckButtonCheckable( bEnable ); |
|
} |
|
|
|
vgui::Label *pLabel = FindControl<vgui::Label>( "AlphaTestLabel" ); |
|
if ( pLabel ) |
|
{ |
|
pLabel->SetEnabled( bEnable ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdateSelfIllum() |
|
{ |
|
if ( m_pSelfIllumCheckButton ) |
|
{ |
|
bool bSelected = m_pSelfIllumCheckButton->IsSelected(); |
|
m_VMTKeyValues->SetBool( ">=DX90/$selfillum", bSelected ); |
|
UpdateSelfIllumDisplay( bSelected ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdateSelfIllumDisplay( bool bEnable ) |
|
{ |
|
m_bSelfIllumEnabled = bEnable; |
|
|
|
static const char* pszSelfIllumLabels[] = |
|
{ |
|
"SelfIllumTintLabel", |
|
"SelfIllumTextureLabel" |
|
}; |
|
|
|
for ( int i=0; i<ARRAYSIZE(pszSelfIllumLabels); ++i ) |
|
{ |
|
vgui::Label *pLabel = FindControl<vgui::Label>( pszSelfIllumLabels[i] ); |
|
if ( pLabel ) |
|
{ |
|
pLabel->SetEnabled( bEnable ); |
|
} |
|
} |
|
|
|
static const char* pszSelfIllumButtons[] = |
|
{ |
|
"SelfIllumTextureBrowse", |
|
"SelfIllumTextureClear" |
|
}; |
|
|
|
for ( int i=0; i<ARRAYSIZE(pszSelfIllumButtons); ++i ) |
|
{ |
|
vgui::Button *pButton = FindControl<vgui::Button>( pszSelfIllumButtons[i] ); |
|
if ( pButton ) |
|
{ |
|
pButton->SetEnabled( bEnable ); |
|
} |
|
} |
|
|
|
m_pSelfIllumTextureFileLabel->SetEnabled( bEnable ); |
|
m_pSelfIllumTintRedTextEntry->SetEnabled( bEnable ); |
|
m_pSelfIllumTintGreenTextEntry->SetEnabled( bEnable ); |
|
m_pSelfIllumTintBlueTextEntry->SetEnabled( bEnable ); |
|
|
|
// blend tint color over base is not compatible with selfillum. must turn it off |
|
UpdateBlendTintColorOverBaseDisplay( !bEnable ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdateSelfIllumTint( int nSkinIndex, const char* pszColor ) |
|
{ |
|
m_strSelfIllumTint[nSkinIndex] = pszColor; |
|
|
|
// +1 to skip [ |
|
const char *pszStrippedSelfIllumTintColor = pszColor + 1; |
|
float selfIllumTint[3]; |
|
UTIL_StringToFloatArray( selfIllumTint, ARRAYSIZE( selfIllumTint ), pszStrippedSelfIllumTintColor ); |
|
if ( m_pSelfIllumTintRedTextEntry ) |
|
{ |
|
m_pSelfIllumTintRedTextEntry->SetText( CFmtStr( "%d", int( selfIllumTint[0] * 255.f ) ) ); |
|
} |
|
if ( m_pSelfIllumTintGreenTextEntry ) |
|
{ |
|
m_pSelfIllumTintGreenTextEntry->SetText( CFmtStr( "%d", int( selfIllumTint[1] * 255.f ) ) ); |
|
} |
|
if ( m_pSelfIllumTintBlueTextEntry ) |
|
{ |
|
m_pSelfIllumTintBlueTextEntry->SetText( CFmtStr( "%d", int( selfIllumTint[2] * 255.f ) ) ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdateEnvmapDisplay( bool bEnable ) |
|
{ |
|
static const char* pszEnvmapLabels[] = |
|
{ |
|
"EnvmapAlphaMaskLabel", |
|
"EnvmapTintLabel" |
|
}; |
|
|
|
for ( int i=0; i<ARRAYSIZE(pszEnvmapLabels); ++i ) |
|
{ |
|
vgui::Label *pLabel = FindControl<vgui::Label>( pszEnvmapLabels[i] ); |
|
if ( pLabel ) |
|
{ |
|
pLabel->SetEnabled( bEnable ); |
|
} |
|
} |
|
|
|
m_pEnvmapAlphaMaskComboBox->SetEnabled( bEnable ); |
|
m_pCubemapTintRedTextEntry->SetEnabled( bEnable ); |
|
m_pCubemapTintGreenTextEntry->SetEnabled( bEnable ); |
|
m_pCubemapTintBlueTextEntry->SetEnabled( bEnable ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFImportMaterialEditDialog::UpdateUniqueLabels() |
|
{ |
|
static Color color[NUM_IMPORT_MATERIALS_PER_TEAM] = { Color( 189, 59, 59, 255 ), Color( 57, 92, 120, 255 ) }; |
|
static const char* pszLabelNames[] = |
|
{ |
|
"BaseTextureLabel", |
|
"ColorTintBaseLabel", |
|
"SelfIllumTintLabel" |
|
}; |
|
|
|
for ( int i=0; i<ARRAYSIZE( pszLabelNames ); ++i ) |
|
{ |
|
vgui::Label* pLabel = FindControl<vgui::Label>( pszLabelNames[i] ); |
|
if ( pLabel ) |
|
{ |
|
pLabel->InvalidateLayout( true, true ); |
|
pLabel->SetFgColor( color[m_nSkinIndex] ); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Preview an item after building it |
|
//----------------------------------------------------------------------------- |
|
class CImportPreviewItemPanel : public CTFStorePreviewItemPanel2 |
|
{ |
|
DECLARE_CLASS_SIMPLE( CImportPreviewItemPanel, CTFStorePreviewItemPanel2 ); |
|
|
|
public: |
|
CImportPreviewItemPanel( vgui::Panel *parent, KeyValues *pItemValues, int nSelectedClass ); |
|
virtual ~CImportPreviewItemPanel(); |
|
|
|
virtual void PreviewItem( int iClass, CEconItemView *pItem, const econ_store_entry_t* pEntry = NULL ) OVERRIDE; |
|
|
|
protected: |
|
void ResetHandles(); |
|
|
|
virtual void OnThink(); |
|
virtual void ApplySchemeSettings( vgui::IScheme *pScheme ); |
|
virtual void OnCommand( const char *command ); |
|
virtual void OnKeyCodeTyped( KeyCode code ); |
|
virtual void PerformLayout( void ); |
|
virtual void OnClose(); |
|
|
|
virtual void UpdatePlayerModelButtons(); |
|
void UpdateActivityUI(); |
|
void UpdateActivity(); |
|
void UpdateMaterialButtons(); |
|
|
|
virtual bool AllowUnusualPreview() const { return true; } |
|
|
|
int GetSequence( const char *pszGesture = NULL ); |
|
void StartAction(); |
|
void StartGesture( const char *pszGesture ); |
|
void EndGestures(); |
|
|
|
bool ClassHasModels( int nClassIndex ) |
|
{ |
|
for ( int nModelIndex = 0; nModelIndex < NUM_IMPORT_LODS; ++nModelIndex ) |
|
{ |
|
if ( V_stricmp( m_pItemValues->GetString( CFmtStr( kClassLODNFile, kClassFolders[ nClassIndex ], nModelIndex ) ), "" ) != 0 ) |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", data ); |
|
MESSAGE_FUNC_PARAMS( OnClassIconSelected, "ClassIconSelected", data ); |
|
|
|
void ResetCamera(); |
|
|
|
vgui::ComboBox *m_pLODComboBox; |
|
vgui::ComboBox *m_pLoadoutComboBox; |
|
vgui::ComboBox *m_pPoseComboBox; |
|
vgui::ComboBox *m_pActionComboBox; |
|
vgui::ComboBox *m_pEffectComboBox; |
|
CUtlVector< vgui::Button* > m_pMaterialButtons; |
|
|
|
KeyValues *m_pItemValues; |
|
int m_nCurrentLOD; |
|
loadout_positions_t m_nCurrentLoadout; |
|
CUtlString m_sCurrentPose; |
|
CUtlString m_sCurrentAction; |
|
bool m_bIsVCDFileNameOnly; |
|
float m_flGestureEndTime; |
|
int m_nSelectedClass; |
|
|
|
int m_nCacheModelDetail; |
|
bool m_bIsTaunt; |
|
}; |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CImportPreviewItemPanel::CImportPreviewItemPanel( vgui::Panel *parent, KeyValues *pItemValues, int nSelectedClass ) |
|
: CTFStorePreviewItemPanel2( parent, "resource/ui/ImportPreviewItemPanel.res", "importpreviewitem", NULL ) |
|
, m_pItemValues( pItemValues ) |
|
, m_nCurrentLOD( 0 ) |
|
, m_nCurrentLoadout( LOADOUT_POSITION_PRIMARY ) |
|
, m_sCurrentPose( kModelPoses[ kDefaultModelPoseIndex ] ) |
|
, m_bIsVCDFileNameOnly( true ) |
|
, m_flGestureEndTime( 0.0f ) |
|
, m_nSelectedClass( nSelectedClass ) |
|
{ |
|
ResetHandles(); |
|
|
|
static ConVarRef r_rootlod( "r_rootlod" ); |
|
if ( r_rootlod.IsValid() ) |
|
{ |
|
m_nCacheModelDetail = r_rootlod.GetInt(); |
|
r_rootlod.SetValue( 0 ); |
|
} |
|
|
|
m_bIsTaunt = FStrEq( m_pItemValues->GetString( kItemPrefab ), "taunt" ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CImportPreviewItemPanel::~CImportPreviewItemPanel() |
|
{ |
|
g_PlayerPreviewEffect.Reset(); |
|
|
|
static ConVarRef r_rootlod( "r_rootlod" ); |
|
if ( r_rootlod.IsValid() ) |
|
{ |
|
r_rootlod.SetValue( m_nCacheModelDetail ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CImportPreviewItemPanel::PreviewItem( int iClass, CEconItemView *pItem, const econ_store_entry_t* pEntry ) |
|
{ |
|
if ( m_pPlayerModelPanel && m_iState == PS_PLAYER ) |
|
{ |
|
// Preserve state when refreshing the preview |
|
Vector vecSavedCameraOffset; |
|
Vector vecSavedCameraPos; |
|
QAngle angSavedCameraDir; |
|
m_pPlayerModelPanel->GetCameraOffset( vecSavedCameraOffset ); |
|
m_pPlayerModelPanel->GetCameraPositionAndAngles( vecSavedCameraPos, angSavedCameraDir ); |
|
|
|
int iSavedClass = m_iCurrentClass; |
|
|
|
BaseClass::PreviewItem( iClass, pItem, pEntry ); |
|
|
|
KeyValuesAD pKeyValues( "data" ); |
|
pKeyValues->SetInt( "class", iSavedClass ); |
|
OnClassIconSelected( pKeyValues ); |
|
|
|
m_pPlayerModelPanel->ResetCameraPivot(); |
|
m_pPlayerModelPanel->SetCameraOffset( vecSavedCameraOffset ); |
|
m_pPlayerModelPanel->SetCameraPositionAndAngles( vecSavedCameraPos, angSavedCameraDir ); |
|
m_pPlayerModelPanel->SetForcedCameraPosition( true ); |
|
|
|
m_pPlayerModelPanel->SetLOD( m_nCurrentLOD ); |
|
} |
|
else |
|
{ |
|
BaseClass::PreviewItem( iClass, pItem, pEntry ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CImportPreviewItemPanel::ResetHandles() |
|
{ |
|
m_pLODComboBox = NULL; |
|
m_pLoadoutComboBox = NULL; |
|
m_pPoseComboBox = NULL; |
|
m_pActionComboBox = NULL; |
|
m_pEffectComboBox = NULL; |
|
m_pMaterialButtons.RemoveAll(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CImportPreviewItemPanel::OnThink() |
|
{ |
|
// We want to skip CTFStorePreviewItemPanel2::OnThink() because it closes when the mouse is clicked outside the dialog. |
|
CTFStorePreviewItemPanelBase::OnThink(); |
|
|
|
// There's no event when the team color changes, but this is a super cheap call so we'll poll. |
|
g_PlayerPreviewEffect.SetTeam( GetPreviewTeam() ); |
|
|
|
if ( m_flGestureEndTime && gpGlobals->curtime >= m_flGestureEndTime ) |
|
{ |
|
EndGestures(); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CImportPreviewItemPanel::ApplySchemeSettings( vgui::IScheme *pScheme ) |
|
{ |
|
ResetHandles(); |
|
|
|
BaseClass::ApplySchemeSettings( pScheme ); |
|
|
|
// We don't use the scrollbar in this view |
|
if ( m_pScrollBar ) |
|
{ |
|
m_pScrollBar->MarkForDeletion(); |
|
m_pScrollBar = NULL; |
|
} |
|
|
|
vgui::Button *pButton = FindControl<vgui::Button>( "AddToCartButton", true ); |
|
if ( pButton ) |
|
{ |
|
pButton->SetVisible( false ); |
|
} |
|
|
|
m_pLODComboBox = FindControl<vgui::ComboBox>( "LODComboBox", true ); |
|
if ( m_pLODComboBox ) |
|
{ |
|
m_pLODComboBox->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pLoadoutComboBox = FindControl<vgui::ComboBox>( "LoadoutComboBox", true ); |
|
if ( m_pLoadoutComboBox ) |
|
{ |
|
m_pLoadoutComboBox->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pPoseComboBox = FindControl<vgui::ComboBox>( "PoseComboBox", true ); |
|
if ( m_pPoseComboBox ) |
|
{ |
|
m_pPoseComboBox->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pActionComboBox = FindControl<vgui::ComboBox>( "ActionComboBox", true ); |
|
if ( m_pActionComboBox ) |
|
{ |
|
m_pActionComboBox->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pEffectComboBox = FindControl<vgui::ComboBox>( "EffectComboBox", true ); |
|
if ( m_pEffectComboBox ) |
|
{ |
|
m_pEffectComboBox->RemoveAll(); |
|
|
|
KeyValuesAD pKeyValues( "data" ); |
|
for ( int iEffect = 0; iEffect < C_TFPlayerPreviewEffect::NUM_PREVIEW_EFFECTS; ++iEffect ) |
|
{ |
|
pKeyValues->SetInt( "effect", iEffect ); |
|
int iRow = m_pEffectComboBox->AddItem( CFmtStr( "#TF_ImportPreview_Effect%d", iEffect ), pKeyValues ); |
|
if ( g_PlayerPreviewEffect.GetEffect() == iEffect ) |
|
{ |
|
m_pEffectComboBox->ActivateItemByRow( iRow ); |
|
} |
|
} |
|
|
|
m_pEffectComboBox->AddActionSignalTarget( this ); |
|
} |
|
|
|
// Default to the character view, because that's the most valuable for preview here |
|
const CTFItemDefinition *pItemData = m_item.GetItemDefinition(); |
|
if ( pItemData ) |
|
{ |
|
for ( int iClass = TF_FIRST_NORMAL_CLASS; iClass < TF_LAST_NORMAL_CLASS; iClass++ ) |
|
{ |
|
if ( !pItemData->CanBeUsedByClass(iClass) ) |
|
continue; |
|
|
|
KeyValuesAD pKeyValues( "data" ); |
|
pKeyValues->SetInt( "class", iClass ); |
|
OnClassIconSelected( pKeyValues ); |
|
break; |
|
} |
|
} |
|
|
|
pButton = FindControl<vgui::Button>( "ButtonAction", true ); |
|
if ( pButton ) |
|
{ |
|
pButton->AddActionSignalTarget( this ); |
|
} |
|
|
|
pButton = FindControl<vgui::Button>( "ButtonEditQC", true ); |
|
if ( pButton ) |
|
{ |
|
pButton->AddActionSignalTarget( this ); |
|
} |
|
|
|
int nSkinType = m_pItemValues->GetInt( kSkinType ); |
|
m_pMaterialButtons.SetCount( MAX_MATERIAL_COUNT ); |
|
for ( int i = 0; i < MAX_MATERIAL_COUNT; ++i ) |
|
{ |
|
m_pMaterialButtons[i] = FindControl<vgui::Button>( CFmtStr( "ButtonEditMaterial%d", i ), true ); |
|
if ( m_pMaterialButtons[i] ) |
|
{ |
|
int nSkinIndex = i / NUM_IMPORT_MATERIALS_PER_TEAM; |
|
int nMaterialIndex = i % NUM_IMPORT_MATERIALS_PER_TEAM; |
|
const char* pszTeam; |
|
if ( nSkinType == 0 ) |
|
{ |
|
pszTeam = "ALL"; |
|
} |
|
else |
|
{ |
|
pszTeam = nSkinIndex == 0 ? "RED" : "BLU"; |
|
} |
|
m_pMaterialButtons[i]->SetText( CFmtStr( "Edit VMT%d %s", nMaterialIndex + 1, pszTeam ) ); |
|
m_pMaterialButtons[i]->AddActionSignalTarget( this ); |
|
} |
|
} |
|
|
|
// Fix up the fullscreen panel with our desired control set |
|
if ( m_pFullscreenPanel ) |
|
{ |
|
pButton = m_pFullscreenPanel->FindControl<vgui::Button>( "RotateLeftButton", true ); |
|
if ( pButton ) |
|
{ |
|
pButton->SetVisible( false ); |
|
} |
|
|
|
pButton = m_pFullscreenPanel->FindControl<vgui::Button>( "RotateRightButton", true ); |
|
if ( pButton ) |
|
{ |
|
pButton->SetVisible( false ); |
|
} |
|
|
|
pButton = m_pFullscreenPanel->FindControl<vgui::Button>( "ZoomButton", true ); |
|
if ( pButton ) |
|
{ |
|
pButton->SetVisible( false ); |
|
} |
|
} |
|
|
|
pButton = FindControl<vgui::Button>( "ButtonEditQCI", true ); |
|
if ( pButton ) |
|
{ |
|
pButton->SetVisible( m_bIsTaunt ); |
|
} |
|
|
|
vgui::Label *pLabel = FindControl<vgui::Label>( "AdvancedLabel", true ); |
|
if ( pLabel ) |
|
{ |
|
pLabel->SetVisible( !m_bIsTaunt ); |
|
} |
|
vgui::Panel *pPanel = FindControl<vgui::Panel>( "AdvancedFrame", true ); |
|
if ( pPanel ) |
|
{ |
|
pPanel->SetVisible( !m_bIsTaunt ); |
|
} |
|
|
|
UpdateActivityUI(); |
|
UpdateMaterialButtons(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CImportPreviewItemPanel::OnCommand( const char *command ) |
|
{ |
|
if ( V_strcasecmp( command, "show_explanations" ) == 0 ) |
|
{ |
|
CExplanationPopup *pPopup = dynamic_cast<CExplanationPopup*>( FindChildByName("StartExplanation") ); |
|
if ( pPopup ) |
|
{ |
|
pPopup->Popup(); |
|
} |
|
} |
|
else if ( V_strcasecmp( command, "action" ) == 0 ) |
|
{ |
|
StartAction(); |
|
} |
|
else if ( V_strcasecmp( command, "BuildPreview" ) == 0 || |
|
V_strcasecmp( command, "EditQC" ) == 0 || |
|
V_strcasecmp( command, "EditQCI" ) == 0 || |
|
V_strncasecmp( command, "EditMaterial", V_strlen( "EditMaterial" ) ) == 0 ) |
|
{ |
|
// Dispatch directly to our parent because the base class tries to run the command through the console interpreter |
|
GetParent()->OnCommand( command ); |
|
} |
|
else |
|
{ |
|
BaseClass::OnCommand( command ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CImportPreviewItemPanel::OnKeyCodeTyped( KeyCode code ) |
|
{ |
|
if ( code == KEY_F5 ) |
|
{ |
|
OnCommand( "BuildPreview" ); |
|
return; |
|
} |
|
|
|
BaseClass::OnKeyCodeTyped( code ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CImportPreviewItemPanel::PerformLayout( void ) |
|
{ |
|
CTFStorePreviewItemPanel2::PerformLayout(); |
|
|
|
PlaceControl( m_pDetailsViewChild, NULL, "UsedByLabel", m_iSmallVerticalBreakSize, true ); |
|
PlaceControl( m_pDetailsViewChild, "UsedByLabel", "UsedByTextLabel", m_iHorizontalBreakSize, false ); |
|
PlaceControl( m_pDetailsViewChild, "UsedByLabel", "SlotLabel", m_iSmallVerticalBreakSize, true ); |
|
PlaceControl( m_pDetailsViewChild, "SlotLabel", "SlotTextLabel", m_iHorizontalBreakSize, false ); |
|
PlaceControl( m_pDetailsViewChild, "SlotLabel", "AttributesLabel", m_iBigVerticalBreakSize, true ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CImportPreviewItemPanel::OnClose() |
|
{ |
|
GetParent()->OnCommand( "PreviewDone" ); |
|
MarkForDeletion(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CImportPreviewItemPanel::UpdatePlayerModelButtons() |
|
{ |
|
BaseClass::UpdatePlayerModelButtons(); |
|
|
|
UpdateActivityUI(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CImportPreviewItemPanel::UpdateActivityUI() |
|
{ |
|
if ( m_pLODComboBox ) |
|
{ |
|
m_pLODComboBox->RemoveAll(); |
|
m_pLODComboBox->SetText( "" ); |
|
|
|
Assert( m_nSelectedClass != TF_CLASS_UNDEFINED ); |
|
if ( m_iState == PS_PLAYER ) |
|
{ |
|
KeyValuesAD pKeyValues( "data" ); |
|
int nDefaultRow = -1; |
|
int nLastValidLOD = 0; |
|
for ( int nLOD = 0; nLOD < NUM_IMPORT_LODS; ++nLOD ) |
|
{ |
|
KeyValues *pKey = m_pItemValues->FindKey( CFmtStr( kClassLODN, kClassFolders[ m_nSelectedClass ], nLOD ) ); |
|
if ( pKey && *pKey->GetString( "file" ) ) |
|
{ |
|
nLastValidLOD = nLOD; |
|
} |
|
|
|
pKeyValues->SetInt( "LOD", nLOD ); |
|
int nRow = m_pLODComboBox->AddItem( CFmtStr( "LOD%d", nLOD ), pKeyValues ); |
|
if ( m_nCurrentLOD == nLOD ) |
|
{ |
|
nDefaultRow = nRow; |
|
} |
|
} |
|
Assert( nDefaultRow >= 0 ); |
|
m_pLODComboBox->ActivateItemByRow( nDefaultRow ); |
|
} |
|
} |
|
|
|
if ( m_pLoadoutComboBox ) |
|
{ |
|
m_pLoadoutComboBox->RemoveAll(); |
|
m_pLoadoutComboBox->SetText( "" ); |
|
|
|
if ( m_iState == PS_PLAYER ) |
|
{ |
|
KeyValuesAD pKeyValues( "data" ); |
|
int nDefaultRow = -1; |
|
loadout_positions_t nFirstLoadout = LOADOUT_POSITION_INVALID; |
|
for ( int iLoadoutPosition = 0; iLoadoutPosition < CLASS_LOADOUT_POSITION_COUNT; ++iLoadoutPosition ) |
|
{ |
|
CEconItemView *pItem = TFInventoryManager()->GetBaseItemForClass( m_iCurrentClass, iLoadoutPosition ); |
|
if ( pItem && pItem->IsValid() ) |
|
{ |
|
const char *pszLabel = ItemSystem()->GetItemSchema()->GetLoadoutStringsForDisplay( pItem->GetItemDefinition()->GetEquipType() )[ iLoadoutPosition ]; |
|
pKeyValues->SetInt( "loadout", iLoadoutPosition ); |
|
int nRow = m_pLoadoutComboBox->AddItem( pszLabel, pKeyValues ); |
|
if ( iLoadoutPosition == m_nCurrentLoadout ) |
|
{ |
|
nDefaultRow = nRow; |
|
} |
|
if ( nFirstLoadout == LOADOUT_POSITION_INVALID ) |
|
{ |
|
nFirstLoadout = (loadout_positions_t)iLoadoutPosition; |
|
} |
|
} |
|
} |
|
Assert(nFirstLoadout != LOADOUT_POSITION_INVALID); |
|
|
|
if (nDefaultRow < 0) |
|
{ |
|
// Didn't find our current loadout position, pick the first one |
|
nDefaultRow = 0; |
|
m_nCurrentLoadout = nFirstLoadout; |
|
} |
|
m_pLoadoutComboBox->ActivateItemByRow( nDefaultRow ); |
|
} |
|
} |
|
|
|
if ( m_pPoseComboBox ) |
|
{ |
|
m_pPoseComboBox->RemoveAll(); |
|
m_pPoseComboBox->SetText( "" ); |
|
|
|
if ( m_iState == PS_PLAYER ) |
|
{ |
|
KeyValuesAD pKeyValues( "data" ); |
|
int nDefaultRow = -1; |
|
for ( int iPose = 0; iPose < ARRAYSIZE(kModelPoses); ++iPose ) |
|
{ |
|
pKeyValues->SetString( "pose", kModelPoses[ iPose ] ); |
|
int nRow = m_pPoseComboBox->AddItem( CFmtStr( "#TF_ImportPreview_Pose%s", kModelPoses[ iPose ] ), pKeyValues ); |
|
if ( m_sCurrentPose == kModelPoses[ iPose ] ) |
|
{ |
|
nDefaultRow = nRow; |
|
} |
|
} |
|
Assert( nDefaultRow >= 0 ); |
|
m_pPoseComboBox->ActivateItemByRow( nDefaultRow ); |
|
} |
|
} |
|
|
|
if ( m_pActionComboBox ) |
|
{ |
|
m_pActionComboBox->RemoveAll(); |
|
m_pActionComboBox->SetText( "" ); |
|
|
|
if ( m_iState == PS_PLAYER ) |
|
{ |
|
KeyValuesAD pKeyValues("data"); |
|
if ( m_bIsTaunt ) |
|
{ |
|
CTFFileImportDialog *pFileImportDialog = dynamic_cast<CTFFileImportDialog*>(GetParent()); |
|
if (pFileImportDialog) |
|
{ |
|
KeyValuesAD pItemSchema(pFileImportDialog->BuildItemSchema("item_preview")); |
|
|
|
const CUtlVector<const char *>&vecUsabilityStrings = ItemSystem()->GetItemSchema()->GetClassUsabilityStrings(); |
|
KeyValues *pTauntKey = pItemSchema->FindKey("taunt"); |
|
if (pTauntKey) |
|
{ |
|
KeyValues *pCustomTauntPerClass = pTauntKey->FindKey("custom_taunt_scene_per_class"); |
|
if (pCustomTauntPerClass) |
|
{ |
|
const char *pSceneName = pCustomTauntPerClass->GetString(vecUsabilityStrings[m_nSelectedClass]); |
|
if (pSceneName && *pSceneName) |
|
{ |
|
pKeyValues->SetString("action", pSceneName); |
|
pKeyValues->SetBool("file_name_only", false); |
|
m_pActionComboBox->AddItem("#TF_ImportPreview_Taunt", pKeyValues); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
for (int iAction = 0; iAction < ARRAYSIZE(kModelActions); ++iAction) |
|
{ |
|
pKeyValues->SetString("action", kModelActions[iAction]); |
|
pKeyValues->SetBool("file_name_only", true); |
|
m_pActionComboBox->AddItem(CFmtStr("#TF_ImportPreview_Action%d", iAction), pKeyValues); |
|
} |
|
} |
|
|
|
Assert( m_pActionComboBox->GetItemCount() >= 0 ); |
|
m_pActionComboBox->ActivateItemByRow( 0 ); |
|
|
|
// init default value |
|
KeyValues *pData = m_pActionComboBox->GetActiveItemUserData(); |
|
m_sCurrentAction = pData->GetString( "action" ); |
|
m_bIsVCDFileNameOnly = pData->GetBool( "file_name_only" ); |
|
} |
|
} |
|
|
|
UpdateActivity(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CImportPreviewItemPanel::UpdateActivity() |
|
{ |
|
if ( !m_pPlayerModelPanel || !m_pPlayerModelPanel->GetStudioHdr() || m_iState != PS_PLAYER ) |
|
{ |
|
return; |
|
} |
|
|
|
static CEconItemView tempItem; |
|
if ( m_bIsTaunt && ClassHasModels( m_nSelectedClass ) ) |
|
{ |
|
// use preview item if specified for taunt |
|
tempItem.Init( PREVIEW_ITEM_DEFINITION_INDEX, AE_UNIQUE, AE_USE_SCRIPT_VALUE, true ); |
|
} |
|
else |
|
{ |
|
// FIXME: Once we support weapons we'll need to check to see if we want to display the preview item here instead. |
|
CEconItemView *pItem = TFInventoryManager()->GetBaseItemForClass( m_iCurrentClass, m_nCurrentLoadout ); |
|
Assert( pItem && pItem->IsValid() ); |
|
tempItem = *pItem; |
|
} |
|
m_pPlayerModelPanel->SwitchHeldItemTo( &tempItem ); |
|
|
|
int iSequence = GetSequence(); |
|
if ( iSequence >= 0 ) |
|
{ |
|
m_pPlayerModelPanel->SetSequence( iSequence ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CImportPreviewItemPanel::GetSequence( const char *pszGesture ) |
|
{ |
|
if ( !m_pPlayerModelPanel || !m_pPlayerModelPanel->GetStudioHdr() ) |
|
{ |
|
return -1; |
|
} |
|
|
|
CEconItemView *pItem = m_pPlayerModelPanel->GetHeldItem(); |
|
if ( !pItem ) |
|
{ |
|
return -1; |
|
} |
|
|
|
int iAnimSlot = pItem->GetAnimationSlot(); |
|
if ( iAnimSlot < 0 ) |
|
{ |
|
iAnimSlot = pItem->GetItemDefinition()->GetLoadoutSlot( m_iCurrentClass ); |
|
} |
|
if ( iAnimSlot < 0 ) |
|
{ |
|
return -1; |
|
} |
|
|
|
CStudioHdr studioHdr( m_pPlayerModelPanel->GetStudioHdr(), g_pMDLCache ); |
|
|
|
// Look for the bind pose by label since it's not an activity |
|
if ( !pszGesture && V_strcasecmp( m_sCurrentPose.Get(), "ref" ) == 0 ) |
|
{ |
|
for ( int iSeq = 0; iSeq < studioHdr.GetNumSeq(); ++iSeq ) |
|
{ |
|
mstudioseqdesc_t &seqDesc = studioHdr.pSeqdesc( iSeq ); |
|
if ( V_strcasecmp( seqDesc.pszLabel(), m_sCurrentPose.Get() ) == 0 ) |
|
{ |
|
return iSeq; |
|
} |
|
} |
|
return -1; |
|
} |
|
|
|
CUtlString sActivity; |
|
const char *pszActivityOverride; |
|
CUtlString sAnimSuffix = GetItemSchema()->GetWeaponTypeSubstrings()[ iAnimSlot ]; |
|
sAnimSuffix.ToUpper(); |
|
|
|
if ( pszGesture ) |
|
{ |
|
CUtlString sGesture = pszGesture; |
|
sGesture.ToUpper(); |
|
sActivity.Format( "ACT_MP_%s_%s_%s", sGesture.Get(), m_sCurrentPose.Get(), sAnimSuffix.Get() ); |
|
} |
|
else |
|
{ |
|
sActivity.Format( "ACT_MP_%s_%s", m_sCurrentPose.Get(), sAnimSuffix.Get() ); |
|
} |
|
pszActivityOverride = pItem->GetItemDefinition()->GetActivityOverride( GetPreviewTeam(), sActivity ); |
|
if ( pszActivityOverride ) |
|
{ |
|
sActivity = pszActivityOverride; |
|
} |
|
return m_pPlayerModelPanel->FindSequenceFromActivity( &studioHdr, sActivity.Get() ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CImportPreviewItemPanel::UpdateMaterialButtons() |
|
{ |
|
if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) |
|
return; |
|
|
|
KeyValues* pModelKey = m_pItemValues->FindKey( CFmtStr( kClassLODN, kClassFolders[ m_nSelectedClass ], 0 ) ); |
|
if ( !pModelKey) |
|
return; |
|
|
|
int nSkinType = m_pItemValues->GetInt( kSkinType ); |
|
int nMaterialCount = pModelKey->GetInt( "materialCount" ); |
|
for ( int i=0; i<m_pMaterialButtons.Count(); ++i ) |
|
{ |
|
int nSkinIndex = i / NUM_IMPORT_MATERIALS_PER_TEAM; |
|
int nMaterialIndex = i % NUM_IMPORT_MATERIALS_PER_TEAM; |
|
bool bVisible = nSkinIndex <= nSkinType && nMaterialIndex < nMaterialCount; |
|
m_pMaterialButtons[i]->SetVisible( bVisible ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CImportPreviewItemPanel::StartAction() |
|
{ |
|
const char *pszAction = m_sCurrentAction.String(); |
|
if ( !pszAction || !*pszAction ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( !m_pPlayerModelPanel ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( V_strncasecmp( pszAction, "gesture_", 8 ) == 0 ) |
|
{ |
|
pszAction += 8; |
|
StartGesture( pszAction ); |
|
} |
|
else |
|
{ |
|
m_pPlayerModelPanel->PlayVCD( pszAction, NULL, false, m_bIsVCDFileNameOnly ); |
|
UpdateActivity(); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CImportPreviewItemPanel::StartGesture( const char *pszGesture ) |
|
{ |
|
int iSequence = GetSequence( pszGesture ); |
|
if ( iSequence >= 0 ) |
|
{ |
|
CStudioHdr studioHdr( m_pPlayerModelPanel->GetStudioHdr(), g_pMDLCache ); |
|
|
|
MDLSquenceLayer_t tmpSequenceLayers[1]; |
|
tmpSequenceLayers[0].m_nSequenceIndex = iSequence; |
|
tmpSequenceLayers[0].m_flWeight = 1.0; |
|
tmpSequenceLayers[0].m_bNoLoop = true; |
|
tmpSequenceLayers[0].m_flCycleBeganAt = 0.0f; |
|
m_pPlayerModelPanel->SetSequenceLayers( tmpSequenceLayers, 1 ); |
|
|
|
float flGestureDuration = Studio_Duration( &studioHdr, iSequence, NULL ); |
|
m_flGestureEndTime = gpGlobals->curtime + flGestureDuration; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CImportPreviewItemPanel::EndGestures() |
|
{ |
|
Assert(m_pPlayerModelPanel); |
|
m_pPlayerModelPanel->SetSequenceLayers( NULL, 0 ); |
|
m_flGestureEndTime = 0.0f; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CImportPreviewItemPanel::OnTextChanged( KeyValues *data ) |
|
{ |
|
Panel *pPanel = reinterpret_cast<vgui::Panel *>( data->GetPtr( "panel" ) ); |
|
|
|
vgui::ComboBox *pComboBox = dynamic_cast< vgui::ComboBox * >( pPanel ); |
|
if ( pComboBox ) |
|
{ |
|
if( pComboBox == m_pLODComboBox ) |
|
{ |
|
KeyValues *pData = pComboBox->GetActiveItemUserData(); |
|
int nLOD = pData->GetInt( "LOD" ); |
|
if ( nLOD != m_nCurrentLOD ) |
|
{ |
|
m_nCurrentLOD = nLOD; |
|
if ( m_pPlayerModelPanel ) |
|
{ |
|
m_pPlayerModelPanel->SetLOD( m_nCurrentLOD ); |
|
} |
|
} |
|
} |
|
else if( pComboBox == m_pLoadoutComboBox ) |
|
{ |
|
KeyValues *pData = pComboBox->GetActiveItemUserData(); |
|
loadout_positions_t nLoadout = (loadout_positions_t)pData->GetInt( "loadout" ); |
|
if ( nLoadout != m_nCurrentLoadout ) |
|
{ |
|
m_nCurrentLoadout = nLoadout; |
|
UpdateActivity(); |
|
} |
|
} |
|
else if ( pComboBox == m_pPoseComboBox ) |
|
{ |
|
KeyValues *pData = pComboBox->GetActiveItemUserData(); |
|
const char *pszPose = pData->GetString( "pose" ); |
|
if ( V_strcmp( pszPose, m_sCurrentPose ) != 0 ) |
|
{ |
|
m_sCurrentPose = pszPose; |
|
UpdateActivity(); |
|
|
|
// Changing pose resets the camera |
|
ResetCamera(); |
|
} |
|
} |
|
else if ( pComboBox == m_pActionComboBox ) |
|
{ |
|
KeyValues *pData = pComboBox->GetActiveItemUserData(); |
|
m_sCurrentAction = pData->GetString( "action" ); |
|
m_bIsVCDFileNameOnly = pData->GetBool( "file_name_only" ); |
|
} |
|
else if ( pComboBox == m_pEffectComboBox ) |
|
{ |
|
KeyValues *pData = pComboBox->GetActiveItemUserData(); |
|
g_PlayerPreviewEffect.SetEffect( (C_TFPlayerPreviewEffect::PREVIEW_EFFECT)pData->GetInt("effect") ); |
|
} |
|
return; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CImportPreviewItemPanel::ResetCamera() |
|
{ |
|
if ( m_pPlayerModelPanel ) |
|
{ |
|
m_pPlayerModelPanel->SetForcedCameraPosition( false ); |
|
m_pPlayerModelPanel->InvalidateLayout( true, true ); |
|
m_pPlayerModelPanel->SetForcedCameraPosition( true ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CImportPreviewItemPanel::OnClassIconSelected( KeyValues *data ) |
|
{ |
|
BaseClass::OnClassIconSelected( data ); |
|
|
|
m_nSelectedClass = data->GetInt( "class" ); |
|
|
|
// Clicking on a class icon resets the camera |
|
ResetCamera(); |
|
UpdateMaterialButtons(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Import file dialog |
|
//----------------------------------------------------------------------------- |
|
CTFFileImportDialog::CTFFileImportDialog( vgui::Panel *parent ) |
|
: Frame( parent, "ImportFileDialog" ), |
|
m_tempQC( 0, 0, CUtlBuffer::TEXT_BUFFER ) |
|
{ |
|
vgui::HScheme scheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme" ); |
|
SetScheme(scheme); |
|
SetProportional( true ); |
|
|
|
m_nSelectedClass = TF_CLASS_UNDEFINED; |
|
m_nFileOpenMode = FILE_OPEN_NONE; |
|
|
|
m_pItemValues = new KeyValues( "ImportSession" ); |
|
m_pItemValues->UsesEscapeSequences( true ); |
|
|
|
m_pPreviewSchema = NULL; |
|
|
|
m_pNameTextEntry = NULL; |
|
m_pTypeComboBox = NULL; |
|
m_pSwapVMTButton = NULL; |
|
m_pSkinComboBox = NULL; |
|
m_pWorkshopIDTextEntry = NULL; |
|
m_pTFEnglishNameTextEntry = NULL; |
|
m_pPerforceCheckButton = NULL; |
|
m_pPartnerCheckButton = NULL; |
|
|
|
m_pEquipRegionPanel = NULL; |
|
m_pEquipRegionComboBox = NULL; |
|
|
|
m_pIconImagePanel = NULL; |
|
|
|
V_memset( m_pClassRadioButtons, 0, sizeof( m_pClassRadioButtons ) ); |
|
V_memset( m_pClassHighlights, 0, sizeof( m_pClassHighlights ) ); |
|
|
|
m_pBodygroupsPanel = NULL; |
|
|
|
m_pLODsPanel = NULL; |
|
|
|
m_pSkinsPanel = NULL; |
|
|
|
m_pTauntInputPanel = NULL; |
|
m_pAnimationSourceFile = NULL; |
|
m_pAnimationVCDFile = NULL; |
|
m_pAnimationDurationLabel = NULL; |
|
m_pAnimationPropLabel = NULL; |
|
m_pAnimationLoopCheckButton = NULL; |
|
m_pAnimationLoopStartTextEntry = NULL; |
|
|
|
m_pBuildButton = NULL; |
|
|
|
m_pTextEditDialog = NULL; |
|
m_pMaterialEditDialog = NULL; |
|
m_pPreviewDialog = NULL; |
|
m_pPlayerModelPanel = NULL; |
|
|
|
// force sv_cheats 1 so we can run some client command |
|
static ConVarRef sv_cheats("sv_cheats"); |
|
if ( sv_cheats.IsValid() ) |
|
{ |
|
m_bWasCheatOn = sv_cheats.GetBool(); |
|
sv_cheats.SetValue( true ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFFileImportDialog::~CTFFileImportDialog() |
|
{ |
|
m_pItemValues->deleteThis(); |
|
|
|
if ( m_pPreviewSchema ) |
|
{ |
|
m_pPreviewSchema->deleteThis(); |
|
} |
|
|
|
// restore sv_cheats value before coming into the tool |
|
static ConVarRef sv_cheats("sv_cheats"); |
|
if ( sv_cheats.IsValid() ) |
|
{ |
|
sv_cheats.SetValue( m_bWasCheatOn ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::ApplySchemeSettings( vgui::IScheme *pScheme ) |
|
{ |
|
vgui::Button *pButton; |
|
|
|
BaseClass::ApplySchemeSettings( pScheme ); |
|
|
|
LoadControlSettings( "Resource/UI/ImportFileDialog.res" ); |
|
|
|
m_pNameTextEntry = FindControl<vgui::TextEntry>( "Name" ); |
|
if ( m_pNameTextEntry ) |
|
{ |
|
m_pNameTextEntry->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pTypeComboBox = FindControl<vgui::ComboBox>( "TypeComboBox" ); |
|
if ( m_pTypeComboBox ) |
|
{ |
|
m_pTypeComboBox->RemoveAll(); |
|
|
|
KeyValuesAD pKeyValues( "data" ); |
|
|
|
// Add all the public prefabs |
|
const CEconItemSchema::PrefabMap_t &prefabMap = ItemSystem()->GetItemSchema()->GetPrefabMap(); |
|
for ( int i = prefabMap.FirstInorder(); i != prefabMap.InvalidIndex(); i = prefabMap.NextInorder( i ) ) |
|
{ |
|
KeyValues *pPrefabKeyValues = prefabMap [ i ]; |
|
if ( pPrefabKeyValues->GetBool( "public_prefab" ) ) |
|
{ |
|
for ( int j=0; j<ARRAYSIZE(kPrefabs); ++j ) |
|
{ |
|
if ( V_strcmp( kPrefabs[j], pPrefabKeyValues->GetName() ) == 0 ) |
|
{ |
|
pKeyValues->SetString( kItemPrefab, pPrefabKeyValues->GetName() ); |
|
m_pTypeComboBox->AddItem( CFmtStr( "#TF_ItemPrefab_%s", pPrefabKeyValues->GetName() ), pKeyValues ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
SetItemPrefab( kDefaultPrefab ); |
|
|
|
m_pTypeComboBox->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pEquipRegionPanel = FindControl<vgui::EditablePanel>( "EquipRegionPanel" ); |
|
m_pEquipRegionComboBox = FindControl<vgui::ComboBox>( "EquipRegionComboBox", true ); |
|
if ( m_pEquipRegionComboBox ) |
|
{ |
|
KeyValuesAD pKey( "data" ); |
|
const CEconItemSchema::EquipRegionsList_t& list = ItemSystem()->GetItemSchema()->GetEquipRegionsList(); |
|
CUtlStringList strEquipRegionNameList; |
|
|
|
for ( int j=0; j<list.Count(); ++j ) |
|
{ |
|
const char* pszEquipRegion = list[j].m_sName.Get(); |
|
strEquipRegionNameList.CopyAndAddToTail( pszEquipRegion ); |
|
} |
|
strEquipRegionNameList.Sort( strEquipRegionNameList.SortFunc ); |
|
|
|
for ( int j=0; j<strEquipRegionNameList.Count(); ++j ) |
|
{ |
|
const char* pszEquipRegion = strEquipRegionNameList[j]; |
|
pKey->SetString( kEquipRegion, pszEquipRegion ); |
|
m_pEquipRegionComboBox->AddItem( pszEquipRegion, pKey ); |
|
} |
|
|
|
SetEquipRegion( kDefaultEquipRegion ); |
|
|
|
m_pEquipRegionComboBox->AddActionSignalTarget( this ); |
|
} |
|
|
|
if ( vgui::Label* pLabel = FindControl<vgui::Label>( "WorkshopIDLabel" ) ) |
|
{ |
|
pLabel->SetVisible( p4 ); |
|
} |
|
|
|
m_pWorkshopIDTextEntry = FindControl<vgui::TextEntry>( "WorkshopIDTextEntry" ); |
|
if ( m_pWorkshopIDTextEntry ) |
|
{ |
|
m_pWorkshopIDTextEntry->SetVisible( p4 ); |
|
} |
|
|
|
if ( vgui::Label* pLabel = FindControl<vgui::Label>( "TFEnglishNameLabel" ) ) |
|
{ |
|
pLabel->SetVisible( p4 ); |
|
} |
|
|
|
m_pTFEnglishNameTextEntry = FindControl<vgui::TextEntry>( "TFEnglishNameTextEntry" ); |
|
if ( m_pTFEnglishNameTextEntry ) |
|
{ |
|
m_pTFEnglishNameTextEntry->SetVisible( p4 ); |
|
} |
|
|
|
m_pPerforceCheckButton = FindControl<vgui::CheckButton>( "PerforceCheckButton" ); |
|
if ( m_pPerforceCheckButton ) |
|
{ |
|
m_pPerforceCheckButton->SetVisible( p4 ); |
|
} |
|
|
|
m_pPartnerCheckButton = FindControl<vgui::CheckButton>( "PartnerCheckButton" ); |
|
if ( m_pPartnerCheckButton ) |
|
{ |
|
m_pPartnerCheckButton->SetVisible( p4 ); |
|
} |
|
|
|
m_pIconImagePanel = FindControl<vgui::ImagePanel>( "Icon", true ); |
|
if ( m_pIconImagePanel ) |
|
{ |
|
// Set black background, and center the 512x512 backpack icon |
|
m_pIconImagePanel->SetFillColor( Color(0, 0, 0, 255) ); |
|
} |
|
|
|
pButton = FindControl<vgui::Button>( "ButtonIconClear", true ); |
|
if ( pButton ) |
|
{ |
|
pButton->AddActionSignalTarget( this ); |
|
} |
|
pButton = FindControl<vgui::Button>( "ButtonIconBrowse", true ); |
|
if ( pButton ) |
|
{ |
|
pButton->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pPaintableCheckButtons.SetCount( 2 ); |
|
for ( int i=0; i<m_pPaintableCheckButtons.Count(); ++i ) |
|
{ |
|
m_pPaintableCheckButtons[i] = FindControl<vgui::CheckButton>( CFmtStr( "Paintable%dCheckBox", i ), true ); |
|
if ( m_pPaintableCheckButtons[i] ) |
|
{ |
|
m_pPaintableCheckButtons[i]->AddActionSignalTarget( this ); |
|
} |
|
} |
|
|
|
for ( int i = TF_FIRST_NORMAL_CLASS; i < TF_LAST_NORMAL_CLASS; ++i ) |
|
{ |
|
m_pClassHighlights[ i ] = FindControl<vgui::Panel>( CFmtStr( "ClassHighlight%d", i ), true ); |
|
m_pClassRadioButtons[i] = FindControl<vgui::RadioButton>( CFmtStr( "ButtonSelectClass%d", i ), true ); |
|
if ( m_pClassRadioButtons[i] ) |
|
m_pClassRadioButtons[i]->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pBodygroupsPanel = FindControl<vgui::EditablePanel>( "BodygroupsPanel" ); |
|
m_pBodygroups.SetCount( ARRAYSIZE( kBodygroupArray ) ); |
|
for ( int i=0; i<m_pBodygroups.Count(); ++i ) |
|
{ |
|
m_pBodygroups[i] = FindControl<vgui::CheckButton>( CFmtStr( "Bodygroup%d", i ), true ); |
|
AssertMsg( m_pBodygroups[i], CFmtStr( "Missing Bodygroup%d CheckButton in ImportFileDialog.res", i ) ); |
|
if ( m_pBodygroups[i] ) |
|
{ |
|
m_pBodygroups[i]->AddActionSignalTarget( this ); |
|
m_pBodygroups[i]->SetSelected( true ); |
|
m_pBodygroups[i]->SetCheckButtonCheckable( false ); |
|
m_pBodygroups[i]->SetText( kBodygroupArray[i] ); |
|
} |
|
} |
|
|
|
m_pLODsPanel = FindControl<vgui::EditablePanel>( "LODsPanel" ); |
|
m_pLODPanels.SetCount( NUM_IMPORT_LODS ); |
|
m_pLODFiles.SetCount( NUM_IMPORT_LODS ); |
|
m_pLODDetails.SetCount( NUM_IMPORT_LODS ); |
|
for ( int i = 0; i < NUM_IMPORT_LODS; ++i ) |
|
{ |
|
m_pLODPanels[ i ] = FindControl<vgui::Panel>( CFmtStr( "LOD%dPanel", i ), true ); |
|
m_pLODFiles[ i ] = FindControl<vgui::Label>( CFmtStr( "LOD%dFile", i ), true ); |
|
m_pLODDetails[ i ] = FindControl<vgui::Label>( CFmtStr( "LOD%dDetails", i ), true ); |
|
|
|
pButton = FindControl<vgui::Button>( CFmtStr( "ButtonLOD%dBrowse", i ), true ); |
|
if ( pButton ) |
|
{ |
|
pButton->AddActionSignalTarget( this ); |
|
} |
|
|
|
pButton = FindControl<vgui::Button>( CFmtStr( "ButtonLOD%dClear", i ), true ); |
|
if ( pButton ) |
|
{ |
|
pButton->AddActionSignalTarget( this ); |
|
} |
|
} |
|
|
|
pButton = FindControl<vgui::Button>( "ButtonEditQC", true ); |
|
if (pButton) |
|
{ |
|
pButton->AddActionSignalTarget(this); |
|
} |
|
|
|
m_pSkinsPanel = FindControl<vgui::EditablePanel>( "SkinsPanel" ); |
|
|
|
m_pSwapVMTButton = FindControl<vgui::Button>( "SwapVMTButton", true ); |
|
if ( m_pSwapVMTButton ) |
|
{ |
|
m_pSwapVMTButton->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pSkinComboBox = FindControl<vgui::ComboBox>( "SkinComboBox", true ); |
|
if ( m_pSkinComboBox ) |
|
{ |
|
m_pSkinComboBox->RemoveAll(); |
|
|
|
KeyValuesAD pKeyValues( "data" ); |
|
for ( int j=0; j<NUM_IMPORT_MATERIALS_PER_TEAM; ++j ) |
|
{ |
|
pKeyValues->SetInt( kSkinType, j ); |
|
m_pSkinComboBox->AddItem( CFmtStr( "#TF_ItemSkinType_%d", j ), pKeyValues ); |
|
} |
|
|
|
m_pSkinComboBox->ActivateItemByRow( 0 ); |
|
|
|
m_pSkinComboBox->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pMaterialPanels.SetCount( MAX_MATERIAL_COUNT ); |
|
m_pMaterialLabels.SetCount( MAX_MATERIAL_COUNT ); |
|
m_pMaterialFiles.SetCount( MAX_MATERIAL_COUNT ); |
|
for ( int i = 0; i < MAX_MATERIAL_COUNT; ++i ) |
|
{ |
|
m_pMaterialPanels[ i ] = FindControl<vgui::Panel>( CFmtStr( "Material%dPanel", i ), true ); |
|
m_pMaterialLabels[ i ] = FindControl<vgui::Label>( CFmtStr( "Material%dLabel", i ), true ); |
|
m_pMaterialFiles[ i ] = FindControl<vgui::Label>( CFmtStr( "Material%dFile", i ), true ); |
|
|
|
pButton = FindControl<vgui::Button>( CFmtStr( "ButtonMaterial%dEdit", i ), true ); |
|
if ( pButton ) |
|
{ |
|
pButton->AddActionSignalTarget( this ); |
|
} |
|
|
|
pButton = FindControl<vgui::Button>( CFmtStr( "ButtonMaterial%dBrowse", i ), true ); |
|
if ( pButton ) |
|
{ |
|
pButton->AddActionSignalTarget( this ); |
|
} |
|
|
|
pButton = FindControl<vgui::Button>( CFmtStr( "ButtonMaterial%dClear", i ), true ); |
|
if ( pButton ) |
|
{ |
|
pButton->AddActionSignalTarget( this ); |
|
} |
|
} |
|
|
|
m_pTauntInputPanel = FindControl<vgui::EditablePanel>( "TauntInputPanel" ); |
|
if ( m_pTauntInputPanel ) |
|
{ |
|
m_pAnimationSourceFile = FindControl<vgui::Label>( "AnimationSourceFile", true ); |
|
pButton = FindControl<vgui::Button>( "ButtonAnimationSourceBrowse", true ); |
|
if ( pButton ) |
|
{ |
|
pButton->AddActionSignalTarget( this ); |
|
} |
|
|
|
pButton = FindControl<vgui::Button>( "ButtonAnimationSourceClear", true ); |
|
if ( pButton ) |
|
{ |
|
pButton->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pAnimationVCDFile = FindControl<vgui::Label>( "AnimationVCDFile", true ); |
|
pButton = FindControl<vgui::Button>( "ButtonAnimationVCDBrowse", true ); |
|
if ( pButton ) |
|
{ |
|
pButton->AddActionSignalTarget( this ); |
|
} |
|
|
|
pButton = FindControl<vgui::Button>( "ButtonAnimationVCDClear", true ); |
|
if ( pButton ) |
|
{ |
|
pButton->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pAnimationDurationLabel = FindControl<vgui::Label>( "AnimDurationLabel", true ); |
|
|
|
m_pAnimationLoopCheckButton = FindControl<vgui::CheckButton>( "AnimationLoopCheckButton", true ); |
|
if ( m_pAnimationLoopCheckButton ) |
|
{ |
|
m_pAnimationLoopCheckButton->AddActionSignalTarget( this ); |
|
} |
|
|
|
m_pAnimationLoopStartTextEntry = FindControl<vgui::TextEntry>( "AnimationLoopStartTextEntry", true ); |
|
if ( m_pAnimationLoopStartTextEntry ) |
|
{ |
|
m_pAnimationLoopStartTextEntry->AddActionSignalTarget( this ); |
|
} |
|
|
|
pButton = FindControl<vgui::Button>( "ButtonEditQCI", true ); |
|
if (pButton) |
|
{ |
|
pButton->AddActionSignalTarget(this); |
|
} |
|
} |
|
m_pAnimationPropLabel = FindControl<vgui::Label>( "AnimationPropLabel" ); |
|
|
|
m_pBuildButton = FindControl<vgui::Button>( "ButtonBuild" ); |
|
if ( m_pBuildButton ) |
|
{ |
|
m_pBuildButton->SetEnabled( false ); |
|
} |
|
|
|
m_pPlayerModelPanel = dynamic_cast<CTFPlayerModelPanel*>( FindChildByName("classmodelpanel") ); |
|
|
|
OnOpen(); |
|
|
|
UpdateMaterialDisplay(); |
|
UpdateBodygroupsDisplay(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::OnCommand( const char *command ) |
|
{ |
|
if ( V_stricmp( command, "Load" ) == 0 ) |
|
{ |
|
OnCommandLoad(); |
|
} |
|
else if ( V_stricmp( command, "Save" ) == 0 ) |
|
{ |
|
OnCommandSave(); |
|
} |
|
else if ( V_stricmp( command, "ClearIcon" ) == 0 ) |
|
{ |
|
SetItemIcon( "" ); |
|
} |
|
else if ( V_stricmp( command, "BrowseIcon" ) == 0 ) |
|
{ |
|
OnCommandBrowseIcon(); |
|
} |
|
else if ( V_stricmp( command, "UpdateBodygroup" ) == 0 ) |
|
{ |
|
OnCommandUpdateBodygroup(); |
|
} |
|
else if ( V_strncasecmp( command, "UpdatePaintable", V_strlen( "UpdatePaintable" ) ) == 0 ) |
|
{ |
|
int nMaterialIndex = V_atoi( &command[ V_strlen( "UpdatePaintable" ) ] ); |
|
SetPaintable( m_pPaintableCheckButtons[nMaterialIndex]->IsSelected(), nMaterialIndex ); |
|
} |
|
else if ( V_strncasecmp( command, "ClearLOD", V_strlen( "ClearLOD" ) ) == 0 ) |
|
{ |
|
int index = V_atoi( &command[ V_strlen( "ClearLOD" ) ] ); |
|
|
|
SetLOD( m_nSelectedClass, index, "" ); |
|
} |
|
else if ( V_strncasecmp( command, "BrowseLOD", V_strlen( "BrowseLOD" ) ) == 0 ) |
|
{ |
|
if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) |
|
{ |
|
ShowMessageBox( "#TF_ImportFile_SelectClassTitle", "#TF_ImportFile_SelectClass" ); |
|
return; |
|
} |
|
|
|
int index = V_atoi( &command[ V_strlen( "BrowseLOD" ) ] ); |
|
|
|
OnCommandBrowseLOD( index ); |
|
} |
|
else if ( V_stricmp( command, "SwapVMT" ) == 0 ) |
|
{ |
|
OnCommandSwapVMT(); |
|
} |
|
else if ( V_strncasecmp( command, "EditMaterialDone", V_strlen( "EditMaterialDone" ) ) == 0 ) |
|
{ |
|
int nSkinIndex, nMaterialIndex; |
|
if ( sscanf( command + V_strlen( "EditMaterialDone" ), "%d,%d", &nSkinIndex, &nMaterialIndex ) == 2 ) |
|
{ |
|
OnCommandEditMaterialDone( nSkinIndex, nMaterialIndex ); |
|
} |
|
} |
|
else if ( V_strncasecmp( command, "EditMaterial", V_strlen( "EditMaterial" ) ) == 0 ) |
|
{ |
|
int nMaterialPanelIndex; |
|
if ( sscanf( command + V_strlen( "EditMaterial" ), "%d", &nMaterialPanelIndex ) == 1 ) |
|
{ |
|
int nSkinIndex = nMaterialPanelIndex / NUM_IMPORT_MATERIALS_PER_TEAM; |
|
int nMaterialIndex = nMaterialPanelIndex % NUM_IMPORT_MATERIALS_PER_TEAM; |
|
OnCommandEditMaterial( nSkinIndex, nMaterialIndex ); |
|
} |
|
} |
|
else if ( V_stricmp( command, "UpdateAnimationLoopable" ) == 0 ) |
|
{ |
|
SetLoopableTaunt( IsLoopableTaunt(), GetAnimationLoopStartTime() ); |
|
} |
|
else if ( V_stricmp( command, "ClearAnimationSource" ) == 0 ) |
|
{ |
|
SetAnimationSource( m_nSelectedClass, NULL ); |
|
} |
|
else if ( V_stricmp( command, "ClearAnimationVCD" ) == 0 ) |
|
{ |
|
SetAnimationVCD( m_nSelectedClass, NULL ); |
|
} |
|
else if ( V_stricmp( command, "BrowseAnimationSource" ) == 0 ) |
|
{ |
|
if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) |
|
{ |
|
ShowMessageBox( "#TF_ImportFile_SelectClassTitle", "#TF_ImportFile_SelectClass" ); |
|
return; |
|
} |
|
|
|
OnCommandBrowseAnimationSource(); |
|
} |
|
else if ( V_stricmp( command, "BrowseAnimationVCD" ) == 0 ) |
|
{ |
|
if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) |
|
{ |
|
ShowMessageBox( "#TF_ImportFile_SelectClassTitle", "#TF_ImportFile_SelectClass" ); |
|
return; |
|
} |
|
|
|
OnCommandBrowseAnimationVCD(); |
|
} |
|
else if ( V_stricmp( command, "EditQC" ) == 0 ) |
|
{ |
|
OnCommandEditQC(); |
|
} |
|
else if ( V_stricmp( command, "EditQCI") == 0 ) |
|
{ |
|
OnCommandEditQCI(); |
|
} |
|
else if ( V_stricmp( command, "EditQCDone" ) == 0 ) |
|
{ |
|
OnCommandEditQCDone(); |
|
} |
|
else if ( V_stricmp( command, "EditQCIDone" ) == 0 ) |
|
{ |
|
OnCommandEditQCIDone(); |
|
} |
|
else if ( V_stricmp( command, "BuildPreview" ) == 0 ) |
|
{ |
|
OnCommandBuild( BUILD_PREVIEW ); |
|
} |
|
else if ( V_stricmp( command, "BuildVerify") == 0 ) |
|
{ |
|
OnCommandBuild( BUILD_VERIFY ); |
|
} |
|
else if ( V_stricmp( command, "BuildFinal" ) == 0 ) |
|
{ |
|
OnCommandBuild( BUILD_FINAL ); |
|
} |
|
else if ( V_stricmp( command, "PreviewDone" ) == 0 ) |
|
{ |
|
CleanupPreviewData(); |
|
} |
|
else |
|
{ |
|
BaseClass::OnCommand( command ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::OnCommandLoad() |
|
{ |
|
vgui::FileOpenDialog *pDialog = new vgui::FileOpenDialog( NULL, "#TF_ImportFile_SelectFile", vgui::FOD_OPEN ); |
|
pDialog->AddFilter( "*.txt,*.zip", "#TF_ImportFile_LoadSessionFileType", true); |
|
pDialog->AddActionSignalTarget( this ); |
|
char pszStartPath[ MAX_PATH ]; |
|
if ( g_pFullFileSystem->RelativePathToFullPath_safe( CFmtStr( kSteamWorkshopDir, GetWorkshopFolder() ), "GAME", pszStartPath ) ) |
|
{ |
|
pDialog->SetStartDirectory( pszStartPath ); |
|
} |
|
pDialog->DoModal(); |
|
pDialog->Activate(); |
|
m_nFileOpenMode = FILE_OPEN_LOAD; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::OnCommandSave() |
|
{ |
|
vgui::FileOpenDialog *pDialog = new vgui::FileOpenDialog( NULL, "#TF_ImportFile_SelectFile", vgui::FOD_SAVE ); |
|
pDialog->AddFilter( "*.txt", "#TF_ImportFile_SaveSessionFileType", true); |
|
pDialog->AddActionSignalTarget( this ); |
|
char pszStartPath[ MAX_PATH ]; |
|
if ( g_pFullFileSystem->RelativePathToFullPath_safe( CFmtStr( kSteamWorkshopDir, GetWorkshopFolder() ), "GAME", pszStartPath ) ) |
|
{ |
|
pDialog->SetStartDirectory( pszStartPath ); |
|
} |
|
pDialog->DoModal(); |
|
pDialog->Activate(); |
|
m_nFileOpenMode = FILE_OPEN_SAVE; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::OnCommandBrowseIcon() |
|
{ |
|
vgui::FileOpenDialog *pDialog = new vgui::FileOpenDialog( NULL, "#TF_ImportFile_SelectImage", vgui::FOD_OPEN ); |
|
pDialog->AddFilter( "*.tga,*.psd", "#TF_ImportFile_IconFileType", true); |
|
pDialog->AddActionSignalTarget( this ); |
|
const char *pszStartPath = tf_steam_workshop_import_icon_path.GetString(); |
|
if ( pszStartPath && *pszStartPath ) |
|
{ |
|
pDialog->SetStartDirectory( pszStartPath ); |
|
} |
|
pDialog->DoModal(); |
|
pDialog->Activate(); |
|
m_nFileOpenMode = FILE_OPEN_ICON; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::OnCommandBrowseLOD( int index ) |
|
{ |
|
vgui::FileOpenDialog *pDialog = new vgui::FileOpenDialog( NULL, "#TF_ImportFile_SelectModel", vgui::FOD_OPEN ); |
|
pDialog->AddFilter( "*.smd,*.dmx,*.fbx", "#TF_ImportFile_ModelFileType", true); |
|
pDialog->AddActionSignalTarget( this ); |
|
const char *pszStartPath = tf_steam_workshop_import_model_path.GetString(); |
|
if ( pszStartPath && *pszStartPath ) |
|
{ |
|
pDialog->SetStartDirectory( pszStartPath ); |
|
} |
|
pDialog->DoModal(); |
|
pDialog->Activate(); |
|
m_nFileOpenMode = static_cast<FileOpenMode>( FILE_OPEN_LOD0 + index ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::OnCommandBrowseAnimationSource() |
|
{ |
|
vgui::FileOpenDialog *pDialog = new vgui::FileOpenDialog( NULL, "#TF_ImportFile_SelectAnimationSource", vgui::FOD_OPEN ); |
|
pDialog->AddFilter( "*.smd,*.dmx,*.fbx", "#TF_ImportFile_AnimationSourceFileType", true); |
|
pDialog->AddActionSignalTarget( this ); |
|
const char *pszStartPath = tf_steam_workshop_import_model_path.GetString(); |
|
if ( pszStartPath && *pszStartPath ) |
|
{ |
|
pDialog->SetStartDirectory( pszStartPath ); |
|
} |
|
pDialog->DoModal(); |
|
pDialog->Activate(); |
|
m_nFileOpenMode = static_cast<FileOpenMode>( FILE_OPEN_ANIMATION_SOURCE ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::OnCommandBrowseAnimationVCD() |
|
{ |
|
vgui::FileOpenDialog *pDialog = new vgui::FileOpenDialog( NULL, "#TF_ImportFile_SelectAnimationVCD", vgui::FOD_OPEN ); |
|
pDialog->AddFilter( "*.vcd", "#TF_ImportFile_AnimationVCDFileType", true); |
|
pDialog->AddActionSignalTarget( this ); |
|
const char *pszStartPath = tf_steam_workshop_import_model_path.GetString(); |
|
if ( pszStartPath && *pszStartPath ) |
|
{ |
|
pDialog->SetStartDirectory( pszStartPath ); |
|
} |
|
pDialog->DoModal(); |
|
pDialog->Activate(); |
|
m_nFileOpenMode = static_cast<FileOpenMode>( FILE_OPEN_ANIMATION_VCD ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::OnCommandSwapVMT() |
|
{ |
|
bool bSwapPaint = false; |
|
for ( int nSkin=0; nSkin<CItemUpload::Manifest()->GetNumMaterialSkins(); ++nSkin ) |
|
{ |
|
KeyValues *pVMT0 = GetItemValues()->FindKey( CFmtStr( kMaterialSkinN, CItemUpload::Manifest()->GetMaterialSkin( nSkin ), 0 ) ); |
|
KeyValues *pVMT1 = GetItemValues()->FindKey( CFmtStr( kMaterialSkinN, CItemUpload::Manifest()->GetMaterialSkin( nSkin ), 1 ) ); |
|
if ( pVMT0 && pVMT1 ) |
|
{ |
|
KeyValuesAD pTemp( pVMT0->MakeCopy() ); |
|
pVMT0->Clear(); |
|
pVMT1->CopySubkeys( pVMT0 ); |
|
pVMT1->Clear(); |
|
pTemp->CopySubkeys( pVMT1 ); |
|
|
|
if ( !bSwapPaint ) |
|
{ |
|
bool bPaintable0 = IsPaintable( 0 ); |
|
bool bPaintable1 = IsPaintable( 1 ); |
|
SetPaintable( bPaintable1, 0 ); |
|
SetPaintable( bPaintable0, 1 ); |
|
bSwapPaint = true; |
|
} |
|
} |
|
} |
|
|
|
UpdateMaterialDisplay(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::OnCommandEditMaterial( int nSkinIndex, int nMaterialIndex ) |
|
{ |
|
CTFImportMaterialEditDialog *pDialog = new CTFImportMaterialEditDialog( this, nSkinIndex, nMaterialIndex, GetItemValues() ); |
|
pDialog->InvalidateLayout( true, true ); |
|
|
|
CUtlBuffer sRedMaterialText, sBlueMaterialText; |
|
pDialog->SetVMTKeyValues( GetMaterialText( 0, nMaterialIndex, sRedMaterialText ), GetMaterialText( 1, nMaterialIndex, sBlueMaterialText ) ); |
|
pDialog->DoModal(); |
|
pDialog->Activate(); |
|
|
|
m_pMaterialEditDialog = pDialog; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::OnCommandEditMaterialDone( int nSkinIndex, int nMaterialIndex ) |
|
{ |
|
if ( !m_pMaterialEditDialog ) |
|
{ |
|
return; |
|
} |
|
|
|
CUtlStringList oldMaterials; |
|
CUtlStringList oldBaseTextures; |
|
CUtlStringList oldNormalTextures; |
|
CUtlStringList oldPhongExponentTextures; |
|
CUtlStringList oldSelfIllumTextures; |
|
|
|
bool bAllTeam = m_pItemValues->GetInt( kSkinType ) == 0; |
|
const int nNumSkin = bAllTeam ? 1 : CItemUpload::Manifest()->GetNumMaterialSkins(); |
|
for ( int nSkin=0; nSkin < nNumSkin; ++nSkin ) |
|
{ |
|
KeyValuesAD pKV( m_pMaterialEditDialog->GetVMTKeyValues( nSkin )->MakeCopy() ); |
|
BUILD_RESULT nResult = ValidateMaterialValues( pKV, nMaterialIndex ); |
|
if ( nResult != BUILD_OKAY ) |
|
{ |
|
ShowMessageBoxWithFile( "#TF_SteamWorkshop_Error", kBuildResultMessages[ nResult ], CFmtStr( "VMT%d", 1 + nMaterialIndex ) ); |
|
return; |
|
} |
|
|
|
CUtlBuffer sOldText; |
|
GetMaterialText( nSkin, nMaterialIndex, sOldText ); |
|
oldMaterials.CopyAndAddToTail( sOldText.String() ); |
|
oldBaseTextures.CopyAndAddToTail( GetMaterialTextureFile( nSkin, nMaterialIndex, MATERIAL_FILE_BASETEXTURE ) ); |
|
oldNormalTextures.CopyAndAddToTail( GetMaterialTextureFile( nSkin, nMaterialIndex, MATERIAL_FILE_NORMAL ) ); |
|
oldPhongExponentTextures.CopyAndAddToTail( GetMaterialTextureFile( nSkin, nMaterialIndex, MATERIAL_FILE_PHONGEXPONENT ) ); |
|
oldSelfIllumTextures.CopyAndAddToTail( GetMaterialTextureFile( nSkin, nMaterialIndex, MATERIAL_FILE_SELFILLUM ) ); |
|
|
|
// set new material text |
|
CUtlBuffer sNewText; |
|
sNewText.SetBufferType( true, true ); |
|
pKV->RecursiveSaveToFile( sNewText, 0, false, true ); |
|
sNewText.SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); |
|
SetMaterialText( nSkin, nMaterialIndex, sNewText.String() ); |
|
|
|
// set new textures |
|
SetMaterial( nSkin, nMaterialIndex, m_pMaterialEditDialog->GetBaseTextureFile( nSkin ), MATERIAL_FILE_BASETEXTURE ); |
|
SetMaterial( nSkin, nMaterialIndex, m_pMaterialEditDialog->GetNormalTextureFile(), MATERIAL_FILE_NORMAL ); |
|
SetMaterial( nSkin, nMaterialIndex, m_pMaterialEditDialog->GetPhongExponentTextureFile(), MATERIAL_FILE_PHONGEXPONENT ); |
|
SetMaterial( nSkin, nMaterialIndex, m_pMaterialEditDialog->GetSelfIllumTextureFile(), MATERIAL_FILE_SELFILLUM ); |
|
} |
|
|
|
if ( m_pPreviewDialog ) |
|
{ |
|
// Refresh the preview and see if everything builds correctly |
|
if ( !OnCommandBuild( BUILD_PREVIEW ) ) |
|
{ |
|
for ( int nSkin=0; nSkin<nNumSkin; ++nSkin ) |
|
{ |
|
SetMaterialText( nSkin, nMaterialIndex, oldMaterials[nSkin] ); |
|
SetMaterial( nSkin, nMaterialIndex, oldBaseTextures[nSkin], MATERIAL_FILE_BASETEXTURE ); |
|
SetMaterial( nSkin, nMaterialIndex, oldNormalTextures[nSkin], MATERIAL_FILE_NORMAL ); |
|
SetMaterial( nSkin, nMaterialIndex, oldPhongExponentTextures[nSkin], MATERIAL_FILE_PHONGEXPONENT ); |
|
SetMaterial( nSkin, nMaterialIndex, oldSelfIllumTextures[nSkin], MATERIAL_FILE_SELFILLUM ); |
|
} |
|
return; |
|
} |
|
} |
|
|
|
m_pMaterialEditDialog->OnCommand( "Close" ); |
|
m_pMaterialEditDialog.Set(INVALID_PANEL); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::OnCommandEditQC() |
|
{ |
|
// The QC template is dependent on the item type, so make sure that's set first |
|
if ( V_strcmp( GetItemPrefab(), "" ) == 0 ) |
|
{ |
|
ShowMessageBox( "#TF_SteamWorkshop_Error", "#TF_ImportFile_BuildFailedNoType" ); |
|
return; |
|
} |
|
|
|
if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) |
|
{ |
|
ShowMessageBox( "#TF_ImportFile_SelectClassTitle", "#TF_ImportFile_SelectClass" ); |
|
return; |
|
} |
|
|
|
CTFFileImportTextEditDialog *pDialog = new CTFFileImportTextEditDialog( this, "#TF_ImportFile_EditQC", "EditQCDone" ); |
|
pDialog->SetText( GetQCTemplate( m_nSelectedClass ) ); |
|
pDialog->DoModal(); |
|
pDialog->Activate(); |
|
|
|
m_pTextEditDialog = pDialog; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::OnCommandEditQCI() |
|
{ |
|
// The QC template is dependent on the item type, so make sure that's set first |
|
if ( V_strcmp(GetItemPrefab(), "") == 0 ) |
|
{ |
|
ShowMessageBox( "#TF_SteamWorkshop_Error", "#TF_ImportFile_BuildFailedNoType" ); |
|
return; |
|
} |
|
|
|
if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) |
|
{ |
|
ShowMessageBox( "#TF_ImportFile_SelectClassTitle", "#TF_ImportFile_SelectClass" ); |
|
return; |
|
} |
|
|
|
CTFFileImportTextEditDialog *pDialog = new CTFFileImportTextEditDialog(this, "#TF_ImportFile_EditQCI", "EditQCIDone"); |
|
pDialog->SetText( GetQCITemplate( m_nSelectedClass ) ); |
|
pDialog->DoModal(); |
|
pDialog->Activate(); |
|
|
|
m_pTextEditDialog = pDialog; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::OnCommandEditQCDone() |
|
{ |
|
if ( !m_pTextEditDialog ) |
|
{ |
|
return; |
|
} |
|
|
|
char pszText[MAX_TEXT_EDIT_SIZE]; |
|
m_pTextEditDialog->GetText( pszText, sizeof(pszText) ); |
|
|
|
static const char *pszRequiredText[] = { |
|
"<ITEMTEST_REPLACE_MDLABSPATH>", |
|
"<ITEMTEST_REPLACE_LOD0>", |
|
"<ITEMTEST_REPLACE_SKIN_OPTIONALBLOCK>", |
|
}; |
|
for ( int i = 0; i < ARRAYSIZE(pszRequiredText); ++i ) |
|
{ |
|
if ( !V_strstr( pszText, pszRequiredText[i] ) ) |
|
{ |
|
KeyValuesAD pData( "Data" ); |
|
pData->SetString( "text", pszRequiredText[i] ); |
|
ShowMessageBox( "#TF_SteamWorkshop_Error", "#TF_ImportFile_QCMissingText", pData ); |
|
return; |
|
} |
|
} |
|
|
|
static const char *pszUnsupportedText[] = |
|
{ |
|
"$keyvalues", |
|
}; |
|
for ( int i = 0; i < ARRAYSIZE(pszUnsupportedText); ++i ) |
|
{ |
|
if ( V_strstr( pszText, pszUnsupportedText[i] ) ) |
|
{ |
|
KeyValuesAD pData( "Data" ); |
|
pData->SetString( "text", pszUnsupportedText[i] ); |
|
ShowMessageBox( "#TF_SteamWorkshop_Error", "#TF_ImportFile_QCUnsupportedText", pData ); |
|
return; |
|
} |
|
} |
|
|
|
const char* pszQCKeyName = CFmtStr( kClassQC, kClassFolders[ m_nSelectedClass ] ); |
|
CUtlString sOldText = GetItemValues()->GetString( pszQCKeyName ); |
|
GetItemValues()->SetString( pszQCKeyName, pszText ); |
|
|
|
if ( m_pPreviewDialog ) |
|
{ |
|
// Refresh the preview and see if everything builds correctly |
|
if ( !OnCommandBuild( BUILD_PREVIEW ) ) |
|
{ |
|
GetItemValues()->SetString( pszQCKeyName, sOldText ); |
|
return; |
|
} |
|
} |
|
|
|
m_pTextEditDialog->OnCommand( "Close" ); |
|
m_pTextEditDialog.Set(INVALID_PANEL); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::OnCommandEditQCIDone() |
|
{ |
|
if ( !m_pTextEditDialog ) |
|
{ |
|
return; |
|
} |
|
|
|
char pszText[MAX_TEXT_EDIT_SIZE]; |
|
m_pTextEditDialog->GetText( pszText, sizeof(pszText) ); |
|
|
|
const char* pszQCKeyName = CFmtStr( kClassQCI, kClassFolders[ m_nSelectedClass ] ); |
|
CUtlString sOldText = GetItemValues()->GetString( pszQCKeyName ); |
|
GetItemValues()->SetString( pszQCKeyName, pszText ); |
|
|
|
if ( m_pPreviewDialog ) |
|
{ |
|
// Refresh the preview and see if everything builds correctly |
|
if ( !OnCommandBuild( BUILD_PREVIEW ) ) |
|
{ |
|
GetItemValues()->SetString( pszQCKeyName, sOldText ); |
|
return; |
|
} |
|
} |
|
|
|
m_pTextEditDialog->OnCommand( "Close" ); |
|
m_pTextEditDialog.Set(INVALID_PANEL); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::OnCommandBuild( BUILD_STAGE buildStage ) |
|
{ |
|
KeyValuesAD pBuildMessageVariables( "data" ); |
|
|
|
// this can take a while, put up a waiting cursor |
|
vgui::surface()->SetCursor( vgui::dc_hourglass ); |
|
|
|
// Set up Perforce integration |
|
CItemUpload::SetP4( ShouldP4AddOrEdit() ); |
|
if ( CItemUpload::GetP4() ) |
|
{ |
|
CUtlString sChangeList( "imported - " ); |
|
sChangeList += GetItemName(); |
|
|
|
g_p4factory->SetOpenFileChangeList( NULL ); |
|
g_p4factory->SetOpenFileChangeList( sChangeList.String() ); |
|
} |
|
|
|
BUILD_RESULT nResult = Build( buildStage, pBuildMessageVariables ); |
|
|
|
if ( CItemUpload::GetP4() ) |
|
{ |
|
g_p4factory->SetOpenFileChangeList( NULL ); |
|
} |
|
|
|
// change the cursor back to normal |
|
vgui::surface()->SetCursor( vgui::dc_user ); |
|
|
|
if ( nResult == BUILD_OKAY ) |
|
{ |
|
switch ( buildStage ) |
|
{ |
|
case BUILD_PREVIEW: |
|
{ |
|
if ( !SetupPreviewData() ) |
|
{ |
|
ShowMessageBox( "#TF_SteamWorkshop_Error", "#TF_ImportFile_PreviewFailed" ); |
|
return false; |
|
} |
|
m_pPreviewDialog->SetVisible( true ); |
|
} |
|
break; |
|
case BUILD_VERIFY: |
|
{ |
|
SetDirty( false ); |
|
} |
|
break; |
|
case BUILD_FINAL: |
|
{ |
|
const char *pszBuildOutput = V_GetFileName( GetItemValues()->GetString( kBuildOutput ) ); |
|
ShowMessageBoxWithFile( "#TF_ImportFile_ImportCompleteTitle", "#TF_ImportFile_ImportComplete", pszBuildOutput ); |
|
SetWorkshopData(); |
|
BaseClass::OnCommand( "Close" ); |
|
} |
|
break; |
|
default: |
|
Assert( 0 ); |
|
} |
|
return true; |
|
} |
|
|
|
// The build failed. |
|
SetDirty( true ); |
|
if ( nResult == BUILD_FAILED_COMPILE ) |
|
{ |
|
CTFFileImportTextEditDialog *pDialog = new CTFFileImportTextEditDialog( this, "#TF_ImportFile_BuildFailed" ); |
|
pDialog->HideCancelButton(); |
|
pDialog->SetText( pBuildMessageVariables->GetString( "log" ) ); |
|
pDialog->DoModal(); |
|
pDialog->Activate(); |
|
} |
|
else |
|
{ |
|
ShowMessageBox( "#TF_ImportFile_BuildFailed", kBuildResultMessages[ nResult ], pBuildMessageVariables ); |
|
} |
|
return false; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::OnCommandUpdateBodygroup() |
|
{ |
|
if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) |
|
{ |
|
return; |
|
} |
|
|
|
KeyValuesAD pBodygroupKey( kBodygroup ); |
|
for ( int i=0; i<m_pBodygroups.Count(); ++i ) |
|
{ |
|
if ( m_pBodygroups[i] && !m_pBodygroups[i]->IsSelected() ) |
|
{ |
|
pBodygroupKey->SetBool( kBodygroupArray[i], true ); |
|
} |
|
} |
|
SetBodygroup( pBodygroupKey ); |
|
|
|
SetDirty( true ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::OnOpen() |
|
{ |
|
// Make sure our workshop directory exists |
|
const char *pszWorkshopDir = CFmtStr( kSteamWorkshopDir, GetWorkshopFolder() ); |
|
g_pFullFileSystem->CreateDirHierarchy( pszWorkshopDir, "GAME" ); |
|
|
|
GetWorkshopData(); |
|
|
|
if ( !CheckSourceSDK() ) |
|
{ |
|
ShowMessageBox( "#TF_SteamWorkshop_Error", "#TF_ImportFile_BuildFailedNoSDK" ); |
|
} |
|
|
|
CUtlString sName; |
|
if ( CItemUpload::SanitizeName( GetItemName(), sName ) ) |
|
{ |
|
char pszSessionPath[ MAX_PATH ]; |
|
V_ComposeFileName( pszWorkshopDir, CFmtStr( "%s.txt", sName.Get() ), pszSessionPath, sizeof(pszSessionPath) ); |
|
CUtlString sFailedPath; |
|
LOAD_RESULT nResult = Load( pszSessionPath, "GAME", sFailedPath ); |
|
|
|
// We ignore a general load failed since it's okay if the file is missing, but if some of the internal |
|
// data is missing from a valid session we want to let the user know. |
|
if ( nResult == LOAD_FAILED_BADMODEL || nResult == LOAD_FAILED_BADMATERIAL ) |
|
{ |
|
ShowMessageBoxWithFile( "#TF_ImportFile_LoadFailed", kLoadResultMessages[ nResult ], sFailedPath ); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::OnClose() |
|
{ |
|
CleanupPreviewData(); |
|
|
|
CUtlString sName; |
|
if ( CItemUpload::SanitizeName( GetItemName(), sName ) ) |
|
{ |
|
char pszSessionPath[ MAX_PATH ]; |
|
V_ComposeFileName( CFmtStr( kSteamWorkshopDir, GetWorkshopFolder() ), CFmtStr( "%s.txt", sName.Get() ), pszSessionPath, sizeof(pszSessionPath) ); |
|
SAVE_RESULT nResult = Save( pszSessionPath, "GAME" ); |
|
if ( nResult != SAVE_OKAY ) |
|
{ |
|
ShowMessageBoxWithFile( "#TF_ImportFile_SaveFailed", kSaveResultMessages[ nResult ], pszSessionPath ); |
|
} |
|
} |
|
|
|
BaseClass::OnClose(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::OnTextChanged( KeyValues *data ) |
|
{ |
|
Panel *pPanel = reinterpret_cast<vgui::Panel *>( data->GetPtr( "panel" ) ); |
|
|
|
vgui::ComboBox *pComboBox = dynamic_cast< vgui::ComboBox * >( pPanel ); |
|
if ( pComboBox ) |
|
{ |
|
if( pComboBox == m_pTypeComboBox ) |
|
{ |
|
KeyValues *pData = m_pTypeComboBox->GetActiveItemUserData(); |
|
SetItemPrefab( pData->GetString( kItemPrefab ) ); |
|
} |
|
else if ( pComboBox == m_pSkinComboBox ) |
|
{ |
|
KeyValues *pData = m_pSkinComboBox->GetActiveItemUserData(); |
|
SetSkinType( pData->GetInt( kSkinType ) ); |
|
} |
|
else if ( pComboBox == m_pEquipRegionComboBox ) |
|
{ |
|
KeyValues *pData = m_pEquipRegionComboBox->GetActiveItemUserData(); |
|
SetEquipRegion( pData->GetString( kEquipRegion ) ); |
|
} |
|
|
|
return; |
|
} |
|
|
|
vgui::TextEntry *pTextEntry = dynamic_cast< vgui::TextEntry * >( pPanel ); |
|
if ( pTextEntry ) |
|
{ |
|
if ( pTextEntry == m_pNameTextEntry ) |
|
{ |
|
char name[256]; |
|
m_pNameTextEntry->GetText( name, sizeof(name) ); |
|
GetItemValues()->SetString( kItemName, name ); |
|
} |
|
else if ( pTextEntry == m_pWorkshopIDTextEntry ) |
|
{ |
|
char szID[256]; |
|
m_pWorkshopIDTextEntry->GetText( szID, ARRAYSIZE( szID ) ); |
|
GetItemValues()->SetString( kWorkshopID, szID ); |
|
} |
|
else if ( pTextEntry == m_pTFEnglishNameTextEntry ) |
|
{ |
|
char name[256]; |
|
m_pTFEnglishNameTextEntry->GetText( name, sizeof(name) ); |
|
GetItemValues()->SetString( kTFEnglishName, name ); |
|
} |
|
else if ( pTextEntry == m_pAnimationLoopStartTextEntry ) |
|
{ |
|
const float flAnimationLoopStartTime = m_pAnimationLoopStartTextEntry->GetValueAsFloat(); |
|
GetItemValues()->SetFloat( kAnimationLoopable, flAnimationLoopStartTime ); |
|
} |
|
return; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::OnFileSelected( char const *fullpath ) |
|
{ |
|
switch ( m_nFileOpenMode ) |
|
{ |
|
case FILE_OPEN_LOAD: |
|
{ |
|
CUtlString sFailedPath; |
|
LOAD_RESULT nResult = Load( fullpath, NULL, sFailedPath ); |
|
if ( nResult != LOAD_OKAY ) |
|
{ |
|
ShowMessageBoxWithFile( "#TF_ImportFile_LoadFailed", kLoadResultMessages[ nResult ], sFailedPath ); |
|
} |
|
} |
|
break; |
|
case FILE_OPEN_SAVE: |
|
{ |
|
SAVE_RESULT nResult = Save( fullpath, NULL ); |
|
if ( nResult != SAVE_OKAY ) |
|
{ |
|
ShowMessageBoxWithFile( "#TF_ImportFile_SaveFailed", kSaveResultMessages[ nResult ], fullpath ); |
|
} |
|
} |
|
break; |
|
case FILE_OPEN_ICON: |
|
{ |
|
SetItemIcon( fullpath ); |
|
SaveBrowsePath( tf_steam_workshop_import_icon_path, fullpath ); |
|
} |
|
break; |
|
case FILE_OPEN_LOD0: |
|
case FILE_OPEN_LOD1: |
|
case FILE_OPEN_LOD2: |
|
{ |
|
KeyValuesAD pKV( "data" ); |
|
LOAD_RESULT result = SetLOD( m_nSelectedClass, (m_nFileOpenMode - FILE_OPEN_LOD0), fullpath, pKV ); |
|
if ( result != LOAD_OKAY ) |
|
{ |
|
ShowMessageBox( "#TF_ImportFile_LoadFailed", kLoadResultMessages[ result ], pKV ); |
|
} |
|
SaveBrowsePath( tf_steam_workshop_import_model_path, fullpath ); |
|
} |
|
break; |
|
case FILE_OPEN_ANIMATION_SOURCE: |
|
{ |
|
KeyValuesAD pKV( "data" ); |
|
LOAD_RESULT result = SetAnimationSource( m_nSelectedClass, fullpath, pKV ); |
|
if ( result != LOAD_OKAY ) |
|
{ |
|
ShowMessageBox( "#TF_ImportFile_LoadFailed", kLoadResultMessages[ result ], pKV ); |
|
} |
|
SaveBrowsePath( tf_steam_workshop_import_model_path, fullpath ); |
|
} |
|
break; |
|
case FILE_OPEN_ANIMATION_VCD: |
|
{ |
|
KeyValuesAD pKV( "data" ); |
|
LOAD_RESULT result = SetAnimationVCD( m_nSelectedClass, fullpath, pKV ); |
|
if ( result != LOAD_OKAY ) |
|
{ |
|
ShowMessageBox( "#TF_ImportFile_LoadFailed", kLoadResultMessages[ result ], pKV ); |
|
} |
|
SaveBrowsePath( tf_steam_workshop_import_model_path, fullpath ); |
|
} |
|
break; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::OnRadioButtonChecked( Panel *panel ) |
|
{ |
|
int i; |
|
|
|
for ( i = TF_FIRST_NORMAL_CLASS; i < TF_LAST_NORMAL_CLASS; ++i ) |
|
{ |
|
if ( panel == m_pClassRadioButtons[i] ) |
|
{ |
|
SelectClass( i ); |
|
return; |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::SetItemName( const char *pszName ) |
|
{ |
|
if ( m_pNameTextEntry ) |
|
{ |
|
m_pNameTextEntry->SetText( pszName ); |
|
} |
|
GetItemValues()->SetString( kItemName, pszName ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
const char *CTFFileImportDialog::GetItemName() |
|
{ |
|
const char *pszName = GetItemValues()->GetString( kItemName ); |
|
|
|
// Skip "The " if someone put it into the item name |
|
const char *kSkip = "The "; |
|
if ( V_strncasecmp(pszName, kSkip, V_strlen( kSkip ) ) == 0 ) |
|
{ |
|
pszName += V_strlen( kSkip ); |
|
} |
|
return pszName; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::IsValidPrefab( const char *pszPrefab ) |
|
{ |
|
KeyValues *pPrefab = ItemSystem()->GetItemSchema()->FindDefinitionPrefabByName( GetItemPrefab() ); |
|
return pPrefab && pPrefab->GetBool( "public_prefab" ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::SetItemPrefab( const char *pszPrefab ) |
|
{ |
|
if ( m_pTypeComboBox ) |
|
{ |
|
ImportPrefab_t nOldPrefab = m_nPrefab; |
|
bool bFound = false; |
|
for ( int i = 0; i < m_pTypeComboBox->GetItemCount(); ++i ) |
|
{ |
|
KeyValues *pKeyValues = m_pTypeComboBox->GetItemUserData( m_pTypeComboBox->GetItemIDFromRow( i ) ); |
|
if ( V_strcasecmp( pszPrefab, pKeyValues->GetString( kItemPrefab ) ) == 0 ) |
|
{ |
|
bFound = true; |
|
m_pTypeComboBox->ActivateItemByRow( i ); |
|
m_nPrefab = ImportPrefab_t(i); |
|
break; |
|
} |
|
} |
|
|
|
if ( ( nOldPrefab != PREFAB_TAUNT && m_nPrefab == PREFAB_TAUNT ) || |
|
( nOldPrefab == PREFAB_TAUNT && m_nPrefab != PREFAB_TAUNT ) ) |
|
{ |
|
ClearLODs(); |
|
} |
|
|
|
pszPrefab = bFound ? pszPrefab : ""; |
|
GetItemValues()->SetString( kItemPrefab, pszPrefab ); |
|
UpdateUIForPrefab( m_nPrefab ); |
|
} |
|
|
|
SetDirty( true ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::UpdateUIForPrefab( ImportPrefab_t nPrefab ) |
|
{ |
|
if ( nPrefab == PREFAB_TAUNT ) |
|
{ |
|
if ( m_pEquipRegionPanel ) |
|
{ |
|
m_pEquipRegionPanel->SetVisible( false ); |
|
} |
|
if ( m_pBodygroupsPanel ) |
|
{ |
|
m_pBodygroupsPanel->SetVisible( false ); |
|
} |
|
if ( m_pTauntInputPanel ) |
|
{ |
|
m_pTauntInputPanel->SetVisible( true ); |
|
} |
|
if ( m_pAnimationPropLabel ) |
|
{ |
|
m_pAnimationPropLabel->SetVisible( true ); |
|
} |
|
|
|
UpdateAnimationSourceDisplay(); |
|
UpdateAnimationVCDDisplay(); |
|
UpdateAnimDurationDisplay(); |
|
} |
|
else |
|
{ |
|
if ( m_pEquipRegionPanel ) |
|
{ |
|
m_pEquipRegionPanel->SetVisible( true ); |
|
} |
|
if ( m_pBodygroupsPanel ) |
|
{ |
|
m_pBodygroupsPanel->SetVisible( true ); |
|
} |
|
if ( m_pTauntInputPanel ) |
|
{ |
|
m_pTauntInputPanel->SetVisible( false ); |
|
} |
|
if ( m_pAnimationPropLabel ) |
|
{ |
|
m_pAnimationPropLabel->SetVisible( false ); |
|
} |
|
|
|
UpdateLODDisplay(); |
|
UpdateMaterialDisplay(); |
|
} |
|
|
|
InvalidateLayout(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
const char *CTFFileImportDialog::GetItemPrefab() |
|
{ |
|
return GetItemValues()->GetString( kItemPrefab ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::GetItemPrefabValue( const char *pszPrefab, const char *pszName, CUtlString& strOutput ) |
|
{ |
|
extern void MergeDefinitionPrefab( KeyValues *pKVWriteItem, KeyValues *pKVSourceItem ); |
|
|
|
KeyValues *pPrefab = ItemSystem()->GetItemSchema()->FindDefinitionPrefabByName( pszPrefab ); |
|
if ( !pPrefab ) |
|
{ |
|
return false; |
|
} |
|
|
|
KeyValuesAD pKVUnpackedPrefab( "prefab" ); |
|
MergeDefinitionPrefab( pKVUnpackedPrefab, pPrefab ); |
|
|
|
strOutput = pKVUnpackedPrefab->GetString( pszName, NULL ); |
|
return !strOutput.IsEmpty(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::SelectClass( int nClassIndex ) |
|
{ |
|
m_nSelectedClass = nClassIndex; |
|
|
|
if ( m_nPrefab == PREFAB_TAUNT ) |
|
{ |
|
UpdateAnimationSourceDisplay(); |
|
UpdateAnimationVCDDisplay(); |
|
UpdateAnimDurationDisplay(); |
|
UpdateLODDisplay(); |
|
UpdateMaterialDisplay(); |
|
} |
|
else |
|
{ |
|
UpdateBodygroupsDisplay(); |
|
UpdateLODDisplay(); |
|
UpdateMaterialDisplay(); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::SetItemIcon( const char *pszFilePath ) |
|
{ |
|
if ( pszFilePath && *pszFilePath && m_pIconImagePanel ) |
|
{ |
|
// clean up old image if there's one |
|
m_pIconImagePanel->EvictImage(); |
|
|
|
Bitmap_t image; |
|
ConversionErrorType nErrorCode = ImgUtl_LoadBitmap( pszFilePath, image ); |
|
if ( nErrorCode != CE_SUCCESS ) |
|
{ |
|
m_pIconImagePanel->SetImage( (vgui::IImage *)0 ); |
|
ShowMessageBoxWithFile( "#TF_ImportFile_LoadFailed", "#TF_ImportFile_LoadFailedBadFile", pszFilePath ); |
|
return; |
|
} |
|
|
|
if ( image.Width() != 512 || image.Height() != 512 ) |
|
{ |
|
ShowMessageBoxWithFile( "#TF_ImportFile_LoadFailed", "#TF_ImportFile_LoadFailedBadIconResolution", pszFilePath ); |
|
return; |
|
} |
|
|
|
if ( image.Format() != IMAGE_FORMAT_RGBA8888 ) |
|
{ |
|
ShowMessageBox( "#TF_ImportFile_LoadFailed", "#TF_ImportFile_LoadFailedImageNot32Bits" ); |
|
return; |
|
} |
|
|
|
int badPixelCount = 0; |
|
static const int startSafeZoneY = 91; |
|
static const int endSafeZoneY = 420; |
|
for ( int y=0; y<512; ++y ) |
|
{ |
|
bool bSafeZone = y >= startSafeZoneY && y < endSafeZoneY; |
|
// check if icon is outside the safezone |
|
for ( int x=0; x<512; ++x ) |
|
{ |
|
RGBA8888_t* pPixel = (RGBA8888_t*)image.GetPixel( x, y ); |
|
|
|
if ( bSafeZone ) |
|
{ |
|
// in the safezone, check if background is black |
|
if ( pPixel->a == 0 && ( pPixel->r || pPixel->g || pPixel->b ) ) |
|
{ |
|
badPixelCount++; |
|
} |
|
} |
|
else |
|
{ |
|
if ( pPixel->r || pPixel->g || pPixel->b || pPixel->a ) |
|
{ |
|
ShowMessageBox( "#TF_ImportFile_LoadFailed", "#TF_ImportFile_LoadFailedImageDoesNotFitInsideSafeZone" ); |
|
return; |
|
} |
|
} |
|
} |
|
} |
|
|
|
static const int nTotalSafeZonePixels = 512 * ( endSafeZoneY - startSafeZoneY ); |
|
float flBadPercentage = (float)badPixelCount / nTotalSafeZonePixels; |
|
if ( flBadPercentage > 0.05f ) |
|
{ |
|
ShowMessageBox( "#TF_ImportFile_LoadFailed", "#TF_ImportFile_LoadFailedBadIconBackground" ); |
|
return; |
|
} |
|
|
|
int wide, tall; |
|
BitmapImage *pBitmapImage = new BitmapImage; |
|
pBitmapImage->SetBitmap( image ); |
|
pBitmapImage->GetSize( wide, tall ); |
|
|
|
// The ImagePanel needs to know the scaling factor for the BitmapImage, to |
|
// center it when it's going to be rendered, and then the BitmapImage needs |
|
// to know how big it should be rendered. |
|
float fScaleAmount = static_cast<float>( m_pIconImagePanel->GetWide() ) / wide; |
|
m_pIconImagePanel->SetShouldCenterImage( true ); |
|
m_pIconImagePanel->SetShouldScaleImage( true ); |
|
m_pIconImagePanel->SetScaleAmount( fScaleAmount ); |
|
pBitmapImage->SetRenderSize( m_pIconImagePanel->GetWide(), static_cast<int>( tall * fScaleAmount ) ); |
|
|
|
m_pIconImagePanel->SetImage( pBitmapImage ); |
|
} |
|
|
|
GetItemValues()->SetString( kItemIcon, pszFilePath ); |
|
SetDirty( true ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
const char *CTFFileImportDialog::GetItemIcon() |
|
{ |
|
return GetItemValues()->GetString( kItemIcon ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::SetPaintable( bool bPaintable, int nMaterialIndex ) |
|
{ |
|
const char* pszPaintable = CFmtStr( kItemPaintable, nMaterialIndex ); |
|
GetItemValues()->SetBool( pszPaintable, bPaintable ); |
|
|
|
if ( m_pPaintableCheckButtons[nMaterialIndex] ) |
|
{ |
|
m_pPaintableCheckButtons[nMaterialIndex]->SetSelected( bPaintable ); |
|
} |
|
|
|
// You should check out how paints look on the item |
|
SetDirty( true ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::IsPaintable( int nMaterialIndex ) |
|
{ |
|
const char* pszPaintable = CFmtStr( kItemPaintable, nMaterialIndex ); |
|
return GetItemValues()->GetBool( pszPaintable ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::IsAnyVMTPaintable() |
|
{ |
|
for ( int nMaterialIndex=0; nMaterialIndex<NUM_IMPORT_MATERIALS_PER_TEAM; ++nMaterialIndex ) |
|
{ |
|
if ( IsPaintable( nMaterialIndex ) ) |
|
{ |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
const char *CTFFileImportDialog::GetUserAnimationQCTemplate( int nSelectedClass, bool bPerforce /*= false*/ ) |
|
{ |
|
Assert( m_nPrefab == PREFAB_TAUNT ); |
|
|
|
CUtlString strQCTemplateFile; |
|
if ( bPerforce ) |
|
{ |
|
// load class_workshop_animations.qc here! |
|
CAssetTF asset; |
|
asset.SetName( "temp" ); |
|
asset.SetClass( GetClassFolder() ); |
|
|
|
asset.AddModel(); |
|
const char *pszClassFolder = kClassFolders[ nSelectedClass ]; |
|
CSmartPtr< CTargetQC > pQC = asset.GetTargetQC(); |
|
const char *pszCustomRelativeDir = CFmtStr( "%s/player/animations", GetWorkshopFolder() ); |
|
pQC->SetCustomRelativeDir( pszCustomRelativeDir ); |
|
// use class_workshop_animations as shipping QC |
|
const char *pszCustomQCOutputName = CFmtStr( "%s_workshop_animations", pszClassFolder ); |
|
pQC->SetCustomOutputName( pszCustomQCOutputName ); |
|
pQC->SetQCITemplate( GetQCTemplate( nSelectedClass ) ); |
|
|
|
// add temp DMX to get QC path |
|
const char *pszFilePath = GetItemValues()->GetString( CFmtStr( kClassAnimationSourceFile, pszClassFolder ) ); |
|
asset.AddTargetDMX( pszFilePath ); |
|
|
|
m_tempQC.Clear(); |
|
if ( pQC->GetOutputPath( strQCTemplateFile, 0 ) ) |
|
{ |
|
// if the QC was checked out, revert it first |
|
char szCorrectCaseFilePath[MAX_PATH]; |
|
g_pFullFileSystem->GetCaseCorrectFullPath( strQCTemplateFile.String(), szCorrectCaseFilePath ); |
|
CP4AutoRevertFile revertFile( szCorrectCaseFilePath ); |
|
|
|
if ( g_pFullFileSystem->ReadFile( strQCTemplateFile, NULL, m_tempQC ) ) |
|
{ |
|
m_tempQC.PutString( "\n" ); |
|
m_tempQC.PutString( "$pushd \"../../../<QCI_RELATIVE_DIR>\"\n" ); |
|
m_tempQC.PutString( "$include \"../../../<QCI_RELATIVE_PATH>\"\n" ); |
|
m_tempQC.PutString( "$popd\n" ); |
|
|
|
return (char *)m_tempQC.Base(); |
|
} |
|
} |
|
} |
|
else if ( GetItemPrefabValue( GetItemPrefab(), "qc_template", strQCTemplateFile ) ) |
|
{ |
|
m_tempQC.Clear(); |
|
if ( g_pFullFileSystem->ReadFile( strQCTemplateFile, "MOD", m_tempQC ) ) |
|
{ |
|
return (char *)m_tempQC.Base(); |
|
} |
|
} |
|
|
|
Warning( "Failed to load specified QC template '%s'.\n", strQCTemplateFile.String() ); |
|
return NULL; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
const char *CTFFileImportDialog::GetQCTemplate( int nSelectedClass ) |
|
{ |
|
const char *pszQCText = GetItemValues()->GetString( CFmtStr( kClassQC, kClassFolders[nSelectedClass] ) ); |
|
if ( V_strlen(pszQCText) == 0 ) |
|
{ |
|
CUtlString strQCTemplateFile; |
|
if ( GetItemPrefabValue( m_nPrefab == PREFAB_TAUNT ? "misc" : GetItemPrefab(), "qc_template", strQCTemplateFile ) ) |
|
{ |
|
m_tempQC.Clear(); |
|
if ( g_pFullFileSystem->ReadFile( strQCTemplateFile, "MOD", m_tempQC ) ) |
|
{ |
|
return (char *)m_tempQC.Base(); |
|
} |
|
else |
|
{ |
|
Warning( "Failed to load specified QC template '%s'.\n", strQCTemplateFile.String() ); |
|
} |
|
} |
|
|
|
return CAssetTF().GetTargetQC()->GetQCTemplate(); |
|
} |
|
return pszQCText; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
const char *CTFFileImportDialog::GetQCITemplate( int nSelectedClass ) |
|
{ |
|
const char *pszQCText = GetItemValues()->GetString( CFmtStr( kClassQCI, kClassFolders[nSelectedClass] ) ); |
|
if ( V_strlen(pszQCText) == 0 ) |
|
{ |
|
CUtlString strQCITemplateFile = CItemUpload::Manifest()->GetQCITemplate(); |
|
CAssetTF asset; |
|
m_tempQC.Clear(); |
|
if ( g_pFullFileSystem->ReadFile( strQCITemplateFile.String(), "MOD", m_tempQC ) ) |
|
{ |
|
return (char *)m_tempQC.Base(); |
|
} |
|
else |
|
{ |
|
Warning( "Failed to load specified QCI template '%s'.\n", strQCITemplateFile.String() ); |
|
} |
|
} |
|
return pszQCText; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::ShouldP4AddOrEdit() const |
|
{ |
|
return p4 && m_pPerforceCheckButton && m_pPerforceCheckButton->IsSelected(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::IsPartnerContent() const |
|
{ |
|
return m_pPartnerCheckButton && m_pPartnerCheckButton->IsVisible() && m_pPartnerCheckButton->IsSelected(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
const char* CTFFileImportDialog::GetWorkshopFolder() const |
|
{ |
|
return IsPartnerContent() ? "workshop_partner" : "workshop"; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CTFFileImportDialog::GetCustomBones( int selectedClass, const char* pszFileName, CUtlStringList& strBoneList ) |
|
{ |
|
strBoneList.PurgeAndDeleteElements(); |
|
|
|
CUtlBuffer hdrBuf; |
|
const studiohdr_t *pItemStudioHdr = NULL; |
|
if ( g_pFullFileSystem->ReadFile( pszFileName, NULL, hdrBuf ) ) |
|
{ |
|
pItemStudioHdr = reinterpret_cast< const studiohdr_t * >( hdrBuf.Base() ); |
|
} |
|
|
|
if ( pItemStudioHdr == NULL ) |
|
{ |
|
return false; |
|
} |
|
|
|
if ( pItemStudioHdr ) |
|
{ |
|
m_pPlayerModelPanel->SetToPlayerClass( selectedClass, false ); |
|
const studiohdr_t* pClassStudioHdr = m_pPlayerModelPanel->GetStudioHdr(); |
|
for ( int iItemBone=0; iItemBone<pItemStudioHdr->numbones; ++iItemBone ) |
|
{ |
|
const char* pszItemBoneName = pItemStudioHdr->pBone( iItemBone )->pszName(); |
|
bool bCustomBone = true; |
|
for ( int iClassBone=0; iClassBone<pClassStudioHdr->numbones; ++iClassBone ) |
|
{ |
|
const char* pszClassBoneName = pClassStudioHdr->pBone( iClassBone )->pszName(); |
|
if ( FStrEq( pszItemBoneName, pszClassBoneName ) ) |
|
{ |
|
bCustomBone = false; |
|
break; |
|
} |
|
} |
|
|
|
if ( bCustomBone ) |
|
{ |
|
strBoneList.CopyAndAddToTail( pszItemBoneName ); |
|
} |
|
} |
|
} |
|
|
|
return strBoneList.Count(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::ClearLODs() |
|
{ |
|
for ( int iClassIndex=TF_FIRST_NORMAL_CLASS; iClassIndex<TF_LAST_NORMAL_CLASS; ++iClassIndex ) |
|
{ |
|
for ( int iLOD=0; iLOD<NUM_IMPORT_LODS; ++iLOD ) |
|
{ |
|
KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassLODN, kClassFolders[ iClassIndex ], iLOD ) ); |
|
if ( pKey ) |
|
{ |
|
pKey->Clear(); |
|
} |
|
} |
|
|
|
if ( m_pClassHighlights[ iClassIndex ] ) |
|
{ |
|
m_pClassHighlights[ iClassIndex ]->SetVisible( false ); |
|
} |
|
} |
|
|
|
Assert( !AnyClassHasModels() ); |
|
ClearMaterials(); |
|
|
|
SetDirty( true ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFFileImportDialog::LOAD_RESULT CTFFileImportDialog::SetLOD( int selectedClass, int nModelIndex, const char *pszFilePath, KeyValues* pKV /*= NULL*/ ) |
|
{ |
|
if ( selectedClass == TF_CLASS_UNDEFINED ) |
|
{ |
|
return LOAD_FAILED; |
|
} |
|
|
|
// Make sure we can load the model first |
|
if ( *pszFilePath ) |
|
{ |
|
CAssetTF asset; |
|
if ( asset.AddTargetDMX( pszFilePath ) < 0 ) |
|
{ |
|
return LOAD_FAILED_BADMODEL; |
|
} |
|
|
|
int nMaxTris = GetModelTriangleBudget( selectedClass, nModelIndex ); |
|
int nTriCount = asset.GetTargetDMX( 0 )->GetTriangleCount(); |
|
if ( nTriCount > nMaxTris ) |
|
{ |
|
pKV->SetInt( "count", nTriCount ); |
|
pKV->SetInt( "limit", nMaxTris ); |
|
SetMessageFileVariable( pKV, pszFilePath ); |
|
|
|
return LOAD_FAILED_COMPLEXMODEL; |
|
} |
|
|
|
CSmartPtr< CTargetQC > pQC = asset.GetTargetQC(); |
|
pQC->SetQCTemplate( GetQCTemplate( m_nSelectedClass ) ); |
|
|
|
// need to compile dmx to output mdl file to get studiohdr_t for bone name list |
|
asset.SetName( "temp" ); |
|
asset.SetClass( kClassFolders[ selectedClass ] ); |
|
if ( asset.CompilePreview() ) |
|
{ |
|
const CUtlVector< CUtlString >& strBuiltFiles = asset.GetBuiltFiles(); |
|
CUtlString strMDLPath; |
|
for ( int i=0; i<strBuiltFiles.Count(); ++i ) |
|
{ |
|
char pszExtention[16]; |
|
V_ExtractFileExtension( strBuiltFiles[i], pszExtention, ARRAYSIZE( pszExtention ) ); |
|
if ( FStrEq( pszExtention, "mdl" ) ) |
|
{ |
|
strMDLPath = strBuiltFiles[i]; |
|
break; |
|
} |
|
} |
|
|
|
CUtlStringList strBoneList; |
|
int nCustomBones = GetCustomBones( selectedClass, strMDLPath.String(), strBoneList ); |
|
|
|
// remove all the temp file |
|
for ( int i=0; i<strBuiltFiles.Count(); ++i ) |
|
{ |
|
g_pFullFileSystem->RemoveFile( strBuiltFiles[i] ); |
|
} |
|
|
|
const int nCustomBoneLimit = GetModelBoneBudget(); |
|
if ( nCustomBones > nCustomBoneLimit ) |
|
{ |
|
CUtlString strCustomBones = strBoneList[0]; |
|
for ( int i=1; i<nCustomBones; ++i ) |
|
{ |
|
strCustomBones += CFmtStr( ", %s", strBoneList[i] ); |
|
} |
|
pKV->SetInt( "count", nCustomBones ); |
|
pKV->SetInt( "limit", nCustomBoneLimit ); |
|
pKV->SetString( "custom_bones", strCustomBones.String() ); |
|
SetMessageFileVariable( pKV, pszFilePath ); |
|
|
|
return LOAD_FAILED_TOOMANYBONES; |
|
} |
|
} |
|
|
|
int nMaterialCount = asset.GetTargetVMTCount(); |
|
if ( nMaterialCount > NUM_IMPORT_MATERIALS_PER_TEAM ) |
|
{ |
|
pKV->SetInt( "count", nMaterialCount ); |
|
pKV->SetInt( "limit", NUM_IMPORT_MATERIALS_PER_TEAM ); |
|
SetMessageFileVariable( pKV, pszFilePath ); |
|
return LOAD_FAILED_TOOMANYMATERIALS; |
|
} |
|
|
|
// check if material count is not more than the higher LOD |
|
if ( nModelIndex > 0 ) |
|
{ |
|
KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassLODN, kClassFolders[ selectedClass ], nModelIndex - 1 ) ); |
|
Assert( pKey ); |
|
if ( pKey ) |
|
{ |
|
int nHigherLODMaterialCount = pKey->GetInt( "materialCount" ); |
|
if ( nHigherLODMaterialCount < nMaterialCount ) |
|
{ |
|
SetMessageFileVariable( pKV, pszFilePath ); |
|
return LOAD_FAILED_MATERIALCOUNTMISMATCH; |
|
} |
|
} |
|
} |
|
|
|
for ( int i = 0; i < nMaterialCount; ++i ) |
|
{ |
|
CFmtStr sMaterialName( kMaterialN, i ); |
|
if ( !GetItemValues()->GetString( sMaterialName, NULL ) ) |
|
{ |
|
char pszMaterialId[MAX_PATH]; |
|
V_FileBase( asset.GetTargetVMT( i )->GetMaterialId(), pszMaterialId, sizeof(pszMaterialId) ); |
|
GetItemValues()->SetString( sMaterialName, pszMaterialId ); |
|
} |
|
} |
|
|
|
KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassLODN, kClassFolders[ selectedClass ], nModelIndex ), true ); |
|
pKey->SetString( "file", pszFilePath ); |
|
pKey->SetInt( "polyCount", asset.GetTargetDMX( 0 )->GetPolyCount() ); |
|
pKey->SetInt( "triangleCount", nTriCount ); |
|
pKey->SetInt( "vertexCount", asset.GetTargetDMX( 0 )->GetVertexCount() ); |
|
pKey->SetInt( "materialCount", nMaterialCount ); |
|
|
|
// if we're already under the lowest budget, no need for more LODs |
|
if ( nTriCount <= GetModelTriangleBudget( selectedClass, NUM_IMPORT_LODS - 1 ) ) |
|
{ |
|
for ( int i=nModelIndex+1; i<NUM_IMPORT_LODS; ++i ) |
|
{ |
|
KeyValues *pKeyLOD = GetItemValues()->FindKey( CFmtStr( kClassLODN, kClassFolders[ selectedClass ], i ) ); |
|
if ( pKeyLOD ) |
|
{ |
|
pKeyLOD->Clear(); |
|
} |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
for ( int i=nModelIndex; i<NUM_IMPORT_LODS; ++i ) |
|
{ |
|
KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassLODN, kClassFolders[ selectedClass ], i ) ); |
|
if ( pKey ) |
|
{ |
|
pKey->Clear(); |
|
} |
|
} |
|
|
|
if ( !AnyClassHasModels() ) |
|
{ |
|
ClearMaterials(); |
|
} |
|
} |
|
|
|
SetDirty( true ); |
|
|
|
if ( selectedClass == m_nSelectedClass ) |
|
{ |
|
UpdateLODDisplay(); |
|
} |
|
UpdateMaterialDisplay(); |
|
|
|
// Show a highlight for classes that have models |
|
if ( m_pClassHighlights[ selectedClass ] ) |
|
{ |
|
m_pClassHighlights[ selectedClass ]->SetVisible( ClassHasModels( selectedClass ) ); |
|
} |
|
|
|
return LOAD_OKAY; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::UpdateLODDisplay() |
|
{ |
|
if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) |
|
{ |
|
return; |
|
} |
|
|
|
int nMinTriRequirement = GetModelTriangleBudget( m_nSelectedClass, NUM_IMPORT_LODS - 1 ); |
|
int nPreviousTriCount = INT_MAX; |
|
|
|
for ( int i=0; i<NUM_IMPORT_LODS; ++i ) |
|
{ |
|
const char *pszFilePath = ""; |
|
int nTriCount = 0; |
|
|
|
KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassLODN, kClassFolders[ m_nSelectedClass ], i ) ); |
|
if ( pKey ) |
|
{ |
|
pszFilePath = pKey->GetString( "file" ); |
|
nTriCount = pKey->GetInt( "triangleCount" ); |
|
} |
|
|
|
if ( nPreviousTriCount != 0 && nPreviousTriCount > nMinTriRequirement ) |
|
{ |
|
SetLODPanelEnable( true, i ); |
|
} |
|
else |
|
{ |
|
SetLODPanelEnable( false, i ); |
|
} |
|
|
|
vgui::Label *pFileLabel = m_pLODFiles[ i ]; |
|
if ( pFileLabel ) |
|
{ |
|
if ( *pszFilePath ) |
|
{ |
|
char file[MAX_PATH]; |
|
V_FileBase( pszFilePath, file, sizeof(file) ); |
|
pFileLabel->SetText( file ); |
|
} |
|
else |
|
{ |
|
pFileLabel->SetText( "#TF_PublishFile_NoFileSelected" ); |
|
} |
|
} |
|
|
|
vgui::Label *pDetailsLabel = m_pLODDetails[ i ]; |
|
if ( pDetailsLabel ) |
|
{ |
|
if ( *pszFilePath ) |
|
{ |
|
wchar_t details[1024]; |
|
g_pVGuiLocalize->ConstructString_safe( details, "#TF_ImportFile_ModelDetails", pKey ); |
|
pDetailsLabel->SetText( details, true ); |
|
} |
|
else |
|
{ |
|
pDetailsLabel->SetText( "" ); |
|
} |
|
} |
|
|
|
nPreviousTriCount = nTriCount; |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CTFFileImportDialog::GetModelTriangleBudget( int selectedClass, int nModelIndex ) |
|
{ |
|
// Return the budget for this item type |
|
if ( nModelIndex >= NUM_IMPORT_LODS ) |
|
{ |
|
Warning( "GetModelTriangleBudget: bad model index\n" ); |
|
return 0; |
|
} |
|
|
|
int nTriangleBudget = kDefaultTriangleBudget[nModelIndex]; |
|
|
|
CUtlString strTriangleBudget; |
|
if ( GetItemPrefabValue( GetItemPrefab(), CFmtStr( "triangle_budget_lod%d", nModelIndex ), strTriangleBudget ) ) |
|
{ |
|
nTriangleBudget = V_atoi( strTriangleBudget.String() ); |
|
} |
|
|
|
return nTriangleBudget; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CTFFileImportDialog::GetModelBoneBudget() |
|
{ |
|
int nBoneBudget = kDefaultBoneBudget; |
|
CUtlString strBoneBudget; |
|
if ( GetItemPrefabValue( GetItemPrefab(), "custom_bone_budget", strBoneBudget ) ) |
|
{ |
|
nBoneBudget = V_atoi( strBoneBudget.String() ); |
|
} |
|
|
|
return nBoneBudget; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::SetMaterial( int nMaterialPanelIndex, const char* pszFilePath, MATERIAL_FILE_TYPE fileType ) |
|
{ |
|
int selectedSkin = nMaterialPanelIndex / NUM_IMPORT_MATERIALS_PER_TEAM; |
|
int nMaterialIndex = nMaterialPanelIndex % NUM_IMPORT_MATERIALS_PER_TEAM; |
|
|
|
return SetMaterial( selectedSkin, nMaterialIndex, pszFilePath, fileType ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::SetMaterial( int selectedSkin, int nMaterialIndex, const char *pszFilePath, MATERIAL_FILE_TYPE fileType ) |
|
{ |
|
if ( *pszFilePath ) |
|
{ |
|
CAssetTF asset; |
|
CTargetTGA image( &asset, NULL ); |
|
if ( !image.SetInputFile( pszFilePath ) ) |
|
{ |
|
return false; |
|
} |
|
|
|
const char *pszMaterialFilePrefix = s_pszMaterialFilePrefixes[fileType]; |
|
|
|
KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kMaterialSkinN, CItemUpload::Manifest()->GetMaterialSkin( selectedSkin ), nMaterialIndex ), true ); |
|
pKey->SetString( CFmtStr( "%s_texture_file", pszMaterialFilePrefix ), pszFilePath ); |
|
pKey->SetInt( CFmtStr( "%s_texture_width", pszMaterialFilePrefix ), image.GetWidth() ); |
|
pKey->SetInt( CFmtStr( "%s_texture_height", pszMaterialFilePrefix ), image.GetHeight() ); |
|
pKey->SetInt( CFmtStr( "%s_texture_channels", pszMaterialFilePrefix ), image.GetChannelCount() ); |
|
pKey->SetBool( CFmtStr( "%s_texture_alpha", pszMaterialFilePrefix ), image.HasAlpha() ); |
|
} |
|
else |
|
{ |
|
static const char* s_removeKeyNames[] = |
|
{ |
|
"%s_texture_file", |
|
"%s_texture_width", |
|
"%s_texture_height", |
|
"%s_texture_channels", |
|
"%s_texture_alpha" |
|
}; |
|
|
|
KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kMaterialSkinN, CItemUpload::Manifest()->GetMaterialSkin( selectedSkin ), nMaterialIndex ) ); |
|
if ( pKey ) |
|
{ |
|
const char *pszMaterialFilePrefix = s_pszMaterialFilePrefixes[fileType]; |
|
for ( int i=0; i<ARRAYSIZE( s_removeKeyNames ); ++i ) |
|
{ |
|
KeyValues *pSubKey = pKey->FindKey( CFmtStr( s_removeKeyNames[i], pszMaterialFilePrefix ) ); |
|
if ( pSubKey ) |
|
{ |
|
pKey->RemoveSubKey( pSubKey ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
SetDirty( true ); |
|
|
|
UpdateMaterialDisplay( selectedSkin, nMaterialIndex ); |
|
|
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
const char* CTFFileImportDialog::GetMaterialTextureFile( int selectedSkin, int nMaterialIndex, MATERIAL_FILE_TYPE fileType ) |
|
{ |
|
KeyValues* pMaterialKey = GetItemValues()->FindKey( CFmtStr( kMaterialSkinN, CItemUpload::Manifest()->GetMaterialSkin( selectedSkin ), nMaterialIndex ) ); |
|
if ( pMaterialKey ) |
|
{ |
|
const char *pszMaterialFilePrefix = s_pszMaterialFilePrefixes[fileType]; |
|
return pMaterialKey->GetString( CFmtStr( "%s_texture_file", pszMaterialFilePrefix ) ); |
|
} |
|
|
|
return ""; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CUtlString CTFFileImportDialog::GetMaterialName( int selectedSkin, int nMaterialIndex ) |
|
{ |
|
const char* pszFilePath = GetMaterialTextureFile( selectedSkin, nMaterialIndex, MATERIAL_FILE_BASETEXTURE ); |
|
if ( FStrEq( pszFilePath, "" ) ) |
|
{ |
|
return ""; |
|
} |
|
|
|
// Turn the texture name into vmt name |
|
CUtlString strMaterialName = V_GetFileName( pszFilePath ); |
|
strMaterialName += ".vmt"; |
|
|
|
return strMaterialName; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::ClearMaterials() |
|
{ |
|
KeyValues *pKeyParent = GetItemValues()->FindKey( "Materials" ); |
|
if ( pKeyParent ) |
|
{ |
|
for ( int nMaterialIndex = 0; nMaterialIndex < NUM_IMPORT_MATERIALS_PER_TEAM; ++nMaterialIndex ) |
|
{ |
|
KeyValues *pKey = pKeyParent->FindKey( CFmtStr( "Material%d", nMaterialIndex ) ); |
|
if ( pKey ) |
|
{ |
|
pKeyParent->RemoveSubKey( pKey ); |
|
pKey->deleteThis(); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::ClearMaterial( int nSkinIndex, int nMaterialIndex ) |
|
{ |
|
KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kMaterialSkinN, CItemUpload::Manifest()->GetMaterialSkin( nSkinIndex ), nMaterialIndex ) ); |
|
if ( pKey ) |
|
{ |
|
pKey->Clear(); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::UpdateMaterialDisplay() |
|
{ |
|
if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) |
|
{ |
|
return; |
|
} |
|
|
|
int nModelMaterials = 0; |
|
KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassLODN, kClassFolders[ m_nSelectedClass ], 0 ) ); |
|
if ( pKey ) |
|
{ |
|
nModelMaterials = pKey->GetInt( "materialCount" ); |
|
} |
|
|
|
if ( m_pSwapVMTButton ) |
|
{ |
|
m_pSwapVMTButton->SetVisible( nModelMaterials > 1 ); |
|
} |
|
|
|
int nSkinType = GetItemValues()->GetInt( kSkinType ); |
|
for ( int nMaterialPaneIndex = 0; nMaterialPaneIndex < MAX_MATERIAL_COUNT; ++nMaterialPaneIndex ) |
|
{ |
|
vgui::Panel *pMaterialPanel = m_pMaterialPanels[ nMaterialPaneIndex ]; |
|
if (!pMaterialPanel) |
|
{ |
|
continue; |
|
} |
|
|
|
int nSkinIndex = nMaterialPaneIndex / NUM_IMPORT_MATERIALS_PER_TEAM; |
|
int nMaterialIndex = nMaterialPaneIndex % NUM_IMPORT_MATERIALS_PER_TEAM; |
|
bool bWasVisible = pMaterialPanel->IsVisible(); |
|
bool bVisible = nSkinIndex <= nSkinType && nMaterialIndex < nModelMaterials; |
|
pMaterialPanel->SetVisible( bVisible ); |
|
|
|
if ( bVisible ) |
|
{ |
|
if ( !bWasVisible ) |
|
{ |
|
pMaterialPanel->InvalidateLayout( true, true ); |
|
} |
|
UpdateMaterialDisplay( nSkinIndex, nMaterialIndex ); |
|
} |
|
} |
|
|
|
// update paintable buttons |
|
for ( int nMaterialIndex=0; nMaterialIndex<m_pPaintableCheckButtons.Count(); ++nMaterialIndex ) |
|
{ |
|
bool bVisible = nMaterialIndex < nModelMaterials; |
|
if ( m_pPaintableCheckButtons[nMaterialIndex] ) |
|
{ |
|
m_pPaintableCheckButtons[nMaterialIndex]->SetVisible( bVisible ); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::UpdateMaterialDisplay( int nSkinIndex, int nMaterialIndex ) |
|
{ |
|
int nMaterialPanelIndex = nSkinIndex * NUM_IMPORT_MATERIALS_PER_TEAM + nMaterialIndex; |
|
if ( nMaterialPanelIndex >= MAX_MATERIAL_COUNT ) |
|
{ |
|
// nSkinIndex could be 2 for Preview Image |
|
return; |
|
} |
|
|
|
vgui::Label *pLabel = m_pMaterialLabels[ nMaterialPanelIndex ]; |
|
if ( pLabel ) |
|
{ |
|
const char* pszInputName = "Input"; |
|
if ( GetItemValues()->GetInt( kSkinType ) ) |
|
{ |
|
pszInputName = ( nSkinIndex == 0 ) ? "Red Input" : "Blue Input"; |
|
} |
|
|
|
pLabel->SetText( CFmtStr( "%s: \"%s\"", pszInputName, GetItemValues()->GetString( CFmtStr( kMaterialN, nMaterialIndex ) ) ) ); |
|
} |
|
|
|
pLabel = m_pMaterialFiles[ nMaterialPanelIndex ]; |
|
if ( pLabel ) |
|
{ |
|
const char *pszFilePath = GetMaterialTextureFile( nSkinIndex, nMaterialIndex, MATERIAL_FILE_BASETEXTURE ); |
|
if ( *pszFilePath ) |
|
{ |
|
char file[MAX_PATH]; |
|
V_FileBase( pszFilePath, file, sizeof(file) ); |
|
pLabel->SetText( file ); |
|
pLabel->SetFgColor( Color( 255, 255, 255, 255 ) ); |
|
} |
|
else |
|
{ |
|
pLabel->SetText( "#TF_PublishFile_NoFileSelected" ); |
|
pLabel->SetFgColor( Color( 255, 0, 0, 255 ) ); |
|
} |
|
} |
|
} |
|
|
|
const char *CTFFileImportDialog::GetMaterialText( int nSkinIndex, int nMaterialIndex, CUtlBuffer &sMaterialText ) |
|
{ |
|
sMaterialText.Clear(); |
|
sMaterialText.SetBufferType( true, true ); |
|
|
|
if ( !sMaterialText.TellPut() ) |
|
{ |
|
KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kMaterialSkinN, CItemUpload::Manifest()->GetMaterialSkin( nSkinIndex ), nMaterialIndex ) ); |
|
if ( pKey ) |
|
{ |
|
KeyValuesAD pVMTKey( "VMT" ); |
|
if ( pVMTKey->LoadFromBuffer( "VMT", pKey->GetString( "vmt" ) ) ) |
|
{ |
|
if ( ValidateMaterialValues( pVMTKey, nMaterialIndex ) == BUILD_OKAY ) |
|
{ |
|
sMaterialText.PutString( pKey->GetString( "vmt" ) ); |
|
} |
|
else |
|
{ |
|
// HACK! We had proxies bug that will invalidate the material |
|
// Try to update the proxies from the template to see if this fixes the issue |
|
KeyValues *pCurrentProxies = pVMTKey->FindKey( "Proxies" ); |
|
if ( pCurrentProxies ) |
|
{ |
|
KeyValuesAD pKVTemplate( "Template" ); |
|
if ( pKVTemplate->LoadFromFile( g_pFullFileSystem, "materials/models/player/items/templates/standard.vmt", "GAME" ) ) |
|
{ |
|
KeyValues *pTemplateProxiesKey = pKVTemplate->FindKey( "Proxies" ); |
|
if ( pTemplateProxiesKey ) |
|
{ |
|
// clear old proxies and copy a new one |
|
pCurrentProxies->Clear(); |
|
pCurrentProxies->RecursiveMergeKeyValues( pTemplateProxiesKey ); |
|
|
|
// try again |
|
if ( ValidateMaterialValues( pVMTKey, nMaterialIndex ) == BUILD_OKAY ) |
|
{ |
|
sMaterialText.SetBufferType( true, true ); |
|
pVMTKey->RecursiveSaveToFile( sMaterialText, 0, false, true ); |
|
sMaterialText.SeekGet( CUtlBuffer::SEEK_HEAD, 0 ); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
if ( !sMaterialText.TellPut() ) |
|
{ |
|
g_pFullFileSystem->ReadFile( "materials/models/player/items/templates/standard.vmt", "GAME", sMaterialText ); |
|
} |
|
|
|
if ( !sMaterialText.TellPut() ) |
|
{ |
|
return NULL; |
|
} |
|
return sMaterialText.String(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::SetMaterialText( int nSkinIndex, int nMaterialIndex, const char* pszMaterialText ) |
|
{ |
|
KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kMaterialSkinN, CItemUpload::Manifest()->GetMaterialSkin( nSkinIndex ), nMaterialIndex ), true ); |
|
if ( pKey ) |
|
{ |
|
pKey->SetString( "vmt", pszMaterialText ); |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFFileImportDialog::BUILD_RESULT CTFFileImportDialog::ValidateMaterialValues( KeyValues *pKV, int nMaterialIndex ) |
|
{ |
|
static const char *MATERIAL_SHADER = "VertexlitGeneric"; |
|
static const int CONDITION_PAINTABLE = 0x01; |
|
static const int CONDITION_NOTPAINTABLE = 0x02; |
|
static const int MAX_MATERIAL_VARIABLES = 8; |
|
static struct MaterialCheck { |
|
BUILD_RESULT nErrorResult; |
|
int nCondition; |
|
const char *vecVariables[MAX_MATERIAL_VARIABLES]; |
|
} sVecMaterialChecks[] = { |
|
{ |
|
BUILD_FAILED_MATERIALMISSINGCLOAK, 0, |
|
{ |
|
"$cloakPassEnabled", "Proxies/invis" |
|
} |
|
}, |
|
{ |
|
BUILD_FAILED_MATERIALMISSINGBURNING, 0, |
|
{ |
|
"$detail", "$detailscale", "$detailblendfactor", "$detailblendmode", "Proxies/AnimatedTexture", "Proxies/BurnLevel" |
|
} |
|
}, |
|
{ |
|
BUILD_FAILED_MATERIALMISSINGJARATE, CONDITION_NOTPAINTABLE, |
|
{ |
|
"$yellow", "Proxies/YellowLevel", "Proxies/Equals" |
|
} |
|
}, |
|
{ |
|
BUILD_FAILED_MATERIALMISSINGJARATE, CONDITION_PAINTABLE, |
|
{ |
|
"$yellow", "Proxies/YellowLevel", "Proxies/Multiply" |
|
} |
|
}, |
|
{ |
|
BUILD_FAILED_MATERIALMISSINGPAINTABLE, CONDITION_PAINTABLE, |
|
{ |
|
"$blendtintbybasealpha", "$blendtintcoloroverbase", "$colortint_base", "$color2", "$colortint_tmp", |
|
"Proxies/ItemTintColor", "Proxies/SelectFirstIfNonZero" |
|
} |
|
}, |
|
}; |
|
|
|
if ( V_strcasecmp( pKV->GetName(), MATERIAL_SHADER ) != 0 ) |
|
{ |
|
return BUILD_FAILED_MATERIALMISSINGSHADER; |
|
} |
|
|
|
for ( int iCheck = 0; iCheck < ARRAYSIZE(sVecMaterialChecks); ++iCheck ) |
|
{ |
|
const MaterialCheck &check = sVecMaterialChecks[ iCheck ]; |
|
|
|
bool bIsPaintable = IsPaintable( nMaterialIndex ); |
|
|
|
if ( ( check.nCondition & CONDITION_PAINTABLE ) && !bIsPaintable ) |
|
{ |
|
continue; |
|
} |
|
|
|
if ( ( check.nCondition & CONDITION_NOTPAINTABLE ) && bIsPaintable ) |
|
{ |
|
continue; |
|
} |
|
|
|
for ( int i = 0; i < ARRAYSIZE(check.vecVariables) && check.vecVariables[i]; ++i ) |
|
{ |
|
if ( !pKV->FindKey( check.vecVariables[i] ) ) |
|
{ |
|
return check.nErrorResult; |
|
} |
|
} |
|
} |
|
|
|
// Ugh, terrible hack... |
|
// If a KeyValues key doesn't have a value or subkeys, it won't get written out. |
|
// Unfortunately we need Proxies/invis to be written out as an empty set, |
|
// so it needs to have _something_ in it to force it to be written to disk. |
|
const char *kSubkeyHack = "hack_not_written_to_disk"; |
|
KeyValues *pSubKey = pKV->FindKey( "Proxies/invis" ); |
|
Assert(pSubKey); |
|
if ( !pSubKey->FindKey( kSubkeyHack ) ) |
|
{ |
|
pSubKey->AddSubKey( new KeyValues( kSubkeyHack ) ); |
|
} |
|
|
|
return BUILD_OKAY; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::RemoveUnnecessaryParametersFromVMT( KeyValues *pKV, int nMaterialIndex ) |
|
{ |
|
RemoveLightParameters( pKV, nMaterialIndex ); |
|
RemovePaintParameters( pKV, nMaterialIndex ); |
|
RemoveTranslucentParameters( pKV ); |
|
RemoveCubeMapParameters( pKV ); |
|
RemoveSelfIllumParameters( pKV ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::RemoveLightParameters( KeyValues *pKV, int nMaterialIndex ) |
|
{ |
|
static const char *vecLightingKeys[] = |
|
{ |
|
"$basemapalphaphongmask", "$halflambert" |
|
}; |
|
for ( int i=0; i<ARRAYSIZE(vecLightingKeys); ++i ) |
|
{ |
|
const char *pszLightKeyName = vecLightingKeys[i]; |
|
if ( !pKV->GetBool( pszLightKeyName ) ) |
|
{ |
|
KeyValues *pSubKey = pKV->FindKey( pszLightKeyName ); |
|
if ( pSubKey ) |
|
{ |
|
pKV->RemoveSubKey( pSubKey ); |
|
pSubKey->deleteThis(); |
|
} |
|
} |
|
} |
|
|
|
if ( FStrEq( GetMaterialTextureFile( 0, nMaterialIndex, MATERIAL_FILE_PHONGEXPONENT ), "" ) ) |
|
{ |
|
KeyValues* pSubKey = pKV->FindKey( "$rimmask" ); |
|
if ( pSubKey ) |
|
{ |
|
pKV->RemoveSubKey( pSubKey ); |
|
pSubKey->deleteThis(); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::RemovePaintParameters( KeyValues *pKV, int nMaterialIndex ) |
|
{ |
|
if ( IsPaintable( nMaterialIndex ) ) |
|
{ |
|
static const char *vecNonPaintableProxyKeys[] = |
|
{ |
|
"Equals" |
|
}; |
|
|
|
// Now remove proxies |
|
KeyValues *pProxyKV = pKV->FindKey( "Proxies" ); |
|
if ( pProxyKV ) |
|
{ |
|
for ( int iProxyKey = 0; iProxyKey < ARRAYSIZE(vecNonPaintableProxyKeys); ++iProxyKey ) |
|
{ |
|
KeyValues *pKey = pProxyKV->FindKey( vecNonPaintableProxyKeys[ iProxyKey ] ); |
|
if ( pKey ) |
|
{ |
|
pProxyKV->RemoveSubKey( pKey ); |
|
pKey->deleteThis(); |
|
} |
|
} |
|
} |
|
|
|
return; |
|
} |
|
|
|
static const char *vecPaintableKeys[] = |
|
{ |
|
"$blendtintbybasealpha", "$blendtintcoloroverbase", "$colortint_base", "$colortint_tmp" |
|
}; |
|
static const char *vecPaintableProxyKeys[] = |
|
{ |
|
"ItemTintColor", "SelectFirstIfNonZero", "Multiply" |
|
}; |
|
|
|
// First remove all the variables |
|
for ( int iKey = 0; iKey < ARRAYSIZE(vecPaintableKeys); ++iKey ) |
|
{ |
|
KeyValues *pKey = pKV->FindKey( vecPaintableKeys[ iKey ] ); |
|
if ( pKey ) |
|
{ |
|
pKV->RemoveSubKey( pKey ); |
|
pKey->deleteThis(); |
|
} |
|
} |
|
|
|
// Now remove proxies |
|
KeyValues *pProxyKV = pKV->FindKey( "Proxies" ); |
|
if ( pProxyKV ) |
|
{ |
|
for ( int iProxyKey = 0; iProxyKey < ARRAYSIZE(vecPaintableProxyKeys); ++iProxyKey ) |
|
{ |
|
KeyValues *pKey = pProxyKV->FindKey( vecPaintableProxyKeys[ iProxyKey ] ); |
|
if ( pKey ) |
|
{ |
|
pProxyKV->RemoveSubKey( pKey ); |
|
pKey->deleteThis(); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::RemoveTranslucentParameters( KeyValues *pKV ) |
|
{ |
|
if ( !pKV->GetBool( "$additive" ) ) |
|
{ |
|
KeyValues *pSubKey = pKV->FindKey( "$additive" ); |
|
if ( pSubKey ) |
|
{ |
|
pKV->RemoveSubKey( pSubKey ); |
|
pSubKey->deleteThis(); |
|
} |
|
} |
|
|
|
if ( !pKV->GetBool( "$translucent" ) ) |
|
{ |
|
KeyValues *pSubKey = pKV->FindKey( "$translucent" ); |
|
if ( pSubKey ) |
|
{ |
|
pKV->RemoveSubKey( pSubKey ); |
|
pSubKey->deleteThis(); |
|
} |
|
|
|
pSubKey = pKV->FindKey( "$alphatest" ); |
|
if ( pSubKey ) |
|
{ |
|
pKV->RemoveSubKey( pSubKey ); |
|
pSubKey->deleteThis(); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::RemoveCubeMapParameters( KeyValues *pKV ) |
|
{ |
|
static const char* vecEnvmapKeys[] = |
|
{ |
|
"$envmap", |
|
"$basealphaenvmapmask", |
|
"$normalmapalphaenvmapmask", |
|
"$envmaptint" |
|
}; |
|
|
|
const char* pszEnvmapName = pKV->GetString( "$envmap" ); |
|
if ( FStrEq( pszEnvmapName, "" ) ) |
|
{ |
|
for ( int i=0; i<ARRAYSIZE(vecEnvmapKeys); ++i ) |
|
{ |
|
const char* pszEnvmapKey = vecEnvmapKeys[i]; |
|
KeyValues *pSubKey = pKV->FindKey( pszEnvmapKey ); |
|
if ( pSubKey ) |
|
{ |
|
pKV->RemoveSubKey( pSubKey ); |
|
pSubKey->deleteThis(); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::RemoveSelfIllumParameters( KeyValues *pKV ) |
|
{ |
|
static const char* vecSelfIllumKeys[] = |
|
{ |
|
"$selfillum", |
|
"$selfillumtint", |
|
"$selfillummask" |
|
}; |
|
|
|
bool bSelfIllum = false; |
|
KeyValues *pDX9Key = pKV->FindKey( ">=DX90" ); |
|
if ( pDX9Key ) |
|
{ |
|
bSelfIllum = pDX9Key->GetBool( "$selfillum" ); |
|
} |
|
|
|
if ( !bSelfIllum ) |
|
{ |
|
for ( int i=0; i<ARRAYSIZE( vecSelfIllumKeys ); ++i ) |
|
{ |
|
KeyValues *pSubKey = pKV->FindKey( vecSelfIllumKeys[i] ); |
|
if ( pSubKey ) |
|
{ |
|
pKV->RemoveSubKey( pSubKey ); |
|
pSubKey->deleteThis(); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::UpdateBodygroupsDisplay() |
|
{ |
|
KeyValues *pKey = GetItemValues()->FindKey( kBodygroup ); |
|
for ( int i=0; i<ARRAYSIZE( kBodygroupArray ); ++i ) |
|
{ |
|
const char* pszBodygroupName = kBodygroupArray[i]; |
|
vgui::CheckButton* pButton = m_pBodygroups[i]; |
|
if ( pButton ) |
|
{ |
|
pButton->SetCheckButtonCheckable( true ); |
|
pButton->SetSelected( !pKey || !pKey->GetBool( pszBodygroupName ) ); |
|
|
|
if ( m_nSelectedClass != TF_CLASS_UNDEFINED ) |
|
{ |
|
m_pPlayerModelPanel->SetToPlayerClass( m_nSelectedClass, false ); |
|
const studiohdr_t* pMDL = m_pPlayerModelPanel->GetStudioHdr(); |
|
|
|
bool bEnabled = false; |
|
for ( int iBodygroup=0; iBodygroup<pMDL->numbodyparts; ++iBodygroup ) |
|
{ |
|
const char* pszValidBodygroup = pMDL->pBodypart( iBodygroup )->pszName(); |
|
if ( FStrEq( pszValidBodygroup, pszBodygroupName ) ) |
|
{ |
|
bEnabled = true; |
|
break; |
|
} |
|
} |
|
|
|
pButton->SetEnabled( bEnabled ); |
|
} |
|
pButton->SetCheckButtonCheckable( pButton->IsEnabled() ); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::SetBodygroup( KeyValues* pBodygroupKey ) |
|
{ |
|
if ( !pBodygroupKey ) |
|
{ |
|
return; |
|
} |
|
|
|
KeyValues *pKey = GetItemValues()->FindKey( kBodygroup, true ); |
|
if ( pKey ) |
|
{ |
|
pKey->Clear(); |
|
for ( int i=0; i<ARRAYSIZE( kBodygroupArray ); ++i ) |
|
{ |
|
const char* pszBodygroup = kBodygroupArray[i]; |
|
if ( pBodygroupKey->GetBool( pszBodygroup ) ) |
|
{ |
|
pKey->SetBool( pszBodygroup, true ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFFileImportDialog::LOAD_RESULT CTFFileImportDialog::SetAnimationSource( int selectedClass, const char *pszFilePath, KeyValues* pKV /*= NULL*/ ) |
|
{ |
|
if ( selectedClass == TF_CLASS_UNDEFINED ) |
|
{ |
|
SetMessageFileVariable( pKV, pszFilePath ); |
|
return LOAD_FAILED; |
|
} |
|
|
|
// Make sure we can load the model first |
|
if ( pszFilePath && *pszFilePath ) |
|
{ |
|
CAssetTF asset; |
|
|
|
CSmartPtr< CTargetQC > pQC = asset.GetTargetQC(); |
|
pQC->SetQCTemplate( GetUserAnimationQCTemplate( selectedClass ) ); |
|
pQC->SetQCITemplate( GetQCTemplate( selectedClass ) ); |
|
|
|
if ( asset.AddTargetDMX( pszFilePath ) < 0 ) |
|
{ |
|
SetMessageFileVariable( pKV, pszFilePath ); |
|
return LOAD_FAILED_BADMODEL; |
|
} |
|
|
|
CSmartPtr< CTargetDMX > pDMX = pQC->GetTargetDMX( 0 ); |
|
float flFrameRate; |
|
int nFrameCount; |
|
float flAnimDuration = 0.f; |
|
if ( pDMX.IsValid() && pDMX->GetAnimationFrameInfo( flFrameRate, nFrameCount ) ) |
|
{ |
|
flAnimDuration = (float)nFrameCount/flFrameRate; |
|
if ( flAnimDuration > GetMaxTauntDuration() ) |
|
{ |
|
if ( pKV ) |
|
{ |
|
pKV->SetFloat( "current_anim_duration", flAnimDuration ); |
|
pKV->SetInt( "max_anim_duration", GetMaxTauntDuration() ); |
|
} |
|
SetMessageFileVariable( pKV, pszFilePath ); |
|
|
|
return LOAD_FAIL_ANIMATIONTOOLONG; |
|
} |
|
} |
|
|
|
KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassAnimation, kClassFolders[ selectedClass ] ), true ); |
|
pKey->SetString( "source_file", pszFilePath ); |
|
|
|
SetAnimationDuration( selectedClass, flAnimDuration ); |
|
} |
|
else |
|
{ |
|
KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassAnimation, kClassFolders[ selectedClass ] ) ); |
|
if ( pKey ) |
|
{ |
|
KeyValues *pVCDKey = pKey->FindKey( "source_file" ); |
|
if ( pVCDKey ) |
|
{ |
|
pKey->RemoveSubKey( pVCDKey ); |
|
pVCDKey->deleteThis(); |
|
} |
|
} |
|
} |
|
|
|
SetDirty( true ); |
|
|
|
if ( selectedClass == m_nSelectedClass ) |
|
{ |
|
UpdateAnimationSourceDisplay(); |
|
} |
|
|
|
// Show a highlight for classes that have models |
|
if ( m_pClassHighlights[ selectedClass ] ) |
|
{ |
|
m_pClassHighlights[ selectedClass ]->SetVisible( ClassHasTauntSources( selectedClass ) ); |
|
} |
|
|
|
return LOAD_OKAY; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFFileImportDialog::LOAD_RESULT CTFFileImportDialog::SetAnimationVCD( int selectedClass, const char *pszFilePath, KeyValues* pKV /*= NULL*/ ) |
|
{ |
|
if ( selectedClass == TF_CLASS_UNDEFINED ) |
|
{ |
|
SetMessageFileVariable( pKV, pszFilePath ); |
|
return LOAD_FAILED; |
|
} |
|
|
|
if ( pszFilePath && *pszFilePath ) |
|
{ |
|
KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassAnimation, kClassFolders[ selectedClass ] ), true ); |
|
pKey->SetString( "vcd_file", pszFilePath ); |
|
} |
|
else |
|
{ |
|
KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassAnimation, kClassFolders[ selectedClass ] ) ); |
|
if ( pKey ) |
|
{ |
|
KeyValues *pVCDKey = pKey->FindKey( "vcd_file" ); |
|
if ( pVCDKey ) |
|
{ |
|
pKey->RemoveSubKey( pVCDKey ); |
|
pVCDKey->deleteThis(); |
|
} |
|
} |
|
} |
|
|
|
SetDirty( true ); |
|
|
|
if ( selectedClass == m_nSelectedClass ) |
|
{ |
|
UpdateAnimationVCDDisplay(); |
|
} |
|
|
|
// Show a highlight for classes that have models |
|
if ( m_pClassHighlights[ selectedClass ] ) |
|
{ |
|
m_pClassHighlights[ selectedClass ]->SetVisible( ClassHasTauntSources( selectedClass ) ); |
|
} |
|
|
|
return LOAD_OKAY; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::SetAnimationDuration( int selectedClass, float flDuration ) |
|
{ |
|
if ( selectedClass == TF_CLASS_UNDEFINED ) |
|
{ |
|
return; |
|
} |
|
|
|
float flClampedDuration = clamp( flDuration, 0.f, GetMaxTauntDuration() ); |
|
KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassAnimation, kClassFolders[ selectedClass ] ) ); |
|
if ( pKey ) |
|
{ |
|
pKey->SetFloat( "taunt_duration", flClampedDuration ); |
|
} |
|
|
|
UpdateAnimDurationDisplay(); |
|
} |
|
|
|
|
|
extern CChoreoScene *LoadSceneForModel( const char *filename, IChoreoEventCallback *pCallback, float *flSceneEndTime ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFFileImportDialog::BUILD_RESULT CTFFileImportDialog::VerifyVCD( const CAssetTF &asset ) |
|
{ |
|
if ( m_nPrefab != PREFAB_TAUNT ) |
|
return BUILD_OKAY; |
|
|
|
// force reload scene cache |
|
scenefilecache->Reload(); |
|
CUtlVector< int > vcdFileIndices; |
|
const CUtlVector< CUtlString > &builtFiles = asset.GetBuiltFiles(); |
|
const CUtlVector< CUtlString > &relPathBuiltFiles = asset.GetRelativePathBuiltFiles(); |
|
for ( int iFile=0; iFile<builtFiles.Count(); ++iFile ) |
|
{ |
|
char pszExtention[16]; |
|
V_ExtractFileExtension( builtFiles[iFile].String(), pszExtention, ARRAYSIZE( pszExtention ) ); |
|
if ( !FStrEq( pszExtention, "vcd" ) ) |
|
{ |
|
continue; |
|
} |
|
|
|
const char *pszFullPath = builtFiles[iFile].String(); |
|
const char *pszRelPath = V_stristr( pszFullPath, "scenes" ); |
|
if ( !pszRelPath ) |
|
{ |
|
return BUILD_FAILED_BAD_VCD_FILE; |
|
} |
|
|
|
float flSceneEndTime = -1.f; |
|
|
|
CChoreoScene *pScene = LoadSceneForModel( pszRelPath, NULL, &flSceneEndTime ); |
|
if ( pScene ) |
|
{ |
|
CChoreoEvent *pEventSequence = NULL; |
|
for ( int iEvent=0; iEvent<pScene->GetNumEvents() && !pEventSequence; ++iEvent ) |
|
{ |
|
CChoreoEvent *pEvent = pScene->GetEvent( iEvent ); |
|
if ( pEvent && pEvent->GetType() == CChoreoEvent::EVENTTYPE::SEQUENCE ) |
|
{ |
|
pEventSequence = pEvent; |
|
} |
|
} |
|
|
|
if ( !pEventSequence ) |
|
{ |
|
delete pScene; |
|
return BUILD_FAILED_VCD_MISSING_EVENT_SEQUENCE; |
|
} |
|
|
|
if ( pEventSequence->GetEndTime() > GetMaxTauntDuration() ) |
|
{ |
|
delete pScene; |
|
return BUILD_FAILED_VCD_EVENT_SEQUENCE_TOO_LONG; |
|
} |
|
|
|
char szFileName[MAX_PATH]; |
|
V_FileBase( pszRelPath, szFileName, sizeof( szFileName ) ); |
|
|
|
pEventSequence->SetParameters( szFileName ); |
|
pScene->SaveToFile( pszFullPath ); |
|
|
|
vcdFileIndices.AddToTail( iFile ); |
|
|
|
delete pScene; |
|
} |
|
} |
|
|
|
const char *pszArchiveName = asset.GetArchivePath(); |
|
if ( pszArchiveName && *pszArchiveName ) |
|
{ |
|
CUtlBuffer buf; |
|
if ( !g_pFullFileSystem->ReadFile( pszArchiveName, NULL, buf ) ) |
|
{ |
|
// failed to parse zip file |
|
return BUILD_FAILED_BAD_VCD_FILE; |
|
} |
|
|
|
IZip *pZip = IZip::CreateZip(); |
|
if ( pZip ) |
|
{ |
|
pZip->ParseFromBuffer( buf.Base(), buf.Size() ); |
|
for ( int i=0; i<vcdFileIndices.Count(); ++i ) |
|
{ |
|
int vcdIndex = vcdFileIndices[i]; |
|
const char *pszFullPath = builtFiles[vcdIndex].String(); |
|
const char *pszRelPath = relPathBuiltFiles[vcdIndex].String(); |
|
pZip->AddFileToZip( pszRelPath, pszFullPath ); |
|
} |
|
|
|
pZip->SaveToBuffer( buf ); |
|
IZip::ReleaseZip( pZip ); |
|
|
|
g_pFullFileSystem->WriteFile( pszArchiveName, NULL, buf ); |
|
} |
|
else |
|
{ |
|
// failed to parse zip file |
|
return BUILD_FAILED_BAD_VCD_FILE; |
|
} |
|
} |
|
|
|
return BUILD_OKAY; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::UpdateAnimationSourceDisplay() |
|
{ |
|
if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( m_pAnimationSourceFile ) |
|
{ |
|
const char *pszFilePath = GetItemValues()->GetString( CFmtStr( kClassAnimationSourceFile, kClassFolders[ m_nSelectedClass ] ) ); |
|
if ( pszFilePath && *pszFilePath ) |
|
{ |
|
char file[MAX_PATH]; |
|
V_FileBase( pszFilePath, file, sizeof(file) ); |
|
m_pAnimationSourceFile->SetText( file ); |
|
} |
|
else |
|
{ |
|
m_pAnimationSourceFile->SetText( "#TF_PublishFile_NoFileSelected" ); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::UpdateAnimationVCDDisplay() |
|
{ |
|
if ( m_nSelectedClass == TF_CLASS_UNDEFINED ) |
|
{ |
|
return; |
|
} |
|
|
|
if ( m_pAnimationVCDFile ) |
|
{ |
|
const char *pszFilePath = GetItemValues()->GetString( CFmtStr( kClassAnimationVCDFile, kClassFolders[ m_nSelectedClass ] ) ); |
|
if ( pszFilePath && *pszFilePath ) |
|
{ |
|
char file[MAX_PATH]; |
|
V_FileBase( pszFilePath, file, sizeof(file) ); |
|
m_pAnimationVCDFile->SetText( file ); |
|
} |
|
else |
|
{ |
|
m_pAnimationVCDFile->SetText( "#TF_PublishFile_NoFileSelected" ); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::UpdateAnimDurationDisplay() |
|
{ |
|
if ( m_pAnimationDurationLabel ) |
|
{ |
|
float flDuration = GetItemValues()->GetFloat( CFmtStr( kClassAnimationDuration, kClassFolders[ m_nSelectedClass ] ) ); |
|
wchar_t wszTemp[256]; |
|
wchar_t wszCount[10]; |
|
_snwprintf( wszCount, ARRAYSIZE( wszCount ), L"%.4f", flDuration ); |
|
g_pVGuiLocalize->ConstructString_safe( wszTemp, g_pVGuiLocalize->Find("#TF_ImportFile_AnimationDuration"), 1, wszCount ); |
|
m_pAnimationDurationLabel->SetText( wszTemp ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::SetDirty( bool bDirty ) |
|
{ |
|
if ( m_pBuildButton ) |
|
{ |
|
m_pBuildButton->SetEnabled( !bDirty ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
static int FindSuffix( const char *pszString, const char *pszSuffix ) |
|
{ |
|
int nStringLen = V_strlen(pszString); |
|
int nSuffixLen = V_strlen(pszSuffix); |
|
int nSuffixOffset = nStringLen - nSuffixLen; |
|
if ( nSuffixOffset >= 0 && V_strcasecmp( (pszString + nSuffixOffset), pszSuffix ) == 0 ) |
|
{ |
|
return nSuffixOffset; |
|
} |
|
return -1; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
static bool FindTexture( const char *pszStrippedPath, const char *pszSuffix, CUtlString &sOutputPath ) |
|
{ |
|
static const char *vecTextureExtensions[] = { |
|
".tga", |
|
".psd" |
|
}; |
|
|
|
for ( int i = 0; i < ARRAYSIZE(vecTextureExtensions); ++i ) |
|
{ |
|
char pszFullPath[MAX_PATH]; |
|
V_snprintf(pszFullPath, sizeof(pszFullPath), "%s%s%s", pszStrippedPath, pszSuffix, vecTextureExtensions[ i ]); |
|
if ( CItemUpload::FileExists( pszFullPath ) ) |
|
{ |
|
sOutputPath = pszFullPath; |
|
return true; |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::SetLoopableTaunt( bool bLoopable, float flLoopStartTime ) |
|
{ |
|
GetItemValues()->SetFloat( kAnimationLoopable, flLoopStartTime ); |
|
|
|
if ( m_pAnimationLoopCheckButton ) |
|
{ |
|
m_pAnimationLoopCheckButton->SetSelected( bLoopable ); |
|
} |
|
|
|
if ( m_pAnimationLoopStartTextEntry ) |
|
{ |
|
m_pAnimationLoopStartTextEntry->SetEnabled( bLoopable ); |
|
m_pAnimationLoopStartTextEntry->SetText( CFmtStr( "%f", bLoopable ? flLoopStartTime : -1.f ) ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::IsLoopableTaunt() const |
|
{ |
|
return m_pAnimationLoopCheckButton && m_pAnimationLoopCheckButton->IsSelected(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
float CTFFileImportDialog::GetAnimationLoopStartTime() const |
|
{ |
|
if ( m_pAnimationLoopStartTextEntry ) |
|
{ |
|
return m_pAnimationLoopStartTextEntry->GetValueAsFloat(); |
|
} |
|
|
|
return 0.f; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFFileImportDialog::BUILD_RESULT CTFFileImportDialog::AddTauntToAsset( CAssetTF &asset, int nClassIndex, bool bIsMulticlass, BUILD_STAGE buildStage, KeyValues *pItemData, KeyValues *pBuildMessageVariables ) |
|
{ |
|
const uint nPathFlags = (CTargetBase::PATH_FLAG_ALL & ~CTargetBase::PATH_FLAG_ABSOLUTE) | CTargetBase::PATH_FLAG_ZIP; |
|
const CUtlVector<const char *>&vecUsabilityStrings = ItemSystem()->GetItemSchema()->GetClassUsabilityStrings(); |
|
|
|
bool bPreview = buildStage == BUILD_PREVIEW; |
|
|
|
asset.AddModel(); |
|
|
|
const char *pszClassFolder = kClassFolders[ nClassIndex ]; |
|
|
|
CSmartPtr< CTargetQC > pQC = asset.GetTargetQC(); |
|
|
|
asset.ExcludeFileExtension( "qc" ); |
|
asset.ExcludeFileExtension( "mdl" ); |
|
|
|
// Are we checking out files to perforce? |
|
bool bPerforce = !bPreview && ShouldP4AddOrEdit(); |
|
|
|
pQC->GetCustomKeyValues()->SetString( "<CLASS_NAME>", pszClassFolder ); |
|
pQC->SetQCTemplate( GetUserAnimationQCTemplate( nClassIndex, bPerforce ) ); |
|
pQC->SetQCITemplate( GetQCITemplate( nClassIndex ) ); |
|
|
|
const char *pszVCDFile = GetItemValues()->GetString( CFmtStr( kClassAnimationVCDFile, pszClassFolder ) ); |
|
CSmartPtr< CTargetVCD > pVCD = pQC->GetTargetVCD(); |
|
pVCD->SetInputFile( pszVCDFile ); |
|
const char *pszCustomRelativeDir = CFmtStr( "%s/player/%s/low", GetWorkshopFolder(), vecUsabilityStrings[nClassIndex] ); |
|
pVCD->SetCustomRelativeDir( pszCustomRelativeDir ); |
|
if ( bPreview ) |
|
{ |
|
pVCD->SetCustomModPath( "custom/workshop" ); |
|
} |
|
|
|
// Dir for MDL |
|
pszCustomRelativeDir = bPerforce ? CFmtStr( "%s/player/animations", GetWorkshopFolder() ) : "player"; |
|
const char *pszAnimMDLMiddleName = bPerforce ? "workshop" : "user"; // use class_user_animations as temp MDL and class_workshop_animations as shipping MDL |
|
const char *pszCustomMDLOutputName = CFmtStr( "%s_%s_animations", pszClassFolder, pszAnimMDLMiddleName ); |
|
CSmartPtr< CTargetMDL > pMDL = asset.GetTargetMDL(); |
|
pMDL->SetCustomRelativeDir( pszCustomRelativeDir ); |
|
pMDL->SetCustomOutputName( pszCustomMDLOutputName ); |
|
if ( bPreview ) |
|
{ |
|
pMDL->SetCustomModPath( "custom/workshop" ); |
|
} |
|
|
|
// Dir for QC |
|
pszCustomRelativeDir = bPerforce ? CFmtStr( "%s/player/animations", GetWorkshopFolder() ) : CFmtStr( "player/%s", pszClassFolder ); |
|
const char *pszAnimQCMiddleName = bPerforce ? "workshop" : "preview"; // use class_preview_animations as temp QC and class_workshop_animations as shipping QC |
|
const char *pszCustomQCOutputName = CFmtStr( "%s_%s_animations", pszClassFolder, pszAnimQCMiddleName ); |
|
pQC->SetCustomRelativeDir( pszCustomRelativeDir ); |
|
pQC->SetCustomOutputName( pszCustomQCOutputName ); |
|
pQC->SetIgnoreP4( !bPerforce ); |
|
|
|
const char *pszFilePath = GetItemValues()->GetString( CFmtStr( kClassAnimationSourceFile, pszClassFolder ) ); |
|
if ( pszFilePath && *pszFilePath ) |
|
{ |
|
int nLOD = asset.AddTargetDMX( pszFilePath ); |
|
if ( nLOD < 0 ) |
|
{ |
|
SetMessageFileVariable( pBuildMessageVariables, pszFilePath ); |
|
return BUILD_FAILED_BADMODEL; |
|
} |
|
|
|
CSmartPtr< CTargetDMX > pTargetDMX = asset.GetTargetDMX( nLOD ); |
|
|
|
if ( bIsMulticlass ) |
|
{ |
|
pTargetDMX->SetNameSuffix( CFmtStr( "_%s", pszClassFolder ) ); |
|
} |
|
|
|
// Update the item data for the path inside the asset archive |
|
CUtlString sOutputPath; |
|
pTargetDMX->GetOutputPath( sOutputPath, 0, nPathFlags ); |
|
pItemData->SetString( CFmtStr( kClassAnimationSourceFile, pszClassFolder ), sOutputPath ); |
|
|
|
CUtlString sSequenceName; |
|
pTargetDMX->GetOutputPath( sSequenceName, 0, CTargetBase::PATH_FLAG_FILE ); |
|
|
|
float flFrameRate; |
|
int nFrameCount; |
|
pTargetDMX->GetAnimationFrameInfo( flFrameRate, nFrameCount ); |
|
float flTotalAnimTime = (float)nFrameCount / flFrameRate; |
|
|
|
// set custom keys for DMX |
|
pTargetDMX->GetCustomKeyValues()->SetString( "<ITEMTEST_SEQUENCE_NAME>", sSequenceName.String() ); |
|
pTargetDMX->GetCustomKeyValues()->SetString( "<CLASS_NAME>", pszClassFolder ); |
|
pTargetDMX->GetCustomKeyValues()->SetFloat( "<MAX_SEQUENCE_LENGTH>", flTotalAnimTime ); |
|
|
|
if ( IsLoopableTaunt() ) |
|
{ |
|
float flStartTime = Clamp( GetAnimationLoopStartTime(), 0.f, flTotalAnimTime ); |
|
pTargetDMX->SetAnimationLoopStartTime( flStartTime ); |
|
} |
|
|
|
pTargetDMX->SetSoundScriptFilePath( kWorkshopSoundScriptFile ); |
|
|
|
if ( bPreview ) |
|
{ |
|
pTargetDMX->SetCustomModPath( "custom/workshop" ); |
|
} |
|
} |
|
|
|
// check out files before compiling (INTERNAL ONLY) |
|
if ( p4 ) |
|
{ |
|
CUtlString sMDLAbsPath; |
|
pMDL->GetOutputPath( sMDLAbsPath, 0 ); |
|
char szCorrectCaseFilePath[MAX_PATH]; |
|
g_pFullFileSystem->GetCaseCorrectFullPath( sMDLAbsPath.String(), szCorrectCaseFilePath ); |
|
CP4AutoEditAddFile editMDL( szCorrectCaseFilePath, "binary" ); |
|
|
|
// check out class_workshop_animation.qc to submit the final workshop |
|
if ( bPerforce ) |
|
{ |
|
CUtlString sQCAbsPath; |
|
pQC->GetOutputPath( sQCAbsPath, 0 ); |
|
g_pFullFileSystem->GetCaseCorrectFullPath( sQCAbsPath.String(), szCorrectCaseFilePath ); |
|
CP4AutoEditAddFile editQC( szCorrectCaseFilePath ); |
|
} |
|
|
|
const char *pszSoundScriptFile = GetWorkshopSoundScriptFile(); |
|
if ( pszSoundScriptFile ) |
|
{ |
|
CP4AutoEditAddFile editSoundScript( pszSoundScriptFile ); |
|
} |
|
} |
|
|
|
return BUILD_OKAY; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFFileImportDialog::BUILD_RESULT CTFFileImportDialog::AddModelToAsset( CAssetTF &asset, int nClassIndex, bool bIsMulticlass, BUILD_STAGE buildStage, KeyValues *pItemData, KeyValues *pBuildMessageVariables ) |
|
{ |
|
const uint nPathFlags = (CTargetBase::PATH_FLAG_ALL & ~CTargetBase::PATH_FLAG_ABSOLUTE) | CTargetBase::PATH_FLAG_ZIP; |
|
bool bPreview = buildStage == BUILD_PREVIEW; |
|
|
|
asset.AddModel(); |
|
|
|
const char *pszClassFolder = kClassFolders[ nClassIndex ]; |
|
|
|
if ( bIsMulticlass ) |
|
{ |
|
asset.GetTargetMDL()->SetNameSuffix( CFmtStr( "_%s", pszClassFolder ) ); |
|
} |
|
|
|
CSmartPtr< CTargetQC > pQC = asset.GetTargetQC(); |
|
pQC->SetQCTemplate( GetQCTemplate( nClassIndex ) ); |
|
|
|
int nLastSpecifiedTriCount = 0; |
|
int nLastSpecifiedLOD = 0; |
|
for ( int nModelIndex = 0; nModelIndex < NUM_IMPORT_LODS; ++nModelIndex ) |
|
{ |
|
const char *pszFilePath = GetItemValues()->GetString( CFmtStr( kClassLODNFile, pszClassFolder, nModelIndex ) ); |
|
if ( *pszFilePath ) |
|
{ |
|
int nLOD = asset.AddTargetDMX( pszFilePath ); |
|
if ( nLOD < 0 ) |
|
{ |
|
SetMessageFileVariable( pBuildMessageVariables, pszFilePath ); |
|
return BUILD_FAILED_BADMODEL; |
|
} |
|
|
|
CSmartPtr< CTargetDMX > pTargetDMX = asset.GetTargetDMX( nLOD ); |
|
|
|
const int nMaxTris = GetModelTriangleBudget( nClassIndex, nModelIndex ); |
|
const int nTriCount = pTargetDMX->GetTriangleCount(); |
|
if ( !bPreview && nTriCount > nMaxTris ) |
|
{ |
|
pBuildMessageVariables->SetInt( "count", nTriCount ); |
|
pBuildMessageVariables->SetInt( "limit", nMaxTris ); |
|
SetMessageFileVariable( pBuildMessageVariables, pszFilePath ); |
|
return BUILD_FAILED_COMPLEXMODEL; |
|
} |
|
|
|
// Update the item data for the path inside the asset archive |
|
CUtlString sOutputPath; |
|
pTargetDMX->GetOutputPath( sOutputPath, 0, nPathFlags ); |
|
pItemData->SetString( CFmtStr( kClassLODNFile, pszClassFolder, nModelIndex ), sOutputPath ); |
|
|
|
nLastSpecifiedLOD = nModelIndex; |
|
nLastSpecifiedTriCount = nTriCount; |
|
} |
|
else if ( !bPreview && nModelIndex == 0 ) |
|
{ |
|
// We need LOD0... |
|
pBuildMessageVariables->SetString( "class", pszClassFolder ); |
|
return BUILD_FAILED_MISSINGMODEL; |
|
} |
|
} // for each LOD |
|
|
|
if ( !bPreview && nLastSpecifiedTriCount > GetModelTriangleBudget( nClassIndex, NUM_IMPORT_LODS - 1 ) ) |
|
{ |
|
pBuildMessageVariables->SetString( "lod", kLODLevels[ nLastSpecifiedLOD + 1 ] ); |
|
const char *pszFilePath = GetItemValues()->GetString( CFmtStr( kClassLODNFile, pszClassFolder, nLastSpecifiedLOD ) ); |
|
SetMessageFileVariable( pBuildMessageVariables, pszFilePath ); |
|
return BUILD_FAILED_NEEDMORELOD; |
|
} |
|
|
|
return BUILD_OKAY; |
|
} |
|
|
|
CTFFileImportDialog::BUILD_RESULT CTFFileImportDialog::AddMaterialsToAsset( CAssetTF &asset, KeyValues *pItemData, KeyValues *pBuildMessageVariables ) |
|
{ |
|
const uint nPathFlags = (CTargetBase::PATH_FLAG_ALL & ~CTargetBase::PATH_FLAG_ABSOLUTE) | CTargetBase::PATH_FLAG_ZIP; |
|
int nValidVMTIndex = 0; |
|
CUtlVector< CUtlString > vecMaterialFiles; |
|
for ( int nVMT = 0; nVMT < asset.GetTargetVMTCount(); nVMT++ ) |
|
{ |
|
CTargetVMT *pVMT = asset.GetTargetVMT( nVMT ); |
|
if ( pVMT ) |
|
{ |
|
if ( pVMT->GetDuplicate() ) |
|
{ |
|
continue; |
|
} |
|
|
|
if ( pVMT->GetMaterialType() == kInvalidMaterialType ) |
|
{ |
|
SetMessageFileVariable( pBuildMessageVariables, pVMT->GetMaterialId() ); |
|
return BUILD_FAILED_BADMATERIALTYPE; |
|
} |
|
|
|
for ( int nSkinIndex = 0; nSkinIndex < CItemUpload::Manifest()->GetNumMaterialSkins(); ++nSkinIndex ) |
|
{ |
|
CUtlString strMaterialName = GetMaterialName( nSkinIndex, nValidVMTIndex ); |
|
if ( strMaterialName.IsEmpty() ) |
|
{ |
|
continue; |
|
} |
|
|
|
KeyValuesAD pKV( "VMT" ); |
|
CUtlBuffer sMaterialText; |
|
if ( !GetMaterialText( nSkinIndex, nValidVMTIndex, sMaterialText ) || |
|
!pKV->LoadFromBuffer( pVMT->GetMaterialId(), sMaterialText ) ) |
|
{ |
|
if ( !strMaterialName.IsEmpty() ) |
|
{ |
|
SetMessageFileVariable( pBuildMessageVariables, strMaterialName ); |
|
} |
|
else |
|
{ |
|
SetMessageFileVariable( pBuildMessageVariables, pVMT->GetMaterialId() ); |
|
} |
|
return BUILD_FAILED_BADMATERIAL; |
|
} |
|
|
|
BUILD_RESULT nMaterialResult = ValidateMaterialValues( pKV, nValidVMTIndex ); |
|
if ( nMaterialResult != BUILD_OKAY ) |
|
{ |
|
if ( !strMaterialName.IsEmpty() ) |
|
{ |
|
SetMessageFileVariable( pBuildMessageVariables, strMaterialName ); |
|
} |
|
else |
|
{ |
|
SetMessageFileVariable( pBuildMessageVariables, pVMT->GetMaterialId() ); |
|
} |
|
return nMaterialResult; |
|
} |
|
|
|
RemoveUnnecessaryParametersFromVMT( pKV, nValidVMTIndex ); |
|
pVMT->SetVMTKV( pKV, nSkinIndex ); |
|
|
|
bool bSelfIllum = pKV->GetBool( ">=DX90/$selfillum" ); |
|
bool bBaseAlphaMask = pKV->GetBool( "$basealphaenvmapmask" ); |
|
Assert( CItemUpload::Manifest()->GetNumTextureTypes() == NUM_MATERIAL_TEXTURE_FILE_TYPE ); |
|
for ( int nTextureType = 0; nTextureType < CItemUpload::Manifest()->GetNumTextureTypes(); ++nTextureType ) |
|
{ |
|
MATERIAL_FILE_TYPE materialFileType = (MATERIAL_FILE_TYPE)nTextureType; |
|
const char *pszTexturePath = GetMaterialTextureFile( nSkinIndex, nValidVMTIndex, materialFileType ); |
|
if ( V_strlen( pszTexturePath ) == 0 ) |
|
{ |
|
continue; |
|
} |
|
|
|
BUILD_RESULT checkImageResult = CheckImageSize( pszTexturePath, materialFileType, pBuildMessageVariables ); |
|
if ( checkImageResult != BUILD_OKAY ) |
|
{ |
|
return checkImageResult; |
|
} |
|
|
|
const char *pszTextureType = CItemUpload::Manifest()->GetTextureType( materialFileType ); |
|
if ( bBaseAlphaMask && FStrEq( pszTextureType, "_normal" ) ) |
|
{ |
|
Assert( materialFileType == MATERIAL_FILE_NORMAL ); |
|
// Base alpha mask will not work in materials using a normal map, use normal map alpha mask instead |
|
continue; |
|
} |
|
else if ( !bSelfIllum && FStrEq( pszTextureType, "_illum" ) ) |
|
{ |
|
Assert( materialFileType == MATERIAL_FILE_SELFILLUM ); |
|
// no need to output illum if self illum is not set |
|
continue; |
|
} |
|
|
|
if ( !pVMT->SetTargetVTF( pszTextureType, pszTexturePath, nSkinIndex ) ) |
|
{ |
|
SetMessageFileVariable( pBuildMessageVariables, pszTexturePath ); |
|
return BUILD_FAILED_BADIMAGE; |
|
} |
|
} |
|
|
|
for ( int iVTF=0; iVTF<pVMT->GetNumTargetVTFS( nSkinIndex ); ++iVTF ) |
|
{ |
|
// Update the item data for the path inside the asset archive |
|
CUtlString sOutputPath; |
|
CTargetVTF *pVTF = pVMT->GetTargetVTF( iVTF, nSkinIndex ); |
|
if ( pVTF ) |
|
{ |
|
pVTF->GetTargetTGA()->GetOutputPath( sOutputPath, 0, nPathFlags ); |
|
sOutputPath = asset.CheckRedundantOutputFilePath( pVTF->GetTargetTGA()->GetInputFile().String(), "", sOutputPath.String() ); |
|
pItemData->SetString( CFmtStr( kMaterialSkinNFile, CItemUpload::Manifest()->GetMaterialSkin( nSkinIndex ), nValidVMTIndex, s_pszMaterialFilePrefixes[iVTF] ), sOutputPath ); |
|
} |
|
} |
|
} |
|
|
|
++nValidVMTIndex; |
|
} |
|
} |
|
|
|
return BUILD_OKAY; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::CheckSourceSDK() |
|
{ |
|
CUtlString sDummy; |
|
return CItemUpload::GetContentDir( sDummy ) && CItemUpload::GetBinDirectory( sDummy ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFFileImportDialog::BUILD_RESULT CTFFileImportDialog::Build( BUILD_STAGE buildStage, KeyValues *pBuildMessageVariables ) |
|
{ |
|
const uint nPathFlags = (CTargetBase::PATH_FLAG_ALL & ~CTargetBase::PATH_FLAG_ABSOLUTE) | CTargetBase::PATH_FLAG_ZIP; |
|
bool bPreview = buildStage == BUILD_PREVIEW; |
|
|
|
if ( !CheckSourceSDK() ) |
|
{ |
|
return BUILD_FAILED_NOSDK; |
|
} |
|
|
|
// check for build errors |
|
if ( !bPreview ) |
|
{ |
|
if ( V_strcmp( GetItemName(), "" ) == 0 ) |
|
{ |
|
return BUILD_FAILED_NONAME; |
|
} |
|
|
|
if ( V_strcmp( GetItemPrefab(), "" ) == 0 ) |
|
{ |
|
return BUILD_FAILED_NOTYPE; |
|
} |
|
|
|
if ( !IsValidPrefab( GetItemPrefab() ) ) |
|
{ |
|
return BUILD_FAILED_BADTYPE; |
|
} |
|
|
|
if ( m_nPrefab == PREFAB_TAUNT ) |
|
{ |
|
if ( !AnyClassHasTauntSources() ) |
|
{ |
|
return BUILD_FAILED_NO_TAUNT_SOURCES; |
|
} |
|
} |
|
else |
|
{ |
|
if ( !AnyClassHasModels() ) |
|
{ |
|
return BUILD_FAILED_NOMODELS; |
|
} |
|
|
|
if ( !AreClassesLODCountMatch() ) |
|
{ |
|
return BUILD_FAILED_LODCOUNTMISMATCH; |
|
} |
|
|
|
if ( !AreClassesMaterialCountMatch() ) |
|
{ |
|
return BUILD_FAILED_MATERIALCOUNTMISMATCH; |
|
} |
|
|
|
if ( !DidSpecifyAllMaterials() ) |
|
{ |
|
return BUILD_FAILED_NOMATERIALS; |
|
} |
|
} |
|
|
|
if ( V_strcmp( GetItemIcon(), "" ) == 0 ) |
|
{ |
|
return BUILD_FAILED_NOBACKPACKICON; |
|
} |
|
} |
|
|
|
bool bPartnerContent = IsPartnerContent(); |
|
// override the manifest data for partner content |
|
CItemUpload::Manifest()->SetItemDirectoryOverride( bPartnerContent ? "workshop_partner/player/items/" : "" ); |
|
CItemUpload::Manifest()->SetAnimationDirectoryOverride( bPartnerContent ? "workshop_partner/player/animations/" : "" ); |
|
CItemUpload::Manifest()->SetIconDirectoryOverride( bPartnerContent ? "backpack/workshop_partner/player/items/" : "" ); |
|
|
|
CAssetTF asset; |
|
CBuildLog buildLog; |
|
|
|
asset.SetItemLog( &buildLog ); |
|
|
|
CUtlString sName = GetItemName(); |
|
if ( bPreview ) |
|
{ |
|
sName = "item_preview"; |
|
} |
|
|
|
// get rid of leading/trailing white spaces |
|
char szTempName[MAX_PATH]; |
|
V_strcpy_safe( szTempName, sName.String() ); |
|
Q_StripPrecedingAndTrailingWhitespace( szTempName ); |
|
sName = szTempName; |
|
|
|
if ( !asset.SetName( sName ) ) |
|
{ |
|
return BUILD_FAILED_BADNAME; |
|
} |
|
asset.SetClass( GetClassFolder() ); |
|
|
|
KeyValuesAD pSessionData( BuildSessionData( sName ) ); |
|
KeyValues *pItemData = pSessionData->FindKey( GetItemValues()->GetName() ); |
|
Assert( pItemData != NULL ); |
|
|
|
const char *pszIcon = GetItemIcon(); |
|
if ( V_strlen( pszIcon ) > 0 ) |
|
{ |
|
int nNumIconTypes = CItemUpload::Manifest()->GetNumIconTypes(); |
|
if ( nNumIconTypes > 0 ) |
|
{ |
|
for ( int nIcon = 0; nIcon < nNumIconTypes; ++nIcon ) |
|
{ |
|
if ( !asset.SetTargetIcon( nIcon, pszIcon ) ) |
|
{ |
|
SetMessageFileVariable( pBuildMessageVariables, pszIcon ); |
|
return BUILD_FAILED_BADIMAGE; |
|
} |
|
} |
|
|
|
// Get the filename from the last (largest) icon type |
|
CSmartPtr< CTargetIcon > pTargetIcon = asset.GetTargetIcon( nNumIconTypes - 1 ); |
|
CUtlString sOutputPath; |
|
pTargetIcon->GetTargetVTF( 0 )->GetTargetTGA()->GetOutputPath( sOutputPath, 0, nPathFlags ); |
|
pItemData->SetString( kItemIcon, sOutputPath ); |
|
} |
|
} |
|
|
|
// clean up "blue" materials if needed |
|
if ( GetItemValues()->GetInt( kSkinType ) == 0 ) |
|
{ |
|
for ( int nMaterialIndex = 0; nMaterialIndex<NUM_IMPORT_MATERIALS_PER_TEAM; ++nMaterialIndex ) |
|
{ |
|
ClearMaterial( 1, nMaterialIndex ); |
|
} |
|
} |
|
|
|
const char *pszSoundScriptFile = GetWorkshopSoundScriptFile(); |
|
if ( pszSoundScriptFile ) |
|
{ |
|
CP4AutoRevertFile revert( pszSoundScriptFile ); |
|
} |
|
|
|
// check and prepare models/taunt sources for compiling |
|
bool bIsMulticlass = IsMulticlass(); |
|
asset.RemoveModels(); |
|
BUILD_RESULT buildResult; |
|
for ( int nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) |
|
{ |
|
if ( ClassHasTauntSources( nClassIndex ) ) |
|
{ |
|
buildResult = AddTauntToAsset( asset, nClassIndex, bIsMulticlass, buildStage, pItemData, pBuildMessageVariables ); |
|
if ( buildResult != BUILD_OKAY ) |
|
return buildResult; |
|
|
|
// should we add prop? |
|
if ( ClassHasModels( nClassIndex ) ) |
|
{ |
|
buildResult = AddModelToAsset( asset, nClassIndex, bIsMulticlass, buildStage, pItemData, pBuildMessageVariables ); |
|
if ( buildResult != BUILD_OKAY ) |
|
return buildResult; |
|
} |
|
} |
|
else if ( ClassHasModels( nClassIndex ) ) |
|
{ |
|
buildResult = AddModelToAsset( asset, nClassIndex, bIsMulticlass, buildStage, pItemData, pBuildMessageVariables ); |
|
if ( buildResult != BUILD_OKAY ) |
|
return buildResult; |
|
} |
|
} // for each class |
|
|
|
buildResult = AddMaterialsToAsset( asset, pItemData, pBuildMessageVariables ); |
|
if ( buildResult != BUILD_OKAY ) |
|
return buildResult; |
|
|
|
// setworkshop ID |
|
if ( !bPreview ) |
|
{ |
|
if ( p4 ) |
|
{ |
|
if ( pItemData->GetUint64( kWorkshopID ) == 0 ) |
|
{ |
|
return BUILD_FAILED_NO_WORKSHOP_ID; |
|
} |
|
} |
|
|
|
if ( CItemUpload::GetP4() ) |
|
{ |
|
KeyValues *pItemSchema = pSessionData->FindKey( CFmtStr( "%s/%s", GetItemValues()->GetName(), kItemSchema ) ); |
|
if ( pItemSchema ) |
|
{ |
|
item_definition_index_t defIndex = AddKeyValuesToItemWorkshopSchema( pItemSchema ); |
|
if ( !IsTFEnglishNameValid( defIndex ) ) |
|
{ |
|
return BUILD_FAILED_BADTFENGLISHNAME; |
|
} |
|
} |
|
} |
|
} |
|
|
|
asset.SetAdditionalManifestData( pSessionData ); |
|
|
|
if ( m_nPrefab == PREFAB_TAUNT ) |
|
{ |
|
asset.SetBuildScenesImage( true ); |
|
|
|
if ( bPreview ) |
|
{ |
|
asset.SetCustomModPath( "custom/workshop" ); |
|
} |
|
} |
|
|
|
if ( bPreview ) |
|
{ |
|
if ( !asset.CompilePreview() ) |
|
{ |
|
pBuildMessageVariables->SetString( "log", buildLog.Get() ); |
|
return BUILD_FAILED_COMPILE; |
|
} |
|
|
|
buildResult = VerifyVCD( asset ); |
|
if ( buildResult != BUILD_OKAY ) |
|
{ |
|
return buildResult; |
|
} |
|
|
|
SavePreviewData( asset ); |
|
} |
|
else |
|
{ |
|
CUtlString sAssetName; |
|
char pszSessionPath[ MAX_PATH ]; |
|
char pszArchivePath[ MAX_PATH ]; |
|
|
|
asset.GetName( sAssetName ); |
|
const char *pszWorkshopDir = CFmtStr( kSteamWorkshopDir, GetWorkshopFolder() ); |
|
if ( !g_pFullFileSystem->RelativePathToFullPath_safe( pszWorkshopDir, "GAME", pszSessionPath ) ) |
|
{ |
|
SetMessageFileVariable( pBuildMessageVariables, pszWorkshopDir ); |
|
return BUILD_FAILED_COMPILE; |
|
} |
|
V_ComposeFileName( pszSessionPath, CFmtStr( "%s.zip", sAssetName.Get() ), pszArchivePath, sizeof(pszArchivePath) ); |
|
asset.SetArchivePath( pszArchivePath ); |
|
|
|
if ( !asset.Compile() ) |
|
{ |
|
pBuildMessageVariables->SetString( "log", buildLog.Get() ); |
|
return BUILD_FAILED_COMPILE; |
|
} |
|
|
|
buildResult = VerifyVCD( asset ); |
|
if ( buildResult != BUILD_OKAY ) |
|
{ |
|
return buildResult; |
|
} |
|
|
|
GetItemValues()->SetString( kBuildOutput, pszArchivePath ); |
|
} |
|
|
|
return BUILD_OKAY; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
KeyValues *CTFFileImportDialog::BuildSessionData( const char *pszItemName ) |
|
{ |
|
KeyValues *pData = new KeyValues( "Data" ); |
|
KeyValues *pItemData = GetItemValues()->MakeCopy(); |
|
pItemData->AddSubKey( BuildItemSchema( pszItemName ) ); |
|
pData->AddSubKey( pItemData ); |
|
return pData; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
KeyValues *CTFFileImportDialog::BuildItemSchema( const char *pszItemName ) |
|
{ |
|
const uint nPathFlags = (CTargetBase::PATH_FLAG_ALL & ~CTargetBase::PATH_FLAG_ABSOLUTE); |
|
|
|
KeyValues *pData = new KeyValues( kItemSchema ); |
|
KeyValues *pKey; |
|
int nClassIndex; |
|
|
|
pData->UsesEscapeSequences( true ); |
|
|
|
// Get the sanitized name for item schema tokens |
|
CUtlString sName; |
|
CAssetTF asset; |
|
asset.SetName( pszItemName ); |
|
asset.GetName( sName ); |
|
asset.SetClass( GetClassFolder() ); |
|
|
|
const char* pszTFEnglishName = GetItemValues()->GetString( kTFEnglishName ); |
|
|
|
pData->SetString( kWorkshopName, GetItemValues()->GetString( kItemName ) ); |
|
pData->SetString( "name", pszTFEnglishName ); // TODO: Change this when we add a ship panel to fill in name from tf_english.txt |
|
|
|
const char *pszForcePrefab = "no_craft"; |
|
pData->SetString( "prefab", CFmtStr( "%s %s", pszForcePrefab, GetItemPrefab() ) ); |
|
pData->SetString( "item_name", CFmtStr( "#TF_%s", sName.Get() ) ); |
|
pData->SetString( "item_description", CFmtStr( "#TF_%s_Desc", sName.Get() ) ); |
|
|
|
if ( m_nPrefab != PREFAB_TAUNT ) |
|
{ |
|
pData->SetString( "equip_region", GetItemValues()->GetString( kEquipRegion ) ); |
|
} |
|
|
|
const char *kThe = "The "; |
|
if ( V_strncasecmp( pszTFEnglishName, kThe, V_strlen( kThe ) ) == 0 ) |
|
{ |
|
pData->SetBool( "propername", true ); |
|
} |
|
|
|
if ( m_nPrefab != PREFAB_TAUNT ) |
|
{ |
|
KeyValues *pItemBodygroups = GetItemValues()->FindKey( kBodygroup ); |
|
if ( pItemBodygroups ) |
|
{ |
|
CUtlVector<int> bodygroupIDs; |
|
for ( int i=0; i<ARRAYSIZE( kBodygroupArray ); ++i ) |
|
{ |
|
if ( pItemBodygroups->GetBool( kBodygroupArray[i] ) ) |
|
{ |
|
bodygroupIDs.AddToTail(i); |
|
} |
|
} |
|
|
|
if ( bodygroupIDs.Count() > 0 ) |
|
{ |
|
KeyValues *pSchemaVisualsKey = pData->FindKey( "visuals", true ); |
|
if ( pSchemaVisualsKey ) |
|
{ |
|
KeyValues *pSchemaBodygroupsKey = pSchemaVisualsKey->FindKey( "player_bodygroups", true ); |
|
if ( pSchemaBodygroupsKey ) |
|
{ |
|
for ( int i=0; i<bodygroupIDs.Count(); ++i ) |
|
{ |
|
int nBodygroupIndex = bodygroupIDs[i]; |
|
pSchemaBodygroupsKey->SetBool( kBodygroupArray[nBodygroupIndex], true ); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
else if ( IsLoopableTaunt() ) |
|
{ |
|
KeyValues *pAttributesKey = pData->FindKey( "attributes", true ); |
|
if ( pAttributesKey ) |
|
{ |
|
KeyValues *pLoopAttrKey = pAttributesKey->FindKey( "taunt is press and hold", true ); |
|
if ( pLoopAttrKey ) |
|
{ |
|
pLoopAttrKey->SetString( "attribute_class", "enable_misc2_holdtaunt" ); |
|
pLoopAttrKey->SetInt( "value", 1 ); |
|
} |
|
} |
|
} |
|
|
|
const char *pszIcon = GetItemIcon(); |
|
if ( V_strlen( pszIcon ) > 0 ) |
|
{ |
|
if ( asset.SetTargetIcon( 0, pszIcon ) ) |
|
{ |
|
CSmartPtr< CTargetIcon > pTargetIcon = asset.GetTargetIcon( 0 ); |
|
CUtlString sOutputPath; |
|
if ( pTargetIcon->GetOutputPath( sOutputPath, 0, nPathFlags ) ) |
|
{ |
|
const char *pszMaterialsPrefix = "materials/"; |
|
char *pszOutputPath = sOutputPath.GetForModify(); |
|
V_FixSlashes( pszOutputPath, '/' ); |
|
if ( V_strncmp( pszOutputPath, pszMaterialsPrefix, V_strlen( pszMaterialsPrefix ) ) == 0 ) |
|
{ |
|
pszOutputPath += V_strlen( pszMaterialsPrefix ); |
|
} |
|
V_StripExtension( pszOutputPath, pszOutputPath, V_strlen( pszOutputPath ) + 1 ); |
|
|
|
pData->SetString( "image_inventory", pszOutputPath ); |
|
} |
|
else |
|
{ |
|
Warning( "Couldn't get output path for icon %s", pszIcon ); |
|
} |
|
} |
|
else |
|
{ |
|
Warning( "Couldn't load icon %s", pszIcon ); |
|
} |
|
} |
|
|
|
// always add can_craft_count even if the item is not craftable in case we want to make it craftable in the future |
|
pKey = pData->FindKey( "capabilities", true ); |
|
pKey->SetInt( "can_craft_count", 1 ); |
|
|
|
if ( IsAnyVMTPaintable() ) |
|
{ |
|
pKey->SetBool( "paintable", true ); |
|
} |
|
|
|
const CUtlVector<const char *>&vecUsabilityStrings = ItemSystem()->GetItemSchema()->GetClassUsabilityStrings(); |
|
if ( m_nPrefab != PREFAB_TAUNT ) |
|
{ |
|
bool bIsMulticlass = IsMulticlass(); |
|
asset.RemoveModels(); |
|
for ( nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) |
|
{ |
|
if ( !ClassHasModels( nClassIndex ) ) |
|
continue; |
|
|
|
asset.AddModel(); |
|
|
|
if ( bIsMulticlass ) |
|
{ |
|
asset.GetTargetMDL()->SetNameSuffix( CFmtStr( "_%s", kClassFolders[ nClassIndex ] ) ); |
|
} |
|
|
|
const char *pszFilePath = GetItemValues()->GetString( CFmtStr( kClassLODNFile, kClassFolders[ nClassIndex ], 0 ) ); |
|
if ( *pszFilePath ) |
|
{ |
|
int nLOD = asset.AddTargetDMX( pszFilePath ); |
|
if ( nLOD < 0 ) |
|
{ |
|
Warning( "Couldn't load model %s", pszFilePath ); |
|
continue; |
|
} |
|
|
|
// Update the item data for the path inside the asset archive |
|
CUtlString sOutputPath; |
|
if ( asset.GetTargetMDL()->GetOutputPath( sOutputPath, 0, nPathFlags ) ) |
|
{ |
|
sOutputPath.FixSlashes( '/' ); |
|
|
|
if ( bIsMulticlass ) |
|
{ |
|
pKey = pData->FindKey( "model_player_per_class", true ); |
|
const char* pszClassName = vecUsabilityStrings[ nClassIndex ]; |
|
pKey->SetString( pszClassName, sOutputPath ); |
|
} |
|
else |
|
{ |
|
pData->SetString( "model_player", sOutputPath ); |
|
} |
|
} |
|
else |
|
{ |
|
Warning( "Couldn't get output path for model %s", pszFilePath ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
KeyValues *pUsedByClass = pData->FindKey( "used_by_classes", true ); |
|
for ( nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) |
|
{ |
|
if ( !ClassHasModels( nClassIndex ) && !ClassHasTauntSources( nClassIndex ) ) |
|
continue; |
|
|
|
pUsedByClass->SetBool( vecUsabilityStrings[ nClassIndex ], true ); |
|
} |
|
|
|
// add "taunt" block here |
|
if ( m_nPrefab == PREFAB_TAUNT ) |
|
{ |
|
KeyValues *pTauntKey = pData->FindKey( "taunt", true ); |
|
KeyValues *pCustomTauntPerClass = pTauntKey->FindKey( "custom_taunt_scene_per_class", true ); |
|
|
|
CSmartPtr< CTargetQC > pQC = asset.GetTargetQC(); |
|
CSmartPtr< CTargetVCD > pVCD = pQC->GetTargetVCD(); |
|
|
|
bool bIsMulticlass = IsMulticlass(); |
|
|
|
for ( nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) |
|
{ |
|
const char *pszClass = vecUsabilityStrings[nClassIndex]; |
|
if ( pUsedByClass->GetBool( pszClass ) ) |
|
{ |
|
pVCD->SetCustomRelativeDir( CFmtStr( "%s/player/%s/low", GetWorkshopFolder(), pszClass ) ); |
|
CUtlString sTauntOutputPath; |
|
pVCD->GetOutputPath( sTauntOutputPath, 0, nPathFlags ); |
|
sTauntOutputPath.FixSlashes( '/' ); |
|
pCustomTauntPerClass->SetString( pszClass, sTauntOutputPath.String() ); |
|
|
|
// should we add prop? |
|
if ( !ClassHasModels( nClassIndex ) ) |
|
continue; |
|
|
|
asset.AddModel(); |
|
|
|
if ( bIsMulticlass ) |
|
{ |
|
asset.GetTargetMDL()->SetNameSuffix( CFmtStr( "_%s", kClassFolders[ nClassIndex ] ) ); |
|
} |
|
|
|
const char *pszFilePath = GetItemValues()->GetString( CFmtStr( kClassLODNFile, kClassFolders[ nClassIndex ], 0 ) ); |
|
if ( *pszFilePath ) |
|
{ |
|
int nLOD = asset.AddTargetDMX( pszFilePath ); |
|
if ( nLOD < 0 ) |
|
{ |
|
Warning( "Couldn't load model %s", pszFilePath ); |
|
continue; |
|
} |
|
|
|
// Update the item data for the path inside the asset archive |
|
CUtlString sPropOutputPath; |
|
if ( asset.GetTargetMDL()->GetOutputPath( sPropOutputPath, 0, nPathFlags ) ) |
|
{ |
|
sPropOutputPath.FixSlashes( '/' ); |
|
|
|
KeyValues *pCustomPropPerClass = pTauntKey->FindKey( "custom_taunt_prop_per_class", true ); |
|
pCustomPropPerClass->SetString( pszClass, sPropOutputPath.String() ); |
|
} |
|
else |
|
{ |
|
Warning( "Couldn't get output path for model %s", pszFilePath ); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
return pData; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFFileImportDialog::LOAD_RESULT CTFFileImportDialog::Load( const char *pszFilePath, const char *pathID, CUtlString &sFailedPath ) |
|
{ |
|
const char *pszExtension = V_GetFileExtension( pszFilePath ); |
|
if ( V_strcasecmp( pszExtension, "txt" ) == 0 ) |
|
{ |
|
return LoadTxt( pszFilePath, pathID, sFailedPath ); |
|
} |
|
if ( V_strcasecmp( pszExtension, "zip" ) == 0 ) |
|
{ |
|
return LoadZip( pszFilePath, pathID, sFailedPath ); |
|
} |
|
sFailedPath = pszFilePath; |
|
return LOAD_FAILED; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFFileImportDialog::LOAD_RESULT CTFFileImportDialog::LoadTxt( const char *pszFilePath, const char *pathID, CUtlString &sFailedPath ) |
|
{ |
|
char pszBasePath[MAX_PATH]; |
|
char pszLoadPath[MAX_PATH]; |
|
|
|
V_ExtractFilePath( pszFilePath, pszBasePath, sizeof(pszBasePath) ); |
|
|
|
KeyValuesAD pData( "Data" ); |
|
pData->UsesEscapeSequences( true ); |
|
|
|
if ( !pData->LoadFromFile( g_pFullFileSystem, pszFilePath, pathID ) ) |
|
{ |
|
sFailedPath = pszFilePath; |
|
return LOAD_FAILED; |
|
} |
|
|
|
KeyValues *pItemData = pData->FindKey( GetItemValues()->GetName() ); |
|
if ( !pItemData ) |
|
{ |
|
sFailedPath = pszFilePath; |
|
return LOAD_FAILED; |
|
} |
|
|
|
SetItemName( pItemData->GetString( kItemName) ); |
|
SetItemPrefab( pItemData->GetString( kItemPrefab ) ); |
|
SetSkinType( pItemData->GetInt( kSkinType ) ); |
|
SetEquipRegion( pItemData->GetString( kEquipRegion ) ); |
|
SetWorkshopID( pItemData->GetString( kWorkshopID ) ); |
|
SetTFEnglishName( pItemData->GetString( kTFEnglishName ) ); |
|
|
|
KeyValues *pBodygroup = pItemData->FindKey( kBodygroup ); |
|
if ( pBodygroup ) |
|
{ |
|
SetBodygroup( pBodygroup ); |
|
} |
|
|
|
const char *pszIconFile = pItemData->GetString( kItemIcon ); |
|
if ( *pszIconFile && !V_IsAbsolutePath( pszIconFile) ) |
|
{ |
|
V_ComposeFileName( pszBasePath, pszIconFile, pszLoadPath, sizeof(pszLoadPath) ); |
|
pszIconFile = pszLoadPath; |
|
} |
|
SetItemIcon( pszIconFile ); |
|
|
|
for ( int nMaterialIndex=0; nMaterialIndex<NUM_IMPORT_MATERIALS_PER_TEAM; ++nMaterialIndex ) |
|
{ |
|
const char* pszPaintable = CFmtStr( kItemPaintable, nMaterialIndex ); |
|
SetPaintable( pItemData->GetBool( pszPaintable ), nMaterialIndex ); |
|
} |
|
|
|
bool bSelected = false; |
|
for ( int nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) |
|
{ |
|
const char* pszQCKeyName = CFmtStr( kClassQC, kClassFolders[ nClassIndex ] ); |
|
GetItemValues()->SetString( pszQCKeyName, pItemData->GetString( pszQCKeyName ) ); |
|
|
|
for ( int nModelIndex = 0; nModelIndex < NUM_IMPORT_LODS; ++nModelIndex ) |
|
{ |
|
const char *pszModelFile = pItemData->GetString( CFmtStr( kClassLODNFile, kClassFolders[ nClassIndex ], nModelIndex ) ); |
|
if ( *pszModelFile ) |
|
{ |
|
if ( !V_IsAbsolutePath( pszModelFile) ) |
|
{ |
|
V_ComposeFileName( pszBasePath, pszModelFile, pszLoadPath, sizeof(pszLoadPath) ); |
|
pszModelFile = pszLoadPath; |
|
} |
|
|
|
// set default selected class |
|
if ( !bSelected ) |
|
{ |
|
m_nSelectedClass = nClassIndex; |
|
|
|
if ( m_pClassRadioButtons[ nClassIndex ] ) |
|
{ |
|
m_pClassRadioButtons[ nClassIndex ]->SetSelected( true ); |
|
bSelected = true; |
|
} |
|
} |
|
} |
|
|
|
LOAD_RESULT result = SetLOD( nClassIndex, nModelIndex, pszModelFile ); |
|
if ( result != LOAD_OKAY ) |
|
{ |
|
sFailedPath = pszModelFile; |
|
return result; |
|
} |
|
} |
|
} |
|
|
|
const float flAnimationLoopStartTime = pItemData->GetFloat( kAnimationLoopable, -1.f ); |
|
SetLoopableTaunt( flAnimationLoopStartTime >= 0.f, flAnimationLoopStartTime ); |
|
|
|
// Load animation files |
|
for ( int nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) |
|
{ |
|
const char* pszQCIKeyName = CFmtStr( kClassQCI, kClassFolders[ nClassIndex ] ); |
|
GetItemValues()->SetString( pszQCIKeyName, pItemData->GetString( pszQCIKeyName ) ); |
|
|
|
const char *pszSourceFile = pItemData->GetString( CFmtStr( kClassAnimationSourceFile, kClassFolders[ nClassIndex ] ) ); |
|
if ( *pszSourceFile ) |
|
{ |
|
if ( !V_IsAbsolutePath( pszSourceFile) ) |
|
{ |
|
V_ComposeFileName( pszBasePath, pszSourceFile, pszLoadPath, sizeof(pszLoadPath) ); |
|
pszSourceFile = pszLoadPath; |
|
} |
|
|
|
// set default selected class |
|
if ( !bSelected ) |
|
{ |
|
m_nSelectedClass = nClassIndex; |
|
|
|
if ( m_pClassRadioButtons[ nClassIndex ] ) |
|
{ |
|
m_pClassRadioButtons[ nClassIndex ]->SetSelected( true ); |
|
bSelected = true; |
|
} |
|
} |
|
} |
|
|
|
LOAD_RESULT result = SetAnimationSource( nClassIndex, pszSourceFile ); |
|
if ( result != LOAD_OKAY ) |
|
{ |
|
sFailedPath = pszSourceFile; |
|
return result; |
|
} |
|
|
|
const char *pszVCDFile = pItemData->GetString( CFmtStr( kClassAnimationVCDFile, kClassFolders[ nClassIndex ] ) ); |
|
if ( *pszVCDFile ) |
|
{ |
|
if ( !V_IsAbsolutePath( pszVCDFile) ) |
|
{ |
|
V_ComposeFileName( pszBasePath, pszVCDFile, pszLoadPath, sizeof(pszLoadPath) ); |
|
pszVCDFile = pszLoadPath; |
|
} |
|
} |
|
|
|
result = SetAnimationVCD( nClassIndex, pszVCDFile ); |
|
if ( result != LOAD_OKAY ) |
|
{ |
|
sFailedPath = pszVCDFile; |
|
return result; |
|
} |
|
} |
|
|
|
Assert( CItemUpload::Manifest()->GetNumTextureTypes() == NUM_MATERIAL_TEXTURE_FILE_TYPE ); |
|
for ( int nSkinIndex = 0; nSkinIndex < CItemUpload::Manifest()->GetNumMaterialSkins(); ++nSkinIndex ) |
|
{ |
|
for ( int nMaterialIndex = 0; nMaterialIndex < NUM_IMPORT_MATERIALS_PER_TEAM; ++nMaterialIndex ) |
|
{ |
|
const char *pszMaterialSkin = CItemUpload::Manifest()->GetMaterialSkin( nSkinIndex ); |
|
const char *pszMaterialVMT = pItemData->GetString( CFmtStr( kMaterialSkinNVMT, pszMaterialSkin, nMaterialIndex ) ); |
|
const char* pszMaterialFile = pItemData->GetString( CFmtStr( kMaterialSkinNFile, pszMaterialSkin, nMaterialIndex, s_pszMaterialFilePrefixes[MATERIAL_FILE_BASETEXTURE] ) ); |
|
if ( *pszMaterialFile && !V_IsAbsolutePath( pszMaterialFile) ) |
|
{ |
|
V_ComposeFileName( pszBasePath, pszMaterialFile, pszLoadPath, sizeof(pszLoadPath) ); |
|
pszMaterialFile = pszLoadPath; |
|
} |
|
|
|
CUtlBuffer sMaterialText; |
|
if ( FStrEq( pszMaterialVMT, "" ) ) |
|
{ |
|
sMaterialText.SetBufferType( true, true ); |
|
g_pFullFileSystem->ReadFile( pszMaterialFile, NULL, sMaterialText ); |
|
pszMaterialVMT = sMaterialText.String(); |
|
} |
|
|
|
if ( !SetMaterialText( nSkinIndex, nMaterialIndex, pszMaterialVMT ) ) |
|
{ |
|
sFailedPath = pszMaterialFile; |
|
return LOAD_FAILED_BADMATERIAL; |
|
} |
|
|
|
for ( int nTextureType = 0; nTextureType < CItemUpload::Manifest()->GetNumTextureTypes(); ++nTextureType ) |
|
{ |
|
const char *pszMaterialTextureFile = pItemData->GetString( CFmtStr( kMaterialSkinNFile, pszMaterialSkin, nMaterialIndex, s_pszMaterialFilePrefixes[nTextureType] ) ); |
|
if ( *pszMaterialTextureFile && !V_IsAbsolutePath( pszMaterialTextureFile) ) |
|
{ |
|
V_ComposeFileName( pszBasePath, pszMaterialTextureFile, pszLoadPath, sizeof(pszLoadPath) ); |
|
pszMaterialTextureFile = pszLoadPath; |
|
} |
|
|
|
if ( !SetMaterial( nSkinIndex, nMaterialIndex, pszMaterialTextureFile, (MATERIAL_FILE_TYPE)nTextureType ) ) |
|
{ |
|
sFailedPath = pszMaterialTextureFile; |
|
return LOAD_FAILED_BADMATERIAL; |
|
} |
|
} |
|
} |
|
} |
|
|
|
return LOAD_OKAY; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFFileImportDialog::LOAD_RESULT CTFFileImportDialog::LoadZip( const char *pszFilePath, const char *pathID, CUtlString &sFailedPath ) |
|
{ |
|
// Unzip the file into the temporary directory |
|
char pszZipName[MAX_PATH]; |
|
V_FileBase( pszFilePath, pszZipName, sizeof(pszZipName) ); |
|
|
|
char pszTempPath[MAX_PATH]; |
|
V_StripExtension( pszFilePath, pszTempPath, sizeof(pszTempPath) ); |
|
|
|
if ( ShouldP4AddOrEdit() ) |
|
{ |
|
char szCorrectCaseFilePath[MAX_PATH]; |
|
g_pFullFileSystem->GetCaseCorrectFullPath( pszFilePath, szCorrectCaseFilePath ); |
|
CP4AutoEditFile a( szCorrectCaseFilePath ); |
|
} |
|
|
|
if ( !g_pFullFileSystem->UnzipFile( pszFilePath, pathID, pszTempPath ) ) |
|
{ |
|
sFailedPath = pszFilePath; |
|
return LOAD_FAILED; |
|
} |
|
|
|
char pszManifest[MAX_PATH]; |
|
V_ComposeFileName( pszTempPath, "manifest.txt", pszManifest, sizeof(pszManifest) ); |
|
|
|
return LoadTxt( pszManifest, pathID, sFailedPath ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFFileImportDialog::SAVE_RESULT CTFFileImportDialog::Save( const char *pszFilePath, const char *pathID ) |
|
{ |
|
KeyValuesAD pData( BuildSessionData( GetItemName() ) ); |
|
|
|
CUtlBuffer sNewText; |
|
sNewText.SetBufferType( true, true ); |
|
pData->RecursiveSaveToFile( sNewText, 0, false, true ); |
|
|
|
if ( !pData->SaveToFile( g_pFullFileSystem, pszFilePath, pathID ) ) |
|
{ |
|
return SAVE_FAILED; |
|
} |
|
return SAVE_OKAY; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::SavePreviewData( CAssetTF &asset ) |
|
{ |
|
KeyValues *pSessionData = asset.GetAdditionalManifestData(); |
|
|
|
if ( m_pPreviewSchema ) |
|
{ |
|
m_pPreviewSchema->deleteThis(); |
|
m_pPreviewSchema = NULL; |
|
} |
|
|
|
KeyValues *pItemSchema = pSessionData->FindKey( CFmtStr( "%s/%s", GetItemValues()->GetName(), kItemSchema ) ); |
|
if ( pItemSchema ) |
|
{ |
|
m_pPreviewSchema = pItemSchema->MakeCopy(); |
|
} |
|
Assert(m_pPreviewSchema); |
|
|
|
// Save the files that were built so we can remove them later |
|
m_vecPreviewFiles = asset.GetBuiltFiles(); |
|
m_vecCustomModFiles = asset.GetModFiles(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::SetupPreviewData() |
|
{ |
|
KeyValuesAD pPreviewSchema( m_pPreviewSchema->MakeCopy() ); |
|
pPreviewSchema->SetString( "item_name", pPreviewSchema->GetString( "name" ) ); |
|
|
|
if ( !ItemSystem()->GetItemSchema()->SetupPreviewItemDefinition( pPreviewSchema ) ) |
|
{ |
|
return false; |
|
} |
|
|
|
// must call this to flush old model and force load new model with the same name |
|
engine->ExecuteClientCmd( "r_flushlod" ); |
|
engine->ExecuteClientCmd( "mat_reloadallmaterials" ); |
|
engine->ExecuteClientCmd( "cl_soundemitter_flush" ); |
|
|
|
if ( !m_pPreviewDialog ) |
|
{ |
|
m_pPreviewDialog = new CImportPreviewItemPanel( this, GetItemValues(), m_nSelectedClass ); |
|
m_pPreviewDialog->MakePopup( false ); |
|
} |
|
|
|
CEconItemView itemData; |
|
itemData.Init( PREVIEW_ITEM_DEFINITION_INDEX, AE_UNIQUE, AE_USE_SCRIPT_VALUE, true ); |
|
itemData.SetClientItemFlags( kEconItemFlagClient_Preview ); |
|
m_pPreviewDialog->PreviewItem( 0, &itemData ); |
|
|
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::CleanupPreviewData() |
|
{ |
|
m_pPreviewDialog.Set( INVALID_PANEL ); |
|
|
|
FOR_EACH_VEC( m_vecPreviewFiles, i ) |
|
{ |
|
const char *pszFileName = m_vecPreviewFiles[ i ].String(); |
|
if ( p4 && V_strstr( pszFileName, "_user_animations.mdl" ) ) |
|
{ |
|
char szCorrectCaseFilePath[MAX_PATH]; |
|
g_pFullFileSystem->GetCaseCorrectFullPath( pszFileName, szCorrectCaseFilePath ); |
|
CP4AutoRevertFile revert( szCorrectCaseFilePath ); |
|
} |
|
else |
|
{ |
|
g_pFullFileSystem->RemoveFile( pszFileName ); |
|
} |
|
} |
|
m_vecPreviewFiles.RemoveAll(); |
|
|
|
FOR_EACH_VEC( m_vecCustomModFiles, i ) |
|
{ |
|
g_pFullFileSystem->RemoveFile( m_vecCustomModFiles[ i ] ); |
|
} |
|
m_vecCustomModFiles.RemoveAll(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::IsMulticlass() |
|
{ |
|
int nClasses = 0; |
|
for ( int nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) |
|
{ |
|
if ( ClassHasModels( nClassIndex ) || ClassHasTauntSources( nClassIndex ) ) |
|
++nClasses; |
|
} |
|
return (nClasses > 1); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
const char *CTFFileImportDialog::GetClassFolder() |
|
{ |
|
const char *pszClassName = NULL; |
|
|
|
for ( int nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) |
|
{ |
|
if ( ClassHasModels( nClassIndex ) || ClassHasTauntSources( nClassIndex ) ) |
|
{ |
|
if ( pszClassName ) |
|
{ |
|
pszClassName = kClassFolderMulticlass; |
|
} |
|
else |
|
{ |
|
pszClassName = kClassFolders[ nClassIndex ]; |
|
} |
|
} |
|
} |
|
|
|
return pszClassName; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::AnyClassHasModels() |
|
{ |
|
for ( int nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) |
|
{ |
|
if ( ClassHasModels( nClassIndex ) ) |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::ClassHasModels( int nClassIndex ) |
|
{ |
|
for ( int nModelIndex = 0; nModelIndex < NUM_IMPORT_LODS; ++nModelIndex ) |
|
{ |
|
if ( V_stricmp( GetItemValues()->GetString( CFmtStr( kClassLODNFile, kClassFolders[ nClassIndex ], nModelIndex ) ), "" ) != 0 ) |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::DidSpecifyAllMaterials() |
|
{ |
|
for ( int nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) |
|
{ |
|
KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassLODN, kClassFolders[ nClassIndex ], 0 ) ); |
|
if ( pKey ) |
|
{ |
|
int nSkinType = GetItemValues()->GetInt( kSkinType ); |
|
int nMaterialCount = pKey->GetInt( "materialCount" ); |
|
for ( int nSkinIndex=0; nSkinIndex<=nSkinType; ++nSkinIndex ) |
|
{ |
|
for ( int nMaterialIndex=0; nMaterialIndex<nMaterialCount; ++nMaterialIndex ) |
|
{ |
|
const char *pszMaterialFile = GetItemValues()->GetString( CFmtStr( kMaterialSkinNFile, CItemUpload::Manifest()->GetMaterialSkin( nSkinIndex ), nMaterialIndex, s_pszMaterialFilePrefixes[MATERIAL_FILE_BASETEXTURE] ) ); |
|
if ( FStrEq( pszMaterialFile, "" ) ) |
|
{ |
|
return false; |
|
} |
|
} |
|
} |
|
|
|
// only need to check materials for one class because we already check AreClassesMaterialCountMatch |
|
break; |
|
} |
|
} // for each LOD |
|
|
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::AreClassesLODCountMatch() |
|
{ |
|
int nCurrentLODCount = 0; |
|
for ( int nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) |
|
{ |
|
int nNumClassLOD = 0; |
|
for ( int nLOD=0; nLOD<NUM_IMPORT_LODS; ++nLOD ) |
|
{ |
|
KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassLODN, kClassFolders[ nClassIndex ], nLOD ) ); |
|
if ( pKey ) |
|
{ |
|
if ( !FStrEq( pKey->GetString( "file" ), "" ) ) |
|
{ |
|
nNumClassLOD++; |
|
} |
|
} |
|
} // for each LOD |
|
|
|
if ( nCurrentLODCount == 0 ) |
|
{ |
|
nCurrentLODCount = nNumClassLOD; |
|
} |
|
else if ( nNumClassLOD != 0 && nCurrentLODCount != nNumClassLOD ) |
|
{ |
|
return false; |
|
} |
|
} // for each class |
|
|
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::AreClassesMaterialCountMatch() |
|
{ |
|
for ( int nLOD=0; nLOD<NUM_IMPORT_LODS; ++nLOD ) |
|
{ |
|
int nCurrentMaterialCount = -1; |
|
for ( int nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) |
|
{ |
|
KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassLODN, kClassFolders[ nClassIndex ], nLOD ) ); |
|
if ( pKey ) |
|
{ |
|
if ( !FStrEq( pKey->GetString( "file" ), "" ) ) |
|
{ |
|
int nMaterialCount = pKey->GetInt( "materialCount" ); |
|
if ( nCurrentMaterialCount == -1 ) |
|
{ |
|
nCurrentMaterialCount = nMaterialCount; |
|
} |
|
else if ( nCurrentMaterialCount != nMaterialCount ) |
|
{ |
|
return false; |
|
} |
|
} |
|
} |
|
} // for each class |
|
} // for each LOD |
|
|
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::AnyClassHasTauntSources() |
|
{ |
|
for ( int nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; ++nClassIndex ) |
|
{ |
|
if ( ClassHasTauntSources( nClassIndex ) ) |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFFileImportDialog::ClassHasTauntSources( int nClassIndex ) |
|
{ |
|
if ( nClassIndex == TF_CLASS_UNDEFINED ) |
|
return false; |
|
|
|
KeyValues *pKey = GetItemValues()->FindKey( CFmtStr( kClassAnimation, kClassFolders[ nClassIndex ] ) ); |
|
if ( pKey ) |
|
{ |
|
const char *pszSource = pKey->GetString( "source_file" ); |
|
if ( pszSource && *pszSource ) |
|
{ |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFFileImportDialog::GetWorkshopData() |
|
{ |
|
CFilePublishDialog *pPublishDialog = dynamic_cast< CFilePublishDialog * >( GetParent() ); |
|
if ( !pPublishDialog ) |
|
return; |
|
|
|
vgui::TextEntry *pTextEntry = pPublishDialog->FindControl<vgui::TextEntry>( "FileTitle" ); |
|
if ( pTextEntry ) |
|
{ |
|
char pszName[1024]; |
|
pTextEntry->GetText( pszName, sizeof(pszName) ); |
|
SetItemName( pszName ); |
|
} |
|
} |
|
|
|
void CTFFileImportDialog::SetWorkshopData() |
|
{ |
|
CFilePublishDialog *pPublishDialog = dynamic_cast< CFilePublishDialog * >( GetParent() ); |
|
if ( !pPublishDialog ) |
|
return; |
|
|
|
pPublishDialog->SetFile( GetItemValues()->GetString( kBuildOutput ), true ); |
|
|
|
vgui::TextEntry *pTextEntry = pPublishDialog->FindControl<vgui::TextEntry>( "FileTitle" ); |
|
if ( pTextEntry ) |
|
{ |
|
pTextEntry->SetText( GetItemValues()->GetString( kItemName ) ); |
|
} |
|
|
|
vgui::EditablePanel* pClassUsagePanel = pPublishDialog->FindControl<vgui::EditablePanel>( "ClassUsagePanel" ); |
|
if ( pClassUsagePanel ) |
|
{ |
|
for ( int nClassIndex = TF_FIRST_NORMAL_CLASS; nClassIndex < TF_LAST_NORMAL_CLASS; nClassIndex++ ) |
|
{ |
|
SetChildButtonSelected( pClassUsagePanel, VarArgs( "ClassCheckBox%d", nClassIndex ), ClassHasModels( nClassIndex ) ); |
|
} |
|
} |
|
} |
|
|
|
|
|
void CTFFileImportDialog::SetLODPanelEnable( bool bEnable, int nModelIndex ) |
|
{ |
|
vgui::Panel *pLODPanel = m_pLODPanels[nModelIndex]; |
|
if ( pLODPanel ) |
|
{ |
|
for ( int i=0; i<pLODPanel->GetChildCount(); ++i ) |
|
{ |
|
pLODPanel->GetChild(i)->SetEnabled( bEnable ); |
|
} |
|
} |
|
} |
|
|
|
|
|
void CTFFileImportDialog::SetSkinType( int nSkinType ) |
|
{ |
|
if ( m_pSkinComboBox && nSkinType < m_pSkinComboBox->GetItemCount() ) |
|
{ |
|
m_pSkinComboBox->ActivateItemByRow( nSkinType ); |
|
} |
|
GetItemValues()->SetInt( kSkinType, nSkinType ); |
|
|
|
UpdateMaterialDisplay(); |
|
|
|
SetDirty( true ); |
|
} |
|
|
|
void CTFFileImportDialog::SetEquipRegion( const char* pszEquipRegion ) |
|
{ |
|
if ( m_pEquipRegionComboBox ) |
|
{ |
|
bool bFound = false; |
|
for ( int i = 0; i < m_pEquipRegionComboBox->GetItemCount(); ++i ) |
|
{ |
|
KeyValues *pKeyValues = m_pEquipRegionComboBox->GetItemUserData( m_pEquipRegionComboBox->GetItemIDFromRow( i ) ); |
|
if ( V_strcasecmp( pszEquipRegion, pKeyValues->GetString( kEquipRegion ) ) == 0 ) |
|
{ |
|
bFound = true; |
|
m_pEquipRegionComboBox->ActivateItemByRow( i ); |
|
break; |
|
} |
|
} |
|
|
|
GetItemValues()->SetString( kEquipRegion, bFound ? pszEquipRegion : "" ); |
|
} |
|
|
|
SetDirty( true ); |
|
} |
|
|
|
void CTFFileImportDialog::SetWorkshopID( const char* pszWorkshopID ) |
|
{ |
|
if ( m_pWorkshopIDTextEntry->IsVisible() ) |
|
{ |
|
GetItemValues()->SetString( kWorkshopID, pszWorkshopID ); |
|
m_pWorkshopIDTextEntry->SetText( GetItemValues()->GetString( kWorkshopID ) ); |
|
} |
|
SetDirty( true ); |
|
} |
|
|
|
bool CTFFileImportDialog::IsTFEnglishNameValid( item_definition_index_t defIndex ) |
|
{ |
|
// check if the name already exist in item schema |
|
if ( m_pTFEnglishNameTextEntry->IsVisible() ) |
|
{ |
|
if ( defIndex == INVALID_ITEM_DEF_INDEX ) |
|
{ |
|
return false; |
|
} |
|
|
|
const char* pszTFEnglishName = GetItemValues()->GetString( kTFEnglishName ); |
|
const CEconItemSchema::ItemDefinitionMap_t& mapItemDefs = ItemSystem()->GetItemSchema()->GetItemDefinitionMap(); |
|
FOR_EACH_MAP_FAST( mapItemDefs, i ) |
|
{ |
|
CEconItemDefinition *pData = mapItemDefs[i]; |
|
const char *pszExistingItemName = pData->GetDefinitionName(); |
|
item_definition_index_t existingItemDefIndex = pData->GetDefinitionIndex(); |
|
if ( existingItemDefIndex != 0 && existingItemDefIndex != defIndex && FStrEq( pszExistingItemName, pszTFEnglishName ) ) |
|
{ |
|
return false; |
|
} |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
void CTFFileImportDialog::SetTFEnglishName( const char* pszTFEnglishName ) |
|
{ |
|
if ( m_pTFEnglishNameTextEntry->IsVisible() ) |
|
{ |
|
GetItemValues()->SetString( kTFEnglishName, pszTFEnglishName ); |
|
m_pTFEnglishNameTextEntry->SetText( GetItemValues()->GetString( kTFEnglishName ) ); |
|
} |
|
SetDirty( true ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
item_definition_index_t CTFFileImportDialog::AddKeyValuesToItemWorkshopSchema( KeyValues *pKV ) |
|
{ |
|
char szItemWorkshopAbsPath[MAX_PATH]; |
|
if ( !GenerateFullPath( kWorkshopSchemaFile, "MOD", szItemWorkshopAbsPath, ARRAYSIZE( szItemWorkshopAbsPath ) ) ) |
|
{ |
|
Warning( "Failed to GenerateFullPath %s\n", kWorkshopSchemaFile ); |
|
return INVALID_ITEM_DEF_INDEX; |
|
} |
|
char szCorrectCaseFilePath[MAX_PATH]; |
|
g_pFullFileSystem->GetCaseCorrectFullPath( szItemWorkshopAbsPath, szCorrectCaseFilePath ); |
|
CP4AutoEditAddFile a( szCorrectCaseFilePath ); |
|
|
|
KeyValuesAD pWorkshopSchema( "WorkshopSchema" ); |
|
|
|
// This file should force a cache refresh of this specific file otherwise we won't write stuff out. |
|
if ( !pWorkshopSchema->LoadFromFile( g_pFullFileSystem, kWorkshopSchemaFile, "MOD", true ) ) |
|
{ |
|
Warning( "Failed to load %s\n", kWorkshopSchemaFile ); |
|
return INVALID_ITEM_DEF_INDEX; |
|
} |
|
|
|
int nNewItemIndex = kStartWorkshopItemIndex; |
|
const char* pszNewItemName = pKV->GetString( kWorkshopName ); |
|
KeyValues *pNewItemKey = NULL; |
|
KeyValues *pLastKey = NULL; |
|
|
|
KeyValues *pItemKey = pWorkshopSchema; |
|
while ( pItemKey ) |
|
{ |
|
const char* pszItemName = pItemKey->GetString( kWorkshopName ); |
|
nNewItemIndex = atoi( pItemKey->GetName() ); |
|
if ( FStrEq( pszItemName, pszNewItemName ) ) |
|
{ |
|
pNewItemKey = pItemKey; |
|
break; |
|
} |
|
|
|
pLastKey = pItemKey; |
|
pItemKey = pItemKey->GetNextKey(); |
|
} |
|
|
|
if ( !pNewItemKey ) |
|
{ |
|
pNewItemKey = pKV->MakeCopy(); |
|
pNewItemKey->SetName( CFmtStr( "%d", nNewItemIndex + 1 ) ); |
|
pLastKey->SetNextKey( pNewItemKey ); |
|
} |
|
else |
|
{ |
|
KeyValuesAD temp( pNewItemKey->MakeCopy() ); |
|
pKV->CopySubkeys( pNewItemKey ); |
|
pNewItemKey->RecursiveMergeKeyValues( temp ); |
|
} |
|
|
|
KeyValues* pPaymentKey = pNewItemKey->FindKey( "payment_rules/0", true ); |
|
pPaymentKey->SetFloat( "workshop_revenue_share", 0.25f ); |
|
pPaymentKey->SetString( "target", GetItemValues()->GetString( kWorkshopID ) ); |
|
pPaymentKey->SetString( "payment_rule_for_itemdef", pNewItemKey->GetName() ); |
|
|
|
pItemKey = pWorkshopSchema; |
|
CUtlBuffer buffer; |
|
while ( pItemKey ) |
|
{ |
|
pItemKey->RecursiveSaveToFile( buffer, 2, false, true ); |
|
pItemKey = pItemKey->GetNextKey(); |
|
} |
|
|
|
if ( !g_pFullFileSystem->WriteFile( szItemWorkshopAbsPath, NULL, buffer ) ) |
|
{ |
|
Warning( "Failed to save new item to %s", szItemWorkshopAbsPath ); |
|
} |
|
|
|
item_definition_index_t defIndex = atoi( pNewItemKey->GetName() ); |
|
return defIndex; |
|
}
|
|
|