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