|
|
//====== Copyright c 1996-2007, Valve Corporation, All rights reserved. =======//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "stdafx.h"
#include "cmdsyncmesh.h"
#include "cmdhandlers.h"
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <direct.h>
#include <atlenc.h>
#include "hammer.h"
#include "Box3D.h" // For units
#include "History.h"
#include "MainFrm.h"
#include "GlobalFunctions.h"
#include "MapDoc.h"
#include "MapView.h"
#include "ToolManager.h"
#include "smartptr.h"
#include "utlhash.h"
#include "generichash.h"
#include "utlbuffer.h"
#include "valve_ipc_win32.h"
#include "threadtools.h"
#include "mapsolid.h"
#include "mapentity.h"
#include "chunkfile.h"
#include "texturebrowser.h"
#include "vmfentitysupport.h"
#include "vmfmeshdatasupport.h"
//
// Fwd declarations
//
class CToolHandler_SyncMesh;
//
// Friendly structures declarations
//
class CMapDoc_Friendly : public CMapDoc { friend class CToolHandler_SyncMesh; }; static CMapDoc_Friendly * _AsFriendlyDoc( CDocument *pDoc ) { if ( pDoc ) { ASSERT_KINDOF( CMapDoc, pDoc ); } return static_cast< CMapDoc_Friendly * >( pDoc ); }
//
// Settings
//
static bool s_opt_vmf_bStoreMdl = true; static bool s_opt_vmf_bStoreDmx = true; static bool s_opt_vmf_bStoreMa = true;
static bool s_opt_maya_bMeshAtOrigin = false; static bool s_opt_maya_bReplaceSelection = true;
static HWND s_hMainWnd = NULL;
//
// Utility routines
//
BOOL PrepareEmptyTempHammerDir( CString &sPath ) { // Create the temp directory
char const *pszVproject = getenv( "VPROJECT" ); if ( !pszVproject ) return FALSE;
sPath = pszVproject; sPath.Replace( '\\', '/' ); sPath.Append( "/models/.hammer.tmp" );
// Remove the folder
if ( !access( sPath, 00) ) { SHFILEOPSTRUCT sfo; memset( &sfo, 0, sizeof( sfo ) ); sfo.hwnd = AfxGetMainWnd()->GetSafeHwnd(); sfo.wFunc = FO_DELETE; sfo.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT; CArrayAutoPtr< char > bufPathCopy( new char [ sPath.GetLength() + 10 ] ); sprintf( bufPathCopy.Get(), "%s/*.*%c%c", sPath, 0, 0 ); Q_FixSlashes( bufPathCopy.Get() ); sfo.pFrom = bufPathCopy.Get(); if ( SHFileOperation( &sfo ) ) return FALSE; }
// Create it empty
BOOL bDir = !mkdir( sPath ) || ( errno == EEXIST ); if ( !bDir ) return FALSE;
return TRUE; }
BOOL GetMdlCacheDir( CString &sPath ) { // Create the temp directory
char const *pszVproject = getenv( "VPROJECT" ); if ( !pszVproject ) return FALSE;
sPath = pszVproject; sPath.Replace( '\\', '/' ); sPath.Append( "/models/.hammer.mdlcache" );
// Create it empty
BOOL bDir = !mkdir( sPath ) || ( errno == EEXIST ); if ( !bDir ) return FALSE;
return TRUE; }
CString GetSystemTempDir() { CString sPath;
if ( char const *pszTemp = getenv("TEMP") ) { sPath = pszTemp; } else if ( char const *pszTmp = getenv("TMP") ) { sPath = pszTmp; } else { sPath = "c:"; }
sPath.Replace( '\\', '/' ); return sPath; }
int ComputeBufferHash( const void *lpvBuffer, size_t numBytes ) { return HashBlock( lpvBuffer, numBytes ); }
int ComputeFileHash( const char *pszFilename ) { CUtlBuffer bufFile; if ( g_pFileSystem->ReadFile( pszFilename, NULL, bufFile ) ) return ComputeBufferHash( bufFile.Base(), bufFile.TellPut() ); return 0; }
BOOL IsFileReadable( const char *pszFilename ) { return 0 == access( pszFilename, 04 ); }
CString GetOtherFileName( CString &sFile, char const *szNewExt, int nCurExtLen ) { return sFile.Left( sFile.GetLength() - nCurExtLen ) + szNewExt; }
void SwitchActiveWindow( HWND hWndActivate ) { HWND hWndFg = GetForegroundWindow(); if ( hWndActivate == hWndFg ) return;
DWORD dwThreadIdFg, dwThreadIdActivate; dwThreadIdFg = GetWindowThreadProcessId( hWndFg, NULL ); dwThreadIdActivate = GetWindowThreadProcessId( hWndActivate, NULL ); if ( dwThreadIdActivate != dwThreadIdFg ) AttachThreadInput( dwThreadIdFg, dwThreadIdActivate, TRUE );
SetForegroundWindow( hWndActivate ); BringWindowToTop( hWndActivate );
if ( dwThreadIdActivate != dwThreadIdFg ) AttachThreadInput( dwThreadIdFg, dwThreadIdActivate, FALSE );
if ( IsIconic( hWndActivate ) ) ShowWindow( hWndActivate, SW_RESTORE ); else ShowWindow( hWndActivate, SW_SHOW ); }
//
// Command handler classes
//
class CToolHandler_SyncMesh : public IToolHandlerInfo { public: CToolHandler_SyncMesh();
public: virtual BOOL UpdateCmdUI( CCmdUI *pCmdUI ); virtual BOOL Execute( UINT uMsg );
public: BOOL RequestDmxLoad( char const *pszCookie, char const *pszDmxFile ); BOOL RequestTexture( char const *pszTextureString ); void AppMainLoopIdle();
protected: BOOL Setup(); BOOL CanExecute();
protected: BOOL CopySelToClipboard(); BOOL CreateTempDoc(); BOOL PasteSelToTempDoc(); BOOL CreateTempFileName(); BOOL ExportTempDoc(); BOOL CloseTempDoc(); BOOL NotifyMaya();
protected: BOOL ProcessDmxRequest(); BOOL DmxPrepareModelFiles(); BOOL DmxDeleteOrigObjects(); BOOL DmxCreateStaticProp();
protected: CWinApp *m_pApp; CMapDoc_Friendly *m_pDoc; CMapView *m_pView; CSelection *m_pSelection;
CSelection m_origSelection; Vector m_vecSelectionCenter;
IHammerClipboard *m_pCopiedObjects; CMapDoc_Friendly *m_pTempDoc; CString m_strTempFileName;
CString m_strMayaRequest; CString m_strCookie;
CString m_strReqCookie; CString m_strReqDmxFileName; CDialog *m_pAsyncDialogRequest; CThreadFastMutex m_mtxRequest;
CString m_strDmxFileName; CString m_strMdlFileName; } g_ToolHandlerSyncMesh;
IToolHandlerInfo *g_pToolHandlerSyncMesh = &g_ToolHandlerSyncMesh;
static void AppMainLoopIdle_Delegate() { g_ToolHandlerSyncMesh.AppMainLoopIdle(); }
CToolHandler_SyncMesh::CToolHandler_SyncMesh() { m_pApp = NULL; m_pDoc = NULL; m_pView = NULL; m_pSelection = NULL; m_pCopiedObjects = NULL; m_pTempDoc = NULL;
m_pAsyncDialogRequest = NULL;
AppRegisterMessageLoopFn( AppMainLoopIdle_Delegate ); }
//////////////////////////////////////////////////////////////////////////
//
// IPC Server class
//
//////////////////////////////////////////////////////////////////////////
class CHammerIpcServer : public CValveIpcServerUtl { public: CHammerIpcServer() : CValveIpcServerUtl( "HAMMER_IPC_SERVER" ) { AppRegisterPostInitFn( AppInit ); AppRegisterPreShutdownFn( AppShutdown ); }
static void AppInit() { g_HammerIpcServer.EnsureRegisteredAndRunning(); } static void AppShutdown() { g_HammerIpcServer.EnsureStoppedAndUnregistered(); }
public: virtual BOOL ExecuteCommand( CUtlBuffer &cmd, CUtlBuffer &res ); } g_HammerIpcServer;
//////////////////////////////////////////////////////////////////////////
//
// Async texture browser interaction
//
//////////////////////////////////////////////////////////////////////////
class CTextureBrowser_Async : public CTextureBrowser { public: CTextureBrowser_Async();
protected: virtual INT_PTR DoModal();
protected: virtual void OnResult( INT_PTR nModalResult ); };
//////////////////////////////////////////////////////////////////////////
//
// Tool handler implementation
//
//////////////////////////////////////////////////////////////////////////
void CToolHandler_SyncMesh::AppMainLoopIdle() { s_hMainWnd = AfxGetMainWnd()->GetSafeHwnd();
CDialog *pAsyncDlg = NULL; // Fetch requests
{ AUTO_LOCK( m_mtxRequest );
if ( !m_strReqDmxFileName.IsEmpty() ) { m_strDmxFileName = m_strReqDmxFileName; m_strReqDmxFileName.Empty(); m_strReqCookie.Empty(); }
if ( m_pAsyncDialogRequest ) { pAsyncDlg = m_pAsyncDialogRequest; } }
if ( !m_strDmxFileName.IsEmpty() ) { ProcessDmxRequest(); m_strDmxFileName.Empty(); SwitchActiveWindow( s_hMainWnd ); }
if ( pAsyncDlg ) { SwitchActiveWindow( s_hMainWnd ); pAsyncDlg->DoModal(); m_pAsyncDialogRequest = NULL; } }
BOOL CToolHandler_SyncMesh::UpdateCmdUI( CCmdUI *pCmdUI ) { s_hMainWnd = AfxGetMainWnd()->GetSafeHwnd();
BOOL bEnabled = Setup() && CanExecute() ; pCmdUI->Enable( bEnabled );
return TRUE; }
BOOL CToolHandler_SyncMesh::Execute( UINT uMsg ) { // Execute the command
BOOL bSuccess = Setup() && CanExecute(); if ( !bSuccess ) return FALSE;
// Determine if we are processing brushed primitives or model selection
// also remember the selection
m_origSelection = *m_pSelection; m_pSelection->GetBoundsCenter( m_vecSelectionCenter );
bSuccess = CopySelToClipboard() && CreateTempDoc() && PasteSelToTempDoc() && CreateTempFileName() && ExportTempDoc();
CloseTempDoc(); if ( bSuccess ) { NotifyMaya(); } else { AfxMessageBox( "Failed to prepare mesh for Maya", MB_ICONSTOP | MB_OK ); }
// Set new tool to pointer
ToolManager()->SetTool( TOOL_POINTER ); return TRUE; }
//
// Stage by stage implementation
//
BOOL CToolHandler_SyncMesh::Setup() { m_pApp = AfxGetApp(); if ( !m_pApp ) return FALSE;
m_pDoc = _AsFriendlyDoc( CMapDoc::GetActiveMapDoc() ); if ( !m_pDoc ) return FALSE;
m_pView = m_pDoc->GetActiveMapView(); if ( !m_pView ) return FALSE;
m_pSelection = m_pDoc->GetSelection(); if ( !m_pSelection ) return FALSE;
if ( m_pSelection->IsEmpty() || m_pSelection->GetCount() < 1 ) return FALSE;
m_pTempDoc = NULL; m_pCopiedObjects = NULL; m_strTempFileName.Empty();
return TRUE; }
BOOL CToolHandler_SyncMesh::CanExecute() { if ( GetMainWnd()->IsShellSessionActive() ) return FALSE;
if ( ToolManager()->GetActiveToolID() == TOOL_FACEEDIT_MATERIAL ) return FALSE;
// Check selection objects
const CMapObjectList *pList = m_pSelection->GetList(); for ( int k = 0; k < pList->Count(); ++ k ) { CMapClass *pElem = (CUtlReference< CMapClass >)pList->Element( k ); MAPCLASSTYPE eType = pElem->GetType(); ( void ) eType;
if ( pElem->IsMapClass( MAPCLASS_TYPE( CMapEntity ) ) ) { if ( !static_cast< CMapEntity * >( pElem )->IsClass( "prop_static" ) ) return FALSE; else continue; } else if ( pElem->IsMapClass( MAPCLASS_TYPE( CMapSolid ) ) ) continue; else return FALSE; }
return TRUE; }
BOOL CToolHandler_SyncMesh::CopySelToClipboard() { m_pCopiedObjects = IHammerClipboard::CreateInstance(); m_pDoc->Copy( m_pCopiedObjects );
return TRUE; }
BOOL CToolHandler_SyncMesh::CreateTempDoc() { CDocTemplate *pTemplate = NULL; if ( POSITION pos = m_pApp->GetFirstDocTemplatePosition() ) { pTemplate = m_pApp->GetNextDocTemplate( pos ); }
if ( !pTemplate ) return FALSE;
// Force a new document file created
m_pTempDoc = _AsFriendlyDoc( pTemplate->OpenDocumentFile( NULL ) ); if ( !m_pTempDoc ) return FALSE;
return TRUE; }
BOOL CToolHandler_SyncMesh::PasteSelToTempDoc() { // Force snapping off in the doc
bool bSnapping = m_pTempDoc->IsSnapEnabled(); if ( bSnapping ) m_pTempDoc->OnMapSnaptogrid();
// Perform the paste
Vector vecPasteOffset( 0, 0, 0 ), vecSelCenter; m_pSelection->GetBoundsCenter( vecSelCenter ); vecPasteOffset -= vecSelCenter;
if ( !s_opt_maya_bMeshAtOrigin ) vecPasteOffset = Vector( 0, 0, 0 ); m_pTempDoc->Paste( m_pCopiedObjects, m_pTempDoc->GetMapWorld(), vecPasteOffset, QAngle(0, 0, 0), NULL, false, NULL); // Restore snapping mode
if ( bSnapping ) m_pTempDoc->OnMapSnaptogrid();
return TRUE; }
BOOL CToolHandler_SyncMesh::CreateTempFileName() { m_strTempFileName = GetSystemTempDir() + "/hammer_geom.vmf";
ATLTRACE( "[SyncMesh] Temp file name is '%s'\n", (LPCTSTR) m_strTempFileName ); return TRUE; }
BOOL CToolHandler_SyncMesh::ExportTempDoc() { extern BOOL bSaveVisiblesOnly; CAutoPushPop< BOOL > _auto_bSaveVisiblesOnly( bSaveVisiblesOnly, FALSE );
BOOL bSaved = m_pTempDoc->OnSaveDocument( m_strTempFileName ); if ( !bSaved ) return FALSE;
m_strMayaRequest = "hammerBrush";
return TRUE; }
BOOL CToolHandler_SyncMesh::CloseTempDoc() { if ( m_pCopiedObjects ) { m_pCopiedObjects->Destroy(); m_pCopiedObjects = NULL; }
if ( m_pTempDoc ) { m_pTempDoc->SetModifiedFlag( FALSE ); m_pTempDoc->OnFileClose(); }
// Activate the view that used to be active
if ( m_pView ) { m_pDoc->SetActiveView( m_pView ); }
return TRUE; }
BOOL CToolHandler_SyncMesh::NotifyMaya() { CValveIpcClientUtl ipc( "MAYA_VST_UIHOOK_IPC_SERVER" ); while ( !ipc.Connect() ) { int iResponse = AfxMessageBox( "Cannot connect to Maya.\n" "Make sure you have Maya running and proper plug-ins loaded and try again.", MB_ICONWARNING | MB_RETRYCANCEL ); if ( iResponse != IDRETRY ) return FALSE; }
// Update the cookie
m_strCookie.Format( "%d", 1 + atoi( ( LPCTSTR ) m_strCookie ) );
CUtlBuffer cmd;
cmd.PutString( m_strMayaRequest ); cmd.PutString( m_strCookie ); cmd.PutString( m_strTempFileName );
CUtlBuffer res; res.EnsureCapacity( 2 * MAX_PATH ); if ( !ipc.ExecuteCommand( cmd, res ) ) goto comm_error;
int uCode = res.GetInt(); switch ( uCode ) { case 0: // Error
{ char chErrorString[ MAX_PATH ] = {0}; sprintf( chErrorString, "Generic Error" ); res.GetString( chErrorString, sizeof( chErrorString ) - 1 ); AfxMessageBox( chErrorString, MB_ICONSTOP ); return FALSE; } case 1: // OK
return TRUE; default: goto comm_error; }
comm_error: AfxMessageBox( "Cannot communicate with Maya.\n" "Make sure you have Maya running and proper plug-ins loaded and try again.", MB_ICONSTOP | MB_OK ); return FALSE; }
BOOL CToolHandler_SyncMesh::RequestDmxLoad( char const *pszCookie, char const *pszDmxFile ) { if ( stricmp( pszCookie, m_strCookie ) ) return FALSE;
AUTO_LOCK( m_mtxRequest ); m_strReqDmxFileName = pszDmxFile; m_strReqCookie = pszCookie; return TRUE; }
BOOL CToolHandler_SyncMesh::RequestTexture( char const *pszTextureString ) { AFX_MANAGE_STATE( AfxGetStaticModuleState() );
if ( ::GetLastActivePopup( s_hMainWnd ) != s_hMainWnd ) return FALSE;
{ AUTO_LOCK( m_mtxRequest ); if ( m_pAsyncDialogRequest ) return FALSE; CTextureBrowser_Async *pBrowser = new CTextureBrowser_Async; if ( !pBrowser ) return FALSE; m_pAsyncDialogRequest = pBrowser; pBrowser->SetTextureFormat( tfVMT ); if ( pszTextureString ) { pBrowser->SetInitialTexture( pszTextureString ); } }
return TRUE; }
BOOL CToolHandler_SyncMesh::ProcessDmxRequest() { CWaitCursor curWait; CUtlInplaceBuffer bufIndex( 0, 0, CUtlInplaceBuffer::TEXT_BUFFER );
if ( !DmxDeleteOrigObjects() ) goto failed;
if ( !g_pFileSystem->ReadFile( m_strDmxFileName, NULL, bufIndex ) ) goto failed;
while ( char *pszEntry = bufIndex.InplaceGetLinePtr() ) { if ( !*pszEntry ) continue;
m_strDmxFileName = pszEntry; m_strDmxFileName += ".dmx";
if ( DmxPrepareModelFiles() ) DmxCreateStaticProp();
}
m_strCookie.Format( "%d", 1 + atoi( ( LPCTSTR ) m_strCookie ) ); // TODO: for now we just bump the cookie and prevent subsequent import
return TRUE;
failed: AfxMessageBox( "Failed to apply Maya-edited geometry", MB_ICONSTOP | MB_OK ); return TRUE; }
BOOL CToolHandler_SyncMesh::DmxPrepareModelFiles() { if ( !s_opt_vmf_bStoreMdl ) return TRUE;
// Create the temp directory
char const *pszVproject = getenv( "VPROJECT" ); CString sPath; if ( !PrepareEmptyTempHammerDir( sPath ) ) return FALSE;
// Copy the dmx
CString sDmx = sPath + "/mayamesh.dmx"; if ( !CopyFile( m_strDmxFileName, sDmx, FALSE ) ) return FALSE;
// Create a sample .qc
CString sQc = sPath + "/mayamesh.qc"; if ( FILE *fQc = fopen( sQc, "wt" ) ) { fprintf( fQc, " $modelname .hammer.tmp/studiomdl.mdl \n" " $scale 1.0 \n" " $body \"Body\" \"mayamesh.dmx\" \n" " $staticprop \n" " $upaxis y \n" " $sequence \"idle\" \"mayamesh\" fps 30 \n" " $collisionmodel \"mayamesh.dmx\" { $automass $concave }\n" ); fclose( fQc ); } else return FALSE;
// Compile the mdl
CString sExeName; sExeName.Format( "%s/../bin/studiomdl.exe", pszVproject ); CString sMdlCmdLine; sMdlCmdLine.Format( "%s/../bin/studiomdl.exe -nop4 -fastbuild \"%s\"", pszVproject, ( LPCTSTR ) sQc ); STARTUPINFO si; memset( &si, 0, sizeof( si ) ); si.cb = sizeof( si ); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE;
PROCESS_INFORMATION pi; memset( &pi, 0, sizeof( pi ) ); // system( sMdlCmdLine );
BOOL bCreatedProcess = CreateProcess( sExeName.GetBuffer(), sMdlCmdLine.GetBuffer(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ); bCreatedProcess; if ( pi.hThread ) { CloseHandle( pi.hThread ); pi.hThread = NULL; }
if ( pi.hProcess ) { WaitForSingleObject( pi.hProcess, INFINITE ); CloseHandle( pi.hProcess ); pi.hProcess = NULL; }
// We should have the model now
CString sMdl = sPath + "/studiomdl.mdl"; if ( !IsFileReadable( sMdl ) ) return FALSE;
m_strMdlFileName = sMdl; return TRUE; }
BOOL CToolHandler_SyncMesh::DmxDeleteOrigObjects() { // Make sure we are still in the same document and same selection
if ( m_pDoc != m_origSelection.GetMapDoc() ) return FALSE;
if ( s_opt_maya_bReplaceSelection ) { m_pDoc->OnEditDelete(); } else { GetHistory()->MarkUndoPosition( m_pSelection->GetList(), "Delete" );
// Delete objects in selection
const CMapObjectList &lst = *m_origSelection.GetList(); for ( int k = 0; k < lst.Count(); ++ k ) { CMapClass *pObj = (CUtlReference< CMapClass >)lst.Element( k ); m_pDoc->DeleteObject( pObj ); } m_pSelection->RemoveAll(); m_pDoc->SetModifiedFlag(); }
return TRUE; }
BOOL CToolHandler_SyncMesh::DmxCreateStaticProp() { // Make sure we are still in the same document and same selection
if ( m_pDoc != m_origSelection.GetMapDoc() ) return FALSE;
// Compute model hash
int iMdlHash = ComputeFileHash( m_strDmxFileName ); if ( !iMdlHash ) return FALSE;
// Crack the DMX file coordinates
float vecDmxOffset[3] = {0}; if ( m_strDmxFileName.GetLength() > 37 && m_strDmxFileName[ m_strDmxFileName.GetLength() - 37 ] == '@' ) { int arrV[4] = {0}; for ( int k = 0; k < 4; ++ k ) { CString sParse = m_strDmxFileName.Mid( m_strDmxFileName.GetLength() - 37 + 1 + 8 * k, 8 ); arrV[k] = strtoul( sParse, NULL, 16 ); } for ( int k = 1; k < 4; ++ k ) { vecDmxOffset[ k - 1 ] = reinterpret_cast< float & >( arrV[ k ] ); } }
// Move the model to the mdl cache section
CString sMdlPath; if ( !GetMdlCacheDir( sMdlPath ) ) return FALSE; CString sMdlCacheFile; sMdlCacheFile.Format( "%s/%08X.mdl", ( LPCTSTR ) sMdlPath, iMdlHash ); CString sMdlCacheFileRel = sMdlCacheFile.Mid( strlen( getenv( "VPROJECT" ) ) + 1 );
if ( s_opt_vmf_bStoreMdl ) { char const * arrFiles[] = { ".mdl", ".vvd", ".dx90.vtx", ".phy", ".ss2" }; bool arrRequired[] = { true, true, true, false, false }; for ( int j = 0; j < ARRAYSIZE( arrFiles ); ++ j ) { CString sSrc = GetOtherFileName( m_strMdlFileName, arrFiles[ j ], 4 ); CString sDest = GetOtherFileName( sMdlCacheFile, arrFiles[j], 4 ); CopyFile( sSrc, sDest, FALSE ); if ( !IsFileReadable( sDest ) && arrRequired[ j ] ) return FALSE; }
// Patch the MDL file
if ( FILE *fp = fopen( sMdlCacheFile, "r+b" ) ) { fseek( fp, 12, SEEK_SET ); fprintf( fp, "%s%c%c", ( (LPCTSTR) sMdlCacheFileRel ) + strlen( "models/" ), 0, 0 ); fclose( fp ); } else return FALSE; }
if ( s_opt_vmf_bStoreDmx ) { // Copy the dmx file as well
CString sDmxCacheFile; sDmxCacheFile.Format( "%s/%08X.dmx", ( LPCTSTR ) sMdlPath, iMdlHash ); CopyFile( m_strDmxFileName, sDmxCacheFile, FALSE ); if ( !IsFileReadable( sDmxCacheFile ) ) return FALSE; }
if ( s_opt_vmf_bStoreMa ) { // Copy the maya file as well
CString sMayaCacheFile; sMayaCacheFile.Format( "%s/%08X.ma", ( LPCTSTR ) sMdlPath, iMdlHash ); CopyFile( GetOtherFileName( m_strDmxFileName, ".ma", 4 ), sMayaCacheFile, FALSE ); if ( !IsFileReadable( sMayaCacheFile ) ) return FALSE; }
// Create the static prop
Vector vecEntityPos( vecDmxOffset[0], vecDmxOffset[1], vecDmxOffset[2] ); if ( s_opt_maya_bMeshAtOrigin ) vecEntityPos += m_vecSelectionCenter;
CMapEntity *pEnt = m_pDoc->CreateEntity( "prop_static", vecEntityPos.x, vecEntityPos.y, vecEntityPos.z ); pEnt->SetKeyValue( "model", sMdlCacheFileRel ); // TODO: proper DMX/MDL encoding
return TRUE; }
//////////////////////////////////////////////////////////////////////////
//
// Async texture browser implementation
//
//////////////////////////////////////////////////////////////////////////
CTextureBrowser_Async::CTextureBrowser_Async() : CTextureBrowser( AfxGetMainWnd() ) { NULL; }
INT_PTR CTextureBrowser_Async::DoModal() { INT_PTR nResult = CTextureBrowser::DoModal(); OnResult( nResult ); delete this; return nResult; }
void CTextureBrowser_Async::OnResult( INT_PTR nModalResult ) { CValveIpcClientUtl ipc( "MAYA_VST_UIHOOK_IPC_SERVER" ); if ( !ipc.Connect() ) return;
CUtlBuffer cmd;
cmd.PutString( "textureSelected" ); if ( nModalResult == IDOK ) { cmd.PutString( m_cTextureWindow.szCurTexture ); } else { cmd.PutString( "" ); }
CUtlBuffer res; res.EnsureCapacity( 2 * MAX_PATH );
ipc.ExecuteCommand( cmd, res ); }
//////////////////////////////////////////////////////////////////////////
//
// Handling commands from Maya
//
//////////////////////////////////////////////////////////////////////////
BOOL CHammerIpcServer::ExecuteCommand( CUtlBuffer &cmd, CUtlBuffer &res ) { char szCmd[ MAX_PATH ] = {0}; cmd.GetString( szCmd, sizeof( szCmd ) - 1 );
if ( !stricmp( szCmd, "mayaDmx" ) ) { cmd.GetString( szCmd, sizeof( szCmd ) - 1 ); CString sCookie = szCmd;
cmd.GetString( szCmd, sizeof( szCmd ) - 1 ); char const *szDmxName = szCmd;
if ( !g_ToolHandlerSyncMesh.RequestDmxLoad( sCookie, szDmxName ) ) { res.PutInt( 0 ); res.PutString( "Invalid mesh synchronization request!" ); return TRUE; } res.PutInt( 1 ); return TRUE; }
if ( !stricmp( szCmd, "textureBrowse" ) ) { cmd.GetString( szCmd, sizeof( szCmd ) - 1 ); char const *szTextureName = szCmd;
if ( !g_ToolHandlerSyncMesh.RequestTexture( szTextureName ) ) { res.PutInt( 0 ); res.PutString( "Cannot request texture!" ); return TRUE; }
res.PutInt( 1 ); return TRUE; }
return FALSE; }
//////////////////////////////////////////////////////////////////////////
//
// Special implementation of custom load/save chunks for entities
//
//////////////////////////////////////////////////////////////////////////
class CSyncMesh_SaveLoadHandler : public CVmfMeshDataSupport_SaveLoadHandler { public: CSyncMesh_SaveLoadHandler(); ~CSyncMesh_SaveLoadHandler();
public: virtual char const *GetCustomSectionName() { return "meshdata"; }
public: virtual ChunkFileResult_t SaveVMF( CChunkFile *pFile, IMapEntity_SaveInfo_t *pSaveInfo );
protected: virtual ChunkFileResult_t OnFileDataLoaded( CUtlBuffer &bufData ); virtual ChunkFileResult_t OnFileDataWriting( CChunkFile *pFile, char const *szHash ); }; static CSyncMesh_SaveLoadHandler g_syncmesh_saveloadhandler;
CSyncMesh_SaveLoadHandler::CSyncMesh_SaveLoadHandler() { VmfInstallMapEntitySaveLoadHandler( this ); }
CSyncMesh_SaveLoadHandler::~CSyncMesh_SaveLoadHandler() { NULL; }
ChunkFileResult_t CSyncMesh_SaveLoadHandler::SaveVMF( CChunkFile *pFile, IMapEntity_SaveInfo_t *pSaveInfo ) { if ( !m_pEntity->IsClass( "prop_static" ) ) return ChunkFile_Ok;
LPCTSTR szModelName = m_pEntity->GetKeyValue( "model" ); if ( !szModelName || !*szModelName ) return ChunkFile_Ok;
CString sMdlPath; if ( !GetMdlCacheDir( sMdlPath ) ) return ChunkFile_Ok;
CString sMdlRelPath = sMdlPath.Mid( strlen( getenv( "VPROJECT" ) ) + 1 ) + "/"; if ( !StringHasPrefix( szModelName, sMdlRelPath ) ) return ChunkFile_Ok;
// Model is under our special cache path
char szModelHash[ 16 ] = {0}; sprintf( szModelHash, "%.8s", szModelName + sMdlRelPath.GetLength() ); return WriteDataChunk( pFile, szModelHash ); }
ChunkFileResult_t CSyncMesh_SaveLoadHandler::OnFileDataWriting( CChunkFile *pFile, char const *szHash ) { ChunkFileResult_t eResult;
LPCTSTR szModelName = m_pEntity->GetKeyValue( "model" ); CString sMdlPath; GetMdlCacheDir( sMdlPath );
CString sMdlRelPath = sMdlPath.Mid( strlen( getenv( "VPROJECT" ) ) + 1 ) + "/";
char szModelHash[ 16 ] = {0}; sprintf( szModelHash, "%.8s", szModelName + sMdlRelPath.GetLength() );
// Write files
char const * arrFiles[] = { ".ma", ".dmx", ".mdl", ".vvd", ".dx90.vtx", ".phy", ".ss2" }; char const * arrNames[] = { "maa", "dmx", "mdl", "vvd", "vtx", "phy", "ss2" }; bool bOptNames[] = { s_opt_vmf_bStoreMa, s_opt_vmf_bStoreDmx, s_opt_vmf_bStoreMdl, s_opt_vmf_bStoreMdl, s_opt_vmf_bStoreMdl, s_opt_vmf_bStoreMdl, s_opt_vmf_bStoreMdl }; bool bOptRequired[] = { true, true, true, true, true, false }; for ( int j = 0; j < ARRAYSIZE( arrFiles ); ++ j ) { if ( !bOptNames[j] ) continue;
CString sSrc = sMdlPath + CString( "/" ) + CString( szModelHash ) + arrFiles[j];
CUtlBuffer bufFile; if ( !g_pFileSystem->ReadFile( sSrc, NULL, bufFile ) ) { if ( !bOptRequired[ j ] ) continue; else return ChunkFile_OpenFail; }
eResult = WriteBufferData( pFile, bufFile, arrNames[j] ); if ( eResult != ChunkFile_Ok ) return eResult; }
return ChunkFile_Ok; }
ChunkFileResult_t CSyncMesh_SaveLoadHandler::OnFileDataLoaded( CUtlBuffer &bufData ) { char const * arrFiles[] = { ".ma", ".dmx", ".mdl", ".vvd", ".dx90.vtx", ".phy", ".ss2" }; char const * arrNames[] = { "maa", "dmx", "mdl", "vvd", "vtx", "phy", "ss2" };
char const *pFileExt = NULL;
// Determine the file name to save
for ( int j = 0; j < ARRAYSIZE( arrFiles ); ++ j ) { if ( !stricmp( m_hLoadHeader.sPrefix, arrNames[j] ) ) { pFileExt = arrFiles[j]; break; } } if ( !pFileExt ) return ChunkFile_Fail;
// The filename
CString sSaveFileName; if ( !GetMdlCacheDir( sSaveFileName ) ) return ChunkFile_Fail; sSaveFileName += "/"; sSaveFileName += m_hLoadHeader.sHash; sSaveFileName += pFileExt; // We have file data, save it
if ( FILE *f = fopen( sSaveFileName, "wb" ) ) { fwrite( bufData.Base(), 1, bufData.TellPut(), f ); fclose( f ); } else return ChunkFile_Fail;
return ChunkFile_Ok; }
|